diff --git a/Cargo.lock b/Cargo.lock
index 7a9f1966791..24479c72156 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -140,26 +140,6 @@ version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
-[[package]]
-name = "bindgen"
-version = "0.72.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895"
-dependencies = [
- "bitflags 2.9.4",
- "cexpr",
- "clang-sys",
- "itertools 0.12.1",
- "log 0.4.28",
- "prettyplease",
- "proc-macro2",
- "quote",
- "regex",
- "rustc-hash 2.1.1",
- "shlex",
- "syn",
-]
-
[[package]]
name = "bitflags"
version = "1.3.2"
@@ -270,15 +250,6 @@ dependencies = [
"shlex",
]
-[[package]]
-name = "cexpr"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
-dependencies = [
- "nom",
-]
-
[[package]]
name = "cfg-if"
version = "1.0.3"
@@ -378,17 +349,6 @@ dependencies = [
"windows-link 0.2.0",
]
-[[package]]
-name = "clang-sys"
-version = "1.8.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
-dependencies = [
- "glob",
- "libc",
- "libloading",
-]
-
[[package]]
name = "clap"
version = "4.5.48"
@@ -491,9 +451,6 @@ dependencies = [
"serde_json",
"tracing",
"tracing-subscriber",
- "tree-sitter",
- "tree-sitter-embedded-template",
- "tree-sitter-swift",
"yeast",
]
@@ -545,15 +502,6 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
-[[package]]
-name = "convert_case"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "baaaa0ecca5b51987b9423ccdc971514dd8b0bb7b4060b983d3664dad3f1f89f"
-dependencies = [
- "unicode-segmentation",
-]
-
[[package]]
name = "core-foundation-sys"
version = "0.8.7"
@@ -807,12 +755,6 @@ dependencies = [
"typeid",
]
-[[package]]
-name = "fastrand"
-version = "2.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6"
-
[[package]]
name = "figment"
version = "0.10.19"
@@ -861,12 +803,6 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
-[[package]]
-name = "foldhash"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
-
[[package]]
name = "form_urlencoded"
version = "1.2.2"
@@ -951,18 +887,7 @@ checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
dependencies = [
"allocator-api2",
"equivalent",
- "foldhash 0.1.5",
-]
-
-[[package]]
-name = "hashbrown"
-version = "0.16.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
-dependencies = [
- "allocator-api2",
- "equivalent",
- "foldhash 0.2.0",
+ "foldhash",
]
[[package]]
@@ -1167,15 +1092,6 @@ dependencies = [
"serde_core",
]
-[[package]]
-name = "indoc"
-version = "2.0.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706"
-dependencies = [
- "rustversion",
-]
-
[[package]]
name = "inlinable_string"
version = "0.1.15"
@@ -1305,16 +1221,6 @@ version = "0.2.175"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543"
-[[package]]
-name = "libloading"
-version = "0.8.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55"
-dependencies = [
- "cfg-if",
- "windows-link 0.2.0",
-]
-
[[package]]
name = "line-index"
version = "0.1.2"
@@ -1380,12 +1286,6 @@ dependencies = [
"autocfg",
]
-[[package]]
-name = "minimal-lexical"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
-
[[package]]
name = "miniz_oxide"
version = "0.8.9"
@@ -1432,16 +1332,6 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451"
-[[package]]
-name = "nom"
-version = "7.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
-dependencies = [
- "memchr",
- "minimal-lexical",
-]
-
[[package]]
name = "notify"
version = "8.2.0"
@@ -1569,12 +1459,6 @@ dependencies = [
"windows-targets 0.52.6",
]
-[[package]]
-name = "pathdiff"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3"
-
[[package]]
name = "pear"
version = "0.2.9"
@@ -1633,35 +1517,6 @@ dependencies = [
"indexmap 2.14.0",
]
-[[package]]
-name = "phf"
-version = "0.13.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf"
-dependencies = [
- "phf_shared",
- "serde",
-]
-
-[[package]]
-name = "phf_generator"
-version = "0.13.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737"
-dependencies = [
- "fastrand",
- "phf_shared",
-]
-
-[[package]]
-name = "phf_shared"
-version = "0.13.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266"
-dependencies = [
- "siphasher",
-]
-
[[package]]
name = "pin-project-lite"
version = "0.2.16"
@@ -1704,25 +1559,6 @@ dependencies = [
"zerocopy",
]
-[[package]]
-name = "prettyplease"
-version = "0.2.37"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
-dependencies = [
- "proc-macro2",
- "syn",
-]
-
-[[package]]
-name = "proc-macro-crate"
-version = "3.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f"
-dependencies = [
- "toml_edit 0.25.11+spec-1.1.0",
-]
-
[[package]]
name = "proc-macro2"
version = "1.0.101"
@@ -2426,15 +2262,6 @@ version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001"
-[[package]]
-name = "relative-path"
-version = "2.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bca40a312222d8ba74837cb474edef44b37f561da5f773981007a10bbaa992b0"
-dependencies = [
- "serde",
-]
-
[[package]]
name = "rowan"
version = "0.15.15"
@@ -2448,57 +2275,6 @@ dependencies = [
"text-size",
]
-[[package]]
-name = "rquickjs"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a135375fbac5ba723bb6a48f432a72f81539cedde422f0121a86c7c4e96d8e0d"
-dependencies = [
- "rquickjs-core",
- "rquickjs-macro",
-]
-
-[[package]]
-name = "rquickjs-core"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bccb7121a123865c8ace4dea42e7ed84d78b90cbaf4ca32c59849d8d210c9672"
-dependencies = [
- "hashbrown 0.16.1",
- "phf",
- "relative-path",
- "rquickjs-sys",
-]
-
-[[package]]
-name = "rquickjs-macro"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "89f93602cc3112c7f30bf5f29e722784232138692c7df4c52ebbac7e035d900d"
-dependencies = [
- "convert_case",
- "fnv",
- "ident_case",
- "indexmap 2.14.0",
- "phf_generator",
- "phf_shared",
- "proc-macro-crate",
- "proc-macro2",
- "quote",
- "rquickjs-core",
- "syn",
-]
-
-[[package]]
-name = "rquickjs-sys"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57b1b6528590d4d65dc86b5159eae2d0219709546644c66408b2441696d1d725"
-dependencies = [
- "bindgen",
- "cc",
-]
-
[[package]]
name = "rust-extractor-macros"
version = "0.1.0"
@@ -2804,18 +2580,6 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
-[[package]]
-name = "siphasher"
-version = "1.0.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649"
-
-[[package]]
-name = "smallbitvec"
-version = "2.6.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b0e903ee191d8f7a8fbf0d712c3a1699d19e04ceba5ad1eb673053c7d938a09"
-
[[package]]
name = "smallvec"
version = "1.15.1"
@@ -2972,7 +2736,7 @@ dependencies = [
"serde",
"serde_spanned 0.6.9",
"toml_datetime 0.6.11",
- "toml_edit 0.22.27",
+ "toml_edit",
]
[[package]]
@@ -3008,15 +2772,6 @@ dependencies = [
"serde_core",
]
-[[package]]
-name = "toml_datetime"
-version = "1.1.1+spec-1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7"
-dependencies = [
- "serde_core",
-]
-
[[package]]
name = "toml_edit"
version = "0.22.27"
@@ -3031,18 +2786,6 @@ dependencies = [
"winnow 0.7.13",
]
-[[package]]
-name = "toml_edit"
-version = "0.25.11+spec-1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b"
-dependencies = [
- "indexmap 2.14.0",
- "toml_datetime 1.1.1+spec-1.1.0",
- "toml_parser",
- "winnow 1.0.2",
-]
-
[[package]]
name = "toml_parser"
version = "1.1.2+spec-1.1.0"
@@ -3064,12 +2807,6 @@ version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d163a63c116ce562a22cda521fcc4d79152e7aba014456fb5eb442f6d6a10109"
-[[package]]
-name = "topological-sort"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea68304e134ecd095ac6c3574494fc62b909f416c4fca77e440530221e549d3d"
-
[[package]]
name = "tracing"
version = "0.1.41"
@@ -3166,30 +2903,6 @@ dependencies = [
"tree-sitter-language",
]
-[[package]]
-name = "tree-sitter-generate"
-version = "0.26.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3fb2e1bdb1d5f9d23cd5fa68cf98b3bedbd223c92a2edd60bbcf30bcf7180a5"
-dependencies = [
- "bitflags 2.9.4",
- "dunce",
- "indexmap 2.14.0",
- "indoc",
- "log 0.4.28",
- "pathdiff",
- "regex",
- "regex-syntax",
- "rquickjs",
- "rustc-hash 2.1.1",
- "semver",
- "serde",
- "serde_json",
- "smallbitvec",
- "thiserror",
- "topological-sort",
-]
-
[[package]]
name = "tree-sitter-json"
version = "0.24.8"
@@ -3236,15 +2949,6 @@ dependencies = [
"tree-sitter-language",
]
-[[package]]
-name = "tree-sitter-swift"
-version = "0.7.2"
-dependencies = [
- "cc",
- "tree-sitter-generate",
- "tree-sitter-language",
-]
-
[[package]]
name = "triomphe"
version = "0.1.14"
@@ -3294,12 +2998,6 @@ version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0"
-[[package]]
-name = "unicode-segmentation"
-version = "1.13.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c"
-
[[package]]
name = "unicode-xid"
version = "0.2.6"
@@ -3694,9 +3392,6 @@ name = "winnow"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ee1708bef14716a11bae175f579062d4554d95be2c6829f518df847b7b3fdd0"
-dependencies = [
- "memchr",
-]
[[package]]
name = "wit-bindgen"
diff --git a/Cargo.toml b/Cargo.toml
index 9f3780bb1d7..21bde543280 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -9,7 +9,6 @@ members = [
"shared/yeast-schema",
"ruby/extractor",
"unified/extractor",
- "unified/extractor/tree-sitter-swift",
"unified/swift-syntax-rs",
"rust/extractor",
"rust/extractor/macros",
diff --git a/MODULE.bazel b/MODULE.bazel
index b6d7319a13c..24260271eca 100644
--- a/MODULE.bazel
+++ b/MODULE.bazel
@@ -109,7 +109,6 @@ use_repo(
tree_sitter_extractors_deps,
"vendor_ts__anyhow-1.0.100",
"vendor_ts__argfile-0.2.1",
- "vendor_ts__cc-1.2.61",
"vendor_ts__chalk-ir-0.104.0",
"vendor_ts__chrono-0.4.42",
"vendor_ts__clap-4.5.48",
@@ -157,9 +156,7 @@ use_repo(
"vendor_ts__tracing-subscriber-0.3.20",
"vendor_ts__tree-sitter-0.26.8",
"vendor_ts__tree-sitter-embedded-template-0.25.0",
- "vendor_ts__tree-sitter-generate-0.26.8",
"vendor_ts__tree-sitter-json-0.24.8",
- "vendor_ts__tree-sitter-language-0.1.5",
"vendor_ts__tree-sitter-python-0.23.6",
"vendor_ts__tree-sitter-ql-0.23.1",
"vendor_ts__tree-sitter-ruby-0.23.1",
diff --git a/defs.bzl b/defs.bzl
index d6748d83176..d4c5ea5e262 100644
--- a/defs.bzl
+++ b/defs.bzl
@@ -1,5 +1,8 @@
-codeql_platform = select({
- "@platforms//os:linux": "linux64",
- "@platforms//os:macos": "osx64",
- "@platforms//os:windows": "win64",
-})
+load("//misc/bazel:os.bzl", "codeql_platform_select")
+
+codeql_platform = codeql_platform_select(
+ linux64 = "linux64",
+ linux_arm64 = "linux-arm64",
+ osx64 = "osx64",
+ win64 = "win64",
+)
diff --git a/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.26.2.rst b/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.26.2.rst
new file mode 100644
index 00000000000..845988894f0
--- /dev/null
+++ b/docs/codeql/codeql-overview/codeql-changelog/codeql-cli-2.26.2.rst
@@ -0,0 +1,79 @@
+.. _codeql-cli-2.26.2:
+
+==========================
+CodeQL 2.26.2 (2026-07-23)
+==========================
+
+.. contents:: Contents
+ :depth: 2
+ :local:
+ :backlinks: none
+
+This is an overview of changes in the CodeQL CLI and relevant CodeQL query and library packs. For additional updates on changes to the CodeQL code scanning experience, check out the `code scanning section on the GitHub blog `__, `relevant GitHub Changelog updates `__, `changes in the CodeQL extension for Visual Studio Code `__, and the `CodeQL Action changelog `__.
+
+Security Coverage
+-----------------
+
+CodeQL 2.26.2 runs a total of 497 security queries when configured with the Default suite (covering 170 CWE). The Extended suite enables an additional 131 queries (covering 32 more CWE).
+
+CodeQL CLI
+----------
+
+Breaking Changes
+~~~~~~~~~~~~~~~~
+
+* Removed support for parsing :code:`[[`\ -style links in alert messages. This was an undocumented legacy feature that allowed query authors to embed links inline in select clause message strings using :code:`[["text"|"url"]]` syntax. Queries should use :code:`$@` placeholder pairs instead.
+
+Query Packs
+-----------
+
+Minor Analysis Improvements
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+C#
+""
+
+* :code:`System.Web.HttpRequest.RawUrl` is no longer treated as a sanitizer for :code:`cs/web/unvalidated-url-redirection`, since it contains the un-normalized request line. This may lead to more results.
+
+Query Metadata Changes
+~~~~~~~~~~~~~~~~~~~~~~
+
+C/C++
+"""""
+
+* Added the tag :code:`external/cwe/cwe-762` to :code:`cpp/new-free-mismatch`, and removed the tag :code:`external/cwe/cwe-401`. This better matches the behavior of the query.
+
+C#
+""
+
+* The query :code:`cs/useless-assignment-to-local` has been removed from the :code:`code-quality` suite, but it remains in the :code:`code-quality-extended` suite.
+
+Language Libraries
+------------------
+
+Major Analysis Improvements
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Swift
+"""""
+
+* Upgraded to allow analysis of Swift 6.3.3.
+
+Minor Analysis Improvements
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Golang
+""""""
+
+* The function :code:`Rel` in :code:`path/filepath` was incorrectly considered a sanitizer for :code:`go/path-injection` and :code:`go/zipslip`. This has now been fixed, which may lead to more results for those queries.
+
+Java/Kotlin
+"""""""""""
+
+* Kotlin versions up to 2.4.10 are now supported.
+* :code:`java.io.File.getName()` is no longer treated as a complete sanitizer for :code:`java/path-injection`, since it does not remove a :code:`..` path component (for example :code:`new File("..").getName()` returns :code:`".."`). It is now only recognized as a sanitizer when combined with a subsequent check for :code:`..` components, which may result in new alerts.
+
+GitHub Actions
+""""""""""""""
+
+* Altered the logic of :code:`EnvironmentCheck` to make sure it is a check that protects only for non-toctou. This change will result in more results being found by the queries: :code:`actions/untrusted-checkout-toctou/high` and :code:`actions/untrusted-checkout-toctou/critical`.
diff --git a/docs/codeql/codeql-overview/codeql-changelog/index.rst b/docs/codeql/codeql-overview/codeql-changelog/index.rst
index 837fa757368..a0a2e1832d8 100644
--- a/docs/codeql/codeql-overview/codeql-changelog/index.rst
+++ b/docs/codeql/codeql-overview/codeql-changelog/index.rst
@@ -11,6 +11,7 @@ A list of queries for each suite and language `is available here TokenStream {
/// `Option`, iterator chains) splice
/// their elements
/// field: {expr} - extend a named field with `{expr}`'s ids
+/// field: (kind ...)? - set the field only if every `#{expr}`
+/// beneath it has a value (see below)
/// ```
///
+/// # Optional fields
+///
+/// A `?` on a field's value makes that field fallible: if a `#{expr}`
+/// anywhere beneath it interpolates an absent value — an `Option` that is
+/// `None` — the subtree is abandoned and the field is left unset. This
+/// replaces the surrounding `Option::map` that would otherwise be needed:
+///
+/// ```text
+/// (break_expr label: {lbl.map(|l| tree!((identifier #{l})))}) // before
+/// (break_expr label: (identifier #{lbl})?) // after
+/// ```
+///
+/// The value may be nested arbitrarily deeply, and a nested `?` catches
+/// first, so an inner absent value need not discard the outer node:
+///
+/// ```text
+/// (parameter pattern: (name_pattern identifier: (identifier #{name}))? type: {ty})
+/// ```
+///
+/// Only `#{expr}` propagates absence. A `{expr}` splice is unaffected, since
+/// yielding no ids already leaves a field unset, and `?` is rejected on one.
+/// Outside a `?`, interpolating an `Option` with `#{expr}` remains a compile
+/// error, so the choice between "unset the field" and "unwrap it" stays
+/// explicit.
+///
/// Can be called with an explicit context or using the implicit context
/// from an enclosing `rule!`:
///
diff --git a/shared/yeast-macros/src/parse.rs b/shared/yeast-macros/src/parse.rs
index 55ada358849..40f9dbce61c 100644
--- a/shared/yeast-macros/src/parse.rs
+++ b/shared/yeast-macros/src/parse.rs
@@ -1,10 +1,44 @@
use proc_macro2::{Delimiter, Ident, Literal, Span, TokenStream, TokenTree};
use quote::quote;
use std::iter::Peekable;
+use std::sync::atomic::{AtomicUsize, Ordering};
+use syn::Lifetime;
type Tokens = Peekable;
type Result = std::result::Result;
+/// Mints the block label a fallible field breaks out of. Labels must be unique
+/// along a nesting chain, since a `?` nested inside another `?` has to break out
+/// of the inner field only.
+fn fresh_fallible_label() -> Lifetime {
+ static COUNTER: AtomicUsize = AtomicUsize::new(0);
+ let n = COUNTER.fetch_add(1, Ordering::Relaxed);
+ Lifetime::new(&format!("'__yeast_field_{n}"), Span::call_site())
+}
+
+/// Rejects a `?` in a position where there is no field for it to leave unset.
+///
+/// The advice depends on what precedes it: on a `{...}` splice a `?` is
+/// redundant, and anywhere else it belongs on a field's value. Other
+/// quantifiers need no handling — `*` and `+` have never been valid in a
+/// template, and the existing check for stray tokens already rejects them.
+fn reject_stray_optional(tokens: &mut Tokens, after_splice: bool) -> Result<()> {
+ let Some(TokenTree::Punct(p)) = tokens.peek() else {
+ return Ok(());
+ };
+ if p.as_char() != '?' {
+ return Ok(());
+ }
+ let msg = if after_splice {
+ "`?` is not valid on a `{...}` splice; a splice that yields no value \
+ already leaves its field unset"
+ } else {
+ "`?` is only valid on the value of a named field, as in \
+ `label: (identifier #{lbl})?`"
+ };
+ Err(syn::Error::new_spanned(p.clone(), msg))
+}
+
// ---------------------------------------------------------------------------
// Query parsing
// ---------------------------------------------------------------------------
@@ -318,8 +352,9 @@ pub fn parse_tree_top(input: TokenStream) -> Result {
let mut tokens = input.into_iter().peekable();
let ctx = parse_ctx_or_implicit(&mut tokens);
- let first = parse_direct_node(&mut tokens, &ctx)?;
+ let first = parse_direct_node(&mut tokens, &ctx, None)?;
+ reject_stray_optional(&mut tokens, false)?;
if let Some(tok) = tokens.next() {
return Err(syn::Error::new_spanned(
tok,
@@ -352,7 +387,15 @@ pub fn parse_trees_top(input: TokenStream) -> Result {
/// Parse a single node template and generate code that returns an `Id`.
/// Handles: `(kind fields... children...)` and `{expr}`.
-fn parse_direct_node(tokens: &mut Tokens, ctx: &Ident) -> Result {
+///
+/// `scope` is the enclosing fallible field's label, if any: inside one, a
+/// `#{expr}` that interpolates an absent value breaks out to it, leaving that
+/// field unset. See [`parse_direct_node_inner`].
+fn parse_direct_node(
+ tokens: &mut Tokens,
+ ctx: &Ident,
+ scope: Option<&Lifetime>,
+) -> Result {
match tokens.peek() {
Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Brace => {
let group = expect_group(tokens, Delimiter::Brace)?;
@@ -362,7 +405,7 @@ fn parse_direct_node(tokens: &mut Tokens, ctx: &Ident) -> Result {
Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Parenthesis => {
let group = expect_group(tokens, Delimiter::Parenthesis)?;
let mut inner = group.stream().into_iter().peekable();
- parse_direct_node_inner(&mut inner, ctx)
+ parse_direct_node_inner(&mut inner, ctx, scope)
}
Some(tok) => Err(syn::Error::new_spanned(
tok.clone(),
@@ -377,7 +420,11 @@ fn parse_direct_node(tokens: &mut Tokens, ctx: &Ident) -> Result {
/// Parse the inside of a parenthesized node: `kind fields... children...`
/// or `kind "literal"` or `kind $fresh`.
-fn parse_direct_node_inner(tokens: &mut Tokens, ctx: &Ident) -> Result {
+fn parse_direct_node_inner(
+ tokens: &mut Tokens,
+ ctx: &Ident,
+ scope: Option<&Lifetime>,
+) -> Result {
let kind = expect_ident(tokens, "expected node kind")?;
let kind_str = kind.to_string();
@@ -392,6 +439,28 @@ fn parse_direct_node_inner(tokens: &mut Tokens, ctx: &Ident) -> Result Result = Vec::new();
@@ -446,7 +516,47 @@ fn parse_direct_node_inner(tokens: &mut Tokens, ctx: &Ident) -> Result = #label: {
+ ::std::option::Option::Some(#value)
+ };
+ });
+ field_args.push(quote! {
+ if let ::std::option::Option::Some(__id) = #temp {
+ __fields.push((#field_str, vec![__id]));
+ }
+ });
+ } else {
+ // No `?` of its own, so failures beneath it belong to whichever
+ // fallible field encloses this one, if any.
+ let value = parse_direct_node_inner(&mut inner, ctx, scope)?;
+ stmts.push(quote! { let #temp: yeast::Id = #value; });
+ field_args.push(quote! { __fields.push((#field_str, vec![#temp])); });
+ }
+ continue;
+ }
+
+ // Neither form matched; delegate for a consistent error message.
+ let value = parse_direct_node(tokens, ctx, scope)?;
stmts.push(quote! { let #temp: yeast::Id = #value; });
field_args.push(quote! { __fields.push((#field_str, vec![#temp])); });
}
@@ -486,7 +596,8 @@ fn parse_direct_list(tokens: &mut Tokens, ctx: &Ident) -> Result Result bool {
matches!(tokens.peek(), Some(TokenTree::Group(g)) if g.delimiter() == delim)
}
+fn peek_is_punct(tokens: &mut Tokens, ch: char) -> bool {
+ matches!(tokens.peek(), Some(TokenTree::Punct(p)) if p.as_char() == ch)
+}
+
fn peek_is_repetition(tokens: &mut Tokens) -> bool {
matches!(tokens.peek(), Some(TokenTree::Punct(p)) if matches!(p.as_char(), '*' | '+' | '?'))
}
diff --git a/shared/yeast/doc/yeast.md b/shared/yeast/doc/yeast.md
index 90edb510c1a..be3bc913c70 100644
--- a/shared/yeast/doc/yeast.md
+++ b/shared/yeast/doc/yeast.md
@@ -235,6 +235,48 @@ yeast::trees!(ctx,
(identifier #{name}) // an identifier from a Rust variable
```
+### Optional fields (`?`)
+
+A `?` on a field's value makes that field fallible. If a `#{expr}` anywhere
+beneath it interpolates an absent value — an `Option` that is `None` — the
+subtree is abandoned and the field is left unset:
+
+```rust
+rule!((breakStmt label: _? @@lbl) => (break_expr label: (identifier #{lbl})?))
+```
+
+Here an optional capture is being wrapped in a leaf, which without `?` needs
+an `Option::map` to build the leaf only in the `Some` case:
+
+```rust
+// Equivalent, but the intent is buried in the closure:
+(break_expr label: {lbl.map(|l| tree!((identifier #{l})))})
+```
+
+The marker mirrors the query language, where a quantifier likewise follows the
+value it applies to (`label: _? @@lbl`). Note that the schema puts it on the
+other side of the colon — `external_name?: identifier` — because it is
+*declaring* a field's cardinality rather than supplying a value for it.
+
+Absence propagates outwards through as many levels as necessary, and a nested
+`?` catches first, so an inner absent value need not discard the outer node:
+
+```rust
+// If `name` is absent, `pattern` is left unset — but `type` is still set.
+(parameter pattern: (name_pattern identifier: (identifier #{name}))? type: {ty})
+```
+
+Only `#{expr}` propagates absence, because it supplies a node's *content*: with
+no value there is no leaf to build. A `{expr}` splice supplies *children*, where
+yielding nothing already leaves the field unset (see below), so `?` is rejected
+on one. Repetition has no marker at all, in templates or elsewhere: how many
+children a `{expr}` contributes is a property of the expression rather than of
+the syntax.
+
+Outside a `?`, interpolating an `Option` with `#{expr}` remains a compile error.
+That is deliberate: it keeps the choice between "leave the field unset" and
+"unwrap it" explicit at every interpolation.
+
### Fresh identifiers
`(kind $name)` creates a leaf node with an auto-generated unique name. All
@@ -279,6 +321,11 @@ yeast::trees!(ctx,
)
```
+Because an `Option` splices as zero or one id, `field: {opt}` already
+leaves the field unset when `opt` is `None`. Use [`?`](#optional-fields-)
+instead when the optional value has to be *wrapped* in a node first, so that
+there is nothing to wrap when it is absent.
+
The contents of `{…}` are treated as a Rust block, so multi-statement
expressions (with `let` bindings) work too:
diff --git a/shared/yeast/src/lib.rs b/shared/yeast/src/lib.rs
index 14a0ab05576..cf06d2d2c17 100644
--- a/shared/yeast/src/lib.rs
+++ b/shared/yeast/src/lib.rs
@@ -117,6 +117,11 @@ where
/// All standard primitive and string types implement [`YeastDisplay`] via
/// the [`impl_yeast_display_via_display`] macro below. Coherence prevents a
/// blanket `impl`, so additional types must be added explicitly.
+#[diagnostic::on_unimplemented(
+ message = "`{Self}` cannot be interpolated with `#{{...}}`",
+ note = "if the value is optional, mark the enclosing field's value with `?` to leave \
+ that field unset when it is absent, as in `label: (identifier #{{lbl}})?`"
+)]
pub trait YeastDisplay {
fn yeast_to_string(&self, ast: &Ast) -> String;
}
@@ -183,6 +188,81 @@ impl YeastSourceRange for &T {
}
}
+/// Normalizes a `#{expr}` interpolation to an optional value, so that a
+/// fallible field — `field: (kind #{expr})?` — can tell "there is a value to
+/// interpolate" apart from "there is none, so leave the field unset".
+///
+/// Implemented for every [`YeastDisplay`] type, which always yields a value,
+/// and for `Option` of the same, which yields one only when it is `Some`.
+///
+/// The implementations are enumerated rather than blanket: a blanket
+/// `impl` would overlap with the `Option` impl, since
+/// coherence cannot rule out a future `impl YeastDisplay for Option`.
+/// [`YeastDisplay`] itself is enumerated for the same reason.
+///
+/// Note that this is used *only* inside a fallible field. Elsewhere `#{expr}`
+/// still goes directly through [`YeastDisplay`], so interpolating an `Option`
+/// without a `?` remains a compile error rather than silently dropping a node.
+pub trait MaybeYeastValue {
+ /// The interpolated value's type, which knows how to render itself.
+ type Value: YeastDisplay + YeastSourceRange + ?Sized;
+
+ /// Returns the value to interpolate, or `None` to leave the field unset.
+ fn maybe_yeast_value(&self) -> Option<&Self::Value>;
+}
+
+macro_rules! impl_maybe_yeast_value {
+ ($($t:ty),* $(,)?) => {
+ $(
+ impl MaybeYeastValue for $t {
+ type Value = $t;
+ fn maybe_yeast_value(&self) -> Option<&$t> {
+ Some(self)
+ }
+ }
+
+ impl MaybeYeastValue for Option<$t> {
+ type Value = $t;
+ fn maybe_yeast_value(&self) -> Option<&$t> {
+ self.as_ref()
+ }
+ }
+ )*
+ };
+}
+
+impl_maybe_yeast_value! {
+ Id,
+ i8, i16, i32, i64, i128, isize,
+ u8, u16, u32, u64, u128, usize,
+ f32, f64,
+ bool, char,
+ String,
+}
+
+// `str` is unsized, so it has no `Option` counterpart; `Option<&str>` is
+// covered by the reference impls below.
+impl MaybeYeastValue for str {
+ type Value = str;
+ fn maybe_yeast_value(&self) -> Option<&str> {
+ Some(self)
+ }
+}
+
+impl MaybeYeastValue for &T {
+ type Value = T::Value;
+ fn maybe_yeast_value(&self) -> Option<&T::Value> {
+ (**self).maybe_yeast_value()
+ }
+}
+
+impl MaybeYeastValue for Option<&T> {
+ type Value = T::Value;
+ fn maybe_yeast_value(&self) -> Option<&T::Value> {
+ (*self).and_then(MaybeYeastValue::maybe_yeast_value)
+ }
+}
+
#[derive(Debug)]
pub struct AstCursor<'a> {
ast: &'a Ast,
diff --git a/shared/yeast/tests/test.rs b/shared/yeast/tests/test.rs
index 756e219bd89..bdc17c7593d 100644
--- a/shared/yeast/tests/test.rs
+++ b/shared/yeast/tests/test.rs
@@ -674,6 +674,117 @@ fn test_tree_builder() {
);
}
+/// Builds `(assignment left: … right: (integer #{value})?)`, where a `None`
+/// `value` leaves `right` unset rather than producing an `integer` with no
+/// content.
+fn build_optional_right(ast: &mut Ast, value: Option) -> (yeast::Id, yeast::Id) {
+ let captures = yeast::captures::Captures::new();
+ let fresh = yeast::tree_builder::FreshScope::new();
+ let mut user_ctx = ();
+ let mut ctx = yeast::build::BuildCtx::new(ast, &captures, &fresh, &mut user_ctx);
+ let left = yeast::tree!(ctx, (identifier "x"));
+ let root = yeast::tree!(ctx,
+ (assignment
+ left: {left}
+ right: (integer #{value})?
+ )
+ );
+ (root, left)
+}
+
+#[test]
+fn test_optional_field_is_set_when_the_value_is_present() {
+ let runner: Runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), &[]);
+ let mut ast = runner.run("x = 1").unwrap();
+
+ // Any node will do as the interpolated value; `#{…}` renders its source text.
+ let mut cursor = AstCursor::new(&ast);
+ cursor.goto_first_child();
+ let some = cursor.node_id();
+
+ let (root, _) = build_optional_right(&mut ast, Some(some));
+ assert_dump_eq(
+ &dump_ast(&ast, root, "x = 1"),
+ r#"
+ assignment
+ left: identifier "x"
+ right: integer "x = 1"
+ "#,
+ );
+}
+
+#[test]
+fn test_optional_field_is_unset_when_the_value_is_absent() {
+ let runner: Runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), &[]);
+ let mut ast = runner.run("x = 1").unwrap();
+
+ let (root, _) = build_optional_right(&mut ast, None);
+ assert_dump_eq(
+ &dump_ast(&ast, root, "x = 1"),
+ r#"
+ assignment
+ left: identifier "x"
+ "#,
+ );
+}
+
+#[test]
+fn test_optional_field_propagates_through_nested_nodes() {
+ let runner: Runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), &[]);
+ let mut ast = runner.run("x = 1").unwrap();
+
+ let captures = yeast::captures::Captures::new();
+ let fresh = yeast::tree_builder::FreshScope::new();
+ let mut user_ctx = ();
+ let mut ctx = yeast::build::BuildCtx::new(&mut ast, &captures, &fresh, &mut user_ctx);
+
+ // The absent value sits two levels below the `?`, so the whole
+ // `left_assignment_list` subtree is abandoned along with it.
+ let absent: Option = None;
+ let right = yeast::tree!(ctx, (integer "1"));
+ let root = yeast::tree!(ctx,
+ (assignment
+ left: (left_assignment_list child: (identifier #{absent}))?
+ right: {right}
+ )
+ );
+
+ assert_dump_eq(
+ &dump_ast(&ast, root, "x = 1"),
+ r#"
+ assignment
+ right: integer "1"
+ "#,
+ );
+}
+
+#[test]
+fn test_innermost_optional_field_catches_first() {
+ let runner: Runner = Runner::new(tree_sitter_ruby::LANGUAGE.into(), &[]);
+ let mut ast = runner.run("x = 1").unwrap();
+
+ let captures = yeast::captures::Captures::new();
+ let fresh = yeast::tree_builder::FreshScope::new();
+ let mut user_ctx = ();
+ let mut ctx = yeast::build::BuildCtx::new(&mut ast, &captures, &fresh, &mut user_ctx);
+
+ // The inner `?` catches, so only `child` is dropped; `left` survives.
+ let absent: Option = None;
+ let root = yeast::tree!(ctx,
+ (assignment
+ left: (left_assignment_list child: (identifier #{absent})?)?
+ )
+ );
+
+ assert_dump_eq(
+ &dump_ast(&ast, root, "x = 1"),
+ r#"
+ assignment
+ left: left_assignment_list
+ "#,
+ );
+}
+
// ---- Rule tests ----
// These rules use field names from node-types.yml, which extends the
diff --git a/swift/extractor/mangler/SwiftMangler.cpp b/swift/extractor/mangler/SwiftMangler.cpp
index e7dbda6ba91..986cce69510 100644
--- a/swift/extractor/mangler/SwiftMangler.cpp
+++ b/swift/extractor/mangler/SwiftMangler.cpp
@@ -1,6 +1,5 @@
#include "swift/extractor/mangler/SwiftMangler.h"
#include "swift/extractor/infra/SwiftDispatcher.h"
-#include "swift/extractor/trap/generated/decl/TrapClasses.h"
#include "swift/logging/SwiftLogging.h"
#include
@@ -170,15 +169,12 @@ void SwiftMangler::indexExtensionsAndFilePrivateValues(llvm::ArrayRefsubmodules()) {
+ index = indexClangSubmoduleExtensionsAndFilePrivateValues(submodule, moduleLoader, index);
if (auto* swiftSubmodule = moduleLoader->getWrapperForModule(submodule)) {
llvm::SmallVector children;
swiftSubmodule->getTopLevelDecls(children);
@@ -191,6 +187,17 @@ void SwiftMangler::indexClangExtensionsAndFilePrivateValues(
}
}
}
+ return index;
+}
+
+void SwiftMangler::indexClangExtensionsAndFilePrivateValues(
+ const clang::Module* clangModule,
+ swift::ClangModuleLoader* moduleLoader) {
+ if (!moduleLoader) {
+ return;
+ }
+
+ indexClangSubmoduleExtensionsAndFilePrivateValues(clangModule, moduleLoader, 0u);
}
SwiftMangledName SwiftMangler::visitGenericTypeParamDecl(const swift::GenericTypeParamDecl* decl) {
diff --git a/swift/extractor/mangler/SwiftMangler.h b/swift/extractor/mangler/SwiftMangler.h
index 92175b5887b..6b835348f14 100644
--- a/swift/extractor/mangler/SwiftMangler.h
+++ b/swift/extractor/mangler/SwiftMangler.h
@@ -126,6 +126,9 @@ class SwiftMangler : private swift::TypeVisitor,
bool isExtensionOrFilePrivateValue(const swift::Decl* decl);
void indexExtensionsAndFilePrivateValues(llvm::ArrayRef siblings);
+ uint32_t indexClangSubmoduleExtensionsAndFilePrivateValues(const clang::Module* clangModule,
+ swift::ClangModuleLoader* moduleLoader,
+ uint32_t index);
void indexClangExtensionsAndFilePrivateValues(const clang::Module* clangModule,
swift::ClangModuleLoader* moduleLoader);
ExtensionOrFilePrivateValueIndex getExtensionOrFilePrivateValueIndex(const swift::Decl* decl,
diff --git a/unified/AGENTS.md b/unified/AGENTS.md
index a50a49868a2..9c9bbbb534c 100644
--- a/unified/AGENTS.md
+++ b/unified/AGENTS.md
@@ -1,23 +1,32 @@
# Agent instructions
-This is a CodeQL extractor based on tree-sitter.
+This is a CodeQL extractor that maps a language's parse tree onto a shared AST
+using the `yeast` desugaring engine. Swift, the only language so far, is parsed
+by Apple's swift-syntax rather than by tree-sitter.
## Building
- To build the extractor, run `scripts/create-extractor-pack.sh`
## Swift Parser
-- The Swift parser is defined by `extractor/tree-sitter-swift/grammar.js` and can be edited if needed.
+- Swift source is parsed by `swift-syntax-parse`, a small Swift/Rust binary in
+ `swift-syntax-rs` that wraps Apple's swift-syntax and emits the parse tree as
+ JSON. There is no grammar in this repository to edit.
-- After editing the grammar, always run `scripts/regenerate-grammar.sh`.
+- `extractor/src/languages/swift/adapter.rs` converts that JSON into a yeast AST.
-- The raw parse tree is described by `extractor/tree-sitter-swift/node-types.yml` and should be reviewed after grammar changes.
+- The raw parse tree's shape is described by `extractor/swift_node_types.yml`,
+ which is maintained by hand.
## AST Mapping
- The target AST shape is described by `extractor/ast_types.yml`.
- The mapping from the parse tree to the target AST is found in `extractor/src/languages/swift/swift.rs`
-- To run tests for the parser and mapping, run `cargo test` in the `extractor` directory.
+- To run tests for the parser and mapping, run `cargo test` in the `extractor`
+ directory. The tests need the `swift-syntax-parse` binary: point
+ `CODEQL_EXTRACTOR_UNIFIED_SWIFT_SYNTAX_PARSE` at it, or put it on `PATH`.
+ Corpus tests skip themselves when it cannot be found, so check for skips
+ before concluding a change is clean.
- Extractor test cases are located at `extractor/tests/corpus/swift/*/*.swift`.
diff --git a/unified/extractor/BUILD.bazel b/unified/extractor/BUILD.bazel
index 13a3b6b287b..58b32d9fc5c 100644
--- a/unified/extractor/BUILD.bazel
+++ b/unified/extractor/BUILD.bazel
@@ -20,6 +20,5 @@ codeql_rust_binary(
) + [
"//shared/tree-sitter-extractor",
"//shared/yeast",
- "//unified/extractor/tree-sitter-swift",
],
)
diff --git a/unified/extractor/Cargo.toml b/unified/extractor/Cargo.toml
index 39c20598b1f..be333298f1a 100644
--- a/unified/extractor/Cargo.toml
+++ b/unified/extractor/Cargo.toml
@@ -7,9 +7,6 @@ edition = "2024"
# When updating these dependencies, run `misc/bazel/3rdparty/update_cargo_deps.sh`
[dependencies]
-tree-sitter = ">= 0.23.0"
-tree-sitter-embedded-template = "0.25.0"
-tree-sitter-swift = { path = "tree-sitter-swift" }
clap = { version = "4.5", features = ["derive"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3.20", features = ["env-filter"] }
diff --git a/unified/extractor/ast_types.yml b/unified/extractor/ast_types.yml
index 4fa1ff16942..ca5f6d45edc 100644
--- a/unified/extractor/ast_types.yml
+++ b/unified/extractor/ast_types.yml
@@ -49,6 +49,7 @@ supertypes:
- tuple_pattern
- constructor_pattern
- or_pattern
+ - conditional_pattern
- ignore_pattern
- expr_equality_pattern
- bulk_importing_pattern
@@ -56,9 +57,6 @@ supertypes:
# A statement is anything that can appear in a block.
# This type contains all of 'expr' and has partial overlap with 'member'.
# For example, type_alias_declaration can appear either as a stmt or member.
- # constructor_declaration and destructor_declaration appear here because
- # tree-sitter-swift's error recovery for #if/#endif in class bodies can place
- # init/deinit declarations at the wrong (statement) level.
stmt:
- expr
- variable_declaration
@@ -369,7 +367,6 @@ named:
catch_clause:
modifier*: modifier
pattern?: pattern
- guard?: expr
body: block
# `switch value { case pattern: body case ...: default: body }`
@@ -381,11 +378,9 @@ named:
# A single `case ...:` (or `default:`) entry in a switch.
# An entry with multiple `case p1, p2:` patterns uses an `or_pattern`.
# A `default:` entry has no pattern.
- # An optional `guard` corresponds to a `where`-clause on the case.
switch_case:
modifier*: modifier
pattern?: pattern
- guard?: expr
body: block
# Evaluate 'expr' and match its result against 'pattern', and return true if it matches.
@@ -446,6 +441,14 @@ named:
modifier*: modifier
pattern*: pattern
+ # A pattern that matches against a nested pattern, and subsequently checks a condition.
+ # The match is rejected if the condition does not hold.
+ # Variables bound in the nested pattern are in scope within the condition.
+ conditional_pattern:
+ modifier*: modifier
+ condition: expr
+ pattern: pattern
+
# A pattern with an optional associated name.
pattern_element:
modifier*: modifier
diff --git a/unified/extractor/src/languages/swift/adapter.rs b/unified/extractor/src/languages/swift/adapter.rs
index 4ae4040d043..f34e5df3d00 100644
--- a/unified/extractor/src/languages/swift/adapter.rs
+++ b/unified/extractor/src/languages/swift/adapter.rs
@@ -17,9 +17,8 @@
//! * Collection nodes are already elided to JSON arrays upstream, so a
//! list-valued field maps directly to that field holding several children.
//!
-//! Note: this preserves swift-syntax's own kind/field names. Aligning those
-//! names with the tree-sitter-swift schema (so the rewrite rules in
-//! [`super::swift`] fire) is done incrementally in the rules.
+//! Note: this preserves swift-syntax's own kind/field names; the rewrite rules
+//! in [`super::swift`] match those names directly.
use std::collections::BTreeMap;
diff --git a/unified/extractor/src/languages/swift/swift.rs b/unified/extractor/src/languages/swift/swift.rs
index ef3672e1b91..000601b7215 100644
--- a/unified/extractor/src/languages/swift/swift.rs
+++ b/unified/extractor/src/languages/swift/swift.rs
@@ -77,8 +77,8 @@ fn chained_modifier(ctx: &mut yeast::build::BuildCtx<'_, SwiftContext>) -> Optio
/// Combine a list of boolean sub-conditions into a single expression by
/// left-folding with the infix `&&` operator. Used by control-flow
-/// rules (`if`, `guard`, `while`, `repeat-while`) whose tree-sitter
-/// nodes carry one or more comma-separated conditions that the target
+/// rules (`if`, `guard`, `while`, `repeat-while`), which carry one or
+/// more comma-separated conditions that the target
/// AST represents as a single `condition:` field. Panics on an empty
/// input because every caller's grammar guarantees at least one
/// condition.
@@ -94,6 +94,19 @@ fn and_chain(
.expect("control-flow statement must have at least one condition")
}
+/// Return the only pattern unchanged when there is exactly one, otherwise
+/// wrap the list in an `or_pattern`.
+fn make_or_pattern(
+ ctx: &mut yeast::build::BuildCtx<'_, SwiftContext>,
+ items: Vec,
+) -> yeast::Id {
+ if items.len() == 1 {
+ items[0]
+ } else {
+ tree!((or_pattern pattern: {items}))
+ }
+}
+
/// Translate a multi-part identifier (for example `Foo.Bar.Baz`) into a
/// `member_access_expr` chain rooted at a `name_expr` over the first
/// part. Panics on an empty input because the grammar's `_+` quantifier
@@ -144,7 +157,7 @@ fn translation_rules() -> Vec> {
// ---- Literals ----
// swift-syntax does not distinguish the lexical integer/string forms
// (hex/binary/octal, single- vs multi-line, raw): each is a single
- // `*LiteralExpr` kind, so the tree-sitter variants collapse to one rule.
+ // `*LiteralExpr` kind, so one rule per literal type suffices.
rule!((integerLiteralExpr) => (int_literal)),
rule!((floatLiteralExpr) => (float_literal)),
rule!((booleanLiteralExpr) => (boolean_literal)),
@@ -169,8 +182,8 @@ fn translation_rules() -> Vec> {
rule!((declReferenceExpr baseName: @name) => (name_expr identifier: (identifier #{name}))),
// A discard `_` used as an expression — e.g. the target of a discarding
// assignment `_ = x`. swift-syntax models it as a `discardAssignmentExpr`;
- // the tree-sitter path treated the bare `_` as a name, so map it to a
- // `name_expr` too.
+ // the target AST has no expression-level discard (only `ignore_pattern`,
+ // which is a pattern), so it becomes a `name_expr` over the `_` token.
rule!((discardAssignmentExpr wildcard: @@w) => (name_expr identifier: (identifier #{w}))),
// ---- Operators ----
// The parser front-end folds operator chains into nested
@@ -205,6 +218,28 @@ fn translation_rules() -> Vec> {
=>
(assign_expr target: {l} value: {r})
),
+ // In an unresolved `sequenceExpr` (below) the operator positions are not
+ // only `binaryOperatorExpr`s: a plain assignment (`=`), an `as`/`is` cast
+ // and the ternary `?:` can also appear unfolded. Map each to an
+ // `infix_operator` (keeping its spelling) so the sequence stays a clean
+ // alternation of operands and operators instead of dropping the operator
+ // to an opaque `unsupported_node`. These bare nodes only occur inside an
+ // unresolved sequence — folded forms are handled by the dedicated rules
+ // above (assignment) and below (`ternaryExpr`).
+ rule!((assignmentExpr) @op => (infix_operator #{op})),
+ rule!((unresolvedAsExpr) @op => (infix_operator #{op})),
+ rule!((unresolvedIsExpr) @op => (infix_operator #{op})),
+ // The ternary is a three-part operator (`? thenExpr :`) that *wraps* a
+ // nested expression. Splice it into `?`, the then-expression, `:` so the
+ // then-expression survives as a real (traversable) operand rather than
+ // being buried in an opaque token.
+ rule!(
+ (unresolvedTernaryExpr questionMark: @@q thenExpression: @then colon: @@c)
+ =>
+ expr_or_operator* {
+ vec![tree!((infix_operator #{q})), then, tree!((infix_operator #{c}))]
+ }
+ ),
// Escape hatch: an operator chain the front-end could not resolve
// (because it uses an operator of unknown precedence, e.g. imported from
// another module) stays a flat `sequenceExpr`. Preserve it as an
@@ -244,10 +279,9 @@ fn translation_rules() -> Vec> {
accessor_kind: (accessor_kind "get")
body: (block stmt: {body}))
),
- // A property with an explicit accessor block. The two shapes differ only
- // by the presence of an initializer (tree-sitter split them into distinct
- // `willset_didset_block` vs computed-accessor node types; swift-syntax
- // makes both plain `accessorDecl`s):
+ // A property with an explicit accessor block. swift-syntax makes both
+ // shapes plain `accessorDecl`s, so they are told apart by the presence
+ // of an initializer:
//
// * With an initializer (`var x: T = e { willSet {…} didSet {…} }`) it is
// a *stored* property with observers: emit the backing
@@ -391,15 +425,15 @@ fn translation_rules() -> Vec> {
rule!(
(enumCaseParameter firstName: _? @@name type: @ty)
=>
- (parameter pattern: {name.map(|name| tree!((name_pattern identifier: (identifier #{name}))))} type: {ty})
+ (parameter pattern: (name_pattern identifier: (identifier #{name}))? type: {ty})
),
// An enum element with associated values (`case circle(radius: Double)`)
// becomes a nested `class_like_declaration` whose constructor carries the
// payload parameters; an element with a raw value (`case a = 1`) or a
// plain element (`case north`) becomes a `variable_declaration`. All
// carry the shared case modifiers / chained tag from `ctx` (set by the
- // `enumCaseDecl` rule below) and are tagged `enum_case` (after any
- // `chained_declaration` tag, matching the tree-sitter modifier order).
+ // `enumCaseDecl` rule below) and are tagged `enum_case`, after any
+ // `chained_declaration` tag.
rule!(
(enumCaseElement name: @name parameterClause: (enumCaseParameterClause parameters: _* @params))
=>
@@ -432,8 +466,8 @@ fn translation_rules() -> Vec> {
// Enum cases. A single `case` declaration may carry modifiers
// (e.g. `indirect`) and list several comma-separated elements; each
// becomes its own declaration carrying those shared modifiers, and
- // non-first ones are tagged `chained_declaration` (mirroring the
- // tree-sitter `enum_entry` rule). The modifiers are published into `ctx`
+ // non-first ones are tagged `chained_declaration`. The modifiers are
+ // published into `ctx`
// for the element rules above, which build the actual declaration.
rule!(
(enumCaseDecl modifiers: _* @mods elements: _* @@cases)
@@ -487,9 +521,9 @@ fn translation_rules() -> Vec> {
// key; unlabelled elements have no key.
rule!((tuplePattern elements: _* @els) => (tuple_pattern element: {els})),
rule!(
- (tuplePatternElement label: _? @label pattern: @p)
+ (tuplePatternElement label: _? @@label pattern: @p)
=>
- (pattern_element key: {label.map(|l| tree!((identifier #{l})))} pattern: {p})
+ (pattern_element key: (identifier #{label})? pattern: {p})
),
// A type-casting pattern (`case is T`). Not yet supported, so it is
// mapped to `unsupported_node` — an explicit reminder that this needs
@@ -530,7 +564,7 @@ fn translation_rules() -> Vec> {
// A function declaration (parameters/return type/body optional). The
// parameters and return type nest under `signature`; the body is a
// `codeBlock`. A bodyless function (a protocol requirement) still emits
- // an empty `block`, matching the tree-sitter path.
+ // an empty `block`.
rule!(
(functionDecl
name: @name
@@ -560,17 +594,13 @@ fn translation_rules() -> Vec> {
),
// A function parameter. With two names (`firstName`+`secondName`) the
// first is the external argument label and the second the internal name;
- // with one name it is just the internal name. The default value is
- // optional.
- //
- // PARITY: the declared type is intentionally dropped. In the tree-sitter
- // path the untyped-parameter rule was ordered before the typed one and
- // shadowed it (first match wins), so the baseline emits no parameter
- // type; emitting one here would diverge from it.
+ // with one name it is just the internal name. The declared type is
+ // emitted; the default value is optional.
rule!(
(functionParameter
firstName: @@first
secondName: _? @@second
+ type: @ty
defaultValue: (initializerClause value: @val)?)
=>
parameter {
@@ -581,6 +611,7 @@ fn translation_rules() -> Vec> {
tree!((parameter
external_name: {external}
pattern: (name_pattern identifier: (identifier #{name}))
+ type: {ty}
default: {val}))
}
),
@@ -608,26 +639,25 @@ fn translation_rules() -> Vec> {
// The pattern-only shapes (`patternExpr`, `discardAssignmentExpr`) are
// matched first; they never occur as ordinary call arguments.
rule!(
- (labeledExpr label: _? @lbl expression: (patternExpr pattern: @p))
+ (labeledExpr label: _? @@lbl expression: (patternExpr pattern: @p))
=>
- (pattern_element key: {lbl.map(|l| tree!((identifier #{l})))} pattern: {p})
+ (pattern_element key: (identifier #{lbl})? pattern: {p})
),
rule!(
- (labeledExpr label: _? @lbl expression: (discardAssignmentExpr) @@wildcard)
+ (labeledExpr label: _? @@lbl expression: (discardAssignmentExpr) @@wildcard)
=>
- (pattern_element key: {lbl.map(|l| tree!((identifier #{l})))} pattern: (ignore_pattern #{wildcard}))
+ (pattern_element key: (identifier #{lbl})? pattern: (ignore_pattern #{wildcard}))
),
rule!(
- (labeledExpr label: _? @lbl expression: @val)
+ (labeledExpr label: _? @@lbl expression: @val)
=>
argument {
- let key = lbl.map(|l| tree!((identifier #{l})));
if ctx.in_pattern {
tree!((pattern_element
- key: {key}
+ key: (identifier #{lbl})?
pattern: (expr_equality_pattern expr: {val})))
} else {
- tree!((argument name: {key} value: {val}))
+ tree!((argument name: (identifier #{lbl})? value: {val}))
}
}
),
@@ -649,8 +679,8 @@ fn translation_rules() -> Vec> {
// value; `break` / `continue` an optional target label; `throw` its
// thrown expression.
rule!((returnStmt expression: _? @val) => (return_expr value: {val})),
- rule!((breakStmt label: _? @@lbl) => (break_expr label: {lbl.map(|l| tree!((identifier #{l})))})),
- rule!((continueStmt label: _? @@lbl) => (continue_expr label: {lbl.map(|l| tree!((identifier #{l})))})),
+ rule!((breakStmt label: _? @@lbl) => (break_expr label: (identifier #{lbl})?)),
+ rule!((continueStmt label: _? @@lbl) => (continue_expr label: (identifier #{lbl})?)),
rule!((throwStmt expression: @val) => (throw_expr value: {val})),
// ---- Closures ----
// A closure (`{ (x: Int) -> Int in … }`) becomes a `function_expr`. The
@@ -686,7 +716,7 @@ fn translation_rules() -> Vec> {
initializer: (initializerClause value: @val)?)
=>
(variable_declaration
- modifier: {spec.map(|s| tree!((modifier #{s})))}
+ modifier: (modifier #{spec})?
pattern: (name_pattern identifier: (identifier #{name}))
value: {val})
),
@@ -726,8 +756,7 @@ fn translation_rules() -> Vec> {
condition: {and_chain(&mut ctx, cond)}
else: {else_stmts})
),
- // Ternary (`c ? a : b`) desugars to an `if_expr`, as in the tree-sitter
- // path.
+ // Ternary (`c ? a : b`) desugars to an `if_expr`.
rule!(
(ternaryExpr condition: @cond thenExpression: @then_val elseExpression: @else_val)
=>
@@ -746,22 +775,17 @@ fn translation_rules() -> Vec> {
rule!(
(switchCase label: (switchCaseLabel caseItems: _* @items) statements: _* @body)
=>
- switch_case {
- let pattern = if items.len() == 1 {
- items[0]
- } else {
- tree!((or_pattern pattern: {items}))
- };
- tree!((switch_case pattern: {pattern} body: (block stmt: {body})))
- }
+ (switch_case
+ pattern: {make_or_pattern(&mut ctx, items)}
+ body: (block stmt: {body}))
),
rule!(
(switchCase label: (switchDefaultLabel) statements: _* @body)
=>
(switch_case body: (block stmt: {body}))
),
- // A single case item unwraps to its pattern (used as an `or_pattern`
- // element).
+ // A single case item unwraps to its pattern, possibly boxed in conditional_pattern
+ rule!((switchCaseItem pattern: @p whereClause: (whereClause condition: @cond)) => (conditional_pattern pattern: { p } condition: {cond})),
rule!((switchCaseItem pattern: @p) => pattern { p }),
// A pattern-matching condition (`if case let x = e`, `if case .foo(let x)
// = e`) becomes a `pattern_guard_expr`: the matched pattern and the
@@ -772,8 +796,8 @@ fn translation_rules() -> Vec> {
(pattern_guard_expr pattern: {pat} value: {val})
),
// Optional binding (`if let x = foo`, or shorthand `if let x`) desugars
- // to a `pattern_guard_expr` matching `Optional.some(x)`, exactly as the
- // tree-sitter path does. The initialized form is matched first.
+ // to a `pattern_guard_expr` matching `Optional.some(x)`. The initialized
+ // form is matched first.
rule!(
(optionalBindingCondition
pattern: (identifierPattern identifier: @name)
@@ -848,10 +872,12 @@ fn translation_rules() -> Vec> {
),
rule!((arrayElement expression: @e) => expr { e }),
// A dictionary literal (`["a": 1]`) is kept as an opaque `map_literal`
- // leaf (its source span), matching the tree-sitter path.
+ // leaf (its source span).
rule!((dictionaryExpr) => (map_literal)),
- // A subscript access (`xs[0]`) is modelled as a call, exactly as the
- // tree-sitter grammar does (it parses `xs[0]` like `xs(0)`).
+ // A subscript access (`xs[0]`) is modelled as a call. swift-syntax does
+ // report a distinct `subscriptCallExpr`, so giving
+ // subscripts their own shape needs only a `subscript_expr` node in
+ // ast_types.yml and a remap here.
rule!(
(subscriptCallExpr calledExpression: @callee arguments: _* @args)
=>
@@ -877,17 +903,24 @@ fn translation_rules() -> Vec> {
body: {body}
catch_clause: {catches})
),
- // Catch block with bound identifier; optional where-clause guard.
+ rule!(
+ (catchItem pattern: @pattern whereClause: (whereClause condition: @guard))
+ =>
+ (conditional_pattern pattern: {pattern} condition: {guard})
+ ),
+ rule!(
+ (catchItem pattern: @pattern)
+ =>
+ pattern {pattern}
+ ),
+ // Catch block with one or more patterns (which have been translated by the catchItem rules)
rule!(
(catchClause
- catchItems: (catchItem
- pattern: @pattern
- whereClause: (whereClause condition: @guard)?)
+ catchItems: _+ @patterns
body: @body)
=>
(catch_clause
- pattern: {pattern}
- guard: {guard}
+ pattern: {make_or_pattern(&mut ctx, patterns)}
body: {body})
),
// Catch block without error binding
@@ -901,9 +934,8 @@ fn translation_rules() -> Vec> {
rule!((isExpr expression: @val type: @ty) => (type_test_expr expr: {val} operator: (infix_operator "is") type: {ty})),
// Await expression → unary_expr with operator "await"
rule!((awaitExpr expression: @val) => (unary_expr operator: (prefix_operator "await") operand: {val})),
- // Force-unwrap (`x!`) → postfix unary_expr. swift-syntax has a dedicated
- // `forceUnwrapExpr` node (the tree-sitter path used the generic postfix
- // operator rule instead).
+ // Force-unwrap (`x!`) → postfix unary_expr, via swift-syntax's dedicated
+ // `forceUnwrapExpr` node.
rule!((forceUnwrapExpr expression: @e) => (unary_expr operator: (postfix_operator "!") operand: {e})),
// ---- Imports ----
// An import declaration. The dotted path (a list of
@@ -930,7 +962,7 @@ fn translation_rules() -> Vec> {
None => tree!((bulk_importing_pattern)),
};
tree!((import_declaration
- modifier: {kind.map(|k| tree!((modifier #{k})))}
+ modifier: (modifier #{kind})?
modifier: {attrs}
modifier: {mods}
pattern: {pattern}
@@ -947,20 +979,25 @@ fn translation_rules() -> Vec> {
// an ordinary `declReferenceExpr`, already mapped to a `name_expr`.)
rule!((superExpr) => (super_expr)),
// Type expressions. A generic type applied with explicit arguments
- // (`Set`) is represented opaquely, using the whole source text as
- // the name (PARITY(tree-sitter): the generic arguments are not
- // structured `type_argument`s). Matched before the plain `identifierType`
- // rule, which would otherwise drop the arguments.
+ // (`Set`) becomes a `generic_type_expr` whose `base` is the type
+ // name and whose `type_argument`s are the (structured) arguments — the
+ // same shape the sugared `?`/`[]`/`[:]` types desugar to. Matched before
+ // the plain `identifierType` rule, which would otherwise drop the
+ // arguments.
rule!(
- (identifierType genericArgumentClause: (genericArgumentClause)) @@ty
+ (identifierType
+ name: @@name
+ genericArgumentClause: (genericArgumentClause arguments: (genericArgument argument: @args)*))
=>
- (named_type_expr name: (identifier #{ty}))
+ (generic_type_expr
+ base: (named_type_expr name: (identifier #{name}))
+ type_argument: {args})
),
// A named type (`Int`). `identifierType.name` is the type-name token.
rule!((identifierType name: @@n) => (named_type_expr name: (identifier #{n}))),
// A qualified type (`Outer.Inner`, `NSString.CompareOptions`). swift-syntax
- // nests these as `memberType` nodes; like the old tree-sitter `user_type`
- // rule, we keep the whole dotted path as the opaque `named_type_expr` name.
+ // nests these as `memberType` nodes; we keep the whole dotted path as the
+ // opaque `named_type_expr` name.
rule!((memberType) @ty => (named_type_expr name: (identifier #{ty}))),
// Sugared types desugar to `generic_type_expr`: `T?` -> Optional,
// `[T]` -> Array, `[K: V]` -> Dictionary.
@@ -1014,11 +1051,10 @@ fn translation_rules() -> Vec> {
(tupleTypeElement firstName: _? @@name type: @ty)
=>
tuple_type_element {
- let name = name.map(|n| tree!((identifier #{n})));
if ctx.in_function_type {
- tree!((parameter external_name: {name} type: {ty}))
+ tree!((parameter external_name: (identifier #{name})? type: {ty}))
} else {
- tree!((tuple_type_element name: {name} type: {ty}))
+ tree!((tuple_type_element name: (identifier #{name})? type: {ty}))
}
}
),
@@ -1026,81 +1062,107 @@ fn translation_rules() -> Vec> {
// (swift-syntax represents `#selector`/`#keyPath` and other macro
// expansions uniformly as a `macroExpansionExpr`).
rule!((macroExpansionExpr) => (unsupported_node)),
- // PARITY(tree-sitter): a nominal type's `inheritanceClause` (`: Base,
- // Proto`) is not emitted as a `base_type` — the tree-sitter path drops
- // it (no corpus target has a `base_type`). swift-syntax exposes it
- // cleanly, so emitting `base_type` is a correctness improvement to make
- // once tree-sitter is retired. Each declaration keyword gets its own
- // rule; the bodies are identical but for the keyword.
+ // A nominal type's `inheritanceClause` (`: Base, Proto`) becomes a list
+ // of `base_type`s, one per inherited type. Each declaration keyword
+ // gets its own rule; the bodies are identical but for the keyword.
// Class declaration with body containing members
rule!(
- (classDecl classKeyword: @kind modifiers: _* @mods name: @name memberBlock: (memberBlock members: _* @members))
+ (classDecl
+ classKeyword: @kind
+ modifiers: _* @mods
+ name: @name
+ inheritanceClause: (inheritanceClause inheritedTypes: (inheritedType type: @bases)*)?
+ memberBlock: (memberBlock members: _* @members))
=>
(class_like_declaration
modifier: (modifier #{kind})
modifier: {mods}
name: (identifier #{name})
+ base_type: {bases.into_iter().map(|ty| tree!((base_type type: {ty})))}
member: {members})
),
// Enum class declaration: same as a regular class but with an enum body.
rule!(
- (enumDecl enumKeyword: @kind modifiers: _* @mods name: @name memberBlock: (memberBlock members: _* @members))
+ (enumDecl
+ enumKeyword: @kind
+ modifiers: _* @mods
+ name: @name
+ inheritanceClause: (inheritanceClause inheritedTypes: (inheritedType type: @bases)*)?
+ memberBlock: (memberBlock members: _* @members))
=>
(class_like_declaration
modifier: (modifier #{kind})
modifier: {mods}
name: (identifier #{name})
+ base_type: {bases.into_iter().map(|ty| tree!((base_type type: {ty})))}
member: {members})
),
// A `struct` declaration.
rule!(
- (structDecl structKeyword: @kind modifiers: _* @mods name: @name memberBlock: (memberBlock members: _* @members))
+ (structDecl
+ structKeyword: @kind
+ modifiers: _* @mods
+ name: @name
+ inheritanceClause: (inheritanceClause inheritedTypes: (inheritedType type: @bases)*)?
+ memberBlock: (memberBlock members: _* @members))
=>
(class_like_declaration
modifier: (modifier #{kind})
modifier: {mods}
name: (identifier #{name})
+ base_type: {bases.into_iter().map(|ty| tree!((base_type type: {ty})))}
member: {members})
),
// Protocol declaration
rule!(
- (protocolDecl protocolKeyword: @kind modifiers: _* @mods name: @name memberBlock: (memberBlock members: _* @members))
+ (protocolDecl
+ protocolKeyword: @kind
+ modifiers: _* @mods
+ name: @name
+ inheritanceClause: (inheritanceClause inheritedTypes: (inheritedType type: @bases)*)?
+ memberBlock: (memberBlock members: _* @members))
=>
(class_like_declaration
modifier: (modifier #{kind})
modifier: {mods}
name: (identifier #{name})
+ base_type: {bases.into_iter().map(|ty| tree!((base_type type: {ty})))}
member: {members})
),
// An `extension Foo { … }` is likewise a `class_like_declaration`, named
// by the extended type. The extended type is captured opaquely (as its
// source text) so that qualified names (`extension String.Interpolation`,
- // a `memberType`) name the declaration just like simple ones, matching the
- // old tree-sitter `user_type` behaviour.
+ // a `memberType`) name the declaration just like simple ones.
rule!(
- (extensionDecl extensionKeyword: @kind modifiers: _* @mods extendedType: @@name memberBlock: (memberBlock members: _* @members))
+ (extensionDecl
+ extensionKeyword: @kind
+ modifiers: _* @mods
+ extendedType: @@name
+ inheritanceClause: (inheritanceClause inheritedTypes: (inheritedType type: @bases)*)?
+ memberBlock: (memberBlock members: _* @members))
=>
(class_like_declaration
modifier: (modifier #{kind})
modifier: {mods}
name: (identifier #{name})
+ base_type: {bases.into_iter().map(|ty| tree!((base_type type: {ty})))}
member: {members})
),
// A member of a type declaration unwraps to the contained declaration.
rule!((memberBlockItem decl: _* @d) => member* { d }),
// Init declaration → constructor_declaration. Body statements optional;
- // body itself is also optional (protocol requirement).
- //
- // PARITY(tree-sitter): the parameters are not emitted, because the
- // tree-sitter path dropped them (its `(parameter)*` capture missed the
- // field-attached parameters). Emitting them is a future improvement.
+ // body itself is also optional (protocol requirement). The parameters
+ // nest under `signature` (as for `functionDecl`).
rule!(
(initializerDecl
modifiers: _* @mods
+ signature: (functionSignature
+ parameterClause: (functionParameterClause parameters: _* @params))
body: (codeBlock statements: _* @body_stmts)?)
=>
(constructor_declaration
modifier: {mods}
+ parameter: {params}
body: (block stmt: {body_stmts}))
),
// Deinit declaration → destructor_declaration. Body statements optional.
diff --git a/unified/extractor/tests/corpus/swift/collections/set-literal.output b/unified/extractor/tests/corpus/swift/collections/set-literal.output
index c29492c9bc0..a06670231eb 100644
--- a/unified/extractor/tests/corpus/swift/collections/set-literal.output
+++ b/unified/extractor/tests/corpus/swift/collections/set-literal.output
@@ -66,8 +66,13 @@ top_level
name_pattern
identifier: identifier "s"
type:
- named_type_expr
- name: identifier "Set"
+ generic_type_expr
+ base:
+ named_type_expr
+ name: identifier "Set"
+ type_argument:
+ named_type_expr
+ name: identifier "Int"
value:
array_literal
element:
diff --git a/unified/extractor/tests/corpus/swift/collections/subscript-access.output b/unified/extractor/tests/corpus/swift/collections/subscript-access.output
index f7e518b8477..ec24f0c1f1d 100644
--- a/unified/extractor/tests/corpus/swift/collections/subscript-access.output
+++ b/unified/extractor/tests/corpus/swift/collections/subscript-access.output
@@ -1,6 +1,6 @@
-// TODO: tree-sitter-swift parses `xs[0]` as a call_expression (same shape
-// as `xs(0)`), so the mapping currently produces a call_expr. Update the
-// parser / add a separate subscript_expr node and remap when fixed.
+// TODO: `xs[0]` is mapped to a call_expr, even though swift-syntax reports a
+// distinct subscriptCallExpr. Giving subscripts their own shape needs only a
+// subscript_expr node in ast_types.yml and a remap.
let first = xs[0]
---
diff --git a/unified/extractor/tests/corpus/swift/collections/subscript-access.swift b/unified/extractor/tests/corpus/swift/collections/subscript-access.swift
index 00a85bda433..eeffca01739 100644
--- a/unified/extractor/tests/corpus/swift/collections/subscript-access.swift
+++ b/unified/extractor/tests/corpus/swift/collections/subscript-access.swift
@@ -1,4 +1,4 @@
-// TODO: tree-sitter-swift parses `xs[0]` as a call_expression (same shape
-// as `xs(0)`), so the mapping currently produces a call_expr. Update the
-// parser / add a separate subscript_expr node and remap when fixed.
+// TODO: `xs[0]` is mapped to a call_expr, even though swift-syntax reports a
+// distinct subscriptCallExpr. Giving subscripts their own shape needs only a
+// subscript_expr node in ast_types.yml and a remap.
let first = xs[0]
diff --git a/unified/extractor/tests/corpus/swift/control-flow/defer-statement.output b/unified/extractor/tests/corpus/swift/control-flow/defer-statement.output
new file mode 100644
index 00000000000..6e8ec9ae3b9
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/control-flow/defer-statement.output
@@ -0,0 +1,94 @@
+func withCleanup() {
+ defer { print("cleanup") }
+ print("work")
+}
+
+---
+
+sourceFile
+ endOfFileToken: endOfFile
+ statements:
+ codeBlockItem
+ item:
+ functionDecl
+ attributes:
+ body:
+ codeBlock
+ leftBrace: {
+ rightBrace: }
+ statements:
+ codeBlockItem
+ item:
+ deferStmt
+ body:
+ codeBlock
+ leftBrace: {
+ rightBrace: }
+ statements:
+ codeBlockItem
+ item:
+ functionCallExpr
+ leftParen: (
+ rightParen: )
+ arguments:
+ labeledExpr
+ expression:
+ stringLiteralExpr
+ closingQuote: "
+ openingQuote: "
+ segments:
+ stringSegment
+ content: stringSegment "cleanup"
+ additionalTrailingClosures:
+ calledExpression:
+ declReferenceExpr
+ baseName: identifier "print"
+ deferKeyword: defer
+ codeBlockItem
+ item:
+ functionCallExpr
+ leftParen: (
+ rightParen: )
+ arguments:
+ labeledExpr
+ expression:
+ stringLiteralExpr
+ closingQuote: "
+ openingQuote: "
+ segments:
+ stringSegment
+ content: stringSegment "work"
+ additionalTrailingClosures:
+ calledExpression:
+ declReferenceExpr
+ baseName: identifier "print"
+ name: identifier "withCleanup"
+ modifiers:
+ signature:
+ functionSignature
+ parameterClause:
+ functionParameterClause
+ leftParen: (
+ rightParen: )
+ parameters:
+ funcKeyword: func
+
+---
+
+top_level
+ body:
+ block
+ stmt:
+ function_declaration
+ name: identifier "withCleanup"
+ body:
+ block
+ stmt:
+ unsupported_node "defer { print(\"cleanup\") }"
+ call_expr
+ callee:
+ name_expr
+ identifier: identifier "print"
+ argument:
+ argument
+ value: string_literal "\"work\""
diff --git a/unified/extractor/tests/corpus/swift/control-flow/defer-statement.swift b/unified/extractor/tests/corpus/swift/control-flow/defer-statement.swift
new file mode 100644
index 00000000000..0bb8820326d
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/control-flow/defer-statement.swift
@@ -0,0 +1,4 @@
+func withCleanup() {
+ defer { print("cleanup") }
+ print("work")
+}
diff --git a/unified/extractor/tests/corpus/swift/control-flow/discard-statement.output b/unified/extractor/tests/corpus/swift/control-flow/discard-statement.output
new file mode 100644
index 00000000000..7e0eac29c0f
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/control-flow/discard-statement.output
@@ -0,0 +1,81 @@
+struct Resource: ~Copyable {
+ consuming func close() {
+ discard self
+ }
+}
+
+---
+
+sourceFile
+ endOfFileToken: endOfFile
+ statements:
+ codeBlockItem
+ item:
+ structDecl
+ attributes:
+ name: identifier "Resource"
+ inheritanceClause:
+ inheritanceClause
+ colon: :
+ inheritedTypes:
+ inheritedType
+ type:
+ suppressedType
+ type:
+ identifierType
+ name: identifier "Copyable"
+ withoutTilde: prefixOperator "~"
+ memberBlock:
+ memberBlock
+ leftBrace: {
+ rightBrace: }
+ members:
+ memberBlockItem
+ decl:
+ functionDecl
+ attributes:
+ body:
+ codeBlock
+ leftBrace: {
+ rightBrace: }
+ statements:
+ codeBlockItem
+ item:
+ discardStmt
+ expression:
+ declReferenceExpr
+ baseName: self
+ discardKeyword: discard
+ name: identifier "close"
+ modifiers:
+ declModifier
+ name: consuming
+ signature:
+ functionSignature
+ parameterClause:
+ functionParameterClause
+ leftParen: (
+ rightParen: )
+ parameters:
+ funcKeyword: func
+ modifiers:
+ structKeyword: struct
+
+---
+
+top_level
+ body:
+ block
+ stmt:
+ class_like_declaration
+ modifier: modifier "struct"
+ name: identifier "Resource"
+ base_type:
+ base_type
+ type: unsupported_node "~Copyable"
+ member:
+ function_declaration
+ name: identifier "close"
+ body:
+ block
+ stmt: unsupported_node "discard self"
diff --git a/unified/extractor/tests/corpus/swift/control-flow/discard-statement.swift b/unified/extractor/tests/corpus/swift/control-flow/discard-statement.swift
new file mode 100644
index 00000000000..8f207d03da9
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/control-flow/discard-statement.swift
@@ -0,0 +1,5 @@
+struct Resource: ~Copyable {
+ consuming func close() {
+ discard self
+ }
+}
diff --git a/unified/extractor/tests/corpus/swift/control-flow/fallthrough.output b/unified/extractor/tests/corpus/swift/control-flow/fallthrough.output
new file mode 100644
index 00000000000..9cfe8104840
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/control-flow/fallthrough.output
@@ -0,0 +1,118 @@
+func classify(_ x: Int) {
+ switch x {
+ case 1:
+ fallthrough
+ default:
+ break
+ }
+}
+
+---
+
+sourceFile
+ endOfFileToken: endOfFile
+ statements:
+ codeBlockItem
+ item:
+ functionDecl
+ attributes:
+ body:
+ codeBlock
+ leftBrace: {
+ rightBrace: }
+ statements:
+ codeBlockItem
+ item:
+ expressionStmt
+ expression:
+ switchExpr
+ leftBrace: {
+ rightBrace: }
+ cases:
+ switchCase
+ label:
+ switchCaseLabel
+ colon: :
+ caseKeyword: case
+ caseItems:
+ switchCaseItem
+ pattern:
+ expressionPattern
+ expression:
+ integerLiteralExpr
+ literal: integerLiteral "1"
+ statements:
+ codeBlockItem
+ item:
+ fallThroughStmt
+ fallthroughKeyword: fallthrough
+ switchCase
+ label:
+ switchDefaultLabel
+ colon: :
+ defaultKeyword: default
+ statements:
+ codeBlockItem
+ item:
+ breakStmt
+ breakKeyword: break
+ subject:
+ declReferenceExpr
+ baseName: identifier "x"
+ switchKeyword: switch
+ name: identifier "classify"
+ modifiers:
+ signature:
+ functionSignature
+ parameterClause:
+ functionParameterClause
+ leftParen: (
+ rightParen: )
+ parameters:
+ functionParameter
+ colon: :
+ attributes:
+ modifiers:
+ type:
+ identifierType
+ name: identifier "Int"
+ firstName: _
+ secondName: identifier "x"
+ funcKeyword: func
+
+---
+
+top_level
+ body:
+ block
+ stmt:
+ function_declaration
+ name: identifier "classify"
+ parameter:
+ parameter
+ external_name: identifier "_"
+ type:
+ named_type_expr
+ name: identifier "Int"
+ pattern:
+ name_pattern
+ identifier: identifier "x"
+ body:
+ block
+ stmt:
+ switch_expr
+ value:
+ name_expr
+ identifier: identifier "x"
+ case:
+ switch_case
+ pattern:
+ expr_equality_pattern
+ expr: int_literal "1"
+ body:
+ block
+ stmt: unsupported_node "fallthrough"
+ switch_case
+ body:
+ block
+ stmt: break_expr "break"
diff --git a/unified/extractor/tests/corpus/swift/control-flow/fallthrough.swift b/unified/extractor/tests/corpus/swift/control-flow/fallthrough.swift
new file mode 100644
index 00000000000..bedbf059075
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/control-flow/fallthrough.swift
@@ -0,0 +1,8 @@
+func classify(_ x: Int) {
+ switch x {
+ case 1:
+ fallthrough
+ default:
+ break
+ }
+}
diff --git a/unified/extractor/tests/corpus/swift/control-flow/switch-case-item-where-clauses.output b/unified/extractor/tests/corpus/swift/control-flow/switch-case-item-where-clauses.output
new file mode 100644
index 00000000000..9d2041aa2ad
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/control-flow/switch-case-item-where-clauses.output
@@ -0,0 +1,222 @@
+switch n {
+case let x where x > 0:
+ print("positive")
+case let y where y < 0, 0:
+ print("non-positive")
+default:
+ print("other")
+}
+
+---
+
+sourceFile
+ endOfFileToken: endOfFile
+ statements:
+ codeBlockItem
+ item:
+ expressionStmt
+ expression:
+ switchExpr
+ leftBrace: {
+ rightBrace: }
+ cases:
+ switchCase
+ label:
+ switchCaseLabel
+ colon: :
+ caseKeyword: case
+ caseItems:
+ switchCaseItem
+ pattern:
+ valueBindingPattern
+ pattern:
+ identifierPattern
+ identifier: identifier "x"
+ bindingSpecifier: let
+ whereClause:
+ whereClause
+ condition:
+ infixOperatorExpr
+ operator:
+ binaryOperatorExpr
+ operator: binaryOperator ">"
+ leftOperand:
+ declReferenceExpr
+ baseName: identifier "x"
+ rightOperand:
+ integerLiteralExpr
+ literal: integerLiteral "0"
+ whereKeyword: where
+ statements:
+ codeBlockItem
+ item:
+ functionCallExpr
+ leftParen: (
+ rightParen: )
+ arguments:
+ labeledExpr
+ expression:
+ stringLiteralExpr
+ closingQuote: "
+ openingQuote: "
+ segments:
+ stringSegment
+ content: stringSegment "positive"
+ additionalTrailingClosures:
+ calledExpression:
+ declReferenceExpr
+ baseName: identifier "print"
+ switchCase
+ label:
+ switchCaseLabel
+ colon: :
+ caseKeyword: case
+ caseItems:
+ switchCaseItem
+ trailingComma: ,
+ pattern:
+ valueBindingPattern
+ pattern:
+ identifierPattern
+ identifier: identifier "y"
+ bindingSpecifier: let
+ whereClause:
+ whereClause
+ condition:
+ infixOperatorExpr
+ operator:
+ binaryOperatorExpr
+ operator: binaryOperator "<"
+ leftOperand:
+ declReferenceExpr
+ baseName: identifier "y"
+ rightOperand:
+ integerLiteralExpr
+ literal: integerLiteral "0"
+ whereKeyword: where
+ switchCaseItem
+ pattern:
+ expressionPattern
+ expression:
+ integerLiteralExpr
+ literal: integerLiteral "0"
+ statements:
+ codeBlockItem
+ item:
+ functionCallExpr
+ leftParen: (
+ rightParen: )
+ arguments:
+ labeledExpr
+ expression:
+ stringLiteralExpr
+ closingQuote: "
+ openingQuote: "
+ segments:
+ stringSegment
+ content: stringSegment "non-positive"
+ additionalTrailingClosures:
+ calledExpression:
+ declReferenceExpr
+ baseName: identifier "print"
+ switchCase
+ label:
+ switchDefaultLabel
+ colon: :
+ defaultKeyword: default
+ statements:
+ codeBlockItem
+ item:
+ functionCallExpr
+ leftParen: (
+ rightParen: )
+ arguments:
+ labeledExpr
+ expression:
+ stringLiteralExpr
+ closingQuote: "
+ openingQuote: "
+ segments:
+ stringSegment
+ content: stringSegment "other"
+ additionalTrailingClosures:
+ calledExpression:
+ declReferenceExpr
+ baseName: identifier "print"
+ subject:
+ declReferenceExpr
+ baseName: identifier "n"
+ switchKeyword: switch
+
+---
+
+top_level
+ body:
+ block
+ stmt:
+ switch_expr
+ value:
+ name_expr
+ identifier: identifier "n"
+ case:
+ switch_case
+ pattern:
+ conditional_pattern
+ condition:
+ binary_expr
+ left:
+ name_expr
+ identifier: identifier "x"
+ operator: infix_operator ">"
+ right: int_literal "0"
+ pattern:
+ name_pattern
+ identifier: identifier "x"
+ body:
+ block
+ stmt:
+ call_expr
+ callee:
+ name_expr
+ identifier: identifier "print"
+ argument:
+ argument
+ value: string_literal "\"positive\""
+ switch_case
+ pattern:
+ or_pattern
+ pattern:
+ conditional_pattern
+ condition:
+ binary_expr
+ left:
+ name_expr
+ identifier: identifier "y"
+ operator: infix_operator "<"
+ right: int_literal "0"
+ pattern:
+ name_pattern
+ identifier: identifier "y"
+ expr_equality_pattern
+ expr: int_literal "0"
+ body:
+ block
+ stmt:
+ call_expr
+ callee:
+ name_expr
+ identifier: identifier "print"
+ argument:
+ argument
+ value: string_literal "\"non-positive\""
+ switch_case
+ body:
+ block
+ stmt:
+ call_expr
+ callee:
+ name_expr
+ identifier: identifier "print"
+ argument:
+ argument
+ value: string_literal "\"other\""
diff --git a/unified/extractor/tests/corpus/swift/control-flow/switch-case-item-where-clauses.swift b/unified/extractor/tests/corpus/swift/control-flow/switch-case-item-where-clauses.swift
new file mode 100644
index 00000000000..50003cb1fbc
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/control-flow/switch-case-item-where-clauses.swift
@@ -0,0 +1,8 @@
+switch n {
+case let x where x > 0:
+ print("positive")
+case let y where y < 0, 0:
+ print("non-positive")
+default:
+ print("other")
+}
diff --git a/unified/extractor/tests/corpus/swift/expressions/consume-expression.output b/unified/extractor/tests/corpus/swift/expressions/consume-expression.output
new file mode 100644
index 00000000000..f20f89b7255
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/expressions/consume-expression.output
@@ -0,0 +1,85 @@
+let original = [1, 2, 3]
+let consumed = consume original
+
+---
+
+sourceFile
+ endOfFileToken: endOfFile
+ statements:
+ codeBlockItem
+ item:
+ variableDecl
+ attributes:
+ modifiers:
+ bindingSpecifier: let
+ bindings:
+ patternBinding
+ initializer:
+ initializerClause
+ equal: =
+ value:
+ arrayExpr
+ elements:
+ arrayElement
+ expression:
+ integerLiteralExpr
+ literal: integerLiteral "1"
+ trailingComma: ,
+ arrayElement
+ expression:
+ integerLiteralExpr
+ literal: integerLiteral "2"
+ trailingComma: ,
+ arrayElement
+ expression:
+ integerLiteralExpr
+ literal: integerLiteral "3"
+ leftSquare: [
+ rightSquare: ]
+ pattern:
+ identifierPattern
+ identifier: identifier "original"
+ codeBlockItem
+ item:
+ variableDecl
+ attributes:
+ modifiers:
+ bindingSpecifier: let
+ bindings:
+ patternBinding
+ initializer:
+ initializerClause
+ equal: =
+ value:
+ consumeExpr
+ expression:
+ declReferenceExpr
+ baseName: identifier "original"
+ consumeKeyword: consume
+ pattern:
+ identifierPattern
+ identifier: identifier "consumed"
+
+---
+
+top_level
+ body:
+ block
+ stmt:
+ variable_declaration
+ modifier: modifier "let"
+ pattern:
+ name_pattern
+ identifier: identifier "original"
+ value:
+ array_literal
+ element:
+ int_literal "1"
+ int_literal "2"
+ int_literal "3"
+ variable_declaration
+ modifier: modifier "let"
+ pattern:
+ name_pattern
+ identifier: identifier "consumed"
+ value: unsupported_node "consume original"
diff --git a/unified/extractor/tests/corpus/swift/expressions/consume-expression.swift b/unified/extractor/tests/corpus/swift/expressions/consume-expression.swift
new file mode 100644
index 00000000000..37922e03679
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/expressions/consume-expression.swift
@@ -0,0 +1,2 @@
+let original = [1, 2, 3]
+let consumed = consume original
diff --git a/unified/extractor/tests/corpus/swift/expressions/copy-expression.output b/unified/extractor/tests/corpus/swift/expressions/copy-expression.output
new file mode 100644
index 00000000000..9f065b046a9
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/expressions/copy-expression.output
@@ -0,0 +1,85 @@
+let original = [1, 2, 3]
+let copied = copy original
+
+---
+
+sourceFile
+ endOfFileToken: endOfFile
+ statements:
+ codeBlockItem
+ item:
+ variableDecl
+ attributes:
+ modifiers:
+ bindingSpecifier: let
+ bindings:
+ patternBinding
+ initializer:
+ initializerClause
+ equal: =
+ value:
+ arrayExpr
+ elements:
+ arrayElement
+ expression:
+ integerLiteralExpr
+ literal: integerLiteral "1"
+ trailingComma: ,
+ arrayElement
+ expression:
+ integerLiteralExpr
+ literal: integerLiteral "2"
+ trailingComma: ,
+ arrayElement
+ expression:
+ integerLiteralExpr
+ literal: integerLiteral "3"
+ leftSquare: [
+ rightSquare: ]
+ pattern:
+ identifierPattern
+ identifier: identifier "original"
+ codeBlockItem
+ item:
+ variableDecl
+ attributes:
+ modifiers:
+ bindingSpecifier: let
+ bindings:
+ patternBinding
+ initializer:
+ initializerClause
+ equal: =
+ value:
+ copyExpr
+ expression:
+ declReferenceExpr
+ baseName: identifier "original"
+ copyKeyword: copy
+ pattern:
+ identifierPattern
+ identifier: identifier "copied"
+
+---
+
+top_level
+ body:
+ block
+ stmt:
+ variable_declaration
+ modifier: modifier "let"
+ pattern:
+ name_pattern
+ identifier: identifier "original"
+ value:
+ array_literal
+ element:
+ int_literal "1"
+ int_literal "2"
+ int_literal "3"
+ variable_declaration
+ modifier: modifier "let"
+ pattern:
+ name_pattern
+ identifier: identifier "copied"
+ value: unsupported_node "copy original"
diff --git a/unified/extractor/tests/corpus/swift/expressions/copy-expression.swift b/unified/extractor/tests/corpus/swift/expressions/copy-expression.swift
new file mode 100644
index 00000000000..9b7fa65909b
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/expressions/copy-expression.swift
@@ -0,0 +1,2 @@
+let original = [1, 2, 3]
+let copied = copy original
diff --git a/unified/extractor/tests/corpus/swift/expressions/generic-specialization-expression.output b/unified/extractor/tests/corpus/swift/expressions/generic-specialization-expression.output
new file mode 100644
index 00000000000..4f3bd021441
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/expressions/generic-specialization-expression.output
@@ -0,0 +1,56 @@
+let numbers = Array()
+
+---
+
+sourceFile
+ endOfFileToken: endOfFile
+ statements:
+ codeBlockItem
+ item:
+ variableDecl
+ attributes:
+ modifiers:
+ bindingSpecifier: let
+ bindings:
+ patternBinding
+ initializer:
+ initializerClause
+ equal: =
+ value:
+ functionCallExpr
+ leftParen: (
+ rightParen: )
+ arguments:
+ additionalTrailingClosures:
+ calledExpression:
+ genericSpecializationExpr
+ expression:
+ declReferenceExpr
+ baseName: identifier "Array"
+ genericArgumentClause:
+ genericArgumentClause
+ arguments:
+ genericArgument
+ argument:
+ identifierType
+ name: identifier "Int"
+ leftAngle: <
+ rightAngle: >
+ pattern:
+ identifierPattern
+ identifier: identifier "numbers"
+
+---
+
+top_level
+ body:
+ block
+ stmt:
+ variable_declaration
+ modifier: modifier "let"
+ pattern:
+ name_pattern
+ identifier: identifier "numbers"
+ value:
+ call_expr
+ callee: unsupported_node "Array"
diff --git a/unified/extractor/tests/corpus/swift/expressions/generic-specialization-expression.swift b/unified/extractor/tests/corpus/swift/expressions/generic-specialization-expression.swift
new file mode 100644
index 00000000000..8e5f07de556
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/expressions/generic-specialization-expression.swift
@@ -0,0 +1 @@
+let numbers = Array()
diff --git a/unified/extractor/tests/corpus/swift/expressions/key-path-expression.output b/unified/extractor/tests/corpus/swift/expressions/key-path-expression.output
new file mode 100644
index 00000000000..a803e9e594f
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/expressions/key-path-expression.output
@@ -0,0 +1,48 @@
+let keyPath = \String.count
+
+---
+
+sourceFile
+ endOfFileToken: endOfFile
+ statements:
+ codeBlockItem
+ item:
+ variableDecl
+ attributes:
+ modifiers:
+ bindingSpecifier: let
+ bindings:
+ patternBinding
+ initializer:
+ initializerClause
+ equal: =
+ value:
+ keyPathExpr
+ backslash: \
+ components:
+ keyPathComponent
+ period: .
+ component:
+ keyPathPropertyComponent
+ declName:
+ declReferenceExpr
+ baseName: identifier "count"
+ root:
+ identifierType
+ name: identifier "String"
+ pattern:
+ identifierPattern
+ identifier: identifier "keyPath"
+
+---
+
+top_level
+ body:
+ block
+ stmt:
+ variable_declaration
+ modifier: modifier "let"
+ pattern:
+ name_pattern
+ identifier: identifier "keyPath"
+ value: unsupported_node "\\String.count"
diff --git a/unified/extractor/tests/corpus/swift/expressions/key-path-expression.swift b/unified/extractor/tests/corpus/swift/expressions/key-path-expression.swift
new file mode 100644
index 00000000000..943f181b340
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/expressions/key-path-expression.swift
@@ -0,0 +1 @@
+let keyPath = \String.count
diff --git a/unified/extractor/tests/corpus/swift/expressions/unsafe-expression.output b/unified/extractor/tests/corpus/swift/expressions/unsafe-expression.output
new file mode 100644
index 00000000000..2bdc964ddea
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/expressions/unsafe-expression.output
@@ -0,0 +1,51 @@
+func doWork() {}
+unsafe doWork()
+
+---
+
+sourceFile
+ endOfFileToken: endOfFile
+ statements:
+ codeBlockItem
+ item:
+ functionDecl
+ attributes:
+ body:
+ codeBlock
+ leftBrace: {
+ rightBrace: }
+ statements:
+ name: identifier "doWork"
+ modifiers:
+ signature:
+ functionSignature
+ parameterClause:
+ functionParameterClause
+ leftParen: (
+ rightParen: )
+ parameters:
+ funcKeyword: func
+ codeBlockItem
+ item:
+ unsafeExpr
+ expression:
+ functionCallExpr
+ leftParen: (
+ rightParen: )
+ arguments:
+ additionalTrailingClosures:
+ calledExpression:
+ declReferenceExpr
+ baseName: identifier "doWork"
+ unsafeKeyword: unsafe
+
+---
+
+top_level
+ body:
+ block
+ stmt:
+ function_declaration
+ name: identifier "doWork"
+ body: block "func doWork() {}"
+ unsupported_node "unsafe doWork()"
diff --git a/unified/extractor/tests/corpus/swift/expressions/unsafe-expression.swift b/unified/extractor/tests/corpus/swift/expressions/unsafe-expression.swift
new file mode 100644
index 00000000000..e398f9cb659
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/expressions/unsafe-expression.swift
@@ -0,0 +1,2 @@
+func doWork() {}
+unsafe doWork()
diff --git a/unified/extractor/tests/corpus/swift/functions/call-with-inout-argument.output b/unified/extractor/tests/corpus/swift/functions/call-with-inout-argument.output
new file mode 100644
index 00000000000..3dae9884c81
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/functions/call-with-inout-argument.output
@@ -0,0 +1,96 @@
+var a = 1
+var b = 2
+swap(&a, &b)
+
+---
+
+sourceFile
+ endOfFileToken: endOfFile
+ statements:
+ codeBlockItem
+ item:
+ variableDecl
+ attributes:
+ modifiers:
+ bindingSpecifier: var
+ bindings:
+ patternBinding
+ initializer:
+ initializerClause
+ equal: =
+ value:
+ integerLiteralExpr
+ literal: integerLiteral "1"
+ pattern:
+ identifierPattern
+ identifier: identifier "a"
+ codeBlockItem
+ item:
+ variableDecl
+ attributes:
+ modifiers:
+ bindingSpecifier: var
+ bindings:
+ patternBinding
+ initializer:
+ initializerClause
+ equal: =
+ value:
+ integerLiteralExpr
+ literal: integerLiteral "2"
+ pattern:
+ identifierPattern
+ identifier: identifier "b"
+ codeBlockItem
+ item:
+ functionCallExpr
+ leftParen: (
+ rightParen: )
+ arguments:
+ labeledExpr
+ expression:
+ inOutExpr
+ expression:
+ declReferenceExpr
+ baseName: identifier "a"
+ ampersand: &
+ trailingComma: ,
+ labeledExpr
+ expression:
+ inOutExpr
+ expression:
+ declReferenceExpr
+ baseName: identifier "b"
+ ampersand: &
+ additionalTrailingClosures:
+ calledExpression:
+ declReferenceExpr
+ baseName: identifier "swap"
+
+---
+
+top_level
+ body:
+ block
+ stmt:
+ variable_declaration
+ modifier: modifier "var"
+ pattern:
+ name_pattern
+ identifier: identifier "a"
+ value: int_literal "1"
+ variable_declaration
+ modifier: modifier "var"
+ pattern:
+ name_pattern
+ identifier: identifier "b"
+ value: int_literal "2"
+ call_expr
+ callee:
+ name_expr
+ identifier: identifier "swap"
+ argument:
+ argument
+ value: unsupported_node "&a"
+ argument
+ value: unsupported_node "&b"
diff --git a/unified/extractor/tests/corpus/swift/functions/call-with-inout-argument.swift b/unified/extractor/tests/corpus/swift/functions/call-with-inout-argument.swift
new file mode 100644
index 00000000000..fb71b4c89bf
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/functions/call-with-inout-argument.swift
@@ -0,0 +1,3 @@
+var a = 1
+var b = 2
+swap(&a, &b)
diff --git a/unified/extractor/tests/corpus/swift/functions/function-with-default-parameter-value.output b/unified/extractor/tests/corpus/swift/functions/function-with-default-parameter-value.output
index 01c0ddef856..3495a13106f 100644
--- a/unified/extractor/tests/corpus/swift/functions/function-with-default-parameter-value.output
+++ b/unified/extractor/tests/corpus/swift/functions/function-with-default-parameter-value.output
@@ -69,6 +69,9 @@ top_level
name: identifier "greet"
parameter:
parameter
+ type:
+ named_type_expr
+ name: identifier "String"
pattern:
name_pattern
identifier: identifier "name"
diff --git a/unified/extractor/tests/corpus/swift/functions/function-with-inout-parameter.output b/unified/extractor/tests/corpus/swift/functions/function-with-inout-parameter.output
new file mode 100644
index 00000000000..232fb6dc2db
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/functions/function-with-inout-parameter.output
@@ -0,0 +1,81 @@
+func increment(_ x: inout Int) {
+ x += 1
+}
+
+---
+
+sourceFile
+ endOfFileToken: endOfFile
+ statements:
+ codeBlockItem
+ item:
+ functionDecl
+ attributes:
+ body:
+ codeBlock
+ leftBrace: {
+ rightBrace: }
+ statements:
+ codeBlockItem
+ item:
+ infixOperatorExpr
+ operator:
+ binaryOperatorExpr
+ operator: binaryOperator "+="
+ leftOperand:
+ declReferenceExpr
+ baseName: identifier "x"
+ rightOperand:
+ integerLiteralExpr
+ literal: integerLiteral "1"
+ name: identifier "increment"
+ modifiers:
+ signature:
+ functionSignature
+ parameterClause:
+ functionParameterClause
+ leftParen: (
+ rightParen: )
+ parameters:
+ functionParameter
+ colon: :
+ attributes:
+ modifiers:
+ type:
+ attributedType
+ attributes:
+ baseType:
+ identifierType
+ name: identifier "Int"
+ lateSpecifiers:
+ specifiers:
+ simpleTypeSpecifier
+ specifier: inout
+ firstName: _
+ secondName: identifier "x"
+ funcKeyword: func
+
+---
+
+top_level
+ body:
+ block
+ stmt:
+ function_declaration
+ name: identifier "increment"
+ parameter:
+ parameter
+ external_name: identifier "_"
+ type: unsupported_node "inout Int"
+ pattern:
+ name_pattern
+ identifier: identifier "x"
+ body:
+ block
+ stmt:
+ compound_assign_expr
+ target:
+ name_expr
+ identifier: identifier "x"
+ operator: infix_operator "+="
+ value: int_literal "1"
diff --git a/unified/extractor/tests/corpus/swift/functions/function-with-inout-parameter.swift b/unified/extractor/tests/corpus/swift/functions/function-with-inout-parameter.swift
new file mode 100644
index 00000000000..5741998e8b5
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/functions/function-with-inout-parameter.swift
@@ -0,0 +1,3 @@
+func increment(_ x: inout Int) {
+ x += 1
+}
diff --git a/unified/extractor/tests/corpus/swift/functions/function-with-named-parameters.output b/unified/extractor/tests/corpus/swift/functions/function-with-named-parameters.output
index f2024b47362..7488edbcb23 100644
--- a/unified/extractor/tests/corpus/swift/functions/function-with-named-parameters.output
+++ b/unified/extractor/tests/corpus/swift/functions/function-with-named-parameters.output
@@ -61,6 +61,9 @@ top_level
parameter:
parameter
external_name: identifier "person"
+ type:
+ named_type_expr
+ name: identifier "String"
pattern:
name_pattern
identifier: identifier "name"
diff --git a/unified/extractor/tests/corpus/swift/functions/function-with-parameters-and-return-type.output b/unified/extractor/tests/corpus/swift/functions/function-with-parameters-and-return-type.output
index 1ffb391dbc5..e69b1930767 100644
--- a/unified/extractor/tests/corpus/swift/functions/function-with-parameters-and-return-type.output
+++ b/unified/extractor/tests/corpus/swift/functions/function-with-parameters-and-return-type.output
@@ -78,11 +78,17 @@ top_level
parameter:
parameter
external_name: identifier "_"
+ type:
+ named_type_expr
+ name: identifier "Int"
pattern:
name_pattern
identifier: identifier "a"
parameter
external_name: identifier "_"
+ type:
+ named_type_expr
+ name: identifier "Int"
pattern:
name_pattern
identifier: identifier "b"
diff --git a/unified/extractor/tests/corpus/swift/functions/generic-function.output b/unified/extractor/tests/corpus/swift/functions/generic-function.output
index 1652f7f4741..d09aac2744a 100644
--- a/unified/extractor/tests/corpus/swift/functions/generic-function.output
+++ b/unified/extractor/tests/corpus/swift/functions/generic-function.output
@@ -68,6 +68,9 @@ top_level
parameter:
parameter
external_name: identifier "_"
+ type:
+ named_type_expr
+ name: identifier "T"
pattern:
name_pattern
identifier: identifier "x"
diff --git a/unified/extractor/tests/corpus/swift/functions/variadic-function.output b/unified/extractor/tests/corpus/swift/functions/variadic-function.output
index 571f07c35e0..78c20ffc01e 100644
--- a/unified/extractor/tests/corpus/swift/functions/variadic-function.output
+++ b/unified/extractor/tests/corpus/swift/functions/variadic-function.output
@@ -82,6 +82,9 @@ top_level
parameter:
parameter
external_name: identifier "_"
+ type:
+ named_type_expr
+ name: identifier "Int"
pattern:
name_pattern
identifier: identifier "values"
diff --git a/unified/extractor/tests/corpus/swift/literals/line-magic-literal.output b/unified/extractor/tests/corpus/swift/literals/line-magic-literal.output
new file mode 100644
index 00000000000..1616055fc16
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/literals/line-magic-literal.output
@@ -0,0 +1,40 @@
+let currentLine = #line
+
+---
+
+sourceFile
+ endOfFileToken: endOfFile
+ statements:
+ codeBlockItem
+ item:
+ variableDecl
+ attributes:
+ modifiers:
+ bindingSpecifier: let
+ bindings:
+ patternBinding
+ initializer:
+ initializerClause
+ equal: =
+ value:
+ macroExpansionExpr
+ arguments:
+ additionalTrailingClosures:
+ macroName: identifier "line"
+ pound: #
+ pattern:
+ identifierPattern
+ identifier: identifier "currentLine"
+
+---
+
+top_level
+ body:
+ block
+ stmt:
+ variable_declaration
+ modifier: modifier "let"
+ pattern:
+ name_pattern
+ identifier: identifier "currentLine"
+ value: unsupported_node "#line"
diff --git a/unified/extractor/tests/corpus/swift/literals/line-magic-literal.swift b/unified/extractor/tests/corpus/swift/literals/line-magic-literal.swift
new file mode 100644
index 00000000000..11bb1ab77a9
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/literals/line-magic-literal.swift
@@ -0,0 +1 @@
+let currentLine = #line
diff --git a/unified/extractor/tests/corpus/swift/operators/custom-postfix-operator.output b/unified/extractor/tests/corpus/swift/operators/custom-postfix-operator.output
new file mode 100644
index 00000000000..5067671aa99
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/operators/custom-postfix-operator.output
@@ -0,0 +1,48 @@
+postfix operator ^^
+let squared = 3^^
+
+---
+
+sourceFile
+ endOfFileToken: endOfFile
+ statements:
+ codeBlockItem
+ item:
+ operatorDecl
+ name: binaryOperator "^^"
+ fixitySpecifier: postfix
+ operatorKeyword: operator
+ codeBlockItem
+ item:
+ variableDecl
+ attributes:
+ modifiers:
+ bindingSpecifier: let
+ bindings:
+ patternBinding
+ initializer:
+ initializerClause
+ equal: =
+ value:
+ postfixOperatorExpr
+ expression:
+ integerLiteralExpr
+ literal: integerLiteral "3"
+ operator: postfixOperator "^^"
+ pattern:
+ identifierPattern
+ identifier: identifier "squared"
+
+---
+
+top_level
+ body:
+ block
+ stmt:
+ unsupported_node "postfix operator ^^"
+ variable_declaration
+ modifier: modifier "let"
+ pattern:
+ name_pattern
+ identifier: identifier "squared"
+ value: unsupported_node "3^^"
diff --git a/unified/extractor/tests/corpus/swift/operators/custom-postfix-operator.swift b/unified/extractor/tests/corpus/swift/operators/custom-postfix-operator.swift
new file mode 100644
index 00000000000..71951740039
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/operators/custom-postfix-operator.swift
@@ -0,0 +1,2 @@
+postfix operator ^^
+let squared = 3^^
diff --git a/unified/extractor/tests/corpus/swift/operators/partial-range-from.output b/unified/extractor/tests/corpus/swift/operators/partial-range-from.output
new file mode 100644
index 00000000000..1b9208cedf8
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/operators/partial-range-from.output
@@ -0,0 +1,40 @@
+let range = 3...
+
+---
+
+sourceFile
+ endOfFileToken: endOfFile
+ statements:
+ codeBlockItem
+ item:
+ variableDecl
+ attributes:
+ modifiers:
+ bindingSpecifier: let
+ bindings:
+ patternBinding
+ initializer:
+ initializerClause
+ equal: =
+ value:
+ postfixOperatorExpr
+ expression:
+ integerLiteralExpr
+ literal: integerLiteral "3"
+ operator: postfixOperator "..."
+ pattern:
+ identifierPattern
+ identifier: identifier "range"
+
+---
+
+top_level
+ body:
+ block
+ stmt:
+ variable_declaration
+ modifier: modifier "let"
+ pattern:
+ name_pattern
+ identifier: identifier "range"
+ value: unsupported_node "3..."
diff --git a/unified/extractor/tests/corpus/swift/operators/partial-range-from.swift b/unified/extractor/tests/corpus/swift/operators/partial-range-from.swift
new file mode 100644
index 00000000000..e223dc29516
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/operators/partial-range-from.swift
@@ -0,0 +1 @@
+let range = 3...
diff --git a/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-casts.output b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-casts.output
new file mode 100644
index 00000000000..a0563c7bc88
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-casts.output
@@ -0,0 +1,141 @@
+func casts(_ a: Any, _ b: Int) {
+ _ = a as Int .& b
+ _ = a is Int .& b
+}
+
+---
+
+sourceFile
+ endOfFileToken: endOfFile
+ statements:
+ codeBlockItem
+ item:
+ functionDecl
+ attributes:
+ body:
+ codeBlock
+ leftBrace: {
+ rightBrace: }
+ statements:
+ codeBlockItem
+ item:
+ sequenceExpr
+ elements:
+ discardAssignmentExpr
+ wildcard: _
+ assignmentExpr
+ equal: =
+ declReferenceExpr
+ baseName: identifier "a"
+ unresolvedAsExpr
+ asKeyword: as
+ typeExpr
+ type:
+ identifierType
+ name: identifier "Int"
+ binaryOperatorExpr
+ operator: binaryOperator ".&"
+ declReferenceExpr
+ baseName: identifier "b"
+ codeBlockItem
+ item:
+ sequenceExpr
+ elements:
+ discardAssignmentExpr
+ wildcard: _
+ assignmentExpr
+ equal: =
+ declReferenceExpr
+ baseName: identifier "a"
+ unresolvedIsExpr
+ isKeyword: is
+ typeExpr
+ type:
+ identifierType
+ name: identifier "Int"
+ binaryOperatorExpr
+ operator: binaryOperator ".&"
+ declReferenceExpr
+ baseName: identifier "b"
+ name: identifier "casts"
+ modifiers:
+ signature:
+ functionSignature
+ parameterClause:
+ functionParameterClause
+ leftParen: (
+ rightParen: )
+ parameters:
+ functionParameter
+ colon: :
+ attributes:
+ modifiers:
+ trailingComma: ,
+ type:
+ identifierType
+ name: Any
+ firstName: _
+ secondName: identifier "a"
+ functionParameter
+ colon: :
+ attributes:
+ modifiers:
+ type:
+ identifierType
+ name: identifier "Int"
+ firstName: _
+ secondName: identifier "b"
+ funcKeyword: func
+
+---
+
+top_level
+ body:
+ block
+ stmt:
+ function_declaration
+ name: identifier "casts"
+ parameter:
+ parameter
+ external_name: identifier "_"
+ type:
+ named_type_expr
+ name: identifier "Any"
+ pattern:
+ name_pattern
+ identifier: identifier "a"
+ parameter
+ external_name: identifier "_"
+ type:
+ named_type_expr
+ name: identifier "Int"
+ pattern:
+ name_pattern
+ identifier: identifier "b"
+ body:
+ block
+ stmt:
+ unresolved_operator_sequence
+ element:
+ name_expr
+ identifier: identifier "_"
+ infix_operator "="
+ name_expr
+ identifier: identifier "a"
+ infix_operator "as"
+ unsupported_node "Int"
+ infix_operator ".&"
+ name_expr
+ identifier: identifier "b"
+ unresolved_operator_sequence
+ element:
+ name_expr
+ identifier: identifier "_"
+ infix_operator "="
+ name_expr
+ identifier: identifier "a"
+ infix_operator "is"
+ unsupported_node "Int"
+ infix_operator ".&"
+ name_expr
+ identifier: identifier "b"
diff --git a/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-casts.swift b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-casts.swift
new file mode 100644
index 00000000000..b22c93eb31e
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-casts.swift
@@ -0,0 +1,4 @@
+func casts(_ a: Any, _ b: Int) {
+ _ = a as Int .& b
+ _ = a is Int .& b
+}
diff --git a/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-ternary.output b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-ternary.output
new file mode 100644
index 00000000000..57274c32a9c
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-ternary.output
@@ -0,0 +1,157 @@
+func choose(_ c: Bool, _ a: Int, _ b: Int, _ d: Int) -> Int {
+ return c ? a : b .& d
+}
+
+---
+
+sourceFile
+ endOfFileToken: endOfFile
+ statements:
+ codeBlockItem
+ item:
+ functionDecl
+ attributes:
+ body:
+ codeBlock
+ leftBrace: {
+ rightBrace: }
+ statements:
+ codeBlockItem
+ item:
+ returnStmt
+ expression:
+ sequenceExpr
+ elements:
+ declReferenceExpr
+ baseName: identifier "c"
+ unresolvedTernaryExpr
+ colon: :
+ questionMark: ?
+ thenExpression:
+ declReferenceExpr
+ baseName: identifier "a"
+ declReferenceExpr
+ baseName: identifier "b"
+ binaryOperatorExpr
+ operator: binaryOperator ".&"
+ declReferenceExpr
+ baseName: identifier "d"
+ returnKeyword: return
+ name: identifier "choose"
+ modifiers:
+ signature:
+ functionSignature
+ parameterClause:
+ functionParameterClause
+ leftParen: (
+ rightParen: )
+ parameters:
+ functionParameter
+ colon: :
+ attributes:
+ modifiers:
+ trailingComma: ,
+ type:
+ identifierType
+ name: identifier "Bool"
+ firstName: _
+ secondName: identifier "c"
+ functionParameter
+ colon: :
+ attributes:
+ modifiers:
+ trailingComma: ,
+ type:
+ identifierType
+ name: identifier "Int"
+ firstName: _
+ secondName: identifier "a"
+ functionParameter
+ colon: :
+ attributes:
+ modifiers:
+ trailingComma: ,
+ type:
+ identifierType
+ name: identifier "Int"
+ firstName: _
+ secondName: identifier "b"
+ functionParameter
+ colon: :
+ attributes:
+ modifiers:
+ type:
+ identifierType
+ name: identifier "Int"
+ firstName: _
+ secondName: identifier "d"
+ returnClause:
+ returnClause
+ arrow: ->
+ type:
+ identifierType
+ name: identifier "Int"
+ funcKeyword: func
+
+---
+
+top_level
+ body:
+ block
+ stmt:
+ function_declaration
+ name: identifier "choose"
+ parameter:
+ parameter
+ external_name: identifier "_"
+ type:
+ named_type_expr
+ name: identifier "Bool"
+ pattern:
+ name_pattern
+ identifier: identifier "c"
+ parameter
+ external_name: identifier "_"
+ type:
+ named_type_expr
+ name: identifier "Int"
+ pattern:
+ name_pattern
+ identifier: identifier "a"
+ parameter
+ external_name: identifier "_"
+ type:
+ named_type_expr
+ name: identifier "Int"
+ pattern:
+ name_pattern
+ identifier: identifier "b"
+ parameter
+ external_name: identifier "_"
+ type:
+ named_type_expr
+ name: identifier "Int"
+ pattern:
+ name_pattern
+ identifier: identifier "d"
+ return_type:
+ named_type_expr
+ name: identifier "Int"
+ body:
+ block
+ stmt:
+ return_expr
+ value:
+ unresolved_operator_sequence
+ element:
+ name_expr
+ identifier: identifier "c"
+ infix_operator "?"
+ name_expr
+ identifier: identifier "a"
+ infix_operator ":"
+ name_expr
+ identifier: identifier "b"
+ infix_operator ".&"
+ name_expr
+ identifier: identifier "d"
diff --git a/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-ternary.swift b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-ternary.swift
new file mode 100644
index 00000000000..54f164eee9a
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence-with-ternary.swift
@@ -0,0 +1,3 @@
+func choose(_ c: Bool, _ a: Int, _ b: Int, _ d: Int) -> Int {
+ return c ? a : b .& d
+}
diff --git a/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence.output b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence.output
new file mode 100644
index 00000000000..46dc8ca6ae8
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence.output
@@ -0,0 +1,100 @@
+func combine(_ a: Int, _ b: Int) {
+ _ = a .& b
+}
+
+---
+
+sourceFile
+ endOfFileToken: endOfFile
+ statements:
+ codeBlockItem
+ item:
+ functionDecl
+ attributes:
+ body:
+ codeBlock
+ leftBrace: {
+ rightBrace: }
+ statements:
+ codeBlockItem
+ item:
+ sequenceExpr
+ elements:
+ discardAssignmentExpr
+ wildcard: _
+ assignmentExpr
+ equal: =
+ declReferenceExpr
+ baseName: identifier "a"
+ binaryOperatorExpr
+ operator: binaryOperator ".&"
+ declReferenceExpr
+ baseName: identifier "b"
+ name: identifier "combine"
+ modifiers:
+ signature:
+ functionSignature
+ parameterClause:
+ functionParameterClause
+ leftParen: (
+ rightParen: )
+ parameters:
+ functionParameter
+ colon: :
+ attributes:
+ modifiers:
+ trailingComma: ,
+ type:
+ identifierType
+ name: identifier "Int"
+ firstName: _
+ secondName: identifier "a"
+ functionParameter
+ colon: :
+ attributes:
+ modifiers:
+ type:
+ identifierType
+ name: identifier "Int"
+ firstName: _
+ secondName: identifier "b"
+ funcKeyword: func
+
+---
+
+top_level
+ body:
+ block
+ stmt:
+ function_declaration
+ name: identifier "combine"
+ parameter:
+ parameter
+ external_name: identifier "_"
+ type:
+ named_type_expr
+ name: identifier "Int"
+ pattern:
+ name_pattern
+ identifier: identifier "a"
+ parameter
+ external_name: identifier "_"
+ type:
+ named_type_expr
+ name: identifier "Int"
+ pattern:
+ name_pattern
+ identifier: identifier "b"
+ body:
+ block
+ stmt:
+ unresolved_operator_sequence
+ element:
+ name_expr
+ identifier: identifier "_"
+ infix_operator "="
+ name_expr
+ identifier: identifier "a"
+ infix_operator ".&"
+ name_expr
+ identifier: identifier "b"
diff --git a/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence.swift b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence.swift
new file mode 100644
index 00000000000..6ab759752d2
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/operators/unresolved-operator-sequence.swift
@@ -0,0 +1,3 @@
+func combine(_ a: Int, _ b: Int) {
+ _ = a .& b
+}
diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/catch-where-clauses.output b/unified/extractor/tests/corpus/swift/optionals-and-errors/catch-where-clauses.output
new file mode 100644
index 00000000000..79b7879d35f
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/catch-where-clauses.output
@@ -0,0 +1,207 @@
+do {
+ try foo()
+} catch let e where isNetworkError(e), let f where isTimeout(f) {
+ print("retry")
+} catch {
+ print("fallback")
+}
+
+---
+
+sourceFile
+ endOfFileToken: endOfFile
+ statements:
+ codeBlockItem
+ item:
+ doStmt
+ body:
+ codeBlock
+ leftBrace: {
+ rightBrace: }
+ statements:
+ codeBlockItem
+ item:
+ tryExpr
+ expression:
+ functionCallExpr
+ leftParen: (
+ rightParen: )
+ arguments:
+ additionalTrailingClosures:
+ calledExpression:
+ declReferenceExpr
+ baseName: identifier "foo"
+ tryKeyword: try
+ catchClauses:
+ catchClause
+ body:
+ codeBlock
+ leftBrace: {
+ rightBrace: }
+ statements:
+ codeBlockItem
+ item:
+ functionCallExpr
+ leftParen: (
+ rightParen: )
+ arguments:
+ labeledExpr
+ expression:
+ stringLiteralExpr
+ closingQuote: "
+ openingQuote: "
+ segments:
+ stringSegment
+ content: stringSegment "retry"
+ additionalTrailingClosures:
+ calledExpression:
+ declReferenceExpr
+ baseName: identifier "print"
+ catchItems:
+ catchItem
+ trailingComma: ,
+ pattern:
+ valueBindingPattern
+ pattern:
+ identifierPattern
+ identifier: identifier "e"
+ bindingSpecifier: let
+ whereClause:
+ whereClause
+ condition:
+ functionCallExpr
+ leftParen: (
+ rightParen: )
+ arguments:
+ labeledExpr
+ expression:
+ declReferenceExpr
+ baseName: identifier "e"
+ additionalTrailingClosures:
+ calledExpression:
+ declReferenceExpr
+ baseName: identifier "isNetworkError"
+ whereKeyword: where
+ catchItem
+ pattern:
+ valueBindingPattern
+ pattern:
+ identifierPattern
+ identifier: identifier "f"
+ bindingSpecifier: let
+ whereClause:
+ whereClause
+ condition:
+ functionCallExpr
+ leftParen: (
+ rightParen: )
+ arguments:
+ labeledExpr
+ expression:
+ declReferenceExpr
+ baseName: identifier "f"
+ additionalTrailingClosures:
+ calledExpression:
+ declReferenceExpr
+ baseName: identifier "isTimeout"
+ whereKeyword: where
+ catchKeyword: catch
+ catchClause
+ body:
+ codeBlock
+ leftBrace: {
+ rightBrace: }
+ statements:
+ codeBlockItem
+ item:
+ functionCallExpr
+ leftParen: (
+ rightParen: )
+ arguments:
+ labeledExpr
+ expression:
+ stringLiteralExpr
+ closingQuote: "
+ openingQuote: "
+ segments:
+ stringSegment
+ content: stringSegment "fallback"
+ additionalTrailingClosures:
+ calledExpression:
+ declReferenceExpr
+ baseName: identifier "print"
+ catchItems:
+ catchKeyword: catch
+ doKeyword: do
+
+---
+
+top_level
+ body:
+ block
+ stmt:
+ try_expr
+ body:
+ block
+ stmt:
+ unary_expr
+ operand:
+ call_expr
+ callee:
+ name_expr
+ identifier: identifier "foo"
+ operator: prefix_operator "try"
+ catch_clause:
+ catch_clause
+ pattern:
+ or_pattern
+ pattern:
+ conditional_pattern
+ condition:
+ call_expr
+ callee:
+ name_expr
+ identifier: identifier "isNetworkError"
+ argument:
+ argument
+ value:
+ name_expr
+ identifier: identifier "e"
+ pattern:
+ name_pattern
+ identifier: identifier "e"
+ conditional_pattern
+ condition:
+ call_expr
+ callee:
+ name_expr
+ identifier: identifier "isTimeout"
+ argument:
+ argument
+ value:
+ name_expr
+ identifier: identifier "f"
+ pattern:
+ name_pattern
+ identifier: identifier "f"
+ body:
+ block
+ stmt:
+ call_expr
+ callee:
+ name_expr
+ identifier: identifier "print"
+ argument:
+ argument
+ value: string_literal "\"retry\""
+ catch_clause
+ body:
+ block
+ stmt:
+ call_expr
+ callee:
+ name_expr
+ identifier: identifier "print"
+ argument:
+ argument
+ value: string_literal "\"fallback\""
diff --git a/unified/extractor/tests/corpus/swift/optionals-and-errors/catch-where-clauses.swift b/unified/extractor/tests/corpus/swift/optionals-and-errors/catch-where-clauses.swift
new file mode 100644
index 00000000000..48995b818e5
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/optionals-and-errors/catch-where-clauses.swift
@@ -0,0 +1,7 @@
+do {
+ try foo()
+} catch let e where isNetworkError(e), let f where isTimeout(f) {
+ print("retry")
+} catch {
+ print("fallback")
+}
diff --git a/unified/extractor/tests/corpus/swift/types/actor-declaration.output b/unified/extractor/tests/corpus/swift/types/actor-declaration.output
new file mode 100644
index 00000000000..b4fcd605b9e
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/types/actor-declaration.output
@@ -0,0 +1,45 @@
+actor Counter {
+ var value = 0
+}
+
+---
+
+sourceFile
+ endOfFileToken: endOfFile
+ statements:
+ codeBlockItem
+ item:
+ actorDecl
+ attributes:
+ name: identifier "Counter"
+ actorKeyword: actor
+ memberBlock:
+ memberBlock
+ leftBrace: {
+ rightBrace: }
+ members:
+ memberBlockItem
+ decl:
+ variableDecl
+ attributes:
+ modifiers:
+ bindingSpecifier: var
+ bindings:
+ patternBinding
+ initializer:
+ initializerClause
+ equal: =
+ value:
+ integerLiteralExpr
+ literal: integerLiteral "0"
+ pattern:
+ identifierPattern
+ identifier: identifier "value"
+ modifiers:
+
+---
+
+top_level
+ body:
+ block
+ stmt: unsupported_node "actor Counter {\n var value = 0\n}"
diff --git a/unified/extractor/tests/corpus/swift/types/actor-declaration.swift b/unified/extractor/tests/corpus/swift/types/actor-declaration.swift
new file mode 100644
index 00000000000..a4c13e4e876
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/types/actor-declaration.swift
@@ -0,0 +1,3 @@
+actor Counter {
+ var value = 0
+}
diff --git a/unified/extractor/tests/corpus/swift/types/class-inheritance.output b/unified/extractor/tests/corpus/swift/types/class-inheritance.output
index 62a0a43414d..12328f4acb0 100644
--- a/unified/extractor/tests/corpus/swift/types/class-inheritance.output
+++ b/unified/extractor/tests/corpus/swift/types/class-inheritance.output
@@ -35,3 +35,8 @@ top_level
class_like_declaration
modifier: modifier "class"
name: identifier "Dog"
+ base_type:
+ base_type
+ type:
+ named_type_expr
+ name: identifier "Animal"
diff --git a/unified/extractor/tests/corpus/swift/types/class-with-initializer.output b/unified/extractor/tests/corpus/swift/types/class-with-initializer.output
index 5e712d739e5..83945d89e3a 100644
--- a/unified/extractor/tests/corpus/swift/types/class-with-initializer.output
+++ b/unified/extractor/tests/corpus/swift/types/class-with-initializer.output
@@ -103,6 +103,14 @@ top_level
named_type_expr
name: identifier "Int"
constructor_declaration
+ parameter:
+ parameter
+ type:
+ named_type_expr
+ name: identifier "Int"
+ pattern:
+ name_pattern
+ identifier: identifier "x"
body:
block
stmt:
diff --git a/unified/extractor/tests/corpus/swift/types/class-with-multiple-base-types.output b/unified/extractor/tests/corpus/swift/types/class-with-multiple-base-types.output
new file mode 100644
index 00000000000..e66b88e9be3
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/types/class-with-multiple-base-types.output
@@ -0,0 +1,51 @@
+class Button: Control, Drawable {}
+
+---
+
+sourceFile
+ endOfFileToken: endOfFile
+ statements:
+ codeBlockItem
+ item:
+ classDecl
+ attributes:
+ name: identifier "Button"
+ inheritanceClause:
+ inheritanceClause
+ colon: :
+ inheritedTypes:
+ inheritedType
+ trailingComma: ,
+ type:
+ identifierType
+ name: identifier "Control"
+ inheritedType
+ type:
+ identifierType
+ name: identifier "Drawable"
+ memberBlock:
+ memberBlock
+ leftBrace: {
+ rightBrace: }
+ members:
+ modifiers:
+ classKeyword: class
+
+---
+
+top_level
+ body:
+ block
+ stmt:
+ class_like_declaration
+ modifier: modifier "class"
+ name: identifier "Button"
+ base_type:
+ base_type
+ type:
+ named_type_expr
+ name: identifier "Control"
+ base_type
+ type:
+ named_type_expr
+ name: identifier "Drawable"
diff --git a/unified/extractor/tests/corpus/swift/types/class-with-multiple-base-types.swift b/unified/extractor/tests/corpus/swift/types/class-with-multiple-base-types.swift
new file mode 100644
index 00000000000..b4f45e5c7a0
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/types/class-with-multiple-base-types.swift
@@ -0,0 +1 @@
+class Button: Control, Drawable {}
diff --git a/unified/extractor/tests/corpus/swift/types/conditional-compilation-in-class-body.output b/unified/extractor/tests/corpus/swift/types/conditional-compilation-in-class-body.output
new file mode 100644
index 00000000000..2c530111b9c
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/types/conditional-compilation-in-class-body.output
@@ -0,0 +1,87 @@
+// Conditional compilation is not yet supported: swift-syntax reports a
+// structured `ifConfigDecl` (whose branches hold ordinary member items), but
+// the mapping has no rule for it, so the whole block becomes one
+// `unsupported_node` and its members are not extracted.
+class C {
+#if DEBUG
+ init(x: Int) {}
+ deinit {}
+#endif
+}
+
+---
+
+sourceFile
+ endOfFileToken: endOfFile
+ statements:
+ codeBlockItem
+ item:
+ classDecl
+ attributes:
+ name: identifier "C"
+ memberBlock:
+ memberBlock
+ leftBrace: {
+ rightBrace: }
+ members:
+ memberBlockItem
+ decl:
+ ifConfigDecl
+ clauses:
+ ifConfigClause
+ elements:
+ memberBlockItem
+ decl:
+ initializerDecl
+ attributes:
+ body:
+ codeBlock
+ leftBrace: {
+ rightBrace: }
+ statements:
+ modifiers:
+ signature:
+ functionSignature
+ parameterClause:
+ functionParameterClause
+ leftParen: (
+ rightParen: )
+ parameters:
+ functionParameter
+ colon: :
+ attributes:
+ modifiers:
+ type:
+ identifierType
+ name: identifier "Int"
+ firstName: identifier "x"
+ initKeyword: init
+ memberBlockItem
+ decl:
+ deinitializerDecl
+ attributes:
+ body:
+ codeBlock
+ leftBrace: {
+ rightBrace: }
+ statements:
+ modifiers:
+ deinitKeyword: deinit
+ condition:
+ declReferenceExpr
+ baseName: identifier "DEBUG"
+ poundKeyword: #if
+ poundEndif: #endif
+ modifiers:
+ classKeyword: class
+
+---
+
+top_level
+ body:
+ block
+ stmt:
+ class_like_declaration
+ modifier: modifier "class"
+ name: identifier "C"
+ member: unsupported_node "#if DEBUG\n init(x: Int) {}\n deinit {}\n#endif"
diff --git a/unified/extractor/tests/corpus/swift/types/conditional-compilation-in-class-body.swift b/unified/extractor/tests/corpus/swift/types/conditional-compilation-in-class-body.swift
new file mode 100644
index 00000000000..fe50583118c
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/types/conditional-compilation-in-class-body.swift
@@ -0,0 +1,10 @@
+// Conditional compilation is not yet supported: swift-syntax reports a
+// structured `ifConfigDecl` (whose branches hold ordinary member items), but
+// the mapping has no rule for it, so the whole block becomes one
+// `unsupported_node` and its members are not extracted.
+class C {
+#if DEBUG
+ init(x: Int) {}
+ deinit {}
+#endif
+}
diff --git a/unified/extractor/tests/corpus/swift/types/constructor-with-parameters.output b/unified/extractor/tests/corpus/swift/types/constructor-with-parameters.output
new file mode 100644
index 00000000000..c9be21dd156
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/types/constructor-with-parameters.output
@@ -0,0 +1,88 @@
+struct Size {
+ init(width w: Int, height h: Int) {}
+}
+
+---
+
+sourceFile
+ endOfFileToken: endOfFile
+ statements:
+ codeBlockItem
+ item:
+ structDecl
+ attributes:
+ name: identifier "Size"
+ memberBlock:
+ memberBlock
+ leftBrace: {
+ rightBrace: }
+ members:
+ memberBlockItem
+ decl:
+ initializerDecl
+ attributes:
+ body:
+ codeBlock
+ leftBrace: {
+ rightBrace: }
+ statements:
+ modifiers:
+ signature:
+ functionSignature
+ parameterClause:
+ functionParameterClause
+ leftParen: (
+ rightParen: )
+ parameters:
+ functionParameter
+ colon: :
+ attributes:
+ modifiers:
+ trailingComma: ,
+ type:
+ identifierType
+ name: identifier "Int"
+ firstName: identifier "width"
+ secondName: identifier "w"
+ functionParameter
+ colon: :
+ attributes:
+ modifiers:
+ type:
+ identifierType
+ name: identifier "Int"
+ firstName: identifier "height"
+ secondName: identifier "h"
+ initKeyword: init
+ modifiers:
+ structKeyword: struct
+
+---
+
+top_level
+ body:
+ block
+ stmt:
+ class_like_declaration
+ modifier: modifier "struct"
+ name: identifier "Size"
+ member:
+ constructor_declaration
+ parameter:
+ parameter
+ external_name: identifier "width"
+ type:
+ named_type_expr
+ name: identifier "Int"
+ pattern:
+ name_pattern
+ identifier: identifier "w"
+ parameter
+ external_name: identifier "height"
+ type:
+ named_type_expr
+ name: identifier "Int"
+ pattern:
+ name_pattern
+ identifier: identifier "h"
+ body: block "init(width w: Int, height h: Int) {}"
diff --git a/unified/extractor/tests/corpus/swift/types/constructor-with-parameters.swift b/unified/extractor/tests/corpus/swift/types/constructor-with-parameters.swift
new file mode 100644
index 00000000000..4f6377fc780
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/types/constructor-with-parameters.swift
@@ -0,0 +1,3 @@
+struct Size {
+ init(width w: Int, height h: Int) {}
+}
diff --git a/unified/extractor/tests/corpus/swift/types/function-type-with-convention-attribute.output b/unified/extractor/tests/corpus/swift/types/function-type-with-convention-attribute.output
new file mode 100644
index 00000000000..3d484d6f65d
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/types/function-type-with-convention-attribute.output
@@ -0,0 +1,73 @@
+let callback: @convention(c) () -> Void = {}
+
+---
+
+sourceFile
+ endOfFileToken: endOfFile
+ statements:
+ codeBlockItem
+ item:
+ variableDecl
+ attributes:
+ modifiers:
+ bindingSpecifier: let
+ bindings:
+ patternBinding
+ initializer:
+ initializerClause
+ equal: =
+ value:
+ closureExpr
+ leftBrace: {
+ rightBrace: }
+ statements:
+ pattern:
+ identifierPattern
+ identifier: identifier "callback"
+ typeAnnotation:
+ typeAnnotation
+ colon: :
+ type:
+ attributedType
+ attributes:
+ attribute
+ leftParen: (
+ rightParen: )
+ arguments:
+ labeledExpr
+ expression:
+ declReferenceExpr
+ baseName: identifier "c"
+ atSign: @
+ attributeName:
+ identifierType
+ name: identifier "convention"
+ baseType:
+ functionType
+ leftParen: (
+ rightParen: )
+ parameters:
+ returnClause:
+ returnClause
+ arrow: ->
+ type:
+ identifierType
+ name: identifier "Void"
+ lateSpecifiers:
+ specifiers:
+
+---
+
+top_level
+ body:
+ block
+ stmt:
+ variable_declaration
+ modifier: modifier "let"
+ pattern:
+ name_pattern
+ identifier: identifier "callback"
+ type: unsupported_node "@convention(c) () -> Void"
+ value:
+ function_expr
+ body: block "{}"
diff --git a/unified/extractor/tests/corpus/swift/types/function-type-with-convention-attribute.swift b/unified/extractor/tests/corpus/swift/types/function-type-with-convention-attribute.swift
new file mode 100644
index 00000000000..f84fa527009
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/types/function-type-with-convention-attribute.swift
@@ -0,0 +1 @@
+let callback: @convention(c) () -> Void = {}
diff --git a/unified/extractor/tests/corpus/swift/types/function-type-with-sendable-attribute.output b/unified/extractor/tests/corpus/swift/types/function-type-with-sendable-attribute.output
new file mode 100644
index 00000000000..ef9f838dadb
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/types/function-type-with-sendable-attribute.output
@@ -0,0 +1,66 @@
+let handler: @Sendable () -> Void = {}
+
+---
+
+sourceFile
+ endOfFileToken: endOfFile
+ statements:
+ codeBlockItem
+ item:
+ variableDecl
+ attributes:
+ modifiers:
+ bindingSpecifier: let
+ bindings:
+ patternBinding
+ initializer:
+ initializerClause
+ equal: =
+ value:
+ closureExpr
+ leftBrace: {
+ rightBrace: }
+ statements:
+ pattern:
+ identifierPattern
+ identifier: identifier "handler"
+ typeAnnotation:
+ typeAnnotation
+ colon: :
+ type:
+ attributedType
+ attributes:
+ attribute
+ atSign: @
+ attributeName:
+ identifierType
+ name: identifier "Sendable"
+ baseType:
+ functionType
+ leftParen: (
+ rightParen: )
+ parameters:
+ returnClause:
+ returnClause
+ arrow: ->
+ type:
+ identifierType
+ name: identifier "Void"
+ lateSpecifiers:
+ specifiers:
+
+---
+
+top_level
+ body:
+ block
+ stmt:
+ variable_declaration
+ modifier: modifier "let"
+ pattern:
+ name_pattern
+ identifier: identifier "handler"
+ type: unsupported_node "@Sendable () -> Void"
+ value:
+ function_expr
+ body: block "{}"
diff --git a/unified/extractor/tests/corpus/swift/types/function-type-with-sendable-attribute.swift b/unified/extractor/tests/corpus/swift/types/function-type-with-sendable-attribute.swift
new file mode 100644
index 00000000000..00810b921e8
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/types/function-type-with-sendable-attribute.swift
@@ -0,0 +1 @@
+let handler: @Sendable () -> Void = {}
diff --git a/unified/extractor/tests/corpus/swift/types/generic-type-arguments.output b/unified/extractor/tests/corpus/swift/types/generic-type-arguments.output
new file mode 100644
index 00000000000..ce12c853d9d
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/types/generic-type-arguments.output
@@ -0,0 +1,83 @@
+let cache: Dictionary> = [:]
+
+---
+
+sourceFile
+ endOfFileToken: endOfFile
+ statements:
+ codeBlockItem
+ item:
+ variableDecl
+ attributes:
+ modifiers:
+ bindingSpecifier: let
+ bindings:
+ patternBinding
+ initializer:
+ initializerClause
+ equal: =
+ value:
+ dictionaryExpr
+ leftSquare: [
+ rightSquare: ]
+ content: :
+ pattern:
+ identifierPattern
+ identifier: identifier "cache"
+ typeAnnotation:
+ typeAnnotation
+ colon: :
+ type:
+ identifierType
+ name: identifier "Dictionary"
+ genericArgumentClause:
+ genericArgumentClause
+ arguments:
+ genericArgument
+ trailingComma: ,
+ argument:
+ identifierType
+ name: identifier "String"
+ genericArgument
+ argument:
+ identifierType
+ name: identifier "Array"
+ genericArgumentClause:
+ genericArgumentClause
+ arguments:
+ genericArgument
+ argument:
+ identifierType
+ name: identifier "Int"
+ leftAngle: <
+ rightAngle: >
+ leftAngle: <
+ rightAngle: >
+
+---
+
+top_level
+ body:
+ block
+ stmt:
+ variable_declaration
+ modifier: modifier "let"
+ pattern:
+ name_pattern
+ identifier: identifier "cache"
+ type:
+ generic_type_expr
+ base:
+ named_type_expr
+ name: identifier "Dictionary"
+ type_argument:
+ named_type_expr
+ name: identifier "String"
+ generic_type_expr
+ base:
+ named_type_expr
+ name: identifier "Array"
+ type_argument:
+ named_type_expr
+ name: identifier "Int"
+ value: map_literal "[:]"
diff --git a/unified/extractor/tests/corpus/swift/types/generic-type-arguments.swift b/unified/extractor/tests/corpus/swift/types/generic-type-arguments.swift
new file mode 100644
index 00000000000..d2156f9cee7
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/types/generic-type-arguments.swift
@@ -0,0 +1 @@
+let cache: Dictionary> = [:]
diff --git a/unified/extractor/tests/corpus/swift/types/inline-array-type.output b/unified/extractor/tests/corpus/swift/types/inline-array-type.output
new file mode 100644
index 00000000000..5f70d9d5516
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/types/inline-array-type.output
@@ -0,0 +1,77 @@
+let triple: [3 of Int] = [1, 2, 3]
+
+---
+
+sourceFile
+ endOfFileToken: endOfFile
+ statements:
+ codeBlockItem
+ item:
+ variableDecl
+ attributes:
+ modifiers:
+ bindingSpecifier: let
+ bindings:
+ patternBinding
+ initializer:
+ initializerClause
+ equal: =
+ value:
+ arrayExpr
+ elements:
+ arrayElement
+ expression:
+ integerLiteralExpr
+ literal: integerLiteral "1"
+ trailingComma: ,
+ arrayElement
+ expression:
+ integerLiteralExpr
+ literal: integerLiteral "2"
+ trailingComma: ,
+ arrayElement
+ expression:
+ integerLiteralExpr
+ literal: integerLiteral "3"
+ leftSquare: [
+ rightSquare: ]
+ pattern:
+ identifierPattern
+ identifier: identifier "triple"
+ typeAnnotation:
+ typeAnnotation
+ colon: :
+ type:
+ inlineArrayType
+ leftSquare: [
+ rightSquare: ]
+ element:
+ genericArgument
+ argument:
+ identifierType
+ name: identifier "Int"
+ count:
+ genericArgument
+ argument:
+ integerLiteralExpr
+ literal: integerLiteral "3"
+ separator: of
+
+---
+
+top_level
+ body:
+ block
+ stmt:
+ variable_declaration
+ modifier: modifier "let"
+ pattern:
+ name_pattern
+ identifier: identifier "triple"
+ type: unsupported_node "[3 of Int]"
+ value:
+ array_literal
+ element:
+ int_literal "1"
+ int_literal "2"
+ int_literal "3"
diff --git a/unified/extractor/tests/corpus/swift/types/inline-array-type.swift b/unified/extractor/tests/corpus/swift/types/inline-array-type.swift
new file mode 100644
index 00000000000..3d27c8dca5c
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/types/inline-array-type.swift
@@ -0,0 +1 @@
+let triple: [3 of Int] = [1, 2, 3]
diff --git a/unified/extractor/tests/corpus/swift/types/noncopyable-type.output b/unified/extractor/tests/corpus/swift/types/noncopyable-type.output
new file mode 100644
index 00000000000..4fb13ca13ec
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/types/noncopyable-type.output
@@ -0,0 +1,71 @@
+struct FileHandle: ~Copyable {
+ let descriptor: Int
+}
+
+---
+
+sourceFile
+ endOfFileToken: endOfFile
+ statements:
+ codeBlockItem
+ item:
+ structDecl
+ attributes:
+ name: identifier "FileHandle"
+ inheritanceClause:
+ inheritanceClause
+ colon: :
+ inheritedTypes:
+ inheritedType
+ type:
+ suppressedType
+ type:
+ identifierType
+ name: identifier "Copyable"
+ withoutTilde: prefixOperator "~"
+ memberBlock:
+ memberBlock
+ leftBrace: {
+ rightBrace: }
+ members:
+ memberBlockItem
+ decl:
+ variableDecl
+ attributes:
+ modifiers:
+ bindingSpecifier: let
+ bindings:
+ patternBinding
+ pattern:
+ identifierPattern
+ identifier: identifier "descriptor"
+ typeAnnotation:
+ typeAnnotation
+ colon: :
+ type:
+ identifierType
+ name: identifier "Int"
+ modifiers:
+ structKeyword: struct
+
+---
+
+top_level
+ body:
+ block
+ stmt:
+ class_like_declaration
+ modifier: modifier "struct"
+ name: identifier "FileHandle"
+ base_type:
+ base_type
+ type: unsupported_node "~Copyable"
+ member:
+ variable_declaration
+ modifier: modifier "let"
+ pattern:
+ name_pattern
+ identifier: identifier "descriptor"
+ type:
+ named_type_expr
+ name: identifier "Int"
diff --git a/unified/extractor/tests/corpus/swift/types/noncopyable-type.swift b/unified/extractor/tests/corpus/swift/types/noncopyable-type.swift
new file mode 100644
index 00000000000..55390c9e6d1
--- /dev/null
+++ b/unified/extractor/tests/corpus/swift/types/noncopyable-type.swift
@@ -0,0 +1,3 @@
+struct FileHandle: ~Copyable {
+ let descriptor: Int
+}
diff --git a/unified/extractor/tests/rules_macro_smoke.rs b/unified/extractor/tests/rules_macro_smoke.rs
deleted file mode 100644
index cde8ae3ca4a..00000000000
--- a/unified/extractor/tests/rules_macro_smoke.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-/// Smoke test: load a few real Swift translation rules through the new
-/// `yeast::rules!` macro using the bare-rule-body syntax, and confirm the
-/// input + output schemas accept them. Compiles only — any type-checking
-/// error surfaces as a compile-time error.
-#[test]
-fn rules_macro_compiles_against_real_swift_schemas() {
- let _rules: Vec = yeast::rules! {
- input: "tree-sitter-swift/node-types.yml",
- output: "ast_types.yml",
- [
- (simple_identifier) @name
- =>
- (name_expr
- identifier: (identifier #{name})),
-
- (integer_literal) @lit
- =>
- (int_literal #{lit}),
-
- (line_string_literal) @lit
- =>
- (string_literal #{lit}),
- ]
- };
-}
diff --git a/unified/extractor/tree-sitter-swift/.gitignore b/unified/extractor/tree-sitter-swift/.gitignore
deleted file mode 100644
index 53796875297..00000000000
--- a/unified/extractor/tree-sitter-swift/.gitignore
+++ /dev/null
@@ -1,9 +0,0 @@
-# Generated by tree-sitter from grammar.js. The Cargo build script
-# (bindings/rust/build.rs) and Bazel's cargo_build_script regenerate them into
-# OUT_DIR. The tree-sitter CLI (parse, test, playground, etc.) expects them in
-# src/, so contributors can run `tree-sitter generate` locally to populate
-# these — they are intentionally untracked.
-src/parser.c
-src/grammar.json
-src/node-types.json
-src/tree_sitter/
diff --git a/unified/extractor/tree-sitter-swift/BUILD.bazel b/unified/extractor/tree-sitter-swift/BUILD.bazel
deleted file mode 100644
index f865f22a142..00000000000
--- a/unified/extractor/tree-sitter-swift/BUILD.bazel
+++ /dev/null
@@ -1,42 +0,0 @@
-load("@rules_rust//cargo:defs.bzl", "cargo_build_script")
-load("@rules_rust//rust:defs.bzl", "rust_library")
-load("//misc/bazel/3rdparty/tree_sitter_extractors_deps:defs.bzl", "aliases", "all_crate_deps")
-
-package(default_visibility = ["//visibility:public"])
-
-# This will run the build script from the root of the workspace, and
-# collect the outputs.
-cargo_build_script(
- name = "tree-sitter-swift-build",
- srcs = ["bindings/rust/build.rs"],
- data = glob([
- "src/scanner.c",
- ]) + [
- "grammar.js",
- ],
- deps = all_crate_deps(
- build = True,
- ),
-)
-
-rust_library(
- name = "tree-sitter-swift",
- srcs = [
- "bindings/rust/lib.rs",
- ],
- aliases = aliases(),
- compile_data = glob([
- "src/**",
- "queries/**",
- ]) + [
- "grammar.js",
- ],
- proc_macro_deps = all_crate_deps(
- proc_macro = True,
- ),
- deps = [":tree-sitter-swift-build"] + all_crate_deps(
- normal = True,
- ),
-)
-
-exports_files(["Cargo.toml"])
diff --git a/unified/extractor/tree-sitter-swift/Cargo.toml b/unified/extractor/tree-sitter-swift/Cargo.toml
deleted file mode 100644
index 8cec03889a8..00000000000
--- a/unified/extractor/tree-sitter-swift/Cargo.toml
+++ /dev/null
@@ -1,22 +0,0 @@
-[package]
-name = "tree-sitter-swift"
-description = "Swift grammar for the tree-sitter parsing library (vendored copy for the unified extractor)"
-version = "0.7.2"
-keywords = ["incremental", "parsing", "swift"]
-categories = ["parsing", "text-editors"]
-repository = "https://github.com/alex-pinkus/tree-sitter-swift"
-edition = "2024"
-license = "MIT"
-
-build = "bindings/rust/build.rs"
-
-[lib]
-path = "bindings/rust/lib.rs"
-
-# When updating these dependencies, run `misc/bazel/3rdparty/update_cargo_deps.sh`
-[dependencies]
-tree-sitter-language = "0.1"
-
-[build-dependencies]
-cc = "1.2"
-tree-sitter-generate = "0.26.8"
diff --git a/unified/extractor/tree-sitter-swift/LICENSE b/unified/extractor/tree-sitter-swift/LICENSE
deleted file mode 100644
index f158d700531..00000000000
--- a/unified/extractor/tree-sitter-swift/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2021 alex-pinkus
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/unified/extractor/tree-sitter-swift/README.md b/unified/extractor/tree-sitter-swift/README.md
deleted file mode 100644
index 5b54f4b617f..00000000000
--- a/unified/extractor/tree-sitter-swift/README.md
+++ /dev/null
@@ -1,127 +0,0 @@
-
-[](https://crates.io/crates/tree-sitter-swift)
-[](https://www.npmjs.com/package/tree-sitter-swift)
-[](https://github.com/alex-pinkus/tree-sitter-swift/actions/workflows/top-repos.yml)
-
-# tree-sitter-swift
-
-This contains a [`tree-sitter`](https://tree-sitter.github.io/tree-sitter) grammar for the Swift programming language.
-
-## Getting started
-
-To use this parser to parse Swift code, you'll want to depend on either the Rust crate or the NPM package.
-
-### Rust
-
-To use the Rust crate, you'll add this to your `Cargo.toml`:
-
-```
-tree-sitter = "0.23.0"
-tree-sitter-swift = "=0.7.0"
-```
-
-Then you can use a `tree-sitter` parser with the language declared here:
-
-```
-let mut parser = tree_sitter::Parser::new();
-parser.set_language(tree_sitter_swift::language())?;
-
-// ...
-
-let tree = parser.parse(&my_source_code, None)
- .ok_or_else(|| /* error handling code */)?;
-```
-
-### Javascript
-
-To use this from NPM, you'll add similar dependencies to `package.json`:
-
-```
-"dependencies: {
- "tree-sitter-swift": "0.7.0",
- "tree-sitter": "^0.22.1"
-}
-```
-
-Your usage of the parser will look like:
-
-```
-const Parser = require("tree-sitter");
-const Swift = require("tree-sitter-swift");
-
-const parser = new Parser();
-parser.setLanguage(Swift);
-
-// ...
-
-const tree = parser.parse(mySourceCode);
-```
-
-### Editing the grammar
-
-With this package checked out, a common workflow for editing the grammar will look something like:
-
-1. Make a change to `grammar.ts`.
-2. Run `npm install && npm test` to see whether the change has had impact on existing parsing behavior. The default
- `npm test` target requires `valgrind` to be installed; if you do not have it installed, and do not wish to, you can
- substitute `tree-sitter test` directly.
-3. Run `tree-sitter parse` on some real Swift codebase and see whether (or where) it fails.
-4. Use any failures to create new corpus test cases.
-
-## Contributions
-
-All contributions to this repository are welcome.
-
-If said contribution is to check generated files (e.g., `parser.c`) into the repository, be aware that your contribution will not be accepted. Make sure to read the [FAQ entry](https://github.com/alex-pinkus/tree-sitter-swift?tab=readme-ov-file#where-is-your-parserc) and the [prior](https://github.com/alex-pinkus/tree-sitter-swift/issues/362) [discussions](https://github.com/alex-pinkus/tree-sitter-swift/pull/315) and [compromises](https://github.com/alex-pinkus/tree-sitter-swift/issues/149) that have occurred already on this topic.
-
-## Using tree-sitter-swift in Web Assembly
-
-To use tree-sitter-swift as a language for the web bindings version tree-sitter, which will likely be a more modern version than the published node
-module. [see](https://github.com/tree-sitter/tree-sitter/blob/master/lib/binding_web/README.md). Follow the instructions below
-
-1. Install the node modules `npm install web-tree-sitter tree-sitter-swift`
-2. Run the tree-sitter cli to create the wasm bundle
- ```sh
- $ npx tree-sitter build-asm ./node_modules/tree-sitter
- ```
-3. Boot tree-sitter wasm like this.
-
-```js
-const Parser = require("web-tree-sitter");
-async function run() {
- //needs to happen first
- await Parser.init();
- //wait for the load of swift
- const Swift = await Parser.Language.load("./tree-sitter-swift.wasm");
-
- const parser = new Parser();
- parser.setLanguage(Swift);
-
- //Parse your swift code here.
- const tree = parser.parse('print("Hello, World!")');
-}
-//if you want to run this
-run().then(console.log, console.error);
-```
-
-## Frequently asked questions
-
-### Where is your `parser.c`?
-
-This repository currently omits most of the code that is autogenerated during a build. This means, for instance, that
-`grammar.json` and `parser.c` are both only available following a build. It also significantly reduces noise during
-diffs.
-
-The side benefit of not checking in `parser.c` is that you can guarantee backwards compatibility. Parsers generated by
-the tree-sitter CLI aren't always backwards compatible. If you need a parser, generate it yourself using the CLI; all
-the information to do so is available in this package. By doing that, you'll also know for sure that your parser version
-and your library version are compatible.
-
-If you need a `parser.c`, and you don't care about the tree-sitter version, but you don't have a local setup that would
-allow you to obtain the parser, you can just download one from a recent workflow run in this package. To do so:
-
-- Go to the [GitHub actions page](https://github.com/alex-pinkus/tree-sitter-swift/actions) for this
- repository.
-- Click on the "Publish `grammar.json` and `parser.c`" action for the appropriate commit.
-- Go down to `Artifacts` and click on `generated-parser-src`. All the relevant parser files will be available in your
- download.
diff --git a/unified/extractor/tree-sitter-swift/binding.gyp b/unified/extractor/tree-sitter-swift/binding.gyp
deleted file mode 100644
index 4d9270af7d4..00000000000
--- a/unified/extractor/tree-sitter-swift/binding.gyp
+++ /dev/null
@@ -1,44 +0,0 @@
-{
- "targets": [
- {
- "target_name": "tree_sitter_swift_binding",
- "dependencies": [
- "
-
-typedef struct TSLanguage TSLanguage;
-
-extern "C" TSLanguage *tree_sitter_swift();
-
-// "tree-sitter", "language" hashed with BLAKE2
-const napi_type_tag LANGUAGE_TYPE_TAG = {
- 0x8AF2E5212AD58ABF, 0xD5006CAD83ABBA16
-};
-
-Napi::Object Init(Napi::Env env, Napi::Object exports) {
- exports["name"] = Napi::String::New(env, "swift");
- auto language = Napi::External::New(env, tree_sitter_swift());
- language.TypeTag(&LANGUAGE_TYPE_TAG);
- exports["language"] = language;
- return exports;
-}
-
-NODE_API_MODULE(tree_sitter_swift_binding, Init)
diff --git a/unified/extractor/tree-sitter-swift/bindings/node/index.js b/unified/extractor/tree-sitter-swift/bindings/node/index.js
deleted file mode 100644
index 6657bcf42de..00000000000
--- a/unified/extractor/tree-sitter-swift/bindings/node/index.js
+++ /dev/null
@@ -1,7 +0,0 @@
-const root = require("path").join(__dirname, "..", "..");
-
-module.exports = require("node-gyp-build")(root);
-
-try {
- module.exports.nodeTypeInfo = require("../../src/node-types.json");
-} catch (_) {}
diff --git a/unified/extractor/tree-sitter-swift/bindings/rust/build.rs b/unified/extractor/tree-sitter-swift/bindings/rust/build.rs
deleted file mode 100644
index 2dd899ea521..00000000000
--- a/unified/extractor/tree-sitter-swift/bindings/rust/build.rs
+++ /dev/null
@@ -1,51 +0,0 @@
-use std::env;
-use std::path::PathBuf;
-
-fn main() {
- // tree-sitter-generate produces parser.c, grammar.json, node-types.json,
- // and src/tree_sitter/*.h headers from grammar.js. We write them into
- // OUT_DIR so the build is sandbox-friendly and we don't litter the source
- // tree.
- let crate_dir: PathBuf = env::var("CARGO_MANIFEST_DIR").unwrap().into();
- let out_dir: PathBuf = env::var("OUT_DIR").unwrap().into();
- let grammar_js = crate_dir.join("grammar.js");
-
- tree_sitter_generate::generate_parser_in_directory(
- &crate_dir,
- Some(&out_dir),
- Some(&grammar_js),
- tree_sitter_generate::ABI_VERSION_MAX,
- None,
- // Evaluate grammar.js with the embedded QuickJS runtime instead of
- // spawning `node`, which isn't available inside Bazel's sandbox.
- Some("native"),
- true,
- tree_sitter_generate::OptLevel::default(),
- )
- .expect("failed to generate tree-sitter-swift parser");
-
- let mut c_config = cc::Build::new();
- c_config
- .std("c11")
- .include(&out_dir)
- .include(out_dir.join("tree_sitter"));
-
- #[cfg(target_env = "msvc")]
- c_config.flag("-utf-8");
-
- c_config.file(out_dir.join("parser.c"));
-
- // scanner.c is hand-written and lives in the source tree.
- let scanner_path = crate_dir.join("src").join("scanner.c");
- c_config.include(crate_dir.join("src")).file(&scanner_path);
-
- println!("cargo:rerun-if-changed={}", grammar_js.to_str().unwrap());
- println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap());
- // Re-export OUT_DIR so consumers can include_str! the generated files.
- println!(
- "cargo:rustc-env=TREE_SITTER_SWIFT_OUT_DIR={}",
- out_dir.to_str().unwrap()
- );
-
- c_config.compile("tree-sitter-swift");
-}
diff --git a/unified/extractor/tree-sitter-swift/bindings/rust/lib.rs b/unified/extractor/tree-sitter-swift/bindings/rust/lib.rs
deleted file mode 100644
index 891df87778f..00000000000
--- a/unified/extractor/tree-sitter-swift/bindings/rust/lib.rs
+++ /dev/null
@@ -1,68 +0,0 @@
-//! This crate provides Swift language support for the [tree-sitter][] parsing library.
-//!
-//! Typically, you will use the [language][language func] function to add this language to a
-//! tree-sitter [Parser][], and then use the parser to parse some code:
-//!
-//! ```
-//! let code = r#"
-//! "#;
-//! let mut parser = tree_sitter::Parser::new();
-//! let language = tree_sitter_swift::LANGUAGE;
-//! parser
-//! .set_language(&language.into())
-//! .expect("Error loading Swift parser");
-//! let tree = parser.parse(code, None).unwrap();
-//! assert!(!tree.root_node().has_error());
-//! ```
-//!
-//! [Language]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Language.html
-//! [language func]: fn.language.html
-//! [Parser]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Parser.html
-//! [tree-sitter]: https://tree-sitter.github.io/
-
-use tree_sitter_language::LanguageFn;
-
-unsafe extern "C" {
- fn tree_sitter_swift() -> *const ();
-}
-
-/// The tree-sitter [`LanguageFn`] for this grammar.
-pub const LANGUAGE: LanguageFn = unsafe { LanguageFn::from_raw(tree_sitter_swift) };
-
-/// The content of the [`node-types.json`][] file for this grammar.
-///
-/// [`node-types.json`]: https://tree-sitter.github.io/tree-sitter/using-parsers#static-node-types
-pub const NODE_TYPES: &str = include_str!(concat!(env!("TREE_SITTER_SWIFT_OUT_DIR"), "/node-types.json"));
-
-pub const HIGHLIGHTS_QUERY: &str = include_str!("../../queries/highlights.scm");
-pub const INJECTIONS_QUERY: &str = include_str!("../../queries/injections.scm");
-pub const LOCALS_QUERY: &str = include_str!("../../queries/locals.scm");
-pub const TAGS_QUERY: &str = include_str!("../../queries/tags.scm");
-
-#[cfg(test)]
-mod tests {
- #[test]
- fn test_can_load_grammar() {
- let mut parser = tree_sitter::Parser::new();
- parser
- .set_language(&super::LANGUAGE.into())
- .expect("Error loading Swift parser");
- }
-
- #[test]
- fn test_can_parse_basic_file() {
- let mut parser = tree_sitter::Parser::new();
- parser
- .set_language(&super::LANGUAGE.into())
- .expect("Error loading Swift parser");
-
- let tree = parser
- .parse("_ = \"Hello!\"\n", None)
- .expect("Unable to parse!");
-
- assert_eq!(
- "(source_file (assignment target: (directly_assignable_expression (simple_identifier)) result: (line_string_literal text: (line_str_text))))",
- tree.root_node().to_sexp(),
- );
- }
-}
diff --git a/unified/extractor/tree-sitter-swift/grammar.js b/unified/extractor/tree-sitter-swift/grammar.js
deleted file mode 100644
index 7052d2ebdd5..00000000000
--- a/unified/extractor/tree-sitter-swift/grammar.js
+++ /dev/null
@@ -1,2113 +0,0 @@
-"use strict";
-/*
- * MIT License
- *
- * Copyright (c) 2021 alex-pinkus
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-const PRECS = {
- multiplication: 11,
- addition: 10,
- infix_operations: 9,
- nil_coalescing: 8,
- check: 7,
- prefix_operations: 7,
- comparison: 6,
- postfix_operations: 6,
- equality: 5,
- conjunction: 4,
- disjunction: 3,
- block: 2,
- loop: 1,
- keypath: 1,
- parameter_pack: 1,
- control_transfer: 0,
- as: -1,
- tuple: -1,
- if: -1,
- switch: -1,
- do: -1,
- fully_open_range: -1,
- range: -1,
- navigation: -1,
- expr: -1,
- ty: -1,
- call: -2,
- ternary: -2,
- try: -2,
- call_suffix: -2,
- range_suffix: -2,
- ternary_binary_suffix: -2,
- await: -2,
- assignment: -3,
- comment: -3,
- lambda: -3,
- regex: -4,
-};
-
-const DYNAMIC_PRECS = {
- call: 1,
-};
-
-const DEC_DIGITS = token(sep1(/[0-9]+/, /_+/));
-const HEX_DIGITS = token(sep1(/[0-9a-fA-F]+/, /_+/));
-const OCT_DIGITS = token(sep1(/[0-7]+/, /_+/));
-const BIN_DIGITS = token(sep1(/[01]+/, /_+/));
-const REAL_EXPONENT = token(seq(/[eE]/, optional(/[+-]/), DEC_DIGITS));
-const HEX_REAL_EXPONENT = token(seq(/[pP]/, optional(/[+-]/), DEC_DIGITS));
-
-var LEXICAL_IDENTIFIER;
-
-if (tree_sitter_version_supports_emoji()) {
- LEXICAL_IDENTIFIER =
- /[_\p{XID_Start}\p{Emoji}&&[^0-9#*]](\p{EMod}|\x{FE0F}\x{20E3}?)?([_\p{XID_Continue}\p{Emoji}\x{200D}](\p{EMod}|\x{FE0F}\x{20E3}?)?)*/;
-} else {
- LEXICAL_IDENTIFIER = /[_\p{XID_Start}][_\p{XID_Continue}]*/;
-}
-
-module.exports = grammar({
- name: "swift",
- supertypes: ($) => [
- $.expression,
- $.unannotated_type,
- $.global_declaration,
- $.type_level_declaration,
- $.local_declaration,
- $.protocol_member_declaration,
- ],
- conflicts: ($) => [
- // @Type(... could either be an annotation constructor invocation or an annotated expression
- [$.attribute],
- [$._attribute_argument],
- // Is `foo { ... }` a constructor invocation or function invocation?
- [$.simple_user_type, $.expression],
- // To support nested types A.B not being interpreted as `(navigation_expression ... (type_identifier)) (navigation_suffix)`
- [$.user_type],
- // How to tell the difference between Foo.bar(with:and:), and Foo.bar(with: smth, and: other)? You need GLR
- [$.value_argument],
- // { (foo, bar) ...
- [$.expression, $.lambda_parameter],
- [$._primary_expression, $.lambda_parameter],
- // (foo) where foo could be a binding pattern or a tuple expression item.
- [$._binding_pattern_with_expr, $.tuple_expression_item],
- // After a `{` in a function or switch context, it's ambigous whether we're starting a set of local statements or
- // applying some modifiers to a capture or pattern.
- [$.modifiers],
- // `+(...)` is ambigously either "call the function produced by a reference to the operator `+`" or "use the unary
- // operator `+` on the result of the parenthetical expression."
- [$._additive_operator, $._prefix_unary_operator],
- [$.referenceable_operator, $._prefix_unary_operator],
- // `{ [self, b, c] ...` could be a capture list or an array literal depending on what else happens.
- [$.capture_list_item, $.expression],
- [$.capture_list_item, $.expression, $.simple_user_type],
- [$._primary_expression, $.capture_list_item],
- // a ? b : c () could be calling c(), or it could be calling a function that's produced by the result of
- // `(a ? b : c)`. We have a small hack to force it to be the former of these by intentionally introducing a
- // conflict.
- [$.call_suffix, $.expr_hack_at_ternary_binary_call_suffix],
- // try {expression} is a bit magic and applies quite broadly: `try foo()` and `try foo { }` show that this is right
- // associative, and `try foo ? bar() : baz` even more so. But it doesn't always win: something like
- // `if try foo { } ...` should award its braces to the `if`. In order to make this actually happen, we need to parse
- // all the options and pick the best one that doesn't error out.
- [$.try_expression, $._unary_expression],
- [$.try_expression, $.expression],
- // await {expression} has the same special cases as `try`.
- [$.await_expression, $._unary_expression],
- [$.await_expression, $.expression],
- // In a computed property, when you see an @attribute, it's not yet clear if that's going to be for a
- // locally-declared class or a getter / setter specifier.
- [
- $._local_property_declaration,
- $._local_typealias_declaration,
- $._local_function_declaration,
- $._local_class_declaration,
- $.computed_getter,
- $.computed_modify,
- $.computed_setter,
- ],
- // The `class` modifier is legal in many of the same positions that a class declaration itself would be.
- [$._bodyless_function_declaration, $.property_modifier],
- [$.init_declaration, $.property_modifier],
- // Patterns, man
- [$._navigable_type_expression, $.case_pattern],
- [$._no_expr_pattern_already_bound, $._binding_pattern_no_expr],
-
- // On encountering a closure starting with `{ @Foo ...`, we don't yet know if that attribute applies to the closure
- // type or to a declaration within the closure. What a mess! We just have to hope that if we keep going, only one of
- // those will parse (because there will be an `in` or a `let`).
- [
- $._lambda_type_declaration,
- $._local_property_declaration,
- $._local_typealias_declaration,
- $._local_function_declaration,
- $._local_class_declaration,
- ],
-
- // We want `foo() { }` to be treated as one function call, but we _also_ want `if foo() { ... }` to be treated as a
- // full if-statement. This means we have to treat it as a conflict rather than purely a left or right associative
- // construct, and let the parser realize that the second expression won't parse properly with the `{ ... }` as a
- // lambda.
- [$.constructor_suffix],
- [$.call_suffix],
-
- // `actor` is allowed to be an identifier, even though it is also a locally permitted declaration. If we encounter
- // it, the only way to know what it's meant to be is to keep going.
- [$._modifierless_class_declaration, $.property_modifier],
- [$._fn_call_lambda_arguments],
-
- // `borrowing` and `consuming` are legal as identifiers, but are also legal modifiers
- [$.parameter_modifiers],
-
- // These are keywords sometimes, but simple identifiers other times, and it just depends on the rest of their usage.
- [$._contextual_simple_identifier, $._modifierless_class_declaration],
- [$._contextual_simple_identifier, $.property_behavior_modifier],
- [$._contextual_simple_identifier, $.parameter_modifier],
- [$._contextual_simple_identifier, $.type_parameter_pack],
- [$._contextual_simple_identifier, $.type_pack_expansion],
- [$._contextual_simple_identifier, $.visibility_modifier],
- ],
- extras: ($) => [
- $.comment,
- $.multiline_comment,
- /\s+/, // Whitespace
- ],
- externals: ($) => [
- // Comments and raw strings are parsed in a custom scanner because they require us to carry forward state to
- // maintain symmetry. For instance, parsing a multiline comment requires us to increment a counter whenever we see
- // `/*`, and decrement it whenever we see `*/`. A standard grammar would only be able to exit the comment at the
- // first `*/` (like C does). Similarly, when you start a string with `##"`, you're required to include the same
- // number of `#` symbols to end it.
- $._multiline_comment,
- $.raw_str_part,
- $.raw_str_continuing_indicator,
- $.raw_str_end_part,
- // Because Swift doesn't have explicit semicolons, we also do some whitespace handling in a custom scanner. Line
- // breaks are _sometimes_ meaningful as the end of a statement: try to write `let foo: Foo let bar: Bar`, for
- // instance and the compiler will complain, but add either a newline or a semicolon and it's fine. We borrow the
- // idea from the Kotlin grammar that a newline is sometimes a "semicolon". By including `\n` in both `_semi` and
- // an anonymous `whitespace` extras, we _should_ be able to let the parser decide if a newline is meaningful. If the
- // parser sees something like `foo.bar(1\n)`, it knows that a "semicolon" would not be valid there, so it parses
- // that as whitespace. On the other hand, `let foo: Foo\n let bar: Bar` has a meaningful newline.
- // Unfortunately, we can't simply stop at that. There are some expressions and statements that remain valid if you
- // end them early, but are expected to be parsed across multiple lines. One particular nefarious example is a
- // function declaration, where you might have something like `func foo(args: A) -> Foo throws where A: Hashable`.
- // This would still be a valid declaration even if it ended after the `)`, the `Foo`, or the `throws`, so a grammar
- // that simply interprets a newline as "sometimes a semi" would parse those incorrectly.
- // To solve that case, our custom scanner must do a bit of extra lookahead itself. If we're about to generate a
- // `_semi`, we advance a bit further to see if the next non-whitespace token would be one of these other operators.
- // If so, we ignore the `_semi` and just produce the operator; if not, we produce the `_semi` and let the rest of
- // the grammar sort it out. This isn't perfect, but it works well enough most of the time.
- $._implicit_semi,
- $._explicit_semi,
- // Every one of the below operators will suppress a `_semi` if we encounter it after a newline.
- $._arrow_operator_custom,
- $._dot_custom,
- $._conjunction_operator_custom,
- $._disjunction_operator_custom,
- $._nil_coalescing_operator_custom,
- $._eq_custom,
- $._eq_eq_custom,
- $._plus_then_ws,
- $._minus_then_ws,
- $._bang_custom,
- $._throws_keyword,
- $._rethrows_keyword,
- $.default_keyword,
- $.where_keyword,
- $["else"],
- $.catch_keyword,
- $._as_custom,
- $._as_quest_custom,
- $._as_bang_custom,
- $._async_keyword_custom,
- $._custom_operator,
- $._hash_symbol_custom,
- $._directive_if,
- $._directive_elseif,
- $._directive_else,
- $._directive_endif,
-
- // Fake operator that will never get triggered, but follows the sequence of characters for `try!`. Tracked by the
- // custom scanner so that it can avoid triggering `$.bang` for that case.
- $._fake_try_bang,
- ],
- inline: ($) => [$._locally_permitted_modifiers],
- rules: {
- ////////////////////////////////
- // File Structure
- ////////////////////////////////
- source_file: ($) =>
- seq(
- optional(field("shebang", $.shebang_line)),
- optional(
- seq(
- field("statement", $._top_level_statement),
- repeat(seq($._semi, field("statement", $._top_level_statement))),
- optional($._semi)
- )
- )
- ),
- _semi: ($) => choice($._implicit_semi, $._explicit_semi),
- shebang_line: ($) => seq($._hash_symbol, "!", /[^\r\n]*/),
- ////////////////////////////////
- // Lexical Structure - https://docs.swift.org/swift-book/ReferenceManual/LexicalStructure.html
- ////////////////////////////////
- comment: ($) => token(prec(PRECS.comment, seq("//", /.*/))),
- // Named wrapper for the unnamed `_multiline_comment` external token, so
- // that multi-line comments still appear in the AST (e.g. as extras between
- // top-level statements) without being extracted as class body members when
- // used only to separate those members.
- multiline_comment: ($) => $._multiline_comment,
- // Identifiers
- simple_identifier: ($) =>
- choice(
- LEXICAL_IDENTIFIER,
- /`[^\r\n` ]*`/,
- /\$[0-9]+/,
- token(seq("$", LEXICAL_IDENTIFIER)),
- $._contextual_simple_identifier
- ),
- // Keywords that were added after they were already legal as identifiers. `tree-sitter` will prefer exact matches
- // when parsing so unless we explicitly say that these are legal, the parser will interpret them as their keyword.
- _contextual_simple_identifier: ($) =>
- choice(
- "actor",
- "async",
- "each",
- "lazy",
- "repeat",
- "package",
- $._parameter_ownership_modifier
- ),
- identifier: ($) => sep1(field("part", $.simple_identifier), $._dot),
- // Literals
- _basic_literal: ($) =>
- choice(
- $.integer_literal,
- $.hex_literal,
- $.oct_literal,
- $.bin_literal,
- $.real_literal,
- $.boolean_literal,
- $._string_literal,
- $.regex_literal,
- "nil"
- ),
- real_literal: ($) =>
- token(
- choice(
- seq(DEC_DIGITS, REAL_EXPONENT),
- seq(optional(DEC_DIGITS), ".", DEC_DIGITS, optional(REAL_EXPONENT)),
- seq(
- "0x",
- HEX_DIGITS,
- optional(seq(".", HEX_DIGITS)),
- HEX_REAL_EXPONENT
- )
- )
- ),
- integer_literal: ($) => token(seq(optional(/[1-9]/), DEC_DIGITS)),
- hex_literal: ($) => token(seq("0", /[xX]/, HEX_DIGITS)),
- oct_literal: ($) => token(seq("0", /[oO]/, OCT_DIGITS)),
- bin_literal: ($) => token(seq("0", /[bB]/, BIN_DIGITS)),
- boolean_literal: ($) => choice("true", "false"),
- // String literals
- _string_literal: ($) =>
- choice(
- $.line_string_literal,
- $.multi_line_string_literal,
- $.raw_string_literal
- ),
- line_string_literal: ($) =>
- seq(
- '"',
- repeat(choice(field("text", $._line_string_content), $._interpolation)),
- '"'
- ),
- _line_string_content: ($) => choice($.line_str_text, $.str_escaped_char),
- line_str_text: ($) => /[^\\"]+/,
- str_escaped_char: ($) =>
- choice($._escaped_identifier, $._uni_character_literal),
- _uni_character_literal: ($) => seq("\\", "u", /\{[0-9a-fA-F]+\}/),
- multi_line_string_literal: ($) =>
- seq(
- '"""',
- repeat(
- choice(field("text", $._multi_line_string_content), $._interpolation)
- ),
- '"""'
- ),
- raw_string_literal: ($) =>
- seq(
- repeat(
- seq(
- field("text", $.raw_str_part),
- field("interpolation", $.raw_str_interpolation),
- field("continuing", optional($.raw_str_continuing_indicator))
- )
- ),
- field("text", $.raw_str_end_part)
- ),
- raw_str_interpolation: ($) =>
- seq(field("start", $.raw_str_interpolation_start), $._interpolation_contents, ")"),
- raw_str_interpolation_start: ($) => /\\#*\(/,
- _multi_line_string_content: ($) =>
- choice($.multi_line_str_text, $.str_escaped_char, '"'),
- _interpolation: ($) => seq("\\(", $._interpolation_contents, ")"),
- _interpolation_contents: ($) =>
- sep1Opt(
- field(
- "interpolation",
- alias($.value_argument, $.interpolated_expression)
- ),
- ","
- ),
- _escaped_identifier: ($) => /\\[0\\tnr"'\n]/,
- multi_line_str_text: ($) => /[^\\"]+/,
- // Based on https://gitlab.com/woolsweater/tree-sitter-swifter/-/blob/3d47c85bd47ce54cdf2023a9c0e01eb90adfcc1d/grammar.js#L1019
- // But required modifications to hit all of the cases in SE-354
- regex_literal: ($) =>
- choice(
- $._extended_regex_literal,
- $._multiline_regex_literal,
- $._oneline_regex_literal
- ),
-
- _extended_regex_literal: ($) =>
- seq($._hash_symbol, /\/((\/[^#])|[^\n])+\/#/),
-
- _multiline_regex_literal: ($) =>
- seq($._hash_symbol, /\/\n/, /(\/[^#]|[^/])*?\n\/#/),
-
- _oneline_regex_literal: ($) =>
- token(
- prec(
- PRECS.regex,
- seq(
- "/",
- token.immediate(/[^ \t\n]?[^/\n]*[^ \t\n/]/),
- token.immediate("/")
- )
- )
- ),
- ////////////////////////////////
- // Types - https://docs.swift.org/swift-book/ReferenceManual/Types.html
- ////////////////////////////////
- type_annotation: ($) =>
- seq(":", field("type", $._possibly_implicitly_unwrapped_type)),
- _possibly_implicitly_unwrapped_type: ($) =>
- choice($.type, $.implicitly_unwrapped_type),
- implicitly_unwrapped_type: ($) =>
- seq(field("name", $.type), token.immediate("!")),
- type: ($) =>
- prec.right(
- PRECS.ty,
- seq(field("modifiers", optional($.type_modifiers)), field("name", $.unannotated_type))
- ),
- unannotated_type: ($) =>
- prec.right(
- PRECS.ty,
- choice(
- $.user_type,
- $.tuple_type,
- $.function_type,
- $.array_type,
- $.dictionary_type,
- $.optional_type,
- $.metatype,
- $.opaque_type,
- $.existential_type,
- $.protocol_composition_type,
- $.type_parameter_pack,
- $.type_pack_expansion,
- $.suppressed_constraint
- )
- ),
- // The grammar just calls this whole thing a `type-identifier` but that's a bit confusing.
- user_type: ($) => sep1(field("part", $.simple_user_type), $._dot),
- simple_user_type: ($) =>
- prec.right(
- PRECS.ty,
- seq(
- field("name", alias($.simple_identifier, $.type_identifier)),
- field("arguments", optional($.type_arguments))
- )
- ),
- tuple_type: ($) =>
- choice(
- seq(
- "(",
- optional(sep1Opt(field("element", $.tuple_type_item), ",")),
- ")"
- ),
- field("element", alias($.parenthesized_type, $.tuple_type_item))
- ),
- tuple_type_item: ($) =>
- prec(
- PRECS.expr,
- seq(
- optional($._tuple_type_item_identifier),
- field("modifiers", optional($.parameter_modifiers)),
- field("type", $.type)
- )
- ),
- _tuple_type_item_identifier: ($) =>
- prec(
- PRECS.expr,
- seq(
- optional(field("external_name", $.wildcard_pattern)),
- field("name", $.simple_identifier),
- ":"
- )
- ),
- function_type: ($) =>
- seq(
- field("params", choice($.tuple_type, $.unannotated_type)),
- field("async", optional($._async_keyword)),
- field("throws", optional(choice($.throws_clause, $.throws))),
- $._arrow_operator,
- field("return_type", $.type)
- ),
- array_type: ($) => seq("[", field("element", $.type), "]"),
- dictionary_type: ($) =>
- seq("[", field("key", $.type), ":", field("value", $.type), "]"),
- optional_type: ($) =>
- prec.left(
- seq(
- field(
- "wrapped",
- choice($.user_type, $.tuple_type, $.array_type, $.dictionary_type)
- ),
- repeat1(alias($._immediate_quest, "?"))
- )
- ),
- metatype: ($) => seq(field("name", $.unannotated_type), ".", choice("Type", "Protocol")),
- _quest: ($) => "?",
- _immediate_quest: ($) => token.immediate("?"),
- opaque_type: ($) => prec.right(seq("some", field("name", $.unannotated_type))),
- existential_type: ($) => prec.right(seq("any", field("name", $.unannotated_type))),
- type_parameter_pack: ($) => prec.left(seq("each", field("name", $.unannotated_type))),
- type_pack_expansion: ($) => prec.left(seq("repeat", field("name", $.unannotated_type))),
- protocol_composition_type: ($) =>
- prec.left(
- seq(
- field("type", $.unannotated_type),
- repeat1(seq("&", prec.right(field("type", $.unannotated_type))))
- )
- ),
- suppressed_constraint: ($) =>
- prec.right(
- seq(
- "~",
- field("suppressed", alias($.simple_identifier, $.type_identifier))
- )
- ),
- ////////////////////////////////
- // Expressions - https://docs.swift.org/swift-book/ReferenceManual/Expressions.html
- ////////////////////////////////
- expression: ($) =>
- prec(
- PRECS.expr,
- choice(
- $.simple_identifier,
- $._unary_expression,
- $._binary_expression,
- $.ternary_expression,
- $._primary_expression,
- $.if_statement,
- $.switch_statement,
- $.assignment,
- $.value_parameter_pack,
- $.value_pack_expansion,
- $.optional_chain_marker
- )
- ),
- optional_chain_marker: ($) =>
- seq(field("expr", $.expression), alias($._immediate_quest, "?")),
- // Unary expressions
- _unary_expression: ($) =>
- choice(
- $.postfix_expression,
- $.call_expression,
- $.macro_invocation,
- $.constructor_expression,
- $.navigation_expression,
- $.prefix_expression,
- $.as_expression,
- $.selector_expression,
- $.open_start_range_expression,
- $.open_end_range_expression,
- $.directive,
- $.diagnostic
- ),
- postfix_expression: ($) =>
- prec.left(
- PRECS.postfix_operations,
- seq(
- field("target", $.expression),
- field("operation", $._postfix_unary_operator)
- )
- ),
- constructor_expression: ($) =>
- prec(
- PRECS.call,
- seq(
- field(
- "constructed_type",
- choice($.array_type, $.dictionary_type, $.user_type)
- ),
- field("suffix", $.constructor_suffix)
- )
- ),
- parenthesized_type: ($) =>
- seq(
- "(",
- field("type", choice($.opaque_type, $.existential_type, $.dictionary_type)),
- ")"
- ),
- navigation_expression: ($) =>
- prec.left(
- PRECS.navigation,
- seq(
- field(
- "target",
- choice(
- $._navigable_type_expression,
- $.expression,
- $.parenthesized_type
- )
- ),
- field("suffix", $.navigation_suffix)
- )
- ),
- _navigable_type_expression: ($) =>
- choice($.user_type, $.array_type, $.dictionary_type),
- open_start_range_expression: ($) =>
- prec.right(
- PRECS.range,
- seq(
- $._range_operator,
- prec.right(PRECS.range_suffix, field("end", $.expression))
- )
- ),
- _range_operator: ($) =>
- choice($._open_ended_range_operator, $._three_dot_operator),
- open_end_range_expression: ($) =>
- prec.right(
- PRECS.range,
- seq(field("start", $.expression), $._three_dot_operator)
- ),
- prefix_expression: ($) =>
- prec.left(
- PRECS.prefix_operations,
- seq(
- field("operation", $._prefix_unary_operator),
- field(
- "target",
- choice(
- $.expression,
- alias(choice("async", "if", "switch"), $.expression)
- )
- )
- )
- ),
- as_expression: ($) =>
- prec.left(
- PRECS.as,
- seq(field("expr", $.expression), field("operator", $.as_operator), field("type", $.type))
- ),
- selector_expression: ($) =>
- seq(
- $._hash_symbol,
- "selector",
- "(",
- optional(choice("getter:", "setter:")),
- field("expr", $.expression),
- ")"
- ),
- // Binary expressions
- _binary_expression: ($) =>
- choice(
- $.multiplicative_expression,
- $.additive_expression,
- $.range_expression,
- $.infix_expression,
- $.nil_coalescing_expression,
- $.check_expression,
- $.equality_expression,
- $.comparison_expression,
- $.conjunction_expression,
- $.disjunction_expression,
- $.bitwise_operation
- ),
- multiplicative_expression: ($) =>
- prec.left(
- PRECS.multiplication,
- seq(
- field("lhs", $.expression),
- field("op", $._multiplicative_operator),
- field("rhs", $.expression)
- )
- ),
- additive_expression: ($) =>
- prec.left(
- PRECS.addition,
- seq(
- field("lhs", $.expression),
- field("op", $._additive_operator),
- field("rhs", $.expression)
- )
- ),
- range_expression: ($) =>
- prec.right(
- PRECS.range,
- seq(
- field("start", $.expression),
- field("op", $._range_operator),
- field("end", $._expr_hack_at_ternary_binary_suffix)
- )
- ),
- infix_expression: ($) =>
- prec.left(
- PRECS.infix_operations,
- seq(
- field("lhs", $.expression),
- field("op", $.custom_operator),
- field("rhs", $._expr_hack_at_ternary_binary_suffix)
- )
- ),
- nil_coalescing_expression: ($) =>
- prec.right(
- PRECS.nil_coalescing,
- seq(
- field("value", $.expression),
- $._nil_coalescing_operator,
- field("if_nil", $._expr_hack_at_ternary_binary_suffix)
- )
- ),
- check_expression: ($) =>
- prec.left(
- PRECS.check,
- seq(
- field("target", $.expression),
- field("op", $._is_operator),
- field("type", $.type)
- )
- ),
- comparison_expression: ($) =>
- prec.left(
- seq(
- field("lhs", $.expression),
- field("op", $._comparison_operator),
- field("rhs", $._expr_hack_at_ternary_binary_suffix)
- )
- ),
- equality_expression: ($) =>
- prec.left(
- PRECS.equality,
- seq(
- field("lhs", $.expression),
- field("op", $._equality_operator),
- field("rhs", $._expr_hack_at_ternary_binary_suffix)
- )
- ),
- conjunction_expression: ($) =>
- prec.left(
- PRECS.conjunction,
- seq(
- field("lhs", $.expression),
- field("op", $._conjunction_operator),
- field("rhs", $._expr_hack_at_ternary_binary_suffix)
- )
- ),
- disjunction_expression: ($) =>
- prec.left(
- PRECS.disjunction,
- seq(
- field("lhs", $.expression),
- field("op", $._disjunction_operator),
- field("rhs", $._expr_hack_at_ternary_binary_suffix)
- )
- ),
- bitwise_operation: ($) =>
- prec.left(
- seq(
- field("lhs", $.expression),
- field("op", $._bitwise_binary_operator),
- field("rhs", $._expr_hack_at_ternary_binary_suffix)
- )
- ),
- custom_operator: ($) => choice(token(/[\/]+[*]+/), $._custom_operator),
- // Suffixes
- navigation_suffix: ($) =>
- seq(
- $._dot,
- field("suffix", choice($.simple_identifier, $.integer_literal))
- ),
- call_suffix: ($) =>
- prec(
- PRECS.call_suffix,
- choice(
- field("arguments", $.value_arguments),
- prec.dynamic(-1, $._fn_call_lambda_arguments), // Prefer to treat `foo() { }` as one call not two
- seq(field("arguments", $.value_arguments), $._fn_call_lambda_arguments)
- )
- ),
- constructor_suffix: ($) =>
- prec(
- PRECS.call_suffix,
- choice(
- field("arguments", alias($._constructor_value_arguments, $.value_arguments)),
- prec.dynamic(-1, $._fn_call_lambda_arguments), // As above
- seq(
- field("arguments", alias($._constructor_value_arguments, $.value_arguments)),
- $._fn_call_lambda_arguments
- )
- )
- ),
- _constructor_value_arguments: ($) =>
- seq("(", optional(sep1Opt(field("argument", $.value_argument), ",")), ")"),
- _fn_call_lambda_arguments: ($) =>
- sep1(field("lambda", $.lambda_literal), seq(field("name", $.simple_identifier), ":")),
- type_arguments: ($) => prec.left(seq("<", sep1Opt(field("argument", $.type), ","), ">")),
- value_arguments: ($) =>
- seq(
- choice(
- seq("(", optional(sep1Opt(field("argument", $.value_argument), ",")), ")"),
- seq("[", optional(sep1Opt(field("argument", $.value_argument), ",")), "]")
- )
- ),
- value_argument_label: ($) =>
- prec.left(
- field("name", choice(
- $.simple_identifier,
- // We don't rely on $._contextual_simple_identifier here because
- // these don't usually fall into that category.
- alias("if", $.simple_identifier),
- alias("switch", $.simple_identifier)
- ))
- ),
- value_argument: ($) =>
- prec.left(
- seq(
- field("type_modifiers", optional($.type_modifiers)),
- choice(
- repeat1(
- seq(field("reference_specifier", $.value_argument_label), ":")
- ),
- seq(
- optional(seq(field("name", $.value_argument_label), ":")),
- field("value", $.expression)
- )
- )
- )
- ),
- try_expression: ($) =>
- prec.right(
- PRECS["try"],
- seq(
- field("operator", $.try_operator),
- field(
- "expr",
- choice(
- // Prefer direct calls, e.g. `try foo()`, over indirect like `try a ? b() : c`. This allows us to have
- // left associativity for the direct calls, which is technically wrong but is the only way to resolve the
- // ambiguity of `if foo { ... }` in the correct direction.
- prec.right(-2, $.expression),
- prec.left(0, $._binary_expression),
- prec.left(0, $.call_expression),
- // Similarly special case the ternary expression, where `try` may come earlier than it is actually needed.
- // When the parser just encounters some identifier after a `try`, it should prefer the `call_expression` (so
- // this should be lower in priority than that), but when we encounter an ambiguous expression that might be
- // either `try (foo() ? ...)` or `(try foo()) ? ...`, we should prefer the former. We accomplish that by
- // giving it a _static precedence_ of -1 but a _dynamic precedence_ of 1.
- prec.dynamic(1, prec.left(-1, $.ternary_expression))
- )
- )
- )
- ),
- await_expression: ($) =>
- prec.right(
- PRECS.await,
- seq(
- $._await_operator,
- field(
- "expr",
- choice(
- // Prefer direct calls over indirect (same as with `try`).
- prec.right(-2, $.expression),
- prec.left(0, $.call_expression),
- // Special case ternary to `await` the whole thing (same as with `try`).
- prec.dynamic(1, prec.left(-1, $.ternary_expression))
- )
- )
- )
- ),
- _await_operator: ($) => alias("await", "await"),
- ternary_expression: ($) =>
- prec.right(
- PRECS.ternary,
- seq(
- field("condition", $.expression),
- $._quest,
- field("if_true", $.expression),
- ":",
- field("if_false", $._expr_hack_at_ternary_binary_suffix)
- )
- ),
- _expr_hack_at_ternary_binary_suffix: ($) =>
- prec.left(
- PRECS.ternary_binary_suffix,
- choice(
- $.expression,
- alias($.expr_hack_at_ternary_binary_call, $.call_expression)
- )
- ),
- expr_hack_at_ternary_binary_call: ($) =>
- seq(
- field("function", $.expression),
- field("suffix", alias($.expr_hack_at_ternary_binary_call_suffix, $.call_suffix))
- ),
- expr_hack_at_ternary_binary_call_suffix: ($) =>
- prec(PRECS.call_suffix, field("arguments", $.value_arguments)),
- call_expression: ($) =>
- prec(
- PRECS.call,
- prec.dynamic(DYNAMIC_PRECS.call, seq(field("function", $.expression), field("suffix", $.call_suffix)))
- ),
- macro_invocation: ($) =>
- prec(
- PRECS.call,
- prec.dynamic(
- DYNAMIC_PRECS.call,
- seq(
- $._hash_symbol,
- field("name", $.simple_identifier),
- field("type_parameters", optional($.type_parameters)),
- field("suffix", $.call_suffix)
- )
- )
- ),
- _primary_expression: ($) =>
- choice(
- $.tuple_expression,
- $._basic_literal,
- $.lambda_literal,
- $.special_literal,
- $.playground_literal,
- $.array_literal,
- $.dictionary_literal,
- $.self_expression,
- $.super_expression,
- $.try_expression,
- $.await_expression,
- $.referenceable_operator,
- $.key_path_expression,
- $.key_path_string_expression,
- prec.right(
- PRECS.fully_open_range,
- alias($._three_dot_operator, $.fully_open_range)
- )
- ),
- tuple_expression: ($) =>
- prec.right(
- PRECS.tuple,
- seq(
- "(",
- sep1Opt(field("element", $.tuple_expression_item), ","),
- ")"
- )
- ),
- tuple_expression_item: ($) =>
- seq(
- optional(seq(field("name", $.simple_identifier), ":")),
- field("value", $.expression)
- ),
- array_literal: ($) =>
- seq("[", optional(sep1Opt(field("element", $.expression), ",")), "]"),
- dictionary_literal: ($) =>
- seq(
- "[",
- choice(":", sep1Opt(field("element", $.dictionary_literal_item), ",")),
- optional(","),
- "]"
- ),
- dictionary_literal_item: ($) =>
- seq(field("key", $.expression), ":", field("value", $.expression)),
- special_literal: ($) =>
- seq(
- $._hash_symbol,
- choice(
- "file",
- "fileID",
- "filePath",
- "line",
- "column",
- "function",
- "dsohandle"
- )
- ),
- playground_literal: ($) =>
- seq(
- $._hash_symbol,
- field("kind", choice("colorLiteral", "fileLiteral", "imageLiteral")),
- "(",
- sep1Opt(field("argument", $.playground_literal_argument), ","),
- ")"
- ),
- playground_literal_argument: ($) =>
- seq(field("name", $.simple_identifier), ":", field("value", $.expression)),
- lambda_literal: ($) =>
- prec.left(
- PRECS.lambda,
- seq(
- choice("{", "^{"),
- optional($._lambda_type_declaration),
- optional($._statements),
- "}"
- )
- ),
- _lambda_type_declaration: ($) =>
- seq(
- repeat(field("attribute", $.attribute)),
- prec(PRECS.expr, optional(field("captures", $.capture_list))),
- optional(field("type", $.lambda_function_type)),
- "in"
- ),
- capture_list: ($) => seq("[", sep1Opt(field("item", $.capture_list_item), ","), "]"),
- capture_list_item: ($) =>
- choice(
- field("name", $.self_expression),
- prec(
- PRECS.expr,
- seq(
- field("ownership", optional($.ownership_modifier)),
- field("name", $.simple_identifier),
- optional(seq($._equal_sign, field("value", $.expression)))
- )
- )
- ),
- lambda_function_type: ($) =>
- prec(
- PRECS.expr,
- seq(
- choice(
- field("params", $.lambda_function_type_parameters),
- seq("(", field("params", optional($.lambda_function_type_parameters)), ")")
- ),
- field("async", optional($._async_keyword)),
- field("throws", optional(choice($.throws_clause, $.throws))),
- optional(
- seq(
- $._arrow_operator,
- field("return_type", $._possibly_implicitly_unwrapped_type)
- )
- )
- )
- ),
- lambda_function_type_parameters: ($) => sep1Opt(field("parameter", $.lambda_parameter), ","),
- lambda_parameter: ($) =>
- seq(
- choice(
- field("name", $.self_expression),
- prec(PRECS.expr, field("name", $.simple_identifier)),
- prec(
- PRECS.expr,
- seq(
- optional(field("external_name", $.simple_identifier)),
- field("name", $.simple_identifier),
- ":",
- field("modifiers", optional($.parameter_modifiers)),
- field("type", $._possibly_implicitly_unwrapped_type)
- )
- )
- )
- ),
- self_expression: ($) => "self",
- super_expression: ($) => seq("super"),
- _else_options: ($) => choice(field("else_branch", $.block), field("else_branch", $.if_statement)),
- if_statement: ($) =>
- prec.right(
- PRECS["if"],
- seq(
- "if",
- sep1(field("condition", $.if_condition), ","),
- field("body", $.block),
- optional(seq(alias($["else"], "else"), $._else_options))
- )
- ),
- if_condition: ($) =>
- field("kind", choice($.if_let_binding, $.expression, $.availability_condition)),
- if_let_binding: ($) =>
- seq(
- $._direct_or_indirect_binding,
- optional(seq($._equal_sign, field("value", $.expression))),
- field("where", optional($.where_clause))
- ),
- guard_statement: ($) =>
- prec.right(
- PRECS["if"],
- seq(
- "guard",
- sep1(field("condition", $.if_condition), ","),
- alias($["else"], "else"),
- field("body", $.block)
- )
- ),
- switch_statement: ($) =>
- prec.right(
- PRECS["switch"],
- seq(
- "switch",
- field("expr", $.expression),
- "{",
- repeat(field("entry", $.switch_entry)),
- "}"
- )
- ),
- switch_entry: ($) =>
- seq(
- field("modifiers", optional($.modifiers)),
- choice(
- seq(
- "case",
- field("pattern", $.switch_pattern),
- field("where", optional($.where_clause)),
- repeat(seq(",", field("pattern", $.switch_pattern)))
- ),
- field("default", $.default_keyword)
- ),
- ":",
- $._statements,
- optional("fallthrough")
- ),
- switch_pattern: ($) => field("pattern", alias($._binding_pattern_with_expr, $.pattern)),
- do_statement: ($) =>
- prec.right(PRECS["do"], seq("do", field("body", $.block), repeat(field("catch", $.catch_block)))),
- catch_block: ($) =>
- seq(
- field("keyword", $.catch_keyword),
- field("error", optional(alias($._binding_pattern_no_expr, $.pattern))),
- field("where", optional($.where_clause)),
- field("body", $.block)
- ),
- where_clause: ($) => prec.left(seq(field("keyword", $.where_keyword), field("expr", $.expression))),
- key_path_expression: ($) =>
- prec.right(
- PRECS.keypath,
- seq(
- "\\",
- field("type", optional(
- choice($.simple_user_type, $.array_type, $.dictionary_type)
- )),
- repeat(seq(".", field("component", $.key_path_component)))
- )
- ),
- key_path_string_expression: ($) =>
- prec.left(seq($._hash_symbol, "keyPath", "(", field("expr", $.expression), ")")),
- key_path_component: ($) =>
- prec.left(
- choice(
- seq(field("name", $.simple_identifier), repeat(field("postfix", $.key_path_postfix))),
- repeat1(field("postfix", $.key_path_postfix))
- )
- ),
- key_path_postfix: ($) =>
- choice(
- "?",
- field("force_unwrap", $.bang),
- "self",
- seq("[", optional(sep1(field("argument", $.value_argument), ",")), "]")
- ),
- try_operator: ($) =>
- prec.right(
- seq("try", choice(optional($._try_operator_type), $._fake_try_bang))
- ),
- _try_operator_type: ($) =>
- choice(token.immediate("!"), token.immediate("?")),
- _assignment_and_operator: ($) =>
- choice("+=", "-=", "*=", "/=", "%=", $._equal_sign),
- _equality_operator: ($) => choice("!=", "!==", $._eq_eq, "==="),
- _comparison_operator: ($) => choice("<", ">", "<=", ">="),
- _three_dot_operator: ($) => alias("...", "..."), // Weird alias to satisfy highlight queries
- _open_ended_range_operator: ($) => alias("..<", "..<"),
- _is_operator: ($) => "is",
- _additive_operator: ($) =>
- choice(
- alias($._plus_then_ws, "+"),
- alias($._minus_then_ws, "-"),
- "+",
- "-"
- ),
- // The `/` operator conflicts with a regex literal (which itself appears to conflict with a
- // comment, for some reason), so we must give it equivalent token precedence.
- _multiplicative_operator: ($) =>
- choice("*", alias(token(prec(PRECS.regex, "/")), "/"), "%"),
- as_operator: ($) => choice($._as, $._as_quest, $._as_bang),
- _prefix_unary_operator: ($) =>
- prec.right(
- choice(
- "++",
- "--",
- "-",
- "+",
- $.bang,
- "&",
- "~",
- $._dot,
- $.custom_operator
- )
- ),
- _bitwise_binary_operator: ($) => choice("&", "|", "^", "<<", ">>"),
- _postfix_unary_operator: ($) => choice("++", "--", $.bang),
- directly_assignable_expression: ($) => field("expr", $.expression),
-
- ////////////////////////////////
- // Statements - https://docs.swift.org/swift-book/ReferenceManual/Statements.html
- ////////////////////////////////
- _statements: ($) =>
- prec.left(
- // Left precedence is required in switch statements
- seq(
- field("statement", $._local_statement),
- repeat(seq($._semi, field("statement", $._local_statement))),
- optional($._semi)
- )
- ),
- _local_statement: ($) =>
- choice(
- $.expression,
- $.local_declaration,
- $._labeled_statement,
- $.control_transfer_statement
- ),
- _top_level_statement: ($) =>
- choice(
- $.expression,
- $.global_declaration,
- $._labeled_statement,
- $._throw_statement
- ),
- block: ($) => prec(PRECS.block, seq("{", optional($._statements), "}")),
- _labeled_statement: ($) =>
- seq(
- optional($.statement_label),
- choice(
- $.for_statement,
- $.while_statement,
- $.repeat_while_statement,
- $.do_statement,
- $.if_statement,
- $.guard_statement,
- $.switch_statement
- )
- ),
- statement_label: ($) => token(/[a-zA-Z_][a-zA-Z_0-9]*:/),
- for_statement: ($) =>
- prec(
- PRECS.loop,
- seq(
- "for",
- field("try", optional($.try_operator)),
- optional($._await_operator),
- field("item", alias($._binding_pattern_no_expr, $.pattern)),
- field("type", optional($.type_annotation)),
- "in",
- field("collection", $._for_statement_collection),
- field("where", optional($.where_clause)),
- field("body", $.block)
- )
- ),
- _for_statement_collection: ($) =>
- // If this expression has "await", this triggers some special-cased logic to prefer function calls. We prefer
- // the opposite, though, since function calls may contain trailing code blocks, which are undesirable here.
- //
- // To fix that, we simply undo the special casing by defining our own `await_expression`.
- choice($.expression, alias($.for_statement_await, $.await_expression)),
- for_statement_await: ($) => seq($._await_operator, field("expr", $.expression)),
-
- while_statement: ($) =>
- prec(
- PRECS.loop,
- seq(
- "while",
- sep1(field("condition", $.if_condition), ","),
- field("body", $.block)
- )
- ),
- repeat_while_statement: ($) =>
- prec(
- PRECS.loop,
- seq(
- "repeat",
- field("body", $.block),
- // Make sure we make it to the `while` before assuming this is a parameter pack.
- repeat($._implicit_semi),
- "while",
- sep1(field("condition", $.if_condition), ",")
- )
- ),
- control_transfer_statement: ($) =>
- choice(
- prec.right(
- PRECS.control_transfer,
- seq(field("kind", $.throw_keyword), field("result", $.expression))
- ),
- prec.right(
- PRECS.control_transfer,
- seq(
- field("kind", $._optionally_valueful_control_keyword),
- field("result", optional($.expression))
- )
- )
- ),
- _throw_statement: ($) => seq($.throw_keyword, $.expression),
- throw_keyword: ($) => "throw",
- _optionally_valueful_control_keyword: ($) =>
- choice("return", "continue", "break", "yield"),
- assignment: ($) =>
- prec.left(
- PRECS.assignment,
- seq(
- field("target", $.directly_assignable_expression),
- field("operator", $._assignment_and_operator),
- field("result", $.expression)
- )
- ),
- value_parameter_pack: ($) =>
- prec.left(PRECS.parameter_pack, seq("each", field("expr", $.expression))),
- value_pack_expansion: ($) =>
- prec.left(PRECS.parameter_pack, seq("repeat", field("expr", $.expression))),
- availability_condition: ($) =>
- seq(
- $._hash_symbol,
- choice("available", "unavailable"),
- "(",
- sep1Opt($._availability_argument, ","),
- ")"
- ),
- _availability_argument: ($) =>
- choice(seq(field("platform", $.identifier), sep1(field("version", $.integer_literal), ".")), "*"),
- ////////////////////////////////
- // Declarations - https://docs.swift.org/swift-book/ReferenceManual/Declarations.html
- ////////////////////////////////
- global_declaration: ($) =>
- choice(
- $.import_declaration,
- $.property_declaration,
- $.typealias_declaration,
- $.function_declaration,
- $.init_declaration,
- $.class_declaration,
- $.protocol_declaration,
- $.operator_declaration,
- $.precedence_group_declaration,
- $.associatedtype_declaration,
- $.macro_declaration
- ),
- type_level_declaration: ($) =>
- choice(
- $.import_declaration,
- $.property_declaration,
- $.typealias_declaration,
- $.function_declaration,
- $.init_declaration,
- $.class_declaration,
- $.protocol_declaration,
- $.deinit_declaration,
- $.subscript_declaration,
- $.operator_declaration,
- $.precedence_group_declaration,
- $.associatedtype_declaration
- ),
- local_declaration: ($) =>
- choice(
- alias($._local_property_declaration, $.property_declaration),
- alias($._local_typealias_declaration, $.typealias_declaration),
- alias($._local_function_declaration, $.function_declaration),
- alias($._local_class_declaration, $.class_declaration)
- ),
- _local_property_declaration: ($) =>
- seq(
- field("modifiers", optional($._locally_permitted_modifiers)),
- $._modifierless_property_declaration
- ),
- _local_typealias_declaration: ($) =>
- seq(
- field("modifiers", optional($._locally_permitted_modifiers)),
- $._modifierless_typealias_declaration
- ),
- _local_function_declaration: ($) =>
- seq(
- field("modifiers", optional($._locally_permitted_modifiers)),
- $._modifierless_function_declaration
- ),
- _local_class_declaration: ($) =>
- seq(
- field("modifiers", optional($._locally_permitted_modifiers)),
- $._modifierless_class_declaration
- ),
- import_declaration: ($) =>
- seq(
- field("modifiers", optional($.modifiers)),
- "import",
- optional(field("scoped_import_kind", $._import_kind)),
- field("name", $.identifier)
- ),
- _import_kind: ($) =>
- choice(
- "typealias",
- "struct",
- "class",
- "enum",
- "protocol",
- "let",
- "var",
- "func"
- ),
- protocol_property_declaration: ($) =>
- prec.right(
- seq(
- field("modifiers", optional($.modifiers)),
- field("name", alias($._binding_kind_and_pattern, $.pattern)),
- field("type", optional($.type_annotation)),
- field("type_constraints", optional($.type_constraints)),
- field("requirements", $.protocol_property_requirements)
- )
- ),
- protocol_property_requirements: ($) =>
- seq("{", repeat(field("accessor", choice($.getter_specifier, $.setter_specifier))), "}"),
- property_declaration: ($) =>
- seq(field("modifiers", optional($.modifiers)), $._modifierless_property_declaration),
- _modifierless_property_declaration: ($) =>
- prec.right(
- seq(
- $._possibly_async_binding_pattern_kind,
- sep1(field("declarator", $.property_binding), ",")
- )
- ),
- property_binding: ($) =>
- prec.left(
- seq(
- field("name", alias($._no_expr_pattern_already_bound, $.pattern)),
- field("type", optional($.type_annotation)),
- field("type_constraints", optional($.type_constraints)),
- optional(
- choice(
- $._expression_with_willset_didset,
- $._expression_without_willset_didset,
- field("observers", $.willset_didset_block),
- field("computed_value", $.computed_property)
- )
- )
- )
- ),
- _expression_with_willset_didset: ($) =>
- prec.dynamic(
- 1,
- seq(
- $._equal_sign,
- field("value", $.expression),
- field("observers", $.willset_didset_block)
- )
- ),
- _expression_without_willset_didset: ($) =>
- seq($._equal_sign, field("value", $.expression)),
- willset_didset_block: ($) =>
- choice(
- seq("{", field("willset", $.willset_clause), field("didset", optional($.didset_clause)), "}"),
- seq("{", field("didset", $.didset_clause), field("willset", optional($.willset_clause)), "}")
- ),
- willset_clause: ($) =>
- seq(
- field("modifiers", optional($.modifiers)),
- "willSet",
- optional(seq("(", field("parameter", $.simple_identifier), ")")),
- field("body", $.block)
- ),
- didset_clause: ($) =>
- seq(
- field("modifiers", optional($.modifiers)),
- "didSet",
- optional(seq("(", field("parameter", $.simple_identifier), ")")),
- field("body", $.block)
- ),
- typealias_declaration: ($) =>
- seq(field("modifiers", optional($.modifiers)), $._modifierless_typealias_declaration),
- _modifierless_typealias_declaration: ($) =>
- seq(
- "typealias",
- field("name", alias($.simple_identifier, $.type_identifier)),
- field("type_parameters", optional($.type_parameters)),
- $._equal_sign,
- field("value", $.type)
- ),
- function_declaration: ($) =>
- prec.right(
- seq($._bodyless_function_declaration, field("body", $.block))
- ),
- _modifierless_function_declaration: ($) =>
- prec.right(
- seq(
- $._modifierless_function_declaration_no_body,
- field("body", $.block)
- )
- ),
- _bodyless_function_declaration: ($) =>
- seq(
- field("modifiers", optional($.modifiers)),
- optional("class"), // XXX: This should be possible in non-last position, but that creates parsing ambiguity
- $._modifierless_function_declaration_no_body
- ),
- _modifierless_function_declaration_no_body: ($) =>
- prec.right(
- seq(
- $._non_constructor_function_decl,
- field("type_parameters", optional($.type_parameters)),
- $._function_value_parameters,
- field("async", optional($._async_keyword)),
- field("throws", optional(choice($.throws_clause, $.throws))),
- optional(
- seq(
- $._arrow_operator,
- field("return_type", $._possibly_implicitly_unwrapped_type)
- )
- ),
- field("type_constraints", optional($.type_constraints))
- )
- ),
- macro_declaration: ($) =>
- seq(
- $._macro_head,
- field("name", $.simple_identifier),
- field("type_parameters", optional($.type_parameters)),
- $._macro_signature,
- optional(field("definition", $.macro_definition)),
- field("type_constraints", optional($.type_constraints))
- ),
- _macro_head: ($) => seq(field("modifiers", optional($.modifiers)), "macro"),
- _macro_signature: ($) =>
- seq(
- $._function_value_parameters,
- optional(seq($._arrow_operator, field("return_type", $.unannotated_type)))
- ),
- macro_definition: ($) =>
- seq(
- $._equal_sign,
- field("body", choice($.expression, $.external_macro_definition))
- ),
-
- external_macro_definition: ($) =>
- seq($._hash_symbol, "externalMacro", field("arguments", $.value_arguments)),
-
- class_declaration: ($) =>
- seq(field("modifiers", optional($.modifiers)), $._modifierless_class_declaration),
- _modifierless_class_declaration: ($) =>
- prec.right(
- choice(
- seq(
- field("declaration_kind", choice("class", "struct", "actor")),
- field("name", alias($.simple_identifier, $.type_identifier)),
- field("type_parameters", optional($.type_parameters)),
- optional(seq(":", $._inheritance_specifiers)),
- field("type_constraints", optional($.type_constraints)),
- field("body", $.class_body)
- ),
- seq(
- field("declaration_kind", "extension"),
- field("name", $.unannotated_type),
- field("type_parameters", optional($.type_parameters)),
- optional(seq(":", $._inheritance_specifiers)),
- field("type_constraints", optional($.type_constraints)),
- field("body", $.class_body)
- ),
- seq(
- optional("indirect"),
- field("declaration_kind", "enum"),
- field("name", alias($.simple_identifier, $.type_identifier)),
- field("type_parameters", optional($.type_parameters)),
- optional(seq(":", $._inheritance_specifiers)),
- field("type_constraints", optional($.type_constraints)),
- field("body", $.enum_class_body)
- )
- )
- ),
- class_body: ($) => seq("{", optional($._class_member_declarations), "}"),
- _inheritance_specifiers: ($) =>
- prec.left(sep1($._annotated_inheritance_specifier, choice(",", "&"))),
- _annotated_inheritance_specifier: ($) =>
- seq(repeat(field("attribute", $.attribute)), field("inherits", $.inheritance_specifier)),
- inheritance_specifier: ($) =>
- prec.left(
- field(
- "inherits_from",
- choice($.user_type, $.function_type, $.suppressed_constraint)
- )
- ),
- type_parameters: ($) =>
- seq(
- "<",
- sep1Opt(field("parameter", $.type_parameter), ","),
- field("constraints", optional($.type_constraints)),
- ">"
- ),
- type_parameter: ($) =>
- seq(
- field("modifiers", optional($.type_parameter_modifiers)),
- field("name", $._type_parameter_possibly_packed),
- optional(seq(":", field("type", $.type)))
- ),
- _type_parameter_possibly_packed: ($) =>
- choice(
- alias($.simple_identifier, $.type_identifier),
- $.type_parameter_pack
- ),
-
- type_constraints: ($) =>
- prec.right(seq(field("keyword", $.where_keyword), sep1Opt(field("constraint", $.type_constraint), ","))),
- type_constraint: ($) =>
- field("constraint", choice($.inheritance_constraint, $.equality_constraint)),
- inheritance_constraint: ($) =>
- seq(
- repeat(field("attribute", $.attribute)),
- field("constrained_type", $._constrained_type),
- ":",
- field("inherits_from", $._possibly_implicitly_unwrapped_type)
- ),
- equality_constraint: ($) =>
- seq(
- repeat(field("attribute", $.attribute)),
- field("constrained_type", $._constrained_type),
- choice($._equal_sign, $._eq_eq),
- field("must_equal", $.type)
- ),
- _constrained_type: ($) => choice($.identifier, $.nested_type_identifier),
- nested_type_identifier: ($) =>
- seq(
- field("base", $.unannotated_type),
- optional(seq(".", sep1(field("member", $.simple_identifier), ".")))
- ),
- _class_member_separator: ($) => choice($._semi, $._multiline_comment),
- _class_member_declarations: ($) =>
- seq(
- sep1(field("member", $.type_level_declaration), $._class_member_separator),
- optional($._class_member_separator)
- ),
- _function_value_parameters: ($) =>
- repeat1(
- seq("(", optional(sep1Opt(field("parameter", $.function_parameter), ",")), ")")
- ),
- function_parameter: ($) =>
- seq(
- field("attribute", optional($.attribute)),
- field("parameter", $.parameter),
- optional(seq($._equal_sign, field("default_value", $.expression)))
- ),
- parameter: ($) =>
- seq(
- optional(field("external_name", $.simple_identifier)),
- field("name", $.simple_identifier),
- ":",
- field("modifiers", optional($.parameter_modifiers)),
- field("type", $._possibly_implicitly_unwrapped_type),
- optional($._three_dot_operator)
- ),
- _non_constructor_function_decl: ($) =>
- seq(
- "func",
- field("name", choice($.simple_identifier, $.referenceable_operator))
- ),
- referenceable_operator: ($) =>
- field("operator", choice(
- $.custom_operator,
- $._comparison_operator,
- $._additive_operator,
- $._multiplicative_operator,
- $._equality_operator,
- $._assignment_and_operator,
- "++",
- "--",
- $.bang,
- "~",
- "|",
- "^",
- "<<",
- ">>",
- "&"
- )),
- // Hide the fact that certain symbols come from the custom scanner by aliasing them to their
- // string variants. This keeps us from having to see them in the syntax tree (which would be
- // noisy) but allows callers to refer to them as nodes by their text form like with any
- // operator.
- _equal_sign: ($) => alias($._eq_custom, "="),
- _eq_eq: ($) => alias($._eq_eq_custom, "=="),
- _dot: ($) => alias($._dot_custom, "."),
- _arrow_operator: ($) => alias($._arrow_operator_custom, "->"),
- _conjunction_operator: ($) => alias($._conjunction_operator_custom, "&&"),
- _disjunction_operator: ($) => alias($._disjunction_operator_custom, "||"),
- _nil_coalescing_operator: ($) =>
- alias($._nil_coalescing_operator_custom, "??"),
- _as: ($) => alias($._as_custom, "as"),
- _as_quest: ($) => alias($._as_quest_custom, "as?"),
- _as_bang: ($) => alias($._as_bang_custom, "as!"),
- _hash_symbol: ($) => alias($._hash_symbol_custom, "#"),
- bang: ($) => choice($._bang_custom, "!"),
- _async_keyword: ($) => alias($._async_keyword_custom, "async"),
- _async_modifier: ($) => token("async"),
- throws: ($) => choice($._throws_keyword, $._rethrows_keyword),
- throws_clause: ($) =>
- seq($._throws_keyword, "(", field("type", $.unannotated_type), ")"),
- enum_class_body: ($) =>
- seq("{", repeat(field("member", choice($.enum_entry, $.type_level_declaration))), "}"),
- enum_entry: ($) =>
- seq(
- field("modifiers", optional($.modifiers)),
- optional("indirect"),
- "case",
- sep1(field("case", $.enum_case_entry), ","),
- optional(";")
- ),
- enum_case_entry: ($) =>
- seq(
- field("name", $.simple_identifier),
- optional($._enum_entry_suffix)
- ),
- _enum_entry_suffix: ($) =>
- choice(
- field("data_contents", $.enum_type_parameters),
- seq($._equal_sign, field("raw_value", $.expression))
- ),
- enum_type_parameters: ($) =>
- seq(
- "(",
- optional(sep1(field("parameter", $.enum_type_parameter), ",")),
- ")"
- ),
- enum_type_parameter: ($) =>
- seq(
- optional(
- seq(optional(field("external_name", $.wildcard_pattern)), field("name", $.simple_identifier), ":")
- ),
- field("type", $.type),
- optional(seq($._equal_sign, field("default_value", $.expression)))
- ),
- protocol_declaration: ($) =>
- prec.right(
- seq(
- field("modifiers", optional($.modifiers)),
- "protocol",
- field("name", alias($.simple_identifier, $.type_identifier)),
- field("type_parameters", optional($.type_parameters)),
- optional(seq(":", $._inheritance_specifiers)),
- field("type_constraints", optional($.type_constraints)),
- field("body", $.protocol_body)
- )
- ),
- protocol_body: ($) =>
- seq("{", optional($._protocol_member_declarations), "}"),
- _protocol_member_declarations: ($) =>
- seq(sep1(field("member", $.protocol_member_declaration), $._semi), optional($._semi)),
- protocol_member_declaration: ($) =>
- choice(
- $.protocol_function_declaration,
- $.init_declaration,
- $.deinit_declaration,
- $.protocol_property_declaration,
- $.typealias_declaration,
- $.associatedtype_declaration,
- $.subscript_declaration
- ),
- protocol_function_declaration: ($) =>
- seq(
- $._bodyless_function_declaration,
- optional(field("body", $.block))
- ),
- init_declaration: ($) =>
- prec.right(
- seq(
- field("modifiers", optional($.modifiers)),
- optional("class"),
- "init",
- optional(choice($._quest, field("bang", $.bang))),
- field("type_parameters", optional($.type_parameters)),
- $._function_value_parameters,
- field("async", optional($._async_keyword)),
- field("throws", optional(choice($.throws_clause, $.throws))),
- field("type_constraints", optional($.type_constraints)),
- optional(field("body", $.block))
- )
- ),
- deinit_declaration: ($) =>
- prec.right(
- seq(field("modifiers", optional($.modifiers)), "deinit", field("body", $.block))
- ),
- subscript_declaration: ($) =>
- prec.right(
- seq(
- field("modifiers", optional($.modifiers)),
- "subscript",
- field("type_parameters", optional($.type_parameters)),
- $._function_value_parameters,
- optional(
- seq(
- $._arrow_operator,
- field("return_type", $._possibly_implicitly_unwrapped_type)
- )
- ),
- field("type_constraints", optional($.type_constraints)),
- field("body", $.computed_property)
- )
- ),
- computed_property: ($) =>
- seq(
- "{",
- choice(
- optional($._statements),
- repeat(
- field("accessor", choice($.computed_getter, $.computed_setter, $.computed_modify))
- )
- ),
- "}"
- ),
- computed_getter: ($) =>
- seq(repeat(field("attribute", $.attribute)), field("specifier", $.getter_specifier), optional(field("body", $.block))),
- computed_modify: ($) =>
- seq(repeat(field("attribute", $.attribute)), field("specifier", $.modify_specifier), optional(field("body", $.block))),
- computed_setter: ($) =>
- seq(
- repeat(field("attribute", $.attribute)),
- field("specifier", $.setter_specifier),
- optional(seq("(", field("parameter", $.simple_identifier), ")")),
- optional(field("body", $.block))
- ),
- getter_specifier: ($) =>
- seq(field("mutation", optional($.mutation_modifier)), "get", optional($._getter_effects)),
- setter_specifier: ($) => seq(field("mutation", optional($.mutation_modifier)), "set"),
- modify_specifier: ($) => seq(field("mutation", optional($.mutation_modifier)), "_modify"),
- _getter_effects: ($) =>
- repeat1(field("effect", choice(alias($._async_keyword, $.async_keyword), $.throws_clause, $.throws))),
- operator_declaration: ($) =>
- seq(
- field("kind", choice("prefix", "infix", "postfix")),
- "operator",
- field("name", $.referenceable_operator),
- optional(seq(":", field("precedence_group", $.simple_identifier))),
- field("body", optional($.deprecated_operator_declaration_body))
- ),
- // The Swift compiler no longer accepts these, but some very old code still uses it.
- deprecated_operator_declaration_body: ($) =>
- seq("{", repeat(field("entry", choice($.simple_identifier, $._basic_literal))), "}"),
- precedence_group_declaration: ($) =>
- seq(
- "precedencegroup",
- field("name", $.simple_identifier),
- "{",
- field("attributes", optional($.precedence_group_attributes)),
- "}"
- ),
- precedence_group_attributes: ($) => repeat1(field("attribute", $.precedence_group_attribute)),
- precedence_group_attribute: ($) =>
- seq(
- field("name", $.simple_identifier),
- ":",
- field("value", choice($.simple_identifier, $.boolean_literal))
- ),
- associatedtype_declaration: ($) =>
- seq(
- field("modifiers", optional($.modifiers)),
- "associatedtype",
- field("name", alias($.simple_identifier, $.type_identifier)),
- optional(seq(":", field("must_inherit", $.type))),
- field("type_constraints", optional($.type_constraints)),
- optional(seq($._equal_sign, field("default_value", $.type)))
- ),
- ////////////////////////////////
- // Attributes - https://docs.swift.org/swift-book/ReferenceManual/Attributes.html
- ////////////////////////////////
- attribute: ($) =>
- seq(
- "@",
- field("name", $.user_type),
- // attribute arguments are a mess of special cases, maybe this is good enough?
- optional(seq("(", sep1Opt($._attribute_argument, ","), ")"))
- ),
- _attribute_argument: ($) =>
- choice(
- // labeled function parameters, used in custom property wrappers
- seq(field("argument_name", $.simple_identifier), ":", field("argument", $.expression)),
- // Unlabeled function parameters, simple identifiers, or `*`
- field("argument", $.expression),
- // References to param names (used in `@objc(foo:bar:)`)
- repeat1(seq(field("param_ref", $.simple_identifier), ":")),
- // Version restrictions (iOS 3.4.5, Swift 5.0.0)
- seq(repeat1(field("platform", $.simple_identifier)), sep1(field("version", $.integer_literal), "."))
- ),
- ////////////////////////////////
- // Patterns - https://docs.swift.org/swift-book/ReferenceManual/Patterns.html
- ////////////////////////////////
- _universally_allowed_pattern: ($) =>
- choice(
- $.wildcard_pattern,
- $.tuple_pattern,
- $.type_casting_pattern,
- $.case_pattern
- ),
- _bound_identifier: ($) => field("bound_identifier", $.simple_identifier),
-
- _binding_pattern_no_expr: ($) =>
- seq(
- field("kind", choice(
- $._universally_allowed_pattern,
- $.binding_pattern,
- $._bound_identifier
- )),
- optional($._quest)
- ),
- _no_expr_pattern_already_bound: ($) =>
- seq(
- field("kind", choice($._universally_allowed_pattern, $._bound_identifier)),
- optional($._quest)
- ),
- _binding_pattern_with_expr: ($) =>
- seq(
- field("kind", choice(
- $._universally_allowed_pattern,
- $.binding_pattern,
- $.expression
- )),
- optional($._quest)
- ),
- _non_binding_pattern_with_expr: ($) =>
- seq(
- field("kind", choice($._universally_allowed_pattern, $.expression)),
- optional($._quest)
- ),
- _direct_or_indirect_binding: ($) =>
- seq(
- choice(
- field("pattern", alias($._binding_kind_and_pattern, $.pattern)),
- seq("case", field("pattern", alias($._binding_pattern_no_expr, $.pattern)))
- ),
- field("type", optional($.type_annotation))
- ),
- value_binding_pattern: ($) => field("mutability", choice("var", "let")),
- _possibly_async_binding_pattern_kind: ($) =>
- seq(optional($._async_modifier), field("binding", $.value_binding_pattern)),
- _binding_kind_and_pattern: ($) =>
- seq(
- $._possibly_async_binding_pattern_kind,
- $._no_expr_pattern_already_bound
- ),
- wildcard_pattern: ($) => "_",
- tuple_pattern_item: ($) =>
- choice(
- seq(
- field("name", $.simple_identifier),
- ":",
- field("pattern", alias($._binding_pattern_with_expr, $.pattern))
- ),
- field("pattern", alias($._binding_pattern_with_expr, $.pattern))
- ),
- tuple_pattern: ($) => seq("(", sep1Opt(field("item", $.tuple_pattern_item), ","), ")"),
- case_pattern: ($) =>
- seq(
- optional("case"),
- optional(field("type", $.user_type)), // XXX this should just be _type but that creates ambiguity
- field("dot", $._dot),
- field("name", $.simple_identifier),
- optional(field("arguments", $.tuple_pattern))
- ),
- type_casting_pattern: ($) =>
- choice(
- seq("is", field("type", $.type)),
- seq(field("pattern", alias($._binding_pattern_no_expr, $.pattern)), $._as, field("type", $.type))
- ),
- binding_pattern: ($) =>
- seq(
- seq(optional("case"), field("binding", $.value_binding_pattern)),
- field("pattern", alias($._no_expr_pattern_already_bound, $.pattern))
- ),
-
- // ==========
- // Modifiers
- // ==========
- modifiers: ($) =>
- repeat1(
- prec.left(
- field("modifier", choice($._non_local_scope_modifier, $._locally_permitted_modifiers))
- )
- ),
- _locally_permitted_modifiers: ($) =>
- repeat1(choice($.attribute, $._locally_permitted_modifier)),
- parameter_modifiers: ($) => repeat1(field("modifier", $.parameter_modifier)),
- _modifier: ($) =>
- choice($._non_local_scope_modifier, $._locally_permitted_modifier),
- _non_local_scope_modifier: ($) =>
- choice(
- $.member_modifier,
- $.visibility_modifier,
- $.function_modifier,
- $.mutation_modifier,
- $.property_modifier,
- $.parameter_modifier
- ),
- _locally_permitted_modifier: ($) =>
- choice(
- $.ownership_modifier,
- $.inheritance_modifier,
- $.property_behavior_modifier
- ),
- property_behavior_modifier: ($) => "lazy",
- type_modifiers: ($) => repeat1(field("attribute", $.attribute)),
- member_modifier: ($) =>
- choice("override", "convenience", "required", "nonisolated"),
- visibility_modifier: ($) =>
- seq(
- choice(
- "public",
- "private",
- "internal",
- "fileprivate",
- "open",
- "package"
- ),
- optional(seq("(", "set", ")"))
- ),
- type_parameter_modifiers: ($) => repeat1(field("attribute", $.attribute)),
- function_modifier: ($) => choice("infix", "postfix", "prefix"),
- mutation_modifier: ($) => choice("mutating", "nonmutating"),
- property_modifier: ($) =>
- choice("static", "dynamic", "optional", "class", "distributed"),
- inheritance_modifier: ($) => choice("final"),
- parameter_modifier: ($) =>
- choice(
- "inout",
- "@escaping",
- "@autoclosure",
- $._parameter_ownership_modifier
- ),
- ownership_modifier: ($) =>
- choice("weak", "unowned", "unowned(safe)", "unowned(unsafe)"),
- _parameter_ownership_modifier: ($) => choice("borrowing", "consuming"),
- use_site_target: ($) =>
- seq(
- choice(
- "property",
- "get",
- "set",
- "receiver",
- "param",
- "setparam",
- "delegate"
- ),
- ":"
- ),
- directive: ($) =>
- prec.right(
- PRECS.comment,
- choice(
- seq(alias($._directive_if, "#if"), field("condition", $.compilation_condition)),
- seq(alias($._directive_elseif, "#elseif"), field("condition", $.compilation_condition)),
- seq(alias($._directive_else, "#else")),
- seq(alias($._directive_endif, "#endif"))
- )
- ),
- compilation_condition: ($) =>
- prec.right(
- choice(
- seq("os", "(", field("name", $.simple_identifier), ")"),
- seq("arch", "(", field("name", $.simple_identifier), ")"),
- seq(
- "swift",
- "(",
- $._comparison_operator,
- sep1(field("version", $.integer_literal), "."),
- ")"
- ),
- seq(
- "compiler",
- "(",
- $._comparison_operator,
- sep1(field("version", $.integer_literal), "."),
- ")"
- ),
- seq("canImport", "(", sep1(field("name", $.simple_identifier), "."), ")"),
- seq("targetEnvironment", "(", field("name", $.simple_identifier), ")"),
- field("value", $.boolean_literal),
- field("name", $.simple_identifier),
- seq("(", field("inner", $.compilation_condition), ")"),
- seq("!", field("operand", $.compilation_condition)),
- seq(
- field("lhs", $.compilation_condition),
- $._conjunction_operator,
- field("rhs", $.compilation_condition)
- ),
- seq(
- field("lhs", $.compilation_condition),
- $._disjunction_operator,
- field("rhs", $.compilation_condition)
- )
- )
- ),
- diagnostic: ($) =>
- prec(
- PRECS.comment,
- seq(
- $._hash_symbol,
- choice(
- // Using regexes here, rather than actually validating the string literal, because complex string literals
- // cannot be used inside `token()` and we need that to ensure we get the right precedence.
- seq(/error([^\r\n]*)/),
- seq(/warning([^\r\n]*)/),
- seq(/sourceLocation([^\r\n]*)/)
- )
- )
- ),
- // Dumping ground for any nodes that used to exist in the grammar, but have since been removed for whatever
- // reason.
- // Neovim applies updates non-atomically to the parser and the queries. Meanwhile, `tree-sitter` rejects any query
- // that contains any unrecognized nodes. Putting those two facts together, we see that we must never remove nodes
- // that once existed.
- unused_for_backward_compatibility: ($) =>
- choice(alias("unused1", "try?"), alias("unused2", "try!")),
- },
-});
-function sep1(rule, separator) {
- return seq(rule, repeat(seq(separator, rule)));
-}
-function sep1Opt(rule, separator) {
- return seq(rule, repeat(seq(separator, rule)), optional(separator));
-}
-
-function tree_sitter_version_supports_emoji() {
- try {
- return (
- TREE_SITTER_CLI_VERSION_MAJOR > 0 ||
- TREE_SITTER_CLI_VERSION_MINOR > 20 ||
- TREE_SITTER_CLI_VERSION_PATCH >= 5
- );
- } catch (err) {
- if (err instanceof ReferenceError) {
- return false;
- } else {
- throw err;
- }
- }
-}
diff --git a/unified/extractor/tree-sitter-swift/node-types.yml b/unified/extractor/tree-sitter-swift/node-types.yml
deleted file mode 100644
index 35dfb985b4a..00000000000
--- a/unified/extractor/tree-sitter-swift/node-types.yml
+++ /dev/null
@@ -1,875 +0,0 @@
-supertypes:
- expression:
- - additive_expression
- - array_literal
- - as_expression
- - assignment
- - await_expression
- - bin_literal
- - bitwise_operation
- - boolean_literal
- - call_expression
- - check_expression
- - comparison_expression
- - conjunction_expression
- - constructor_expression
- - diagnostic
- - dictionary_literal
- - directive
- - disjunction_expression
- - equality_expression
- - fully_open_range
- - hex_literal
- - if_statement
- - infix_expression
- - integer_literal
- - key_path_expression
- - key_path_string_expression
- - lambda_literal
- - line_string_literal
- - macro_invocation
- - multi_line_string_literal
- - multiplicative_expression
- - navigation_expression
- - "nil"
- - nil_coalescing_expression
- - oct_literal
- - open_end_range_expression
- - open_start_range_expression
- - optional_chain_marker
- - playground_literal
- - postfix_expression
- - prefix_expression
- - range_expression
- - raw_string_literal
- - real_literal
- - referenceable_operator
- - regex_literal
- - selector_expression
- - self_expression
- - simple_identifier
- - special_literal
- - super_expression
- - switch_statement
- - ternary_expression
- - try_expression
- - tuple_expression
- - value_pack_expansion
- - value_parameter_pack
- global_declaration:
- - associatedtype_declaration
- - class_declaration
- - function_declaration
- - import_declaration
- - init_declaration
- - macro_declaration
- - operator_declaration
- - precedence_group_declaration
- - property_declaration
- - protocol_declaration
- - typealias_declaration
- local_declaration:
- - class_declaration
- - function_declaration
- - property_declaration
- - typealias_declaration
- protocol_member_declaration:
- - associatedtype_declaration
- - deinit_declaration
- - init_declaration
- - protocol_function_declaration
- - protocol_property_declaration
- - subscript_declaration
- - typealias_declaration
- type_level_declaration:
- - associatedtype_declaration
- - class_declaration
- - deinit_declaration
- - function_declaration
- - import_declaration
- - init_declaration
- - operator_declaration
- - precedence_group_declaration
- - property_declaration
- - protocol_declaration
- - subscript_declaration
- - typealias_declaration
- unannotated_type:
- - array_type
- - dictionary_type
- - existential_type
- - function_type
- - metatype
- - opaque_type
- - optional_type
- - protocol_composition_type
- - suppressed_constraint
- - tuple_type
- - type_pack_expansion
- - type_parameter_pack
- - user_type
-
-named:
- additive_expression:
- lhs: expression
- op: ["+", "-"]
- rhs: expression
- array_literal:
- element*: expression
- array_type:
- element: type
- as_expression:
- expr: expression
- operator: as_operator
- type: type
- as_operator:
- assignment:
- operator: ["%=", "*=", "+=", "-=", "/=", "="]
- result: expression
- target: directly_assignable_expression
- associatedtype_declaration:
- default_value?: type
- modifiers?: modifiers
- must_inherit?: type
- name: type_identifier
- type_constraints?: type_constraints
- async_keyword:
- attribute:
- argument*: expression
- argument_name*: simple_identifier
- name: user_type
- param_ref*: simple_identifier
- platform*: simple_identifier
- version*: integer_literal
- availability_condition:
- platform*: identifier
- version*: integer_literal
- await_expression:
- expr: expression
- bang:
- bin_literal:
- binding_pattern:
- binding: value_binding_pattern
- pattern: pattern
- bitwise_operation:
- lhs: expression
- op: ["&", "<<", ">>", "^", "|"]
- rhs: expression
- block:
- statement*: [control_transfer_statement, do_statement, expression, for_statement, guard_statement, local_declaration, repeat_while_statement, statement_label, while_statement]
- boolean_literal:
- call_expression:
- function: expression
- suffix: call_suffix
- call_suffix:
- arguments?: value_arguments
- lambda*: lambda_literal
- name*: simple_identifier
- capture_list:
- item+: capture_list_item
- capture_list_item:
- name: [self_expression, simple_identifier]
- ownership?: ownership_modifier
- value?: expression
- case_pattern:
- arguments?: tuple_pattern
- dot: "."
- name: simple_identifier
- type?: user_type
- catch_block:
- body: block
- error?: pattern
- keyword: catch_keyword
- where?: where_clause
- catch_keyword:
- check_expression:
- op: "is"
- target: expression
- type: type
- class_body:
- member*: type_level_declaration
- class_declaration:
- attribute*: attribute
- body: [class_body, enum_class_body]
- declaration_kind: ["actor", "class", "enum", "extension", "struct"]
- inherits*: inheritance_specifier
- modifiers*: [attribute, inheritance_modifier, modifiers, ownership_modifier, property_behavior_modifier]
- name: [type_identifier, unannotated_type]
- type_constraints?: type_constraints
- type_parameters?: type_parameters
- comment:
- comparison_expression:
- lhs: expression
- op: ["<", "<=", ">", ">="]
- rhs: expression
- compilation_condition:
- inner?: compilation_condition
- lhs?: compilation_condition
- name*: simple_identifier
- operand?: compilation_condition
- rhs?: compilation_condition
- value?: boolean_literal
- version*: integer_literal
- computed_getter:
- attribute*: attribute
- body?: block
- specifier: getter_specifier
- computed_modify:
- attribute*: attribute
- body?: block
- specifier: modify_specifier
- computed_property:
- accessor*: [computed_getter, computed_modify, computed_setter]
- statement*: [control_transfer_statement, do_statement, expression, for_statement, guard_statement, local_declaration, repeat_while_statement, statement_label, while_statement]
- computed_setter:
- attribute*: attribute
- body?: block
- parameter?: simple_identifier
- specifier: setter_specifier
- conjunction_expression:
- lhs: expression
- op: "&&"
- rhs: expression
- constructor_expression:
- constructed_type: [array_type, dictionary_type, user_type]
- suffix: constructor_suffix
- constructor_suffix:
- arguments?: value_arguments
- lambda*: lambda_literal
- name*: simple_identifier
- control_transfer_statement:
- kind: ["break", "continue", "return", throw_keyword, "yield"]
- result?: expression
- custom_operator:
- default_keyword:
- deinit_declaration:
- body: block
- modifiers?: modifiers
- deprecated_operator_declaration_body:
- entry*: [bin_literal, boolean_literal, hex_literal, integer_literal, line_string_literal, multi_line_string_literal, "nil", oct_literal, raw_string_literal, real_literal, regex_literal, simple_identifier]
- diagnostic:
- dictionary_literal:
- element*: dictionary_literal_item
- dictionary_literal_item:
- key: expression
- value: expression
- dictionary_type:
- key: type
- value: type
- didset_clause:
- body: block
- modifiers?: modifiers
- parameter?: simple_identifier
- directive:
- condition?: compilation_condition
- directly_assignable_expression:
- expr: expression
- disjunction_expression:
- lhs: expression
- op: "||"
- rhs: expression
- do_statement:
- body: block
- catch*: catch_block
- enum_case_entry:
- data_contents?: enum_type_parameters
- name: simple_identifier
- raw_value?: expression
- enum_class_body:
- member*: [enum_entry, type_level_declaration]
- enum_entry:
- case+: enum_case_entry
- modifiers?: modifiers
- enum_type_parameter:
- default_value?: expression
- external_name?: wildcard_pattern
- name?: simple_identifier
- type: type
- enum_type_parameters:
- parameter*: enum_type_parameter
- equality_constraint:
- attribute*: attribute
- constrained_type: [identifier, nested_type_identifier]
- must_equal: type
- equality_expression:
- lhs: expression
- op: ["!=", "!==", "==", "==="]
- rhs: expression
- existential_type:
- name: unannotated_type
- external_macro_definition:
- arguments: value_arguments
- for_statement:
- body: block
- collection: expression
- item: pattern
- try?: try_operator
- type?: type_annotation
- where?: where_clause
- fully_open_range:
- function_declaration:
- async?: "async"
- body: block
- modifiers*: [attribute, inheritance_modifier, modifiers, ownership_modifier, property_behavior_modifier]
- name: [referenceable_operator, simple_identifier]
- parameter*: function_parameter
- return_type?: [implicitly_unwrapped_type, type]
- throws?: [throws, throws_clause]
- type_constraints?: type_constraints
- type_parameters?: type_parameters
- function_modifier:
- function_parameter:
- attribute?: attribute
- default_value?: expression
- parameter: parameter
- function_type:
- async?: "async"
- params: unannotated_type
- return_type: type
- throws?: [throws, throws_clause]
- getter_specifier:
- effect*: [async_keyword, throws, throws_clause]
- mutation?: mutation_modifier
- guard_statement:
- body: block
- condition+: if_condition
- hex_literal:
- identifier:
- part+: simple_identifier
- if_condition:
- kind: [availability_condition, expression, if_let_binding]
- if_let_binding:
- pattern: pattern
- type?: type_annotation
- value?: expression
- where?: where_clause
- if_statement:
- body: block
- condition+: if_condition
- else_branch?: [block, if_statement]
- implicitly_unwrapped_type:
- name: type
- import_declaration:
- modifiers?: modifiers
- name: identifier
- scoped_import_kind?: ["class", "enum", "func", "let", "protocol", "struct", "typealias", "var"]
- infix_expression:
- lhs: expression
- op: custom_operator
- rhs: expression
- inheritance_constraint:
- attribute*: attribute
- constrained_type: [identifier, nested_type_identifier]
- inherits_from: [implicitly_unwrapped_type, type]
- inheritance_modifier:
- inheritance_specifier:
- inherits_from: [function_type, suppressed_constraint, user_type]
- init_declaration:
- async?: "async"
- bang?: bang
- body?: block
- modifiers?: modifiers
- parameter*: function_parameter
- throws?: [throws, throws_clause]
- type_constraints?: type_constraints
- type_parameters?: type_parameters
- integer_literal:
- interpolated_expression:
- name?: value_argument_label
- reference_specifier*: value_argument_label
- type_modifiers?: type_modifiers
- value?: expression
- key_path_component:
- name?: simple_identifier
- postfix*: key_path_postfix
- key_path_expression:
- component*: key_path_component
- type?: [array_type, dictionary_type, simple_user_type]
- key_path_postfix:
- argument*: value_argument
- force_unwrap?: bang
- key_path_string_expression:
- expr: expression
- lambda_function_type:
- async?: "async"
- params?: lambda_function_type_parameters
- return_type?: [implicitly_unwrapped_type, type]
- throws?: [throws, throws_clause]
- lambda_function_type_parameters:
- parameter+: lambda_parameter
- lambda_literal:
- attribute*: attribute
- captures?: capture_list
- statement*: [control_transfer_statement, do_statement, expression, for_statement, guard_statement, local_declaration, repeat_while_statement, statement_label, while_statement]
- type?: lambda_function_type
- lambda_parameter:
- external_name?: simple_identifier
- modifiers?: parameter_modifiers
- name: [self_expression, simple_identifier]
- type?: [implicitly_unwrapped_type, type]
- line_str_text:
- line_string_literal:
- interpolation*: interpolated_expression
- text*: [line_str_text, str_escaped_char]
- macro_declaration:
- definition?: macro_definition
- modifiers?: modifiers
- name: simple_identifier
- parameter*: function_parameter
- return_type?: unannotated_type
- type_constraints?: type_constraints
- type_parameters?: type_parameters
- macro_definition:
- body: [expression, external_macro_definition]
- macro_invocation:
- name: simple_identifier
- suffix: call_suffix
- type_parameters?: type_parameters
- member_modifier:
- metatype:
- name: unannotated_type
- modifiers:
- modifier+: [attribute, function_modifier, inheritance_modifier, member_modifier, mutation_modifier, ownership_modifier, parameter_modifier, property_behavior_modifier, property_modifier, visibility_modifier]
- modify_specifier:
- mutation?: mutation_modifier
- multi_line_str_text:
- multi_line_string_literal:
- interpolation*: interpolated_expression
- text*: ["\"", multi_line_str_text, str_escaped_char]
- multiline_comment:
- multiplicative_expression:
- lhs: expression
- op: ["%", "*", "/"]
- rhs: expression
- mutation_modifier:
- navigation_expression:
- suffix: navigation_suffix
- target: [array_type, dictionary_type, expression, parenthesized_type, user_type]
- navigation_suffix:
- suffix: [integer_literal, simple_identifier]
- nested_type_identifier:
- base: unannotated_type
- member*: simple_identifier
- nil_coalescing_expression:
- if_nil: expression
- value: expression
- oct_literal:
- opaque_type:
- name: unannotated_type
- open_end_range_expression:
- start: expression
- open_start_range_expression:
- end: expression
- operator_declaration:
- body?: deprecated_operator_declaration_body
- kind: ["infix", "postfix", "prefix"]
- name: referenceable_operator
- precedence_group?: simple_identifier
- optional_chain_marker:
- expr: expression
- optional_type:
- wrapped: [array_type, dictionary_type, tuple_type, user_type]
- ownership_modifier:
- parameter:
- external_name?: simple_identifier
- modifiers?: parameter_modifiers
- name: simple_identifier
- type: [implicitly_unwrapped_type, type]
- parameter_modifier:
- parameter_modifiers:
- modifier+: parameter_modifier
- parenthesized_type:
- type: [dictionary_type, existential_type, opaque_type]
- pattern:
- binding?: value_binding_pattern
- bound_identifier?: simple_identifier
- kind: [binding_pattern, case_pattern, expression, tuple_pattern, type_casting_pattern, wildcard_pattern]
- playground_literal:
- argument+: playground_literal_argument
- kind: ["colorLiteral", "fileLiteral", "imageLiteral"]
- playground_literal_argument:
- name: simple_identifier
- value: expression
- postfix_expression:
- operation: ["++", "--", bang]
- target: expression
- precedence_group_attribute:
- name: simple_identifier
- value: [boolean_literal, simple_identifier]
- precedence_group_attributes:
- attribute+: precedence_group_attribute
- precedence_group_declaration:
- attributes?: precedence_group_attributes
- name: simple_identifier
- prefix_expression:
- operation: ["&", "+", "++", "-", "--", ".", bang, custom_operator, "~"]
- target: expression
- property_behavior_modifier:
- property_binding:
- computed_value?: computed_property
- name: pattern
- observers?: willset_didset_block
- type?: type_annotation
- type_constraints?: type_constraints
- value?: expression
- property_declaration:
- binding: value_binding_pattern
- declarator+: property_binding
- modifiers*: [attribute, inheritance_modifier, modifiers, ownership_modifier, property_behavior_modifier]
- property_modifier:
- protocol_body:
- member*: protocol_member_declaration
- protocol_composition_type:
- type+: unannotated_type
- protocol_declaration:
- attribute*: attribute
- body: protocol_body
- inherits*: inheritance_specifier
- modifiers?: modifiers
- name: type_identifier
- type_constraints?: type_constraints
- type_parameters?: type_parameters
- protocol_function_declaration:
- async?: "async"
- body?: block
- modifiers?: modifiers
- name: [referenceable_operator, simple_identifier]
- parameter*: function_parameter
- return_type?: [implicitly_unwrapped_type, type]
- throws?: [throws, throws_clause]
- type_constraints?: type_constraints
- type_parameters?: type_parameters
- protocol_property_declaration:
- modifiers?: modifiers
- name: pattern
- requirements: protocol_property_requirements
- type?: type_annotation
- type_constraints?: type_constraints
- protocol_property_requirements:
- accessor*: [getter_specifier, setter_specifier]
- range_expression:
- end: expression
- op: ["...", "..<"]
- start: expression
- raw_str_continuing_indicator:
- raw_str_end_part:
- raw_str_interpolation:
- interpolation+: interpolated_expression
- start: raw_str_interpolation_start
- raw_str_interpolation_start:
- raw_str_part:
- raw_string_literal:
- continuing*: raw_str_continuing_indicator
- interpolation*: raw_str_interpolation
- text+: [raw_str_end_part, raw_str_part]
- real_literal:
- referenceable_operator:
- operator: ["!=", "!==", "%", "%=", "&", "*", "*=", "+", "++", "+=", "-", "--", "-=", "/", "/=", "<", "<<", "<=", "=", "==", "===", ">", ">=", ">>", "^", bang, custom_operator, "|", "~"]
- regex_literal:
- repeat_while_statement:
- body: block
- condition+: if_condition
- selector_expression:
- expr: expression
- self_expression:
- setter_specifier:
- mutation?: mutation_modifier
- shebang_line:
- simple_identifier:
- simple_user_type:
- arguments?: type_arguments
- name: type_identifier
- source_file:
- shebang?: shebang_line
- statement*: [do_statement, expression, for_statement, global_declaration, guard_statement, repeat_while_statement, statement_label, throw_keyword, while_statement]
- special_literal:
- statement_label:
- str_escaped_char:
- subscript_declaration:
- body: computed_property
- modifiers?: modifiers
- parameter*: function_parameter
- return_type?: [implicitly_unwrapped_type, type]
- type_constraints?: type_constraints
- type_parameters?: type_parameters
- super_expression:
- suppressed_constraint:
- suppressed: type_identifier
- switch_entry:
- default?: default_keyword
- modifiers?: modifiers
- pattern*: switch_pattern
- statement+: [control_transfer_statement, do_statement, expression, for_statement, guard_statement, local_declaration, repeat_while_statement, statement_label, while_statement]
- where?: where_clause
- switch_pattern:
- pattern: pattern
- switch_statement:
- entry*: switch_entry
- expr: expression
- ternary_expression:
- condition: expression
- if_false: expression
- if_true: expression
- throw_keyword:
- throws:
- throws_clause:
- type: unannotated_type
- try_expression:
- expr: expression
- operator: try_operator
- try_operator:
- tuple_expression:
- element+: tuple_expression_item
- tuple_expression_item:
- name?: simple_identifier
- value: expression
- tuple_pattern:
- item+: tuple_pattern_item
- tuple_pattern_item:
- name?: simple_identifier
- pattern: pattern
- tuple_type:
- element*: tuple_type_item
- tuple_type_item:
- external_name?: wildcard_pattern
- modifiers?: parameter_modifiers
- name?: simple_identifier
- type: [dictionary_type, existential_type, opaque_type, type]
- type:
- modifiers?: type_modifiers
- name: unannotated_type
- type_annotation:
- type: [implicitly_unwrapped_type, type]
- type_arguments:
- argument+: type
- type_casting_pattern:
- pattern?: pattern
- type: type
- type_constraint:
- constraint: [equality_constraint, inheritance_constraint]
- type_constraints:
- constraint+: type_constraint
- keyword: where_keyword
- type_identifier:
- type_modifiers:
- attribute+: attribute
- type_pack_expansion:
- name: unannotated_type
- type_parameter:
- modifiers?: type_parameter_modifiers
- name: [type_identifier, type_parameter_pack]
- type?: type
- type_parameter_modifiers:
- attribute+: attribute
- type_parameter_pack:
- name: unannotated_type
- type_parameters:
- constraints?: type_constraints
- parameter+: type_parameter
- typealias_declaration:
- modifiers*: [attribute, inheritance_modifier, modifiers, ownership_modifier, property_behavior_modifier]
- name: type_identifier
- type_parameters?: type_parameters
- value: type
- user_type:
- part+: simple_user_type
- value_argument:
- name?: value_argument_label
- reference_specifier*: value_argument_label
- type_modifiers?: type_modifiers
- value?: expression
- value_argument_label:
- name: simple_identifier
- value_arguments:
- argument*: value_argument
- value_binding_pattern:
- mutability: ["let", "var"]
- value_pack_expansion:
- expr: expression
- value_parameter_pack:
- expr: expression
- visibility_modifier:
- where_clause:
- expr: expression
- keyword: where_keyword
- where_keyword:
- while_statement:
- body: block
- condition+: if_condition
- wildcard_pattern:
- willset_clause:
- body: block
- modifiers?: modifiers
- parameter?: simple_identifier
- willset_didset_block:
- didset?: didset_clause
- willset?: willset_clause
-
-unnamed:
- - "?"
- - "!"
- - "!="
- - "!=="
- - "\""
- - "\"\"\""
- - "#"
- - "#else"
- - "#elseif"
- - "#endif"
- - "#if"
- - "%"
- - "%="
- - "&"
- - "&&"
- - "("
- - ")"
- - "*"
- - "*="
- - "+"
- - "++"
- - "+="
- - ","
- - "-"
- - "--"
- - "-="
- - "->"
- - "."
- - "..."
- - "..<"
- - "/"
- - "/="
- - ":"
- - ";"
- - "<"
- - "<<"
- - "<="
- - "="
- - "=="
- - "==="
- - ">"
- - ">="
- - ">>"
- - "?"
- - "??"
- - "@"
- - "@autoclosure"
- - "@escaping"
- - "Protocol"
- - "Type"
- - "["
- - "\\"
- - "\\("
- - "]"
- - "^"
- - "^{"
- - "_modify"
- - "actor"
- - "any"
- - "arch"
- - "as"
- - "as!"
- - "as?"
- - "associatedtype"
- - "async"
- - "available"
- - "await"
- - "borrowing"
- - "break"
- - "canImport"
- - "case"
- - "class"
- - "colorLiteral"
- - "column"
- - "compiler"
- - "consuming"
- - "continue"
- - "convenience"
- - "deinit"
- - "didSet"
- - "distributed"
- - "do"
- - "dsohandle"
- - "dynamic"
- - "each"
- - "else"
- - "enum"
- - "extension"
- - "externalMacro"
- - "fallthrough"
- - "false"
- - "file"
- - "fileID"
- - "fileLiteral"
- - "filePath"
- - "fileprivate"
- - "final"
- - "for"
- - "func"
- - "function"
- - "get"
- - "getter:"
- - "guard"
- - "if"
- - "imageLiteral"
- - "import"
- - "in"
- - "indirect"
- - "infix"
- - "init"
- - "inout"
- - "internal"
- - "is"
- - "keyPath"
- - "lazy"
- - "let"
- - "line"
- - "macro"
- - "mutating"
- - "nil"
- - "nonisolated"
- - "nonmutating"
- - "open"
- - "operator"
- - "optional"
- - "os"
- - "override"
- - "package"
- - "postfix"
- - "precedencegroup"
- - "prefix"
- - "private"
- - "protocol"
- - "public"
- - "repeat"
- - "required"
- - "return"
- - "selector"
- - "self"
- - "set"
- - "setter:"
- - "some"
- - "static"
- - "struct"
- - "subscript"
- - "super"
- - "swift"
- - "switch"
- - "targetEnvironment"
- - "true"
- - "try"
- - "typealias"
- - "u"
- - "unavailable"
- - "unowned"
- - "unowned(safe)"
- - "unowned(unsafe)"
- - "var"
- - "weak"
- - "while"
- - "willSet"
- - "yield"
- - "{"
- - "|"
- - "||"
- - "}"
- - "~"
diff --git a/unified/extractor/tree-sitter-swift/package.json b/unified/extractor/tree-sitter-swift/package.json
deleted file mode 100644
index 68dcf7cc42f..00000000000
--- a/unified/extractor/tree-sitter-swift/package.json
+++ /dev/null
@@ -1,68 +0,0 @@
-{
- "name": "tree-sitter-swift",
- "version": "0.7.2",
- "description": "A tree-sitter grammar for the Swift programming language.",
- "main": "bindings/node/index.js",
- "types": "bindings/node",
- "scripts": {
- "install": "node-gyp-build",
- "prestart": "tree-sitter build --wasm",
- "start": "tree-sitter playground",
- "test": "node --test bindings/node/*_test.js"
- },
- "repository": {
- "type": "git",
- "url": "git+https://github.com/alex-pinkus/tree-sitter-swift.git"
- },
- "tree-sitter": [
- {
- "scope": "source.swift",
- "file-types": [
- "swift"
- ],
- "injection-regex": "swift",
- "highlights": "queries/highlights.scm",
- "locals": "queries/locals.scm",
- "injections": "queries/injections.scm"
- }
- ],
- "keywords": [
- "parser",
- "swift"
- ],
- "files": [
- "grammar.js",
- "tree-sitter.json",
- "binding.gyp",
- "prebuilds/**",
- "bindings/node/*",
- "queries/*",
- "scripts/*",
- "src/**"
- ],
- "author": "Alex Pinkus ",
- "license": "MIT",
- "bugs": {
- "url": "https://github.com/alex-pinkus/tree-sitter-swift/issues"
- },
- "homepage": "https://github.com/alex-pinkus/tree-sitter-swift#readme",
- "dependencies": {
- "node-addon-api": "^8.0.0",
- "node-gyp-build": "^4.8.0",
- "tree-sitter-cli": "^0.23",
- "which": "2.0.2"
- },
- "peerDependencies": {
- "tree-sitter": "^0.22.1"
- },
- "peerDependenciesMeta": {
- "tree_sitter": {
- "optional": true
- }
- },
- "devDependencies": {
- "node-gyp": "^10.0.1",
- "prebuildify": "^6.0.0",
- "prettier": "2.3.2"
- }
-}
diff --git a/unified/extractor/tree-sitter-swift/queries/folds.scm b/unified/extractor/tree-sitter-swift/queries/folds.scm
deleted file mode 100644
index ca7f72593aa..00000000000
--- a/unified/extractor/tree-sitter-swift/queries/folds.scm
+++ /dev/null
@@ -1,35 +0,0 @@
-; format-ignore
-[
- (protocol_body) ; protocol Foo { ... }
- (class_body) ; class Foo { ... }
- (enum_class_body) ; enum Foo { ... }
- (function_body) ; func Foo (...) {...}
- (computed_property) ; { ... }
-
- (computed_getter) ; get { ... }
- (computed_setter) ; set { ... }
-
- (do_statement)
- (if_statement)
- (for_statement)
- (switch_statement)
- (while_statement)
- (guard_statement)
- (switch_entry)
-
- (type_parameters) ; x
- (tuple_type) ; (...)
- (array_type) ; [String]
- (dictionary_type) ; [Foo: Bar]
-
- (call_expression) ; callFunc(...)
- (tuple_expression) ; ( foo + bar )
- (array_literal) ; [ foo, bar ]
- (dictionary_literal) ; [ foo: bar, x: y ]
- (lambda_literal)
- (willset_didset_block)
- (willset_clause)
- (didset_clause)
-
- (import_declaration)+
-] @fold
diff --git a/unified/extractor/tree-sitter-swift/queries/highlights.scm b/unified/extractor/tree-sitter-swift/queries/highlights.scm
deleted file mode 100644
index 82ad68d4ed1..00000000000
--- a/unified/extractor/tree-sitter-swift/queries/highlights.scm
+++ /dev/null
@@ -1,336 +0,0 @@
-[
- "."
- ";"
- ":"
- ","
-] @punctuation.delimiter
-
-[
- "("
- ")"
- "["
- "]"
- "{"
- "}"
-] @punctuation.bracket
-
-; Identifiers
-(type_identifier) @type
-
-[
- (self_expression)
- (super_expression)
-] @variable.builtin
-
-; Declarations
-[
- "func"
- "deinit"
-] @keyword.function
-
-[
- (visibility_modifier)
- (member_modifier)
- (function_modifier)
- (property_modifier)
- (parameter_modifier)
- (inheritance_modifier)
- (mutation_modifier)
-] @keyword.modifier
-
-(simple_identifier) @variable
-
-(function_declaration
- (simple_identifier) @function.method)
-
-(protocol_function_declaration
- name: (simple_identifier) @function.method)
-
-(init_declaration
- "init" @constructor)
-
-(parameter
- external_name: (simple_identifier) @variable.parameter)
-
-(parameter
- name: (simple_identifier) @variable.parameter)
-
-(type_parameter
- (type_identifier) @variable.parameter)
-
-(inheritance_constraint
- (identifier
- (simple_identifier) @variable.parameter))
-
-(equality_constraint
- (identifier
- (simple_identifier) @variable.parameter))
-
-[
- "protocol"
- "extension"
- "indirect"
- "nonisolated"
- "override"
- "convenience"
- "required"
- "some"
- "any"
- "weak"
- "unowned"
- "didSet"
- "willSet"
- "subscript"
- "let"
- "var"
- (throws)
- (where_keyword)
- (getter_specifier)
- (setter_specifier)
- (modify_specifier)
- (else)
- (as_operator)
-] @keyword
-
-[
- "enum"
- "struct"
- "class"
- "typealias"
-] @keyword.type
-
-[
- "async"
- "await"
-] @keyword.coroutine
-
-(shebang_line) @keyword.directive
-
-(class_body
- (property_declaration
- (pattern
- (simple_identifier) @variable.member)))
-
-(protocol_property_declaration
- (pattern
- (simple_identifier) @variable.member))
-
-(navigation_expression
- (navigation_suffix
- (simple_identifier) @variable.member))
-
-(value_argument
- name: (value_argument_label
- (simple_identifier) @variable.member))
-
-(import_declaration
- "import" @keyword.import)
-
-(enum_entry
- "case" @keyword)
-
-(modifiers
- (attribute
- "@" @attribute
- (user_type
- (type_identifier) @attribute)))
-
-; Function calls
-(call_expression
- (simple_identifier) @function.call) ; foo()
-
-(call_expression
- ; foo.bar.baz(): highlight the baz()
- (navigation_expression
- (navigation_suffix
- (simple_identifier) @function.call)))
-
-(call_expression
- (prefix_expression
- (simple_identifier) @function.call)) ; .foo()
-
-((navigation_expression
- (simple_identifier) @type) ; SomeType.method(): highlight SomeType as a type
- (#match? @type "^[A-Z]"))
-
-(directive) @keyword.directive
-
-; See https://docs.swift.org/swift-book/documentation/the-swift-programming-language/lexicalstructure/#Keywords-and-Punctuation
-[
- (diagnostic)
- (availability_condition)
- (playground_literal)
- (key_path_string_expression)
- (selector_expression)
- (external_macro_definition)
-] @function.macro
-
-(special_literal) @constant.macro
-
-; Statements
-(for_statement
- "for" @keyword.repeat)
-
-(for_statement
- "in" @keyword.repeat)
-
-[
- "while"
- "repeat"
- "continue"
- "break"
-] @keyword.repeat
-
-(guard_statement
- "guard" @keyword.conditional)
-
-(if_statement
- "if" @keyword.conditional)
-
-(switch_statement
- "switch" @keyword.conditional)
-
-(switch_entry
- "case" @keyword)
-
-(switch_entry
- "fallthrough" @keyword)
-
-(switch_entry
- (default_keyword) @keyword)
-
-"return" @keyword.return
-
-(ternary_expression
- [
- "?"
- ":"
- ] @keyword.conditional.ternary)
-
-[
- (try_operator)
- "do"
- (throw_keyword)
- (catch_keyword)
-] @keyword.exception
-
-(statement_label) @label
-
-; Comments
-[
- (comment)
- (multiline_comment)
-] @comment @spell
-
-((comment) @comment.documentation
- (#match? @comment.documentation "^///[^/]"))
-
-((comment) @comment.documentation
- (#match? @comment.documentation "^///$"))
-
-((multiline_comment) @comment.documentation
- (#match? @comment.documentation "^/[*][*][^*].*[*]/$"))
-
-; String literals
-(line_str_text) @string
-
-(str_escaped_char) @string.escape
-
-(multi_line_str_text) @string
-
-(raw_str_part) @string
-
-(raw_str_end_part) @string
-
-(line_string_literal
- [
- "\\("
- ")"
- ] @punctuation.special)
-
-(multi_line_string_literal
- [
- "\\("
- ")"
- ] @punctuation.special)
-
-(raw_str_interpolation
- [
- (raw_str_interpolation_start)
- ")"
- ] @punctuation.special)
-
-[
- "\""
- "\"\"\""
-] @string
-
-; Lambda literals
-(lambda_literal
- "in" @keyword.operator)
-
-; Basic literals
-[
- (integer_literal)
- (hex_literal)
- (oct_literal)
- (bin_literal)
-] @number
-
-(real_literal) @number.float
-
-(boolean_literal) @boolean
-
-"nil" @constant.builtin
-
-(wildcard_pattern) @character.special
-
-; Regex literals
-(regex_literal) @string.regexp
-
-; Operators
-(custom_operator) @operator
-
-[
- "+"
- "-"
- "*"
- "/"
- "%"
- "="
- "+="
- "-="
- "*="
- "/="
- "<"
- ">"
- "<<"
- ">>"
- "<="
- ">="
- "++"
- "--"
- "^"
- "&"
- "&&"
- "|"
- "||"
- "~"
- "%="
- "!="
- "!=="
- "=="
- "==="
- "?"
- "??"
- "->"
- "..<"
- "..."
- (bang)
-] @operator
-
-(type_arguments
- [
- "<"
- ">"
- ] @punctuation.bracket)
diff --git a/unified/extractor/tree-sitter-swift/queries/indents.scm b/unified/extractor/tree-sitter-swift/queries/indents.scm
deleted file mode 100644
index ec8f8af95c6..00000000000
--- a/unified/extractor/tree-sitter-swift/queries/indents.scm
+++ /dev/null
@@ -1,123 +0,0 @@
-; format-ignore
-[
- ; ... refers to the section that will get affected by this indent.begin capture
- (protocol_body) ; protocol Foo { ... }
- (class_body) ; class Foo { ... }
- (enum_class_body) ; enum Foo { ... }
- (function_declaration) ; func Foo (...) {...}
- (init_declaration) ; init(...) {...}
- (deinit_declaration) ; deinit {...}
- (computed_property) ; { ... }
- (subscript_declaration) ; subscript Foo(...) { ... }
-
- (computed_getter) ; get { ... }
- (computed_setter) ; set { ... }
-
- (assignment) ; a = b
-
- (control_transfer_statement) ; return ...
- (for_statement)
- (while_statement)
- (repeat_while_statement)
- (do_statement)
- (if_statement)
- (switch_statement)
- (guard_statement)
-
- (type_parameters) ; x
- (tuple_type) ; (...)
- (array_type) ; [String]
- (dictionary_type) ; [Foo: Bar]
-
- (call_expression) ; callFunc(...)
- (tuple_expression) ; ( foo + bar )
- (array_literal) ; [ foo, bar ]
- (dictionary_literal) ; [ foo: bar, x: y ]
- (lambda_literal)
- (willset_didset_block)
- (willset_clause)
- (didset_clause)
-] @indent.begin
-
-(init_declaration) @indent.begin
-
-(init_declaration
- [
- "init"
- "("
- ] @indent.branch)
-
-; indentation for init parameters
-(init_declaration
- ")" @indent.branch @indent.end)
-
-(init_declaration
- (parameter) @indent.begin
- (#set! indent.immediate))
-
-; @something(...)
-(modifiers
- (attribute) @indent.begin)
-
-(function_declaration
- (modifiers
- .
- (attribute)
- (_)* @indent.branch)
- .
- _ @indent.branch
- (#not-kind-eq? @indent.branch "type_parameters" "parameter"))
-
-(ERROR
- [
- "<"
- "{"
- "("
- "["
- ]) @indent.begin
-
-; if-elseif
-(if_statement
- (if_statement) @indent.dedent)
-
-; case Foo:
-; default Foo:
-; @attribute default Foo:
-(switch_entry
- .
- _ @indent.branch)
-
-(function_declaration
- ")" @indent.branch)
-
-(type_parameters
- ">" @indent.branch @indent.end .)
-
-(tuple_expression
- ")" @indent.branch @indent.end)
-
-(value_arguments
- ")" @indent.branch @indent.end)
-
-(tuple_type
- ")" @indent.branch @indent.end)
-
-(modifiers
- (attribute
- ")" @indent.branch @indent.end))
-
-[
- "}"
- "]"
-] @indent.branch @indent.end
-
-[
- ; (ERROR)
- (comment)
- (multiline_comment)
- (raw_str_part)
- (multi_line_string_literal)
-] @indent.auto
-
-(directive) @indent.ignore
-
diff --git a/unified/extractor/tree-sitter-swift/queries/injections.scm b/unified/extractor/tree-sitter-swift/queries/injections.scm
deleted file mode 100644
index 512cfa0d522..00000000000
--- a/unified/extractor/tree-sitter-swift/queries/injections.scm
+++ /dev/null
@@ -1,10 +0,0 @@
-; Parse regex syntax within regex literals
-
-((regex_literal) @injection.content
- (#set! injection.language "regex"))
-
-([
- (comment)
- (multiline_comment)
-] @injection.content
- (#set! injection.language "comment"))
diff --git a/unified/extractor/tree-sitter-swift/queries/locals.scm b/unified/extractor/tree-sitter-swift/queries/locals.scm
deleted file mode 100644
index 78032a81810..00000000000
--- a/unified/extractor/tree-sitter-swift/queries/locals.scm
+++ /dev/null
@@ -1,23 +0,0 @@
-(import_declaration
- (identifier) @local.definition.import)
-
-(function_declaration
- name: (simple_identifier) @local.definition.function)
-
-; Scopes
-[
- (statements)
- (for_statement)
- (while_statement)
- (repeat_while_statement)
- (do_statement)
- (if_statement)
- (guard_statement)
- (switch_statement)
- (property_declaration)
- (function_declaration)
- (class_declaration)
- (protocol_declaration)
-] @local.scope
-
-
diff --git a/unified/extractor/tree-sitter-swift/queries/outline.scm b/unified/extractor/tree-sitter-swift/queries/outline.scm
deleted file mode 100644
index 31fe5d9d4a4..00000000000
--- a/unified/extractor/tree-sitter-swift/queries/outline.scm
+++ /dev/null
@@ -1,66 +0,0 @@
-(protocol_declaration
- declaration_kind: "protocol" @name
- .
- _ * @name
- .
- body: (protocol_body)
-) @item
-
-(class_declaration
- declaration_kind: (
- [
- "actor"
- "class"
- "extension"
- "enum"
- "struct"
- ]
- ) @name
- .
- _ * @name
- .
- body: (_)
-) @item
-
-(init_declaration
- name: "init" @name
- .
- _ * @name
- .
- body: (function_body)
-) @item
-
-(deinit_declaration
- "deinit" @name) @item
-
-(function_declaration
- "func" @name
- .
- _ * @name
- .
- body: (function_body)
-) @item
-
-(class_body
- (property_declaration
- (value_binding_pattern) @name
- name: (pattern) @name
- (type_annotation)? @name
- ) @item
-)
-
-(enum_class_body
- (property_declaration
- (value_binding_pattern) @name
- name: (pattern) @name
- (type_annotation)? @name
- ) @item
-)
-
-(
- (protocol_function_declaration) @name
-) @item
-
-(
- (protocol_property_declaration) @name
-) @item
diff --git a/unified/extractor/tree-sitter-swift/queries/tags.scm b/unified/extractor/tree-sitter-swift/queries/tags.scm
deleted file mode 100644
index 0038571e5d7..00000000000
--- a/unified/extractor/tree-sitter-swift/queries/tags.scm
+++ /dev/null
@@ -1,51 +0,0 @@
-(class_declaration
- name: (type_identifier) @name) @definition.class
-
-(protocol_declaration
- name: (type_identifier) @name) @definition.interface
-
-(class_declaration
- (class_body
- [
- (function_declaration
- name: (simple_identifier) @name
- )
- (subscript_declaration
- (parameter (simple_identifier) @name)
- )
- (init_declaration "init" @name)
- (deinit_declaration "deinit" @name)
- ]
- )
-) @definition.method
-
-(protocol_declaration
- (protocol_body
- [
- (protocol_function_declaration
- name: (simple_identifier) @name
- )
- (subscript_declaration
- (parameter (simple_identifier) @name)
- )
- (init_declaration "init" @name)
- ]
- )
-) @definition.method
-
-(class_declaration
- (class_body
- [
- (property_declaration
- (pattern (simple_identifier) @name)
- )
- ]
- )
-) @definition.property
-
-(property_declaration
- (pattern (simple_identifier) @name)
-) @definition.property
-
-(function_declaration
- name: (simple_identifier) @name) @definition.function
\ No newline at end of file
diff --git a/unified/extractor/tree-sitter-swift/queries/textobjects.scm b/unified/extractor/tree-sitter-swift/queries/textobjects.scm
deleted file mode 100644
index da689a1b29f..00000000000
--- a/unified/extractor/tree-sitter-swift/queries/textobjects.scm
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-; MARK: Structure
-
-(function_declaration
- body: (_) @function.inside) @function.around
-
-; TODO: Classes/structs/enums
-
-
-; MARK: Tests
-
-; Only matches prefix test. Other conventions
-; might be nice to add!
-(function_declaration
- name: (simple_identifier) @_name
- (#match? @_name "^test")
-)
-
diff --git a/unified/extractor/tree-sitter-swift/src/scanner.c b/unified/extractor/tree-sitter-swift/src/scanner.c
deleted file mode 100644
index bb2dcac58b2..00000000000
--- a/unified/extractor/tree-sitter-swift/src/scanner.c
+++ /dev/null
@@ -1,929 +0,0 @@
-#include "tree_sitter/parser.h"
-#include
-#include
-
-#define TOKEN_COUNT 33
-
-enum TokenType {
- BLOCK_COMMENT,
- RAW_STR_PART,
- RAW_STR_CONTINUING_INDICATOR,
- RAW_STR_END_PART,
- IMPLICIT_SEMI,
- EXPLICIT_SEMI,
- ARROW_OPERATOR,
- DOT_OPERATOR,
- CONJUNCTION_OPERATOR,
- DISJUNCTION_OPERATOR,
- NIL_COALESCING_OPERATOR,
- EQUAL_SIGN,
- EQ_EQ,
- PLUS_THEN_WS,
- MINUS_THEN_WS,
- BANG,
- THROWS_KEYWORD,
- RETHROWS_KEYWORD,
- DEFAULT_KEYWORD,
- WHERE_KEYWORD,
- ELSE_KEYWORD,
- CATCH_KEYWORD,
- AS_KEYWORD,
- AS_QUEST,
- AS_BANG,
- ASYNC_KEYWORD,
- CUSTOM_OPERATOR,
- HASH_SYMBOL,
- DIRECTIVE_IF,
- DIRECTIVE_ELSEIF,
- DIRECTIVE_ELSE,
- DIRECTIVE_ENDIF,
- FAKE_TRY_BANG
-};
-
-#define OPERATOR_COUNT 20
-
-const char* OPERATORS[OPERATOR_COUNT] = {
- "->",
- ".",
- "&&",
- "||",
- "??",
- "=",
- "==",
- "+",
- "-",
- "!",
- "throws",
- "rethrows",
- "default",
- "where",
- "else",
- "catch",
- "as",
- "as?",
- "as!",
- "async"
-};
-
-enum IllegalTerminatorGroup {
- ALPHANUMERIC,
- OPERATOR_SYMBOLS,
- OPERATOR_OR_DOT,
- NON_WHITESPACE
-};
-
-const enum IllegalTerminatorGroup OP_ILLEGAL_TERMINATORS[OPERATOR_COUNT] = {
- OPERATOR_SYMBOLS, // ->
- OPERATOR_OR_DOT, // .
- OPERATOR_SYMBOLS, // &&
- OPERATOR_SYMBOLS, // ||
- OPERATOR_SYMBOLS, // ??
- OPERATOR_SYMBOLS, // =
- OPERATOR_SYMBOLS, // ==
- NON_WHITESPACE, // +
- NON_WHITESPACE, // -
- OPERATOR_SYMBOLS, // !
- ALPHANUMERIC, // throws
- ALPHANUMERIC, // rethrows
- ALPHANUMERIC, // default
- ALPHANUMERIC, // where
- ALPHANUMERIC, // else
- ALPHANUMERIC, // catch
- ALPHANUMERIC, // as
- OPERATOR_SYMBOLS, // as?
- OPERATOR_SYMBOLS, // as!
- ALPHANUMERIC // async
-};
-
-const enum TokenType OP_SYMBOLS[OPERATOR_COUNT] = {
- ARROW_OPERATOR,
- DOT_OPERATOR,
- CONJUNCTION_OPERATOR,
- DISJUNCTION_OPERATOR,
- NIL_COALESCING_OPERATOR,
- EQUAL_SIGN,
- EQ_EQ,
- PLUS_THEN_WS,
- MINUS_THEN_WS,
- BANG,
- THROWS_KEYWORD,
- RETHROWS_KEYWORD,
- DEFAULT_KEYWORD,
- WHERE_KEYWORD,
- ELSE_KEYWORD,
- CATCH_KEYWORD,
- AS_KEYWORD,
- AS_QUEST,
- AS_BANG,
- ASYNC_KEYWORD
-};
-
-const uint64_t OP_SYMBOL_SUPPRESSOR[OPERATOR_COUNT] = {
- 0, // ARROW_OPERATOR,
- 0, // DOT_OPERATOR,
- 0, // CONJUNCTION_OPERATOR,
- 0, // DISJUNCTION_OPERATOR,
- 0, // NIL_COALESCING_OPERATOR,
- 0, // EQUAL_SIGN,
- 0, // EQ_EQ,
- 0, // PLUS_THEN_WS,
- 0, // MINUS_THEN_WS,
- 1UL << FAKE_TRY_BANG, // BANG,
- 0, // THROWS_KEYWORD,
- 0, // RETHROWS_KEYWORD,
- 0, // DEFAULT_KEYWORD,
- 0, // WHERE_KEYWORD,
- 0, // ELSE_KEYWORD,
- 0, // CATCH_KEYWORD,
- 0, // AS_KEYWORD,
- 0, // AS_QUEST,
- 0, // AS_BANG,
- 0, // ASYNC_KEYWORD
-};
-
-#define RESERVED_OP_COUNT 31
-
-const char* RESERVED_OPS[RESERVED_OP_COUNT] = {
- "/",
- "=",
- "-",
- "+",
- "!",
- "*",
- "%",
- "<",
- ">",
- "&",
- "|",
- "^",
- "?",
- "~",
- ".",
- "..",
- "->",
- "/*",
- "*/",
- "+=",
- "-=",
- "*=",
- "/=",
- "%=",
- ">>",
- "<<",
- "++",
- "--",
- "===",
- "...",
- "..<"
-};
-
-static bool is_cross_semi_token(enum TokenType op) {
- switch(op) {
- case ARROW_OPERATOR:
- case DOT_OPERATOR:
- case CONJUNCTION_OPERATOR:
- case DISJUNCTION_OPERATOR:
- case NIL_COALESCING_OPERATOR:
- case EQUAL_SIGN:
- case EQ_EQ:
- case PLUS_THEN_WS:
- case MINUS_THEN_WS:
- case THROWS_KEYWORD:
- case RETHROWS_KEYWORD:
- case DEFAULT_KEYWORD:
- case WHERE_KEYWORD:
- case ELSE_KEYWORD:
- case CATCH_KEYWORD:
- case AS_KEYWORD:
- case AS_QUEST:
- case AS_BANG:
- case ASYNC_KEYWORD:
- case CUSTOM_OPERATOR:
- return true;
- case BANG:
- default:
- return false;
- }
-}
-
-#define NON_CONSUMING_CROSS_SEMI_CHAR_COUNT 3
-const uint32_t NON_CONSUMING_CROSS_SEMI_CHARS[NON_CONSUMING_CROSS_SEMI_CHAR_COUNT] = { '?', ':', '{' };
-
-/**
- * All possible results of having performed some sort of parsing.
- *
- * A parser can return a result along two dimensions:
- * 1. Should the scanner continue trying to find another result?
- * 2. Was some result produced by this parsing attempt?
- *
- * These are flattened into a single enum together. When the function returns one of the `TOKEN_FOUND` cases, it
- * will always populate its `symbol_result` field. When it returns one of the `STOP_PARSING` cases, callers should
- * immediately return (with the value, if there is one).
- */
-enum ParseDirective {
- CONTINUE_PARSING_NOTHING_FOUND,
- CONTINUE_PARSING_TOKEN_FOUND,
- CONTINUE_PARSING_SLASH_CONSUMED,
- STOP_PARSING_NOTHING_FOUND,
- STOP_PARSING_TOKEN_FOUND,
- STOP_PARSING_END_OF_FILE
-};
-
-struct ScannerState {
- uint32_t ongoing_raw_str_hash_count;
-};
-
-void *tree_sitter_swift_external_scanner_create() {
- return calloc(1, sizeof(struct ScannerState));
-}
-
-void tree_sitter_swift_external_scanner_destroy(void *payload) {
- free(payload);
-}
-
-void tree_sitter_swift_external_scanner_reset(void *payload) {
- struct ScannerState *state = (struct ScannerState *)payload;
- state->ongoing_raw_str_hash_count = 0;
-}
-
-unsigned tree_sitter_swift_external_scanner_serialize(void *payload, char *buffer) {
- struct ScannerState *state = (struct ScannerState *)payload;
- uint32_t hash_count = state->ongoing_raw_str_hash_count;
- buffer[0] = (hash_count >> 24) & 0xff;
- buffer[1] = (hash_count >> 16) & 0xff;
- buffer[2] = (hash_count >> 8) & 0xff;
- buffer[3] = (hash_count) & 0xff;
- return 4;
-}
-
-void tree_sitter_swift_external_scanner_deserialize(
- void *payload,
- const char *buffer,
- unsigned length
-) {
- if (length < 4) {
- return;
- }
-
- uint32_t hash_count = (
- (((uint32_t) buffer[0]) << 24) |
- (((uint32_t) buffer[1]) << 16) |
- (((uint32_t) buffer[2]) << 8) |
- (((uint32_t) buffer[3]))
- );
- struct ScannerState *state = (struct ScannerState *)payload;
- state->ongoing_raw_str_hash_count = hash_count;
-}
-
-static void advance(TSLexer *lexer) {
- lexer->advance(lexer, false);
-}
-
-static bool should_treat_as_wspace(int32_t character) {
- return iswspace(character) || (((int32_t) ';') == character);
-}
-
-static int32_t encountered_op_count(bool *encountered_operator) {
- int32_t encountered = 0;
- for (int op_idx = 0; op_idx < OPERATOR_COUNT; op_idx++) {
- if (encountered_operator[op_idx]) {
- encountered++;
- }
- }
-
- return encountered;
-}
-
-static bool any_reserved_ops(uint8_t *encountered_reserved_ops) {
- for (int op_idx = 0; op_idx < RESERVED_OP_COUNT; op_idx++) {
- if (encountered_reserved_ops[op_idx] == 2) {
- return true;
- }
- }
-
- return false;
-}
-
-static bool is_legal_custom_operator(
- int32_t char_idx,
- int32_t first_char,
- int32_t cur_char
-) {
- bool is_first_char = !char_idx;
- switch (cur_char) {
- case '=':
- case '-':
- case '+':
- case '!':
- case '%':
- case '<':
- case '>':
- case '&':
- case '|':
- case '^':
- case '?':
- case '~':
- return true;
- case '.':
- // Grammar allows `.` for any operator that starts with `.`
- return is_first_char || first_char == '.';
- case '*':
- case '/':
- // Not listed in the grammar, but `/*` and `//` can't be the start of an operator since they start comments
- return char_idx != 1 || first_char != '/';
- default:
- if (
- (cur_char >= 0x00A1 && cur_char <= 0x00A7) ||
- (cur_char == 0x00A9) ||
- (cur_char == 0x00AB) ||
- (cur_char == 0x00AC) ||
- (cur_char == 0x00AE) ||
- (cur_char >= 0x00B0 && cur_char <= 0x00B1) ||
- (cur_char == 0x00B6) ||
- (cur_char == 0x00BB) ||
- (cur_char == 0x00BF) ||
- (cur_char == 0x00D7) ||
- (cur_char == 0x00F7) ||
- (cur_char >= 0x2016 && cur_char <= 0x2017) ||
- (cur_char >= 0x2020 && cur_char <= 0x2027) ||
- (cur_char >= 0x2030 && cur_char <= 0x203E) ||
- (cur_char >= 0x2041 && cur_char <= 0x2053) ||
- (cur_char >= 0x2055 && cur_char <= 0x205E) ||
- (cur_char >= 0x2190 && cur_char <= 0x23FF) ||
- (cur_char >= 0x2500 && cur_char <= 0x2775) ||
- (cur_char >= 0x2794 && cur_char <= 0x2BFF) ||
- (cur_char >= 0x2E00 && cur_char <= 0x2E7F) ||
- (cur_char >= 0x3001 && cur_char <= 0x3003) ||
- (cur_char >= 0x3008 && cur_char <= 0x3020) ||
- (cur_char == 0x3030)
- ) {
- return true;
- } else if (
- (cur_char >= 0x0300 && cur_char <= 0x036f) ||
- (cur_char >= 0x1DC0 && cur_char <= 0x1DFF) ||
- (cur_char >= 0x20D0 && cur_char <= 0x20FF) ||
- (cur_char >= 0xFE00 && cur_char <= 0xFE0F) ||
- (cur_char >= 0xFE20 && cur_char <= 0xFE2F) ||
- (cur_char >= 0xE0100 && cur_char <= 0xE01EF)
- ) {
- return !is_first_char;
- } else {
- return false;
- }
- }
-}
-
-static bool eat_operators(
- TSLexer *lexer,
- const bool *valid_symbols,
- bool mark_end,
- const int32_t prior_char,
- enum TokenType *symbol_result
-) {
- bool possible_operators[OPERATOR_COUNT];
- uint8_t reserved_operators[RESERVED_OP_COUNT];
- for (int op_idx = 0; op_idx < OPERATOR_COUNT; op_idx++) {
- possible_operators[op_idx] = valid_symbols[OP_SYMBOLS[op_idx]] && (!prior_char || OPERATORS[op_idx][0] == prior_char);
- }
- for (int op_idx = 0; op_idx < RESERVED_OP_COUNT; op_idx++) {
- reserved_operators[op_idx] = !prior_char || RESERVED_OPS[op_idx][0] == prior_char;
- }
-
- bool possible_custom_operator = valid_symbols[CUSTOM_OPERATOR];
- int32_t first_char = prior_char ? prior_char : lexer->lookahead;
- int32_t last_examined_char = first_char;
-
- int32_t str_idx = prior_char ? 1 : 0;
- int32_t full_match = -1;
- while(true) {
- for (int op_idx = 0; op_idx < OPERATOR_COUNT; op_idx++) {
- if (!possible_operators[op_idx]) {
- continue;
- }
-
- if (OPERATORS[op_idx][str_idx] == '\0') {
- // Make sure that the operator is allowed to have the next character as its lookahead.
- enum IllegalTerminatorGroup illegal_terminators = OP_ILLEGAL_TERMINATORS[op_idx];
- switch (lexer->lookahead) {
- // See "Operators":
- // https://docs.swift.org/swift-book/ReferenceManual/LexicalStructure.html#ID418
- case '/':
- case '=':
- case '-':
- case '+':
- case '!':
- case '*':
- case '%':
- case '<':
- case '>':
- case '&':
- case '|':
- case '^':
- case '?':
- case '~':
- if (illegal_terminators == OPERATOR_SYMBOLS) {
- break;
- } // Otherwise, intentionally fall through to the OPERATOR_OR_DOT case
- // fall through
- case '.':
- if (illegal_terminators == OPERATOR_OR_DOT) {
- break;
- } // Otherwise, fall through to DEFAULT which checks its groups directly
- // fall through
- default:
- if (iswalnum(lexer->lookahead) && illegal_terminators == ALPHANUMERIC) {
- break;
- }
-
- if (!iswspace(lexer->lookahead) && illegal_terminators == NON_WHITESPACE) {
- break;
- }
-
- full_match = op_idx;
- if (mark_end) {
- lexer->mark_end(lexer);
- }
- }
-
- possible_operators[op_idx] = false;
- continue;
- }
-
- if (OPERATORS[op_idx][str_idx] != lexer->lookahead) {
- possible_operators[op_idx] = false;
- continue;
- }
- }
-
- for (int op_idx = 0; op_idx < RESERVED_OP_COUNT; op_idx++) {
- if (!reserved_operators[op_idx]) {
- continue;
- }
-
- if (RESERVED_OPS[op_idx][str_idx] == '\0') {
- reserved_operators[op_idx] = 0;
- continue;
- }
-
- if (RESERVED_OPS[op_idx][str_idx] != lexer->lookahead) {
- reserved_operators[op_idx] = 0;
- continue;
- }
-
- if (RESERVED_OPS[op_idx][str_idx + 1] == '\0') {
- reserved_operators[op_idx] = 2;
- continue;
- }
- }
-
- possible_custom_operator = possible_custom_operator && is_legal_custom_operator(
- str_idx,
- first_char,
- lexer->lookahead
- );
-
- uint32_t encountered_ops = encountered_op_count(possible_operators);
- if (encountered_ops == 0) {
- if (!possible_custom_operator) {
- break;
- } else if (mark_end && full_match == -1) {
- lexer->mark_end(lexer);
- }
- }
-
- last_examined_char = lexer->lookahead;
- lexer->advance(lexer, false);
- str_idx += 1;
-
- if (encountered_ops == 0 && !is_legal_custom_operator(
- str_idx,
- first_char,
- lexer->lookahead
- )) {
- break;
- }
- }
-
- if (full_match != -1) {
- // We have a match -- first see if that match has a symbol that suppresses it. For example, in `try!`, we do not
- // want to emit the `!` as a symbol in our scanner, because we want the parser to have the chance to parse it as
- // an immediate token.
- uint64_t suppressing_symbols = OP_SYMBOL_SUPPRESSOR[full_match];
- if (suppressing_symbols) {
- for (uint64_t suppressor = 0; suppressor < TOKEN_COUNT; suppressor++) {
- if (!(suppressing_symbols & 1ULL << suppressor)) {
- continue;
- }
-
- // The suppressing symbol is valid in this position, so skip it.
- if (valid_symbols[suppressor]) {
- return false;
- }
- }
- }
- *symbol_result = OP_SYMBOLS[full_match];
- return true;
- }
-
- if (possible_custom_operator && !any_reserved_ops(reserved_operators)) {
- if ((last_examined_char != '<' || iswspace(lexer->lookahead)) && mark_end) {
- lexer->mark_end(lexer);
- }
- *symbol_result = CUSTOM_OPERATOR;
- return true;
- }
-
- return false;
-}
-
-static enum ParseDirective eat_comment(
- TSLexer *lexer,
- const bool *valid_symbols,
- bool mark_end,
- enum TokenType *symbol_result
-) {
- if (lexer->lookahead != '/') {
- return CONTINUE_PARSING_NOTHING_FOUND;
- }
-
- advance(lexer);
-
- if (lexer->lookahead != '*') {
- return CONTINUE_PARSING_SLASH_CONSUMED;
- }
-
- advance(lexer);
-
- bool after_star = false;
- unsigned nesting_depth = 1;
- for (;;) {
- switch (lexer->lookahead) {
- case '\0':
- return STOP_PARSING_END_OF_FILE;
- case '*':
- advance(lexer);
- after_star = true;
- break;
- case '/':
- if (after_star) {
- advance(lexer);
- after_star = false;
- nesting_depth--;
- if (nesting_depth == 0) {
- if (mark_end) {
- lexer->mark_end(lexer);
- }
- *symbol_result = BLOCK_COMMENT;
- return STOP_PARSING_TOKEN_FOUND;
- }
- } else {
- advance(lexer);
- after_star = false;
- if (lexer->lookahead == '*') {
- nesting_depth++;
- advance(lexer);
- }
- }
- break;
- default:
- advance(lexer);
- after_star = false;
- break;
- }
- }
-}
-
-static enum ParseDirective eat_whitespace(
- TSLexer *lexer,
- const bool *valid_symbols,
- enum TokenType *symbol_result
-) {
- enum ParseDirective ws_directive = CONTINUE_PARSING_NOTHING_FOUND;
- bool semi_is_valid = valid_symbols[IMPLICIT_SEMI] && valid_symbols[EXPLICIT_SEMI];
- uint32_t lookahead;
- while (should_treat_as_wspace(lookahead = lexer->lookahead)) {
- if (lookahead == ';') {
- if (semi_is_valid) {
- ws_directive = STOP_PARSING_TOKEN_FOUND;
- lexer->advance(lexer, false);
- }
-
- break;
- }
-
- lexer->advance(lexer, true);
-
- lexer->mark_end(lexer);
-
- if (ws_directive == CONTINUE_PARSING_NOTHING_FOUND && (lookahead == '\n' || lookahead == '\r')) {
- ws_directive = CONTINUE_PARSING_TOKEN_FOUND;
- }
- }
-
- enum ParseDirective any_comment = CONTINUE_PARSING_NOTHING_FOUND;
- if (ws_directive == CONTINUE_PARSING_TOKEN_FOUND && lookahead == '/') {
- bool has_seen_single_comment = false;
- while (lexer->lookahead == '/') {
- // It's possible that this is a comment - start an exploratory mission to find out, and if it is, look for what
- // comes after it. We care about what comes after it for the purpose of suppressing the newline.
-
- enum TokenType multiline_comment_result;
- any_comment = eat_comment(lexer, valid_symbols, /* mark_end */ false, &multiline_comment_result);
- if (any_comment == STOP_PARSING_TOKEN_FOUND) {
- // This is a multiline comment. This scanner should be parsing those, so we might want to bail out and
- // emit it instead. However, we only want to do that if we haven't advanced through a _single_ line
- // comment on the way - otherwise that will get lumped into this.
- if (!has_seen_single_comment) {
- lexer->mark_end(lexer);
- *symbol_result = multiline_comment_result;
- return STOP_PARSING_TOKEN_FOUND;
- }
- } else if (any_comment == STOP_PARSING_END_OF_FILE) {
- return STOP_PARSING_END_OF_FILE;
- } else if (any_comment == CONTINUE_PARSING_SLASH_CONSUMED) {
- // We accidentally ate a slash -- we should actually bail out, say we saw nothing, and let the next pass
- // take it from after the newline.
- return CONTINUE_PARSING_SLASH_CONSUMED;
- } else if (lexer->lookahead == '/') {
- // There wasn't a multiline comment, which we know means that the comment parser ate its `/` and then
- // bailed out. If it had seen anything comment-like after that first `/` it would have continued going
- // and eventually had a well-formed comment or an EOF. Thus, if we're currently looking at a `/`, it's
- // the second one of those and it means we have a single-line comment.
- has_seen_single_comment = true;
- while (lexer->lookahead != '\n' && lexer->lookahead != '\0') {
- lexer->advance(lexer, true);
- }
- } else if (iswspace(lexer->lookahead)) {
- // We didn't see any type of comment - in fact, we saw an operator that we don't normally treat as an
- // operator. Still, this is a reason to stop parsing.
- return STOP_PARSING_NOTHING_FOUND;
- }
-
- // If we skipped through some comment, we're at whitespace now, so advance.
- while(iswspace(lexer->lookahead)) {
- any_comment = CONTINUE_PARSING_NOTHING_FOUND; // We're advancing, so clear out the comment
- lexer->advance(lexer, true);
- }
- }
-
- enum TokenType operator_result;
- bool saw_operator = eat_operators(
- lexer,
- valid_symbols,
- /* mark_end */ false,
- '\0',
- &operator_result
- );
- if (saw_operator) {
- // The operator we saw should suppress the newline, so bail out.
- return STOP_PARSING_NOTHING_FOUND;
- } else {
- // Promote the implicit newline to an explicit one so we don't check for operators again.
- *symbol_result = IMPLICIT_SEMI;
- ws_directive = STOP_PARSING_TOKEN_FOUND;
- }
- }
-
- // Let's consume operators that can live after a "semicolon" style newline. Before we do that, though, we want to
- // check for a set of characters that we do not consume, but that still suppress the semi.
- if (ws_directive == CONTINUE_PARSING_TOKEN_FOUND) {
- for (int i = 0; i < NON_CONSUMING_CROSS_SEMI_CHAR_COUNT; i++) {
- if (NON_CONSUMING_CROSS_SEMI_CHARS[i] == lookahead) {
- return CONTINUE_PARSING_NOTHING_FOUND;
- }
- }
- }
-
- if (semi_is_valid && ws_directive != CONTINUE_PARSING_NOTHING_FOUND) {
- *symbol_result = lookahead == ';' ? EXPLICIT_SEMI : IMPLICIT_SEMI;
- return ws_directive;
- }
-
- return CONTINUE_PARSING_NOTHING_FOUND;
-}
-
-#define DIRECTIVE_COUNT 4
-const char* DIRECTIVES[OPERATOR_COUNT] = {
- "if",
- "elseif",
- "else",
- "endif"
-};
-
-const enum TokenType DIRECTIVE_SYMBOLS[DIRECTIVE_COUNT] = {
- DIRECTIVE_IF,
- DIRECTIVE_ELSEIF,
- DIRECTIVE_ELSE,
- DIRECTIVE_ENDIF
-};
-
-static enum TokenType find_possible_compiler_directive(TSLexer *lexer) {
- bool possible_directives[DIRECTIVE_COUNT];
- for (int dir_idx = 0; dir_idx < DIRECTIVE_COUNT; dir_idx++) {
- possible_directives[dir_idx] = true;
- }
-
- int32_t str_idx = 0;
- int32_t full_match = -1;
- while(true) {
- for (int dir_idx = 0; dir_idx < DIRECTIVE_COUNT; dir_idx++) {
- if (!possible_directives[dir_idx]) {
- continue;
- }
-
- uint8_t expected_char = DIRECTIVES[dir_idx][str_idx];
- if (expected_char == '\0') {
- full_match = dir_idx;
- lexer->mark_end(lexer);
- }
-
- if (expected_char != lexer->lookahead) {
- possible_directives[dir_idx] = false;
- continue;
- }
- }
-
- uint8_t match_count = 0;
- for (int dir_idx = 0; dir_idx < DIRECTIVE_COUNT; dir_idx += 1) {
- if (possible_directives[dir_idx]) {
- match_count += 1;
- }
- }
-
- if (match_count == 0) {
- break;
- }
-
- lexer->advance(lexer, false);
- str_idx += 1;
- }
-
- if (full_match == -1) {
- // No compiler directive found, so just match the starting symbol
- return HASH_SYMBOL;
- }
-
- return DIRECTIVE_SYMBOLS[full_match];
-}
-
-static bool eat_raw_str_part(
- struct ScannerState *state,
- TSLexer *lexer,
- const bool *valid_symbols,
- enum TokenType *symbol_result
-) {
- uint32_t hash_count = state->ongoing_raw_str_hash_count;
- if (!valid_symbols[RAW_STR_PART]) {
- return false;
- } else if (hash_count == 0) {
- // If this is a raw_str_part, it's the first one - look for hashes
- while (lexer->lookahead == '#') {
- hash_count += 1;
- advance(lexer);
- }
-
- if (hash_count == 0) {
- return false;
- }
-
- if (lexer->lookahead == '"') {
- advance(lexer);
- } else if (hash_count == 1) {
- lexer->mark_end(lexer);
- *symbol_result = find_possible_compiler_directive(lexer);
- return true;
- } else {
- return false;
- }
-
- } else if (valid_symbols[RAW_STR_CONTINUING_INDICATOR]) {
- // This is the end of an interpolation - now it's another raw_str_part. This is a synthetic
- // marker to tell us that the grammar just consumed a `(` symbol to close a raw
- // interpolation (since we don't want to fire on every `(` in existence). We don't have
- // anything to do except continue.
- } else {
- return false;
- }
-
- // We're in a state where anything other than `hash_count` hash symbols in a row should be eaten
- // and is part of a string.
- // The last character _before_ the hashes will tell us what happens next.
- // Matters are also complicated by the fact that we don't want to consume every character we
- // visit; if we see a `\#(`, for instance, with the appropriate number of hash symbols, we want
- // to end our parsing _before_ that sequence. This allows highlighting tools to treat that as a
- // separate token.
- while (lexer->lookahead != '\0') {
- uint8_t last_char = '\0';
- lexer->mark_end(lexer); // We always want to parse thru the start of the string so far
- // Advance through anything that isn't a hash symbol, because we want to count those.
- while (lexer->lookahead != '#' && lexer->lookahead != '\0') {
- last_char = lexer->lookahead;
- advance(lexer);
- if (last_char != '\\' || lexer->lookahead == '\\') {
- // Mark a new end, but only if we didn't just advance past a `\` symbol, since we
- // don't want to consume that. Exception: if this is a `\` that happens _right
- // after_ another `\`, we for some reason _do_ want to consume that, because
- // apparently that is parsed as a literal `\` followed by something escaped.
- lexer->mark_end(lexer);
- }
- }
-
- // We hit at least one hash - count them and see if they match.
- uint32_t current_hash_count = 0;
- while (lexer->lookahead == '#' && current_hash_count < hash_count) {
- current_hash_count += 1;
- advance(lexer);
- }
-
- // If we saw exactly the right number of hashes, one of three things is true:
- // 1. We're trying to interpolate into this string.
- // 2. The string just ended.
- // 3. This was just some hash characters doing nothing important.
- if (current_hash_count == hash_count) {
- if (last_char == '\\' && lexer->lookahead == '(') {
- // Interpolation case! Don't consume those chars; they get saved for grammar.js.
- *symbol_result = RAW_STR_PART;
- state->ongoing_raw_str_hash_count = hash_count;
- return true;
- } else if (last_char == '"') {
- // The string is finished! Mark the end here, on the very last hash symbol.
- lexer->mark_end(lexer);
- *symbol_result = RAW_STR_END_PART;
- state->ongoing_raw_str_hash_count = 0;
- return true;
- }
- // Nothing special happened - let the string continue.
- }
- }
-
- return false;
-}
-
-bool tree_sitter_swift_external_scanner_scan(
- void *payload,
- TSLexer *lexer,
- const bool *valid_symbols
-) {
- // Figure out our scanner state
- struct ScannerState *state = (struct ScannerState *)payload;
-
- // Consume any whitespace at the start.
- enum TokenType ws_result;
- enum ParseDirective ws_directive = eat_whitespace(lexer, valid_symbols, &ws_result);
- if (ws_directive == STOP_PARSING_TOKEN_FOUND) {
- lexer->result_symbol = ws_result;
- return true;
- }
-
- if (ws_directive == STOP_PARSING_NOTHING_FOUND || ws_directive == STOP_PARSING_END_OF_FILE) {
- return false;
- }
-
- bool has_ws_result = (ws_directive == CONTINUE_PARSING_TOKEN_FOUND);
-
- // Now consume comments (before custom operators so that those aren't treated as comments)
- enum TokenType comment_result;
- enum ParseDirective comment = ws_directive == CONTINUE_PARSING_SLASH_CONSUMED ? ws_directive : eat_comment(lexer, valid_symbols, /* mark_end */ true, &comment_result);
- if (comment == STOP_PARSING_TOKEN_FOUND) {
- lexer->mark_end(lexer);
- lexer->result_symbol = comment_result;
- return true;
- }
-
- if (comment == STOP_PARSING_END_OF_FILE) {
- return false;
- }
- // Now consume any operators that might cause our whitespace to be suppressed.
- enum TokenType operator_result;
- bool saw_operator = eat_operators(
- lexer,
- valid_symbols,
- /* mark_end */ !has_ws_result,
- comment == CONTINUE_PARSING_SLASH_CONSUMED ? '/' : '\0',
- &operator_result
- );
-
- if (saw_operator && (!has_ws_result || is_cross_semi_token(operator_result))) {
- lexer->result_symbol = operator_result;
- if (has_ws_result) lexer->mark_end(lexer);
- return true;
- }
-
- if (has_ws_result) {
- // Don't `mark_end`, since we may have advanced through some operators.
- lexer->result_symbol = ws_result;
- return true;
- }
-
- // NOTE: this will consume any `#` characters it sees, even if it does not find a result. Keep
- // it at the end so that it doesn't interfere with special literals or selectors!
- enum TokenType raw_str_result;
- bool saw_raw_str_part = eat_raw_str_part(state, lexer, valid_symbols, &raw_str_result);
- if (saw_raw_str_part) {
- lexer->result_symbol = raw_str_result;
- return true;
- }
-
- return false;
-}
-
diff --git a/unified/extractor/tree-sitter-swift/tree-sitter.json b/unified/extractor/tree-sitter-swift/tree-sitter.json
deleted file mode 100644
index 3cd49a28a38..00000000000
--- a/unified/extractor/tree-sitter-swift/tree-sitter.json
+++ /dev/null
@@ -1,39 +0,0 @@
-{
- "grammars": [
- {
- "name": "swift",
- "camelcase": "Swift",
- "scope": "source.swift",
- "path": ".",
- "file-types": [
- "swift"
- ],
- "highlights": "queries/highlights.scm",
- "injections": "queries/injections.scm",
- "locals": "queries/locals.scm",
- "injection-regex": "swift"
- }
- ],
- "metadata": {
- "version": "0.7.2",
- "license": "MIT",
- "description": "A tree-sitter grammar for the Swift programming language.",
- "authors": [
- {
- "name": "Alex Pinkus",
- "email": "alex.pinkus@gmail.com"
- }
- ],
- "links": {
- "repository": "git+https://github.com/alex-pinkus/tree-sitter-swift.git"
- }
- },
- "bindings": {
- "c": true,
- "go": true,
- "node": true,
- "python": true,
- "rust": true,
- "swift": true
- }
-}
diff --git a/unified/ql/lib/codeql/unified/Ast.qll b/unified/ql/lib/codeql/unified/Ast.qll
index e9a827269cc..4ad61ff353b 100644
--- a/unified/ql/lib/codeql/unified/Ast.qll
+++ b/unified/ql/lib/codeql/unified/Ast.qll
@@ -349,9 +349,6 @@ module Unified {
/** Gets the node corresponding to the field `body`. */
final Block getBody() { unified_catch_clause_def(this, result) }
- /** Gets the node corresponding to the field `guard`. */
- final Expr getGuard() { unified_catch_clause_guard(this, result) }
-
/** Gets the node corresponding to the field `modifier`. */
final Modifier getModifier(int i) { unified_catch_clause_modifier(this, i, result) }
@@ -361,7 +358,6 @@ module Unified {
/** Gets a field or child node of this node. */
final override AstNode getAFieldOrChild() {
unified_catch_clause_def(this, result) or
- unified_catch_clause_guard(this, result) or
unified_catch_clause_modifier(this, _, result) or
unified_catch_clause_pattern(this, result)
}
@@ -427,6 +423,28 @@ module Unified {
}
}
+ /** A class representing `conditional_pattern` nodes. */
+ final class ConditionalPattern extends @unified_conditional_pattern, AstNodeImpl {
+ /** Gets the name of the primary QL class for this element. */
+ final override string getAPrimaryQlClass() { result = "ConditionalPattern" }
+
+ /** Gets the node corresponding to the field `condition`. */
+ final Expr getCondition() { unified_conditional_pattern_def(this, result, _) }
+
+ /** Gets the node corresponding to the field `modifier`. */
+ final Modifier getModifier(int i) { unified_conditional_pattern_modifier(this, i, result) }
+
+ /** Gets the node corresponding to the field `pattern`. */
+ final Pattern getPattern() { unified_conditional_pattern_def(this, _, result) }
+
+ /** Gets a field or child node of this node. */
+ final override AstNode getAFieldOrChild() {
+ unified_conditional_pattern_def(this, result, _) or
+ unified_conditional_pattern_modifier(this, _, result) or
+ unified_conditional_pattern_def(this, _, result)
+ }
+ }
+
/** A class representing `constructor_declaration` nodes. */
final class ConstructorDeclaration extends @unified_constructor_declaration, AstNodeImpl {
/** Gets the name of the primary QL class for this element. */
@@ -1125,9 +1143,6 @@ module Unified {
/** Gets the node corresponding to the field `body`. */
final Block getBody() { unified_switch_case_def(this, result) }
- /** Gets the node corresponding to the field `guard`. */
- final Expr getGuard() { unified_switch_case_guard(this, result) }
-
/** Gets the node corresponding to the field `modifier`. */
final Modifier getModifier(int i) { unified_switch_case_modifier(this, i, result) }
@@ -1137,7 +1152,6 @@ module Unified {
/** Gets a field or child node of this node. */
final override AstNode getAFieldOrChild() {
unified_switch_case_def(this, result) or
- unified_switch_case_guard(this, result) or
unified_switch_case_modifier(this, _, result) or
unified_switch_case_pattern(this, result)
}
@@ -1541,8 +1555,6 @@ module Unified {
or
result = node.(CatchClause).getBody() and i = -1 and name = "getBody"
or
- result = node.(CatchClause).getGuard() and i = -1 and name = "getGuard"
- or
result = node.(CatchClause).getModifier(i) and name = "getModifier"
or
result = node.(CatchClause).getPattern() and i = -1 and name = "getPattern"
@@ -1565,6 +1577,12 @@ module Unified {
or
result = node.(CompoundAssignExpr).getValue() and i = -1 and name = "getValue"
or
+ result = node.(ConditionalPattern).getCondition() and i = -1 and name = "getCondition"
+ or
+ result = node.(ConditionalPattern).getModifier(i) and name = "getModifier"
+ or
+ result = node.(ConditionalPattern).getPattern() and i = -1 and name = "getPattern"
+ or
result = node.(ConstructorDeclaration).getBody() and i = -1 and name = "getBody"
or
result = node.(ConstructorDeclaration).getModifier(i) and name = "getModifier"
@@ -1721,8 +1739,6 @@ module Unified {
or
result = node.(SwitchCase).getBody() and i = -1 and name = "getBody"
or
- result = node.(SwitchCase).getGuard() and i = -1 and name = "getGuard"
- or
result = node.(SwitchCase).getModifier(i) and name = "getModifier"
or
result = node.(SwitchCase).getPattern() and i = -1 and name = "getPattern"
diff --git a/unified/ql/lib/codeql/unified/internal/Variables.qll b/unified/ql/lib/codeql/unified/internal/Variables.qll
index 97629f2c57f..539f19930dc 100644
--- a/unified/ql/lib/codeql/unified/internal/Variables.qll
+++ b/unified/ql/lib/codeql/unified/internal/Variables.qll
@@ -178,12 +178,12 @@ private module LocalNameBindingInput implements LocalNameBindingInputSig;
diff --git a/unified/ql/lib/unified.dbscheme b/unified/ql/lib/unified.dbscheme
index 3aafb2a494f..8306c3fcf0c 100644
--- a/unified/ql/lib/unified.dbscheme
+++ b/unified/ql/lib/unified.dbscheme
@@ -292,11 +292,6 @@ unified_call_expr_def(
int callee: @unified_expr_or_type ref
);
-unified_catch_clause_guard(
- unique int unified_catch_clause: @unified_catch_clause ref,
- unique int guard: @unified_expr ref
-);
-
#keyset[unified_catch_clause, index]
unified_catch_clause_modifier(
int unified_catch_clause: @unified_catch_clause ref,
@@ -365,6 +360,19 @@ unified_compound_assign_expr_def(
int value: @unified_expr ref
);
+#keyset[unified_conditional_pattern, index]
+unified_conditional_pattern_modifier(
+ int unified_conditional_pattern: @unified_conditional_pattern ref,
+ int index: int ref,
+ unique int modifier: @unified_token_modifier ref
+);
+
+unified_conditional_pattern_def(
+ unique int id: @unified_conditional_pattern,
+ int condition: @unified_expr ref,
+ int pattern: @unified_pattern ref
+);
+
#keyset[unified_constructor_declaration, index]
unified_constructor_declaration_modifier(
int unified_constructor_declaration: @unified_constructor_declaration ref,
@@ -767,7 +775,7 @@ unified_parameter_def(
unique int id: @unified_parameter
);
-@unified_pattern = @unified_bulk_importing_pattern | @unified_constructor_pattern | @unified_expr_equality_pattern | @unified_name_pattern | @unified_or_pattern | @unified_token_ignore_pattern | @unified_token_unsupported_node | @unified_tuple_pattern
+@unified_pattern = @unified_bulk_importing_pattern | @unified_conditional_pattern | @unified_constructor_pattern | @unified_expr_equality_pattern | @unified_name_pattern | @unified_or_pattern | @unified_token_ignore_pattern | @unified_token_unsupported_node | @unified_tuple_pattern
unified_pattern_element_key(
unique int unified_pattern_element: @unified_pattern_element ref,
@@ -803,11 +811,6 @@ unified_return_expr_def(
@unified_stmt = @unified_accessor_declaration | @unified_class_like_declaration | @unified_constructor_declaration | @unified_destructor_declaration | @unified_do_while_stmt | @unified_expr | @unified_for_each_stmt | @unified_function_declaration | @unified_guard_if_stmt | @unified_import_declaration | @unified_labeled_stmt | @unified_operator_syntax_declaration | @unified_type_alias_declaration | @unified_variable_declaration | @unified_while_stmt
-unified_switch_case_guard(
- unique int unified_switch_case: @unified_switch_case ref,
- unique int guard: @unified_expr ref
-);
-
#keyset[unified_switch_case, index]
unified_switch_case_modifier(
int unified_switch_case: @unified_switch_case ref,
@@ -1085,7 +1088,7 @@ unified_trivia_tokeninfo(
string value: string ref
);
-@unified_ast_node = @unified_accessor_declaration | @unified_argument | @unified_array_literal | @unified_assign_expr | @unified_associated_type_declaration | @unified_base_type | @unified_binary_expr | @unified_block | @unified_bound_type_constraint | @unified_break_expr | @unified_bulk_importing_pattern | @unified_call_expr | @unified_catch_clause | @unified_class_like_declaration | @unified_compound_assign_expr | @unified_constructor_declaration | @unified_constructor_pattern | @unified_continue_expr | @unified_destructor_declaration | @unified_do_while_stmt | @unified_equality_type_constraint | @unified_expr_equality_pattern | @unified_for_each_stmt | @unified_function_declaration | @unified_function_expr | @unified_function_type_expr | @unified_generic_type_expr | @unified_guard_if_stmt | @unified_if_expr | @unified_import_declaration | @unified_initializer_declaration | @unified_key_value_pair | @unified_labeled_stmt | @unified_map_literal | @unified_member_access_expr | @unified_name_expr | @unified_name_pattern | @unified_named_type_expr | @unified_operator_syntax_declaration | @unified_or_pattern | @unified_parameter | @unified_pattern_element | @unified_pattern_guard_expr | @unified_return_expr | @unified_switch_case | @unified_switch_expr | @unified_throw_expr | @unified_token | @unified_top_level | @unified_trivia_token | @unified_try_expr | @unified_tuple_expr | @unified_tuple_pattern | @unified_tuple_type_element | @unified_tuple_type_expr | @unified_type_alias_declaration | @unified_type_cast_expr | @unified_type_parameter | @unified_type_test_expr | @unified_type_test_pattern | @unified_unary_expr | @unified_unresolved_operator_sequence | @unified_variable_declaration | @unified_while_stmt
+@unified_ast_node = @unified_accessor_declaration | @unified_argument | @unified_array_literal | @unified_assign_expr | @unified_associated_type_declaration | @unified_base_type | @unified_binary_expr | @unified_block | @unified_bound_type_constraint | @unified_break_expr | @unified_bulk_importing_pattern | @unified_call_expr | @unified_catch_clause | @unified_class_like_declaration | @unified_compound_assign_expr | @unified_conditional_pattern | @unified_constructor_declaration | @unified_constructor_pattern | @unified_continue_expr | @unified_destructor_declaration | @unified_do_while_stmt | @unified_equality_type_constraint | @unified_expr_equality_pattern | @unified_for_each_stmt | @unified_function_declaration | @unified_function_expr | @unified_function_type_expr | @unified_generic_type_expr | @unified_guard_if_stmt | @unified_if_expr | @unified_import_declaration | @unified_initializer_declaration | @unified_key_value_pair | @unified_labeled_stmt | @unified_map_literal | @unified_member_access_expr | @unified_name_expr | @unified_name_pattern | @unified_named_type_expr | @unified_operator_syntax_declaration | @unified_or_pattern | @unified_parameter | @unified_pattern_element | @unified_pattern_guard_expr | @unified_return_expr | @unified_switch_case | @unified_switch_expr | @unified_throw_expr | @unified_token | @unified_top_level | @unified_trivia_token | @unified_try_expr | @unified_tuple_expr | @unified_tuple_pattern | @unified_tuple_type_element | @unified_tuple_type_expr | @unified_type_alias_declaration | @unified_type_cast_expr | @unified_type_parameter | @unified_type_test_expr | @unified_type_test_pattern | @unified_unary_expr | @unified_unresolved_operator_sequence | @unified_variable_declaration | @unified_while_stmt
unified_ast_node_location(
unique int node: @unified_ast_node ref,
diff --git a/unified/ql/test/library-tests/variables/test.swift b/unified/ql/test/library-tests/variables/test.swift
index 0e6c23782b0..35aac75d393 100644
--- a/unified/ql/test/library-tests/variables/test.swift
+++ b/unified/ql/test/library-tests/variables/test.swift
@@ -80,7 +80,7 @@ func t10(value: Int) { // name=value1
// Switch with multiple cases
func t11(value: Int) { // name=value1
switch value { // $ access=value1
- case let x where x > 0: // name=x1
+ case let x where x > 0: // $ access=x1 // name=x1
print(x) // $ access=x1
case let x: // name=x2
print(x) // $ access=x2
@@ -187,6 +187,8 @@ func t22() {
}
inner() // $ access=inner1
print(x) // $ access=x1
+ let inner = 2 // name=inner2
+ print(inner) // $ access=inner2
}
// Three levels of shadowing
@@ -214,7 +216,7 @@ func t24(optional: Int?) { // name=optional1
}
}
-// Switch with same variable name in different cases
+// Switch with variable shadowed within body of case
func t25(value: Int) { // name=value1
switch value { // $ access=value1
case let x: // name=x1
diff --git a/unified/scripts/regenerate-grammar.sh b/unified/scripts/regenerate-grammar.sh
deleted file mode 100755
index b7a5ce263fb..00000000000
--- a/unified/scripts/regenerate-grammar.sh
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/bin/bash
-# Regenerate the vendored tree-sitter-swift parser tables from grammar.js,
-# then refresh the human-readable node-types.yml companion file.
-#
-# Run this after editing
-# unified/extractor/tree-sitter-swift/grammar.js so that:
-# * src/parser.c, src/grammar.json, src/node-types.json (and the
-# src/tree_sitter/*.h headers) reflect the current grammar; and
-# * node-types.yml shows the same information in a form that's
-# pleasant to review in PR diffs.
-#
-# Requirements: tree-sitter CLI on PATH, and a working cargo toolchain.
-set -euo pipefail
-
-cd "$(dirname "$0")/.."
-SWIFT_DIR="extractor/tree-sitter-swift"
-
-(
- cd "$SWIFT_DIR"
- tree-sitter generate
-)
-
-# Build yeast's node_types_yaml binary and use it to convert the freshly
-# generated src/node-types.json into the human-readable node-types.yml.
-cargo run --release --quiet -p yeast --bin node_types_yaml -- \
- --from-json "$SWIFT_DIR/src/node-types.json" > "$SWIFT_DIR/node-types.yml"
-
-echo "Regenerated $SWIFT_DIR/{src/parser.c,src/grammar.json,src/node-types.json,node-types.yml}"