Skip to content

Commit 9f6bd88

Browse files
committed
unified: vendor in tree-sitter-swift
1 parent 36554d1 commit 9f6bd88

27 files changed

Lines changed: 599675 additions & 0 deletions
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
load("@rules_rust//cargo:defs.bzl", "cargo_build_script")
2+
load("@rules_rust//rust:defs.bzl", "rust_library")
3+
load("//misc/bazel/3rdparty/tree_sitter_extractors_deps:defs.bzl", "aliases", "all_crate_deps")
4+
5+
package(default_visibility = ["//visibility:public"])
6+
7+
# This will run the build script from the root of the workspace, and
8+
# collect the outputs.
9+
cargo_build_script(
10+
name = "tree-sitter-swift-build",
11+
srcs = ["bindings/rust/build.rs"],
12+
data = glob([
13+
"src/**",
14+
]),
15+
deps = all_crate_deps(
16+
build = True,
17+
),
18+
)
19+
20+
rust_library(
21+
name = "tree-sitter-swift",
22+
srcs = [
23+
"bindings/rust/lib.rs",
24+
],
25+
aliases = aliases(),
26+
compile_data = glob([
27+
"src/**",
28+
"queries/**",
29+
]) + [
30+
"grammar.js",
31+
],
32+
proc_macro_deps = all_crate_deps(
33+
proc_macro = True,
34+
),
35+
deps = [":tree-sitter-swift-build"] + all_crate_deps(
36+
normal = True,
37+
),
38+
)
39+
40+
exports_files(["Cargo.toml"])
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
[package]
2+
name = "tree-sitter-swift"
3+
description = "Swift grammar for the tree-sitter parsing library (vendored copy for the unified extractor)"
4+
version = "0.7.2"
5+
keywords = ["incremental", "parsing", "swift"]
6+
categories = ["parsing", "text-editors"]
7+
repository = "https://github.com/alex-pinkus/tree-sitter-swift"
8+
edition = "2024"
9+
license = "MIT"
10+
11+
build = "bindings/rust/build.rs"
12+
13+
[lib]
14+
path = "bindings/rust/lib.rs"
15+
16+
# When updating these dependencies, run `misc/bazel/3rdparty/update_cargo_deps.sh`
17+
[dependencies]
18+
tree-sitter-language = "0.1"
19+
20+
[build-dependencies]
21+
cc = "1.2"
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2021 alex-pinkus
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
![Parse rate badge](https://byob.yarr.is/alex-pinkus/tree-sitter-swift/parse_rate)
2+
[![Crates.io badge](https://byob.yarr.is/alex-pinkus/tree-sitter-swift/crates_io_version)](https://crates.io/crates/tree-sitter-swift)
3+
[![NPM badge](https://byob.yarr.is/alex-pinkus/tree-sitter-swift/npm_version)](https://www.npmjs.com/package/tree-sitter-swift)
4+
[![Build](https://github.com/alex-pinkus/tree-sitter-swift/actions/workflows/top-repos.yml/badge.svg)](https://github.com/alex-pinkus/tree-sitter-swift/actions/workflows/top-repos.yml)
5+
6+
# tree-sitter-swift
7+
8+
This contains a [`tree-sitter`](https://tree-sitter.github.io/tree-sitter) grammar for the Swift programming language.
9+
10+
## Getting started
11+
12+
To use this parser to parse Swift code, you'll want to depend on either the Rust crate or the NPM package.
13+
14+
### Rust
15+
16+
To use the Rust crate, you'll add this to your `Cargo.toml`:
17+
18+
```
19+
tree-sitter = "0.23.0"
20+
tree-sitter-swift = "=0.7.0"
21+
```
22+
23+
Then you can use a `tree-sitter` parser with the language declared here:
24+
25+
```
26+
let mut parser = tree_sitter::Parser::new();
27+
parser.set_language(tree_sitter_swift::language())?;
28+
29+
// ...
30+
31+
let tree = parser.parse(&my_source_code, None)
32+
.ok_or_else(|| /* error handling code */)?;
33+
```
34+
35+
### Javascript
36+
37+
To use this from NPM, you'll add similar dependencies to `package.json`:
38+
39+
```
40+
"dependencies: {
41+
"tree-sitter-swift": "0.7.0",
42+
"tree-sitter": "^0.22.1"
43+
}
44+
```
45+
46+
Your usage of the parser will look like:
47+
48+
```
49+
const Parser = require("tree-sitter");
50+
const Swift = require("tree-sitter-swift");
51+
52+
const parser = new Parser();
53+
parser.setLanguage(Swift);
54+
55+
// ...
56+
57+
const tree = parser.parse(mySourceCode);
58+
```
59+
60+
### Editing the grammar
61+
62+
With this package checked out, a common workflow for editing the grammar will look something like:
63+
64+
1. Make a change to `grammar.ts`.
65+
2. Run `npm install && npm test` to see whether the change has had impact on existing parsing behavior. The default
66+
`npm test` target requires `valgrind` to be installed; if you do not have it installed, and do not wish to, you can
67+
substitute `tree-sitter test` directly.
68+
3. Run `tree-sitter parse` on some real Swift codebase and see whether (or where) it fails.
69+
4. Use any failures to create new corpus test cases.
70+
71+
## Contributions
72+
73+
All contributions to this repository are welcome.
74+
75+
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.
76+
77+
## Using tree-sitter-swift in Web Assembly
78+
79+
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
80+
module. [see](https://github.com/tree-sitter/tree-sitter/blob/master/lib/binding_web/README.md). Follow the instructions below
81+
82+
1. Install the node modules `npm install web-tree-sitter tree-sitter-swift`
83+
2. Run the tree-sitter cli to create the wasm bundle
84+
```sh
85+
$ npx tree-sitter build-asm ./node_modules/tree-sitter
86+
```
87+
3. Boot tree-sitter wasm like this.
88+
89+
```js
90+
const Parser = require("web-tree-sitter");
91+
async function run() {
92+
//needs to happen first
93+
await Parser.init();
94+
//wait for the load of swift
95+
const Swift = await Parser.Language.load("./tree-sitter-swift.wasm");
96+
97+
const parser = new Parser();
98+
parser.setLanguage(Swift);
99+
100+
//Parse your swift code here.
101+
const tree = parser.parse('print("Hello, World!")');
102+
}
103+
//if you want to run this
104+
run().then(console.log, console.error);
105+
```
106+
107+
## Frequently asked questions
108+
109+
### Where is your `parser.c`?
110+
111+
This repository currently omits most of the code that is autogenerated during a build. This means, for instance, that
112+
`grammar.json` and `parser.c` are both only available following a build. It also significantly reduces noise during
113+
diffs.
114+
115+
The side benefit of not checking in `parser.c` is that you can guarantee backwards compatibility. Parsers generated by
116+
the tree-sitter CLI aren't always backwards compatible. If you need a parser, generate it yourself using the CLI; all
117+
the information to do so is available in this package. By doing that, you'll also know for sure that your parser version
118+
and your library version are compatible.
119+
120+
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
121+
allow you to obtain the parser, you can just download one from a recent workflow run in this package. To do so:
122+
123+
- Go to the [GitHub actions page](https://github.com/alex-pinkus/tree-sitter-swift/actions) for this
124+
repository.
125+
- Click on the "Publish `grammar.json` and `parser.c`" action for the appropriate commit.
126+
- Go down to `Artifacts` and click on `generated-parser-src`. All the relevant parser files will be available in your
127+
download.
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
{
2+
"targets": [
3+
{
4+
"target_name": "tree_sitter_swift_binding",
5+
"dependencies": [
6+
"<!(node -p \"require('node-addon-api').targets\"):node_addon_api_except",
7+
],
8+
"include_dirs": [
9+
"src",
10+
],
11+
"sources": [
12+
"bindings/node/binding.cc",
13+
"src/parser.c",
14+
# NOTE: if your language has an external scanner, add it here.
15+
"src/scanner.c",
16+
],
17+
"cflags_c": [
18+
"-std=c11",
19+
],
20+
"actions": [
21+
{
22+
"action_name": "wait_for_tree_sitter",
23+
"action": ["node", "scripts/wait-for-tree-sitter.js"],
24+
"inputs": [],
25+
"outputs": ["node_modules/tree-sitter-cli"]
26+
},
27+
{
28+
"action_name": "generate_header_files",
29+
"inputs": [
30+
"grammar.js",
31+
"node_modules/tree-sitter-cli"
32+
],
33+
"outputs": [
34+
"src/grammar.json",
35+
"src/node-types.json",
36+
"src/parser.c",
37+
"src/tree_sitter",
38+
],
39+
"action": ["tree-sitter", "generate", "--no-bindings"],
40+
}
41+
]
42+
}
43+
]
44+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#include <napi.h>
2+
3+
typedef struct TSLanguage TSLanguage;
4+
5+
extern "C" TSLanguage *tree_sitter_swift();
6+
7+
// "tree-sitter", "language" hashed with BLAKE2
8+
const napi_type_tag LANGUAGE_TYPE_TAG = {
9+
0x8AF2E5212AD58ABF, 0xD5006CAD83ABBA16
10+
};
11+
12+
Napi::Object Init(Napi::Env env, Napi::Object exports) {
13+
exports["name"] = Napi::String::New(env, "swift");
14+
auto language = Napi::External<TSLanguage>::New(env, tree_sitter_swift());
15+
language.TypeTag(&LANGUAGE_TYPE_TAG);
16+
exports["language"] = language;
17+
return exports;
18+
}
19+
20+
NODE_API_MODULE(tree_sitter_swift_binding, Init)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
const root = require("path").join(__dirname, "..", "..");
2+
3+
module.exports = require("node-gyp-build")(root);
4+
5+
try {
6+
module.exports.nodeTypeInfo = require("../../src/node-types.json");
7+
} catch (_) {}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
fn main() {
2+
let src_dir = std::path::Path::new("src");
3+
4+
let mut c_config = cc::Build::new();
5+
c_config.std("c11").include(src_dir);
6+
7+
#[cfg(target_env = "msvc")]
8+
c_config.flag("-utf-8");
9+
10+
let parser_path = src_dir.join("parser.c");
11+
c_config.file(&parser_path);
12+
println!("cargo:rerun-if-changed={}", parser_path.to_str().unwrap());
13+
14+
let scanner_path = src_dir.join("scanner.c");
15+
c_config.file(&scanner_path);
16+
println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap());
17+
18+
c_config.compile("tree-sitter-swift");
19+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
//! This crate provides Swift language support for the [tree-sitter][] parsing library.
2+
//!
3+
//! Typically, you will use the [language][language func] function to add this language to a
4+
//! tree-sitter [Parser][], and then use the parser to parse some code:
5+
//!
6+
//! ```
7+
//! let code = r#"
8+
//! "#;
9+
//! let mut parser = tree_sitter::Parser::new();
10+
//! let language = tree_sitter_swift::LANGUAGE;
11+
//! parser
12+
//! .set_language(&language.into())
13+
//! .expect("Error loading Swift parser");
14+
//! let tree = parser.parse(code, None).unwrap();
15+
//! assert!(!tree.root_node().has_error());
16+
//! ```
17+
//!
18+
//! [Language]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Language.html
19+
//! [language func]: fn.language.html
20+
//! [Parser]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Parser.html
21+
//! [tree-sitter]: https://tree-sitter.github.io/
22+
23+
use tree_sitter_language::LanguageFn;
24+
25+
unsafe extern "C" {
26+
fn tree_sitter_swift() -> *const ();
27+
}
28+
29+
/// The tree-sitter [`LanguageFn`] for this grammar.
30+
pub const LANGUAGE: LanguageFn = unsafe { LanguageFn::from_raw(tree_sitter_swift) };
31+
32+
/// The content of the [`node-types.json`][] file for this grammar.
33+
///
34+
/// [`node-types.json`]: https://tree-sitter.github.io/tree-sitter/using-parsers#static-node-types
35+
pub const NODE_TYPES: &str = include_str!("../../src/node-types.json");
36+
37+
pub const HIGHLIGHTS_QUERY: &str = include_str!("../../queries/highlights.scm");
38+
pub const INJECTIONS_QUERY: &str = include_str!("../../queries/injections.scm");
39+
pub const LOCALS_QUERY: &str = include_str!("../../queries/locals.scm");
40+
pub const TAGS_QUERY: &str = include_str!("../../queries/tags.scm");
41+
42+
#[cfg(test)]
43+
mod tests {
44+
#[test]
45+
fn test_can_load_grammar() {
46+
let mut parser = tree_sitter::Parser::new();
47+
parser
48+
.set_language(&super::LANGUAGE.into())
49+
.expect("Error loading Swift parser");
50+
}
51+
52+
#[test]
53+
fn test_can_parse_basic_file() {
54+
let mut parser = tree_sitter::Parser::new();
55+
parser
56+
.set_language(&super::LANGUAGE.into())
57+
.expect("Error loading Swift parser");
58+
59+
let tree = parser
60+
.parse("_ = \"Hello!\"\n", None)
61+
.expect("Unable to parse!");
62+
63+
assert_eq!(
64+
"(source_file (assignment target: (directly_assignable_expression (simple_identifier)) result: (line_string_literal text: (line_str_text))))",
65+
tree.root_node().to_sexp(),
66+
);
67+
}
68+
}

0 commit comments

Comments
 (0)