Update Swift parser to use crate

pull/730/merge
Wilfred Hughes 2025-02-22 21:41:08 +07:00
parent 97bab83730
commit 1b04d17c4d
65 changed files with 18 additions and 402953 deletions

@ -2,7 +2,7 @@
### Parsing
Updated to the latest tree-sitter parser for Pascal.
Updated to the latest tree-sitter parser for Pascal and Swift.
## 0.63 (released 11th February 2025)

11
Cargo.lock generated

@ -299,6 +299,7 @@ dependencies = [
"tree-sitter-ruby",
"tree-sitter-rust",
"tree-sitter-scala",
"tree-sitter-swift",
"tree-sitter-toml-ng",
"tree-sitter-typescript",
"tree-sitter-xml",
@ -1248,6 +1249,16 @@ dependencies = [
"tree-sitter-language",
]
[[package]]
name = "tree-sitter-swift"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bdc72ea9c62a6d188c9f7d64109a9b14b09231852b87229c68c44e8738b9e6b9"
dependencies = [
"cc",
"tree-sitter-language",
]
[[package]]
name = "tree-sitter-toml-ng"
version = "0.7.0"

@ -102,6 +102,7 @@ tree-sitter-rust = "0.23.2"
tree-sitter-elixir = "0.3.4"
tree-sitter-nix = "0.0.2"
tree-sitter-pascal = "0.10.0"
tree-sitter-swift = "0.7.0"
[dev-dependencies]
# assert_cmd 2.0.10 requires predicates 3.

@ -212,11 +212,6 @@ fn main() {
src_dir: "vendored_parsers/tree-sitter-sql-src",
extra_files: vec!["scanner.cc"],
},
TreeSitterParser {
name: "tree-sitter-swift",
src_dir: "vendored_parsers/tree-sitter-swift-src",
extra_files: vec!["scanner.c"],
},
TreeSitterParser {
name: "tree-sitter-vhdl",
src_dir: "vendored_parsers/tree-sitter-vhdl-src",

@ -88,7 +88,6 @@ extern "C" {
fn tree_sitter_scss() -> ts::Language;
fn tree_sitter_solidity() -> ts::Language;
fn tree_sitter_sql() -> ts::Language;
fn tree_sitter_swift() -> ts::Language;
fn tree_sitter_vhdl() -> ts::Language;
fn tree_sitter_zig() -> ts::Language;
}
@ -1002,16 +1001,15 @@ pub(crate) fn from_language(language: guess::Language) -> TreeSitterConfig {
}
}
Swift => {
let language = unsafe { tree_sitter_swift() };
let language_fn = tree_sitter_swift::LANGUAGE;
let language = tree_sitter::Language::new(language_fn);
TreeSitterConfig {
language: language.clone(),
atom_nodes: ["line_string_literal"].into_iter().collect(),
delimiter_tokens: vec![("{", "}"), ("(", ")"), ("[", "]"), ("<", ">")],
highlight_query: ts::Query::new(
&language,
include_str!("../../vendored_parsers/highlights/swift.scm"),
)
.unwrap(),
highlight_query: ts::Query::new(&language, tree_sitter_swift::HIGHLIGHTS_QUERY)
.unwrap(),
sub_languages: vec![],
}
}

@ -1 +0,0 @@
tree-sitter-swift/src

@ -1 +0,0 @@
test/highlight/* linguist-vendored

@ -1,33 +0,0 @@
name: Check compilation/bindings/style
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Use Node.js 16.x
uses: actions/setup-node@v2
with:
node-version: 16.x
cache: 'npm'
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
- run: npm install
- run: npm run ci
- run: npm run test-ci
- run: make install
env:
PREFIX: /tmp
- run: cargo test
- run: cd ./test-npm-package && npm test; cd -
- run: npm pack && cd .. && npm install -g ./tree-sitter-swift/tree-sitter-swift-*.tgz; cd -

@ -1,15 +0,0 @@
name: Check in static grammar files
on:
push:
tags:
- '*'
jobs:
generate_grammar:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- run: ./scripts/write-generated-grammar.sh ${{github.ref}}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

@ -1,23 +0,0 @@
name: Publish `grammar.json` and `parser.c`
on:
push:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Use Node.js
uses: actions/setup-node@v2
with:
node-version: 16.x
cache: 'npm'
- run: npm install
- run: npm run test-ci
- name: Publish parser source
uses: actions/upload-artifact@v2
with:
name: generated-parser-src
path: src

@ -1,66 +0,0 @@
name: Publish to `npm` and `crates.io`
on:
workflow_run:
workflows: ["Parse top repositories"]
types:
- completed
jobs:
npm_publish:
if: ${{ github.ref == 'refs/heads/main' }}
runs-on: ubuntu-latest
outputs:
type: ${{ steps.npm_publish.outputs.type }}
package_version: ${{ steps.npm_publish.outputs.version }}
steps:
- uses: actions/checkout@v1
- uses: actions/setup-node@v1
with:
node-version: 16
- run: npm install
- run: npm run test-ci
- run: cd ./test-npm-package && npm test; cd ..
- uses: JS-DevTools/npm-publish@v1
id: npm_publish
with:
token: ${{ secrets.NPM_TOKEN }}
crates_io_publish:
runs-on: ubuntu-latest
needs: npm_publish
if: ${{ needs.npm_publish.outputs.type != 'none' }}
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
- run: npm install
- run: npm run test-ci
- run: cargo test
- uses: katyo/publish-crates@v1
with:
registry-token: ${{ secrets.CARGO_REGISTRY_TOKEN }}
args: --allow-dirty
badge_update:
runs-on: ubuntu-latest
needs:
- npm_publish
- crates_io_publish
steps:
- name: Update crates.io badge
uses: RubbaBoy/BYOB@v1.3.0
with:
NAME: crates_io_version
LABEL: 'crates.io'
STATUS: ${{ needs.npm_publish.outputs.package_version }}
COLOR: green
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Update npm badge
uses: RubbaBoy/BYOB@v1.3.0
with:
NAME: npm_version
LABEL: 'npm'
STATUS: ${{ needs.npm_publish.outputs.package_version }}
COLOR: green
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

@ -1,25 +0,0 @@
name: Check compilation on tree-sitter 0.19
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Use Node.js 16.x
uses: actions/setup-node@v2
with:
node-version: 16.x
cache: 'npm'
- run: cp package-json-old-tree-sitter.json package.json
- run: npm install
# corpus tests fail and highlight tests are extremely slow; just remove them!
- run: rm -r test
- run: npx tree-sitter test

@ -1,92 +0,0 @@
name: Parse top repositories
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
repo:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
with:
node-version: '16.x'
cache: 'npm'
- run: npm install
- run: ./scripts/top-repos.sh ${{matrix.repo}}
badge_gen:
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v2
- id: parse_rate
run: echo "##[set-output name=parse_rate;]$(./scripts/calculate-parse-rate.sh)"
- name: BYOB
if: ${{ github.event_name == 'push' }}
uses: RubbaBoy/BYOB@v1.3.0
with:
NAME: parse_rate
LABEL: 'Parse rate'
STATUS: ${{ steps.parse_rate.outputs.parse_rate }}
COLOR: blue
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

@ -1,14 +0,0 @@
name: Update corpus repository versions
on:
schedule:
- cron: '12 4 * * 0'
jobs:
update_repository_versions:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- run: ./scripts/update-top-repos.sh
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

@ -1,15 +0,0 @@
node_modules
/src/*
!/src/scanner.c
*.swp
/build
Cargo.lock
/target/*
*.a
*.dylib
*.so
*.o
bindings/c/*.h
bindings/c/tree-sitter-*.pc
.vscode/
/.build

@ -1,29 +0,0 @@
[package]
name = "tree-sitter-swift"
description = "swift grammar for the tree-sitter parsing library"
version = "0.3.4"
keywords = ["incremental", "parsing", "swift"]
categories = ["parsing", "text-editors"]
repository = "https://github.com/alex-pinkus/tree-sitter-swift"
edition = "2018"
license = "MIT"
build = "bindings/rust/build.rs"
include = [
"bindings/rust/*",
"grammar.ts",
"queries/*",
"src/*",
]
[lib]
path = "bindings/rust/lib.rs"
[dependencies]
tree-sitter = "~0.20.0"
[build-dependencies]
cc = "1.0"
[dev-dependencies]
anyhow = "1.0"

@ -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.

@ -1,118 +0,0 @@
VERSION := 0.3.4
# Repository
SRC_DIR := src
PARSER_REPO_URL := $(shell git -C $(SRC_DIR) remote get-url origin )
ifeq (, $(PARSER_NAME))
PARSER_NAME := $(shell basename $(PARSER_REPO_URL))
PARSER_NAME := $(subst tree-sitter-,,$(PARSER_NAME))
PARSER_NAME := $(subst .git,,$(PARSER_NAME))
endif
ifeq (, $(PARSER_URL))
PARSER_URL := $(subst :,/,$(PARSER_REPO_URL))
PARSER_URL := $(subst git@,https://,$(PARSER_URL))
PARSER_URL := $(subst .git,,$(PARSER_URL))
endif
UPPER_PARSER_NAME := $(shell echo $(PARSER_NAME) | tr a-z A-Z )
# install directory layout
PREFIX ?= /usr/local
INCLUDEDIR ?= $(PREFIX)/include
LIBDIR ?= $(PREFIX)/lib
PCLIBDIR ?= $(LIBDIR)/pkgconfig
# collect C++ sources, and link if necessary
CPPSRC := $(wildcard $(SRC_DIR)/*.cc)
ifeq (, $(CPPSRC))
ADDITIONALLIBS :=
else
ADDITIONALLIBS := -lc++
endif
# collect sources
SRC := $(wildcard $(SRC_DIR)/*.c)
SRC += $(CPPSRC)
OBJ := $(addsuffix .o,$(basename $(SRC)))
# ABI versioning
SONAME_MAJOR := 0
SONAME_MINOR := 0
CFLAGS ?= -O3 -Wall -Wextra -I$(SRC_DIR)
CXXFLAGS ?= -O3 -Wall -Wextra -I$(SRC_DIR)
override CFLAGS += -std=gnu99 -fPIC
override CXXFLAGS += -fPIC
# OS-specific bits
ifeq ($(shell uname),Darwin)
SOEXT = dylib
SOEXTVER_MAJOR = $(SONAME_MAJOR).dylib
SOEXTVER = $(SONAME_MAJOR).$(SONAME_MINOR).dylib
LINKSHARED := $(LINKSHARED)-dynamiclib -Wl,
ifneq ($(ADDITIONALLIBS),)
LINKSHARED := $(LINKSHARED)$(ADDITIONALLIBS),
endif
LINKSHARED := $(LINKSHARED)-install_name,$(LIBDIR)/libtree-sitter-$(PARSER_NAME).$(SONAME_MAJOR).dylib,-rpath,@executable_path/../Frameworks
else
SOEXT = so
SOEXTVER_MAJOR = so.$(SONAME_MAJOR)
SOEXTVER = so.$(SONAME_MAJOR).$(SONAME_MINOR)
LINKSHARED := $(LINKSHARED)-shared -Wl,
ifneq ($(ADDITIONALLIBS),)
LINKSHARED := $(LINKSHARED)$(ADDITIONALLIBS)
endif
LINKSHARED := $(LINKSHARED)-soname,libtree-sitter-$(PARSER_NAME).so.$(SONAME_MAJOR)
endif
ifneq (,$(filter $(shell uname),FreeBSD NetBSD DragonFly))
PCLIBDIR := $(PREFIX)/libdata/pkgconfig
endif
all: libtree-sitter-$(PARSER_NAME).a libtree-sitter-$(PARSER_NAME).$(SOEXTVER) bindings/c/$(PARSER_NAME).h bindings/c/tree-sitter-$(PARSER_NAME).pc
libtree-sitter-$(PARSER_NAME).a: $(OBJ)
$(AR) rcs $@ $^
libtree-sitter-$(PARSER_NAME).$(SOEXTVER): $(OBJ)
$(CC) $(LDFLAGS) $(LINKSHARED) $^ $(LDLIBS) -o $@
ln -sf $@ libtree-sitter-$(PARSER_NAME).$(SOEXT)
ln -sf $@ libtree-sitter-$(PARSER_NAME).$(SOEXTVER_MAJOR)
bindings/c/$(PARSER_NAME).h:
sed -e 's|@UPPER_PARSERNAME@|$(UPPER_PARSER_NAME)|' \
-e 's|@PARSERNAME@|$(PARSER_NAME)|' \
bindings/c/tree-sitter.h.in > $@
bindings/c/tree-sitter-$(PARSER_NAME).pc:
sed -e 's|@LIBDIR@|$(LIBDIR)|;s|@INCLUDEDIR@|$(INCLUDEDIR)|;s|@VERSION@|$(VERSION)|' \
-e 's|=$(PREFIX)|=$${prefix}|' \
-e 's|@PREFIX@|$(PREFIX)|' \
-e 's|@ADDITIONALLIBS@|$(ADDITIONALLIBS)|' \
-e 's|@PARSERNAME@|$(PARSER_NAME)|' \
-e 's|@PARSERURL@|$(PARSER_URL)|' \
bindings/c/tree-sitter.pc.in > $@
install: all
install -d '$(DESTDIR)$(LIBDIR)'
install -m755 libtree-sitter-$(PARSER_NAME).a '$(DESTDIR)$(LIBDIR)'/libtree-sitter-$(PARSER_NAME).a
install -m755 libtree-sitter-$(PARSER_NAME).$(SOEXTVER) '$(DESTDIR)$(LIBDIR)'/libtree-sitter-$(PARSER_NAME).$(SOEXTVER)
ln -sf libtree-sitter-$(PARSER_NAME).$(SOEXTVER) '$(DESTDIR)$(LIBDIR)'/libtree-sitter-$(PARSER_NAME).$(SOEXTVER_MAJOR)
ln -sf libtree-sitter-$(PARSER_NAME).$(SOEXTVER) '$(DESTDIR)$(LIBDIR)'/libtree-sitter-$(PARSER_NAME).$(SOEXT)
install -d '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter
install -m644 bindings/c/$(PARSER_NAME).h '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter/
install -d '$(DESTDIR)$(PCLIBDIR)'
install -m644 bindings/c/tree-sitter-$(PARSER_NAME).pc '$(DESTDIR)$(PCLIBDIR)'/
# Regenerate the parser if the grammar file is newer.
src/parser.c: grammar.js
npx tree-sitter generate
clean:
rm -f $(OBJ) libtree-sitter-$(PARSER_NAME).a libtree-sitter-$(PARSER_NAME).$(SOEXT) libtree-sitter-$(PARSER_NAME).$(SOEXTVER_MAJOR) libtree-sitter-$(PARSER_NAME).$(SOEXTVER)
rm -f bindings/c/$(PARSER_NAME).h bindings/c/tree-sitter-$(PARSER_NAME).pc
.PHONY: all install clean

@ -1,125 +0,0 @@
![Parse rate badge](https://byob.yarr.is/alex-pinkus/tree-sitter-swift/parse_rate)
[![Crates.io badge](https://byob.yarr.is/alex-pinkus/tree-sitter-swift/crates_io_version)](https://crates.io/crates/tree-sitter-swift)
[![NPM badge](https://byob.yarr.is/alex-pinkus/tree-sitter-swift/npm_version)](https://www.npmjs.com/package/tree-sitter-swift)
[![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)
# 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.20.0"
tree-sitter-swift = "=0.3.4"
```
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.3.4",
"tree-sitter": "^0.20.0"
}
```
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
If you have a change to make to this parser, and the change is a net positive, please submit a pull request. I mostly
started this parser to teach myself how `tree-sitter` works, and how to write a grammar, so I welcome improvements. If
you have an issue with the parser, please file a bug and include a test case to put in the `corpus`. I can't promise any
level of support, but having the test case makes it more likely that I want to tinker with it.
## 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.

@ -1,19 +0,0 @@
{
"targets": [
{
"target_name": "tree_sitter_swift_binding",
"include_dirs": [
"<!(node -e \"require('nan')\")",
"src"
],
"sources": [
"bindings/node/binding.cc",
"src/parser.c",
"src/scanner.c"
],
"cflags_c": [
"-std=c99",
]
}
]
}

@ -1,16 +0,0 @@
#ifndef TREE_SITTER_@UPPER_PARSERNAME@_H_
#define TREE_SITTER_@UPPER_PARSERNAME@_H_
#include <tree_sitter/parser.h>
#ifdef __cplusplus
extern "C" {
#endif
extern TSLanguage *tree_sitter_@PARSERNAME@();
#ifdef __cplusplus
}
#endif
#endif // TREE_SITTER_@UPPER_PARSERNAME@_H_

@ -1,11 +0,0 @@
prefix=@PREFIX@
libdir=@LIBDIR@
includedir=@INCLUDEDIR@
additionallibs=@ADDITIONALLIBS@
Name: tree-sitter-@PARSERNAME@
Description: A tree-sitter grammar for the @PARSERNAME@ programming language.
URL: @PARSERURL@
Version: @VERSION@
Libs: -L${libdir} ${additionallibs} -ltree-sitter-@PARSERNAME@
Cflags: -I${includedir}

@ -1,28 +0,0 @@
#include "tree_sitter/parser.h"
#include <node.h>
#include "nan.h"
using namespace v8;
extern "C" TSLanguage * tree_sitter_swift();
namespace {
NAN_METHOD(New) {}
void Init(Local<Object> exports, Local<Object> module) {
Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate>(New);
tpl->SetClassName(Nan::New("Language").ToLocalChecked());
tpl->InstanceTemplate()->SetInternalFieldCount(1);
Local<Function> constructor = Nan::GetFunction(tpl).ToLocalChecked();
Local<Object> instance = constructor->NewInstance(Nan::GetCurrentContext()).ToLocalChecked();
Nan::SetInternalFieldPointer(instance, 0, tree_sitter_swift());
Nan::Set(instance, Nan::New("name").ToLocalChecked(), Nan::New("swift").ToLocalChecked());
Nan::Set(module, Nan::New("exports").ToLocalChecked(), instance);
}
NODE_MODULE(tree_sitter_swift_binding, Init)
} // namespace

@ -1,19 +0,0 @@
try {
module.exports = require("../../build/Release/tree_sitter_swift_binding");
} catch (error1) {
if (error1.code !== "MODULE_NOT_FOUND") {
throw error1;
}
try {
module.exports = require("../../build/Debug/tree_sitter_swift_binding");
} catch (error2) {
if (error2.code !== "MODULE_NOT_FOUND") {
throw error2;
}
throw error1;
}
}
try {
module.exports.nodeTypeInfo = require("../../src/node-types.json");
} catch (_) {}

@ -1,19 +0,0 @@
fn main() {
let src_dir = std::path::Path::new("src");
let mut c_config = cc::Build::new();
c_config.include(&src_dir);
c_config
.flag_if_supported("-Wno-unused-parameter")
.flag_if_supported("-Wno-unused-but-set-variable")
.flag_if_supported("-Wno-trigraphs");
let parser_path = src_dir.join("parser.c");
c_config.file(&parser_path);
let scanner_path = src_dir.join("scanner.c");
c_config.file(&scanner_path);
println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap());
c_config.compile("parser");
println!("cargo:rerun-if-changed={}", parser_path.to_str().unwrap());
}

@ -1,70 +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 = "";
//! let mut parser = tree_sitter::Parser::new();
//! parser.set_language(tree_sitter_swift::language()).expect("Error loading swift grammar");
//! let tree = parser.parse(code, None).unwrap();
//! ```
//!
//! [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;
extern "C" {
fn tree_sitter_swift() -> Language;
}
/// Get the tree-sitter [Language][] for this grammar.
///
/// [Language]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Language.html
pub fn language() -> Language {
unsafe { 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: &'static str = include_str!("../../src/node-types.json");
// Uncomment these to include any queries that this grammar contains
pub const HIGHLIGHTS_QUERY: &'static str = include_str!("../../queries/highlights.scm");
// pub const INJECTIONS_QUERY: &'static str = include_str!("../../queries/injections.scm");
pub const LOCALS_QUERY: &'static str = include_str!("../../queries/locals.scm");
pub const TAGS_QUERY: &'static str = include_str!("../../queries/tags.scm");
#[cfg(test)]
mod tests {
use anyhow::{anyhow, Result};
#[test]
fn test_can_load_grammar() -> Result<()> {
let mut parser = tree_sitter::Parser::new();
parser.set_language(super::language())?;
Ok(())
}
#[test]
fn test_can_parse_basic_file() -> Result<()> {
let mut parser = tree_sitter::Parser::new();
parser.set_language(super::language())?;
let tree = parser.parse("_ = \"Hello!\"\n", None)
.ok_or_else(|| anyhow!("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(),
);
Ok(())
}
}

File diff suppressed because it is too large Load Diff

@ -1,41 +0,0 @@
{
"name": "tree-sitter-swift",
"version": "0.0.0-old-tree-sitter",
"description": "A tree-sitter grammar for the Swift programming language.",
"main": "bindings/node/index.js",
"scripts": {
"install": "node scripts/wait-for-tree-sitter.js && tree-sitter generate"
},
"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"
}
],
"keywords": [
"parser",
"swift"
],
"author": "Alex Pinkus <alex.pinkus@gmail.com>",
"license": "MIT",
"bugs": {
"url": "https://github.com/alex-pinkus/tree-sitter-swift/issues"
},
"homepage": "https://github.com/alex-pinkus/tree-sitter-swift#readme",
"dependencies": {
"nan": "^2.15.0",
"tree-sitter-cli": "=0.19.0",
"which": "2.0.2"
},
"devDependencies": {
"node-gyp": "^8.4.1",
"prettier": "2.3.2"
}
}

File diff suppressed because it is too large Load Diff

@ -1,45 +0,0 @@
{
"name": "tree-sitter-swift",
"version": "0.3.4",
"description": "A tree-sitter grammar for the Swift programming language.",
"main": "bindings/node/index.js",
"scripts": {
"install": "node scripts/wait-for-tree-sitter.js && tree-sitter generate",
"postinstall": "node-gyp configure && node-gyp build",
"ci": "prettier --check grammar.js",
"test-ci": "./scripts/test-with-memcheck.sh --install-valgrind",
"test": "./scripts/test-with-memcheck.sh"
},
"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"
}
],
"keywords": [
"parser",
"swift"
],
"author": "Alex Pinkus <alex.pinkus@gmail.com>",
"license": "MIT",
"bugs": {
"url": "https://github.com/alex-pinkus/tree-sitter-swift/issues"
},
"homepage": "https://github.com/alex-pinkus/tree-sitter-swift#readme",
"dependencies": {
"nan": "^2.15.0",
"tree-sitter-cli": "=0.20.6",
"which": "2.0.2"
},
"devDependencies": {
"node-gyp": "^8.4.1",
"prettier": "2.3.2"
}
}

@ -1,168 +0,0 @@
[ "." ";" ":" "," ] @punctuation.delimiter
[ "\\(" "(" ")" "[" "]" "{" "}"] @punctuation.bracket ; TODO: "\\(" ")" in interpolations should be @punctuation.special
; Identifiers
(attribute) @variable
(type_identifier) @type
(self_expression) @variable.builtin
; Declarations
"func" @keyword.function
[
(visibility_modifier)
(member_modifier)
(function_modifier)
(property_modifier)
(parameter_modifier)
(inheritance_modifier)
] @keyword
(function_declaration (simple_identifier) @method)
(function_declaration ["init" @constructor])
(throws) @keyword
"async" @keyword
"await" @keyword
(where_keyword) @keyword
(parameter external_name: (simple_identifier) @parameter)
(parameter name: (simple_identifier) @parameter)
(type_parameter (type_identifier) @parameter)
(inheritance_constraint (identifier (simple_identifier) @parameter))
(equality_constraint (identifier (simple_identifier) @parameter))
(pattern bound_identifier: (simple_identifier)) @variable
[
"typealias"
"struct"
"class"
"actor"
"enum"
"protocol"
"extension"
"indirect"
"nonisolated"
"override"
"convenience"
"required"
"some"
] @keyword
[
(getter_specifier)
(setter_specifier)
(modify_specifier)
] @keyword
(class_body (property_declaration (pattern (simple_identifier) @property)))
(protocol_property_declaration (pattern (simple_identifier) @property))
(import_declaration ["import" @include])
(enum_entry ["case" @keyword])
; 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)))
((navigation_expression
(simple_identifier) @type) ; SomeType.method(): highlight SomeType as a type
(#match? @type "^[A-Z]"))
(directive) @function.macro
(diagnostic) @function.macro
; Statements
(for_statement ["for" @repeat])
(for_statement ["in" @repeat])
(for_statement (pattern) @variable)
(else) @keyword
(as_operator) @keyword
["while" "repeat" "continue" "break"] @repeat
["let" "var"] @keyword
(guard_statement ["guard" @conditional])
(if_statement ["if" @conditional])
(switch_statement ["switch" @conditional])
(switch_entry ["case" @keyword])
(switch_entry ["fallthrough" @keyword])
(switch_entry (default_keyword) @keyword)
"return" @keyword.return
(ternary_expression
["?" ":"] @conditional)
["do" (throw_keyword) (catch_keyword)] @keyword
(statement_label) @label
; Comments
[
(comment)
(multiline_comment)
] @comment @spell
; String literals
(line_str_text) @string
(str_escaped_char) @string
(multi_line_str_text) @string
(raw_str_part) @string
(raw_str_end_part) @string
(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) @float
(boolean_literal) @boolean
"nil" @variable.builtin
; Regex literals
(regex_literal) @string.regex
; Operators
(custom_operator) @operator
[
"try"
"try?"
"try!"
"!"
"+"
"-"
"*"
"/"
"%"
"="
"+="
"-="
"*="
"/="
"<"
">"
"<="
">="
"++"
"--"
"&"
"~"
"%="
"!="
"!=="
"=="
"==="
"??"
"->"
"..<"
"..."
] @operator

@ -1,18 +0,0 @@
(import_declaration (identifier) @definition.import)
(function_declaration name: (simple_identifier) @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

@ -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)
)
(function_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)
)
(protocol_function_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

@ -1 +0,0 @@
ReactKit/ReactKitTests/OperationTests.swift

@ -1,53 +0,0 @@
Alamofire Alamofire/Alamofire 5.6.2
iina iina/iina v1.3.0-build131
Charts danielgindi/Charts v4.1.0
lottie-ios airbnb/lottie-ios 3.4.4
vapor vapor/vapor 3.3.3
SwiftyJSON SwiftyJSON/SwiftyJSON 5.0.1
RxSwift ReactiveX/RxSwift 6.5.0 0 9
RxSwift ReactiveX/RxSwift 6.5.0 1 9
RxSwift ReactiveX/RxSwift 6.5.0 2 9
RxSwift ReactiveX/RxSwift 6.5.0 3 9
RxSwift ReactiveX/RxSwift 6.5.0 4 9
RxSwift ReactiveX/RxSwift 6.5.0 5 9
RxSwift ReactiveX/RxSwift 6.5.0 6 9
RxSwift ReactiveX/RxSwift 6.5.0 7 9
RxSwift ReactiveX/RxSwift 6.5.0 8 9
HeroTransitions HeroTransitions/Hero 1.6.2
Kingfisher onevcat/Kingfisher 7.4.0
shadowsocks shadowsocks/ShadowsocksX-NG v1.9.4
SnapKit SnapKit/SnapKit 5.0.1
SwiftLint realm/SwiftLint 0.49.1 0 2
SwiftLint realm/SwiftLint 0.49.1 1 2
ClashX yichengchen/clashX 1.95.1
Carthage Carthage/Carthage 0.38.0
Rectangle rxhanson/Rectangle v0.59
PromiseKit mxcl/PromiseKit 6.18.1
Moya Moya/Moya 15.0.3
MonitorControl MonitorControl/MonitorControl v4.1.0
ObjectMapper tristanhimmelman/ObjectMapper 4.2.0
SkeletonView Juanpe/SkeletonView 1.30.3
firefox-ios mozilla-mobile/firefox-ios v39.0 0 6
firefox-ios mozilla-mobile/firefox-ios v39.0 1 6
firefox-ios mozilla-mobile/firefox-ios v39.0 2 6
firefox-ios mozilla-mobile/firefox-ios v39.0 3 6
firefox-ios mozilla-mobile/firefox-ios v39.0 4 6
firefox-ios mozilla-mobile/firefox-ios v39.0 5 6
AudioKit AudioKit/AudioKit 5.5.6
Starscream daltoniam/Starscream 4.0.4
MessageKit MessageKit/MessageKit 4.0.0
KeychainAccess kishikawakatsumi/KeychainAccess v4.2.2
Nuke kean/Nuke 11.3.0
Swinject Swinject/Swinject 2.8.2
GRDB groue/GRDB.swift v6.0.0 0 2
GRDB groue/GRDB.swift v6.0.0 1 2
Dance saoudrizwan/Dance v1.0.7
StyleKit 146BC/StyleKit 0.7.0
ReactKit ReactKit/ReactKit 0.12.0
JASON delba/JASON 3.1.1
Side-Menu Yalantis/Side-Menu.iOS 2.0.2
C4iOS C4Labs/C4iOS 3.0.1
Taylor izqui/Taylor 0.4.5
Runes thoughtbot/Runes v5.1.0
Overdrive saidsikira/Overdrive 0.3
Tactile delba/Tactile 3.0.1

@ -1,20 +0,0 @@
#!/bin/bash
set -e
parser_dir="$(pwd)"
. $parser_dir/scripts/common.sh
# Check out every repository to figure out how many files they contain.
cd $tmpdir
while read line ; do
checkout $line
done < $top_repositories
file_count=$(find "$tmpdir" -name *.swift -not -path '*/Pods/*' | wc -l)
error_count=$(wc -l < $known_failures)
# Now, since we can assume that the "top-repos" workflow ran, our parse rate is the number of
# successful files over the number of total files. Pretty print that to two decimal places.
printf '%.2f%%\n' $(bc -l <<< "($file_count - $error_count) / $file_count * 100")

@ -1,35 +0,0 @@
#!/bin/bash
set -e
known_failures="$parser_dir/script-data/known_failures.txt"
top_repositories="$parser_dir/script-data/top-repositories.txt"
# Run all this logic in a temporary directory that we delete on exit
tmpdir="$(mktemp -d -t top-10-XXXXXX)"
trap 'rm -rf "$tmpdir"' EXIT
# Function to check out a git repository at a given tag.
#
# We use tags so that the source code is deterministic - tags are immutable and reasonable people
# don't delete and recreate them. The tree-sitter-python script this is based on uses raw SHA hashes
# for this, but that would require us to checkout the code at HEAD first and switch to the code at
# the given hash. Using tags means we can do this in one command and include `--depth 1` to reduce
# the number of extra objects we have to fetch.
function checkout() {
repo=$1; url=$2; tag=$3
if [ ! -d "$repo" ]; then
git clone --quiet --branch $tag --depth 1 "https://github.com/$url" "$repo" >/dev/null 2>/dev/null
fi
}
# Locates all the swift source code files that exist in the source tree under the passed-in
# directory.
#
# Does not include code that gets included from dependencies of this repository, to avoid
# overcounting those files.
function swift_files_under() {
find "$1" -name *.swift -not -path '*/Pods/*'
}

@ -1,11 +0,0 @@
#!/bin/bash
set -e
if [[ "$1" == "--install-valgrind" ]]; then
sudo apt-get update # See https://github.com/facebook/zstd/pull/3082
sudo apt install -y valgrind
shift
fi
valgrind tree-sitter test

@ -1,96 +0,0 @@
#!/bin/bash
set -e
parser_dir="$(pwd)"
. $parser_dir/scripts/common.sh
if [ -z "$1" ]; then
repos=$(cat $top_repositories)
echo "Running on all top repositories."
else
repos=$(sed "$1q;d" $top_repositories)
echo "Running on single repository $repos."
fi
# Function to validate that a passed-in git repository can be parsed using this parser.
#
# If the passed-in repository fails to parse in ways that do not match the `known_failures` script
# data, this prints info about the failure and exits the script with a nonzero status code.
function validate() {
repo=$1; url=$2; tag=$3; part=$4; total=$5
if [ -z "$part" ] || [ -z "$total" ]; then
part=0
total=1
fi
data_dir=$tmpdir/.$repo-data-$part
mkdir -p $data_dir || true
# Find the start and end of this section based on the passed-in `part` and `total`.
all_files=$data_dir/all_files.txt
swift_files_under "$tmpdir/$repo" > $all_files
file_count=$(wc -l < $all_files | tr -d ' ')
one_past_the_end=$((file_count + 1))
start=$(($((one_past_the_end * part)) / total))
next_part=$((part + 1))
next_start=$(($((one_past_the_end * next_part)) / total))
end=$((next_start - 1))
len=$((end - start))
failed_files=$(
IFS=$'\n'
for file in $(head -$end < $all_files | tail -$len); do
npx tree-sitter parse -q "$file" 2>/dev/null
done | { grep -v -f "$known_failures" || true; }
unset IFS
)
if [[ "$failed_files" = *[![:space:]]* ]]; then
echo -en "Unexpected parse failure found in $repo "
if [ -z $4 ]; then
echo ":"
else
echo "block $start-$end:"
fi
cat <<<"$failed_files"
exit 1
elif [ -z $4 ]; then
echo "Parsed $repo successfully!"
else
echo "Parsed $repo files $start-$end of $file_count successfully!"
fi
}
# It's really easy to add a blank line to `known_failures.txt`, which will make everything pass.
# This echoes some string from random.org to prove that the grp isn't excluding everything. If we
# added a blank line, this would have zero items, which results in a nonzero exit code from grep.
if ! echo "vkDSrg8n" | grep -v -f "$known_failures" > /dev/null; then
echo "You added a blank line to known_failures!"
exit 1
fi
# Run `validate` on every repository in `top-repositories` sequentially.
while read line ; do
cd $tmpdir
checkout $line
cd $parser_dir
if [ -z "$1" ]; then
validate $line &
pids+=($!)
else
validate $line
fi
done <<<"$repos"
if [ -z "$1" ]; then
for pid in "${pids[@]}" ; do
wait $pid
done
fi

@ -1,63 +0,0 @@
#!/bin/bash
set -e
parser_dir="$(pwd)"
. $parser_dir/scripts/common.sh
function update() {
repo=$1
cd $tmpdir/$repo
git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"
git fetch origin --unshallow 2>/dev/null || git fetch origin
remote_head_commit=$(git ls-remote | grep HEAD | awk '{ print $1 }')
# Find the oldest branch that contains the remote HEAD commit, which will correspond to the remote HEAD branch (i.e.
# what's sometimes called `main` or `master`. Other branches may be newer than this one if they are a fast-forward
# of `main`, but it's not possible for an _older_ branch to have the commit unless it's literally equivalent. If it
# is equivalent, it doesn't matter.
remote_head_branch=$(git branch -r --contains $remote_head_commit --sort=-committerdate | tac | head -1)
# Figure out which branch the passed-in tag was tracking. We prefer the main branch, if possible, but can fall back
# to another if needed.
if git branch -r --contains HEAD | grep -q $remote_head_branch; then
# Our tag was on `main` (or equivalent), so use that branch directly.
branch=$remote_head_branch
else
# Our tag was not on `main`, so use the newest branch that it _was_ on.
branch=$(git branch -r --contains HEAD --sort=-committerdate | head -1)
fi
# Find the latest tag on this branch, and print it along with the other fields that we were given.
new_tag=$(git describe --tags $branch | sed 's/\(.*\)-.*-.*/\1/')
echo $1 $2 $new_tag $4 $5
}
while read line ; do
cd $tmpdir
checkout $line
update $line
done < $top_repositories > $top_repositories.new
mv $top_repositories.new $top_repositories
# If the repository is now dirty, we have new versions available. Commit them and publish a PR.
cd $parser_dir
if ! git diff --quiet; then
git config --local user.email alex.pinkus@gmail.com
git config --local user.name "Alex Pinkus (Bot)"
git add ./script-data
git commit -m "Updating top repository version"
branch_name=repo-update-$(date +%Y-%m-%d)
git checkout -b $branch_name
echo "Creating pull request..."
gh auth setup-git
git remote add dest "https://$GITHUB_ACTOR:$GITHUB_TOKEN@github.com/$GITHUB_REPOSITORY.git"
git push dest HEAD:$branch_name
git fetch origin
gh pr create --fill
echo "Pull request created!"
else
echo "No repositories have been updated, so there's nothing more to do!"
fi

@ -1,77 +0,0 @@
const fs = require("fs");
const os = require("os");
const path = require("path");
const which = require("which");
const { promisify } = require("util");
const stat = promisify(fs.stat);
async function main() {
const treeSitterExecutable = await which("tree-sitter");
if (!treeSitterExecutable.includes("node_modules")) {
// Not installed through npm, so should be safe.
return;
}
const realTreeSitterDir = path.join(
treeSitterExecutable,
"..",
"..",
"tree-sitter-cli"
);
let timeout = undefined;
let timeoutResolve = undefined;
Promise.race([
waitForOneOf(realTreeSitterDir, ["tree-sitter", "tree-sitter.exe"]).then(
() => {
clearTimeout(timeout);
timeoutResolve();
}
),
new Promise((resolve) => {
timeoutResolve = resolve;
timeout = setTimeout(resolve, 10000);
}),
]);
}
async function waitForOneOf(dir, files) {
for (const file of files) {
try {
if (await canExecute(path.join(dir, file))) {
return;
}
} catch {
// File doesn't yet exist -- we must wait for it.
}
}
await new Promise((resolve) => {
try {
fs.watch(dir, { persistent: false }, (eventType, filename) => {
if (
(eventType !== "rename" || os.platform() !== "win32") &&
files.includes(filename)
) {
let resolved = false;
canExecute(path.join(dir, filename)).then((canExec) => {
if (canExec && !resolved) {
resolve();
resolved = true;
}
});
}
});
} catch (err) {
if (err.name !== "AbortError") {
console.error(err);
}
}
});
}
async function canExecute(filePath) {
const fileStat = await stat(filePath);
return fileStat.mode & 0111 || os.platform() === "win32";
}
main();

@ -1,49 +0,0 @@
#!/bin/bash
set -e
ref=$1
branch_name=with-generated-files
# Load the branch that contains generated grammar files.
git checkout $branch_name
# Update our local directory to match the $ref, but then put the HEAD back at the previous commit.
# This will blow away the existing generated grammar. That's OK because this branch is only ever
# updated using this script.
git reset $ref --hard
git reset HEAD@{1}
# Now generate the grammar and validate that it works. Hopefully no one ever creates a tag to a
# commit with a non-working grammar, but the `npm test` protects us against that ever happening.
npm install
npm run test-ci
# Now that we know the parser works, build for ABI 14 (but don't use this as the default because
# it's not compatible everywhere).
mv src/parser.c src/parser_abi13.c
npx tree-sitter generate --abi 14
mv src/parser.c src/parser_abi14.c
mv src/parser_abi13.c src/parser.c
# Commit specific generated files, attributing the changes to the primary maintainer of this
# grammar. Notably, we do not commit the `.o` files generated during the build, just the source.
git config --local user.email alex.pinkus@gmail.com
git config --local user.name "Alex Pinkus (Bot)"
git add ./src/*.c --force
git add ./src/tree_sitter/* --force
git add ./src/*.json --force
git add grammar.js
git add package.json
git add test
git add queries
git add Makefile
git add bindings/c/*.in
git commit -m "Updating grammar files for version ${ref/refs\/tags\//}"
echo "Committing new generated grammar"
# Push the change to github using the secrets from our environment.
gh auth setup-git
git remote add dest "https://$GITHUB_ACTOR:$GITHUB_TOKEN@github.com/$GITHUB_REPOSITORY.git"
git push dest HEAD:$branch_name
echo "Checkin complete!"

File diff suppressed because it is too large Load Diff

@ -1,814 +0,0 @@
#include <tree_sitter/parser.h>
#include <string.h>
#include <wctype.h>
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,
};
#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
};
#define RESERVED_OP_COUNT 31
const char* RESERVED_OPS[RESERVED_OP_COUNT] = {
"/",
"=",
"-",
"+",
"!",
"*",
"%",
"<",
">",
"&",
"|",
"^",
"?",
"~",
".",
"..",
"->",
"/*",
"*/",
"+=",
"-=",
"*=",
"/=",
"%=",
">>",
"<<",
"++",
"--",
"===",
"...",
"..<"
};
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(0, 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) {
*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;
}
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 {
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;
}

@ -1,224 +0,0 @@
#ifndef TREE_SITTER_PARSER_H_
#define TREE_SITTER_PARSER_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#define ts_builtin_sym_error ((TSSymbol)-1)
#define ts_builtin_sym_end 0
#define TREE_SITTER_SERIALIZATION_BUFFER_SIZE 1024
typedef uint16_t TSStateId;
#ifndef TREE_SITTER_API_H_
typedef uint16_t TSSymbol;
typedef uint16_t TSFieldId;
typedef struct TSLanguage TSLanguage;
#endif
typedef struct {
TSFieldId field_id;
uint8_t child_index;
bool inherited;
} TSFieldMapEntry;
typedef struct {
uint16_t index;
uint16_t length;
} TSFieldMapSlice;
typedef struct {
bool visible;
bool named;
bool supertype;
} TSSymbolMetadata;
typedef struct TSLexer TSLexer;
struct TSLexer {
int32_t lookahead;
TSSymbol result_symbol;
void (*advance)(TSLexer *, bool);
void (*mark_end)(TSLexer *);
uint32_t (*get_column)(TSLexer *);
bool (*is_at_included_range_start)(const TSLexer *);
bool (*eof)(const TSLexer *);
};
typedef enum {
TSParseActionTypeShift,
TSParseActionTypeReduce,
TSParseActionTypeAccept,
TSParseActionTypeRecover,
} TSParseActionType;
typedef union {
struct {
uint8_t type;
TSStateId state;
bool extra;
bool repetition;
} shift;
struct {
uint8_t type;
uint8_t child_count;
TSSymbol symbol;
int16_t dynamic_precedence;
uint16_t production_id;
} reduce;
uint8_t type;
} TSParseAction;
typedef struct {
uint16_t lex_state;
uint16_t external_lex_state;
} TSLexMode;
typedef union {
TSParseAction action;
struct {
uint8_t count;
bool reusable;
} entry;
} TSParseActionEntry;
struct TSLanguage {
uint32_t version;
uint32_t symbol_count;
uint32_t alias_count;
uint32_t token_count;
uint32_t external_token_count;
uint32_t state_count;
uint32_t large_state_count;
uint32_t production_id_count;
uint32_t field_count;
uint16_t max_alias_sequence_length;
const uint16_t *parse_table;
const uint16_t *small_parse_table;
const uint32_t *small_parse_table_map;
const TSParseActionEntry *parse_actions;
const char * const *symbol_names;
const char * const *field_names;
const TSFieldMapSlice *field_map_slices;
const TSFieldMapEntry *field_map_entries;
const TSSymbolMetadata *symbol_metadata;
const TSSymbol *public_symbol_map;
const uint16_t *alias_map;
const TSSymbol *alias_sequences;
const TSLexMode *lex_modes;
bool (*lex_fn)(TSLexer *, TSStateId);
bool (*keyword_lex_fn)(TSLexer *, TSStateId);
TSSymbol keyword_capture_token;
struct {
const bool *states;
const TSSymbol *symbol_map;
void *(*create)(void);
void (*destroy)(void *);
bool (*scan)(void *, TSLexer *, const bool *symbol_whitelist);
unsigned (*serialize)(void *, char *);
void (*deserialize)(void *, const char *, unsigned);
} external_scanner;
const TSStateId *primary_state_ids;
};
/*
* Lexer Macros
*/
#define START_LEXER() \
bool result = false; \
bool skip = false; \
bool eof = false; \
int32_t lookahead; \
goto start; \
next_state: \
lexer->advance(lexer, skip); \
start: \
skip = false; \
lookahead = lexer->lookahead;
#define ADVANCE(state_value) \
{ \
state = state_value; \
goto next_state; \
}
#define SKIP(state_value) \
{ \
skip = true; \
state = state_value; \
goto next_state; \
}
#define ACCEPT_TOKEN(symbol_value) \
result = true; \
lexer->result_symbol = symbol_value; \
lexer->mark_end(lexer);
#define END_STATE() return result;
/*
* Parse Table Macros
*/
#define SMALL_STATE(id) id - LARGE_STATE_COUNT
#define STATE(id) id
#define ACTIONS(id) id
#define SHIFT(state_value) \
{{ \
.shift = { \
.type = TSParseActionTypeShift, \
.state = state_value \
} \
}}
#define SHIFT_REPEAT(state_value) \
{{ \
.shift = { \
.type = TSParseActionTypeShift, \
.state = state_value, \
.repetition = true \
} \
}}
#define SHIFT_EXTRA() \
{{ \
.shift = { \
.type = TSParseActionTypeShift, \
.extra = true \
} \
}}
#define REDUCE(symbol_val, child_count_val, ...) \
{{ \
.reduce = { \
.type = TSParseActionTypeReduce, \
.symbol = symbol_val, \
.child_count = child_count_val, \
__VA_ARGS__ \
}, \
}}
#define RECOVER() \
{{ \
.type = TSParseActionTypeRecover \
}}
#define ACCEPT_INPUT() \
{{ \
.type = TSParseActionTypeAccept \
}}
#ifdef __cplusplus
}
#endif
#endif // TREE_SITTER_PARSER_H_

@ -1,25 +0,0 @@
const Parser = require("tree-sitter");
const Swift = require("tree-sitter-swift");
const parser = new Parser();
parser.setLanguage(Swift);
const sourceCode = `
struct HelloWorld {
func a() {
print("Hello, world!")
}
}
HelloWorld().a()
`;
const tree = parser.parse(sourceCode);
console.log(tree.rootNode.toString());
const assert = require("assert");
const smallTree = parser.parse(`_ = "Hello!"\n`);
assert.equal(
`(source_file (assignment target: (directly_assignable_expression (simple_identifier)) result: (line_string_literal text: (line_str_text))))`,
smallTree.rootNode.toString()
);

File diff suppressed because it is too large Load Diff

@ -1,15 +0,0 @@
{
"name": "npm-tree-sitter-test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "npm install && node index.js"
},
"author": "",
"license": "MIT",
"dependencies": {
"tree-sitter": "^0.20.0",
"tree-sitter-swift": "file:../"
}
}

@ -1,75 +0,0 @@
================================================================================
Annotations
================================================================================
@Test
class Empty { }
--------------------------------------------------------------------------------
(source_file
(class_declaration
(modifiers
(attribute
(user_type
(type_identifier))))
(type_identifier)
(class_body)))
================================================================================
Multiple annotations on a variable
================================================================================
class X {
@A @B
override let s: String
}
--------------------------------------------------------------------------------
(source_file
(class_declaration
(type_identifier)
(class_body
(property_declaration
(modifiers
(attribute
(user_type
(type_identifier)))
(attribute
(user_type
(type_identifier)))
(member_modifier))
(pattern
(simple_identifier))
(type_annotation
(user_type
(type_identifier)))))))
================================================================================
Multiple annotations on a function
================================================================================
class X {
@A @B
func s() -> String { }
}
--------------------------------------------------------------------------------
(source_file
(class_declaration
(type_identifier)
(class_body
(function_declaration
(modifiers
(attribute
(user_type
(type_identifier)))
(attribute
(user_type
(type_identifier))))
(simple_identifier)
(user_type
(type_identifier))
(function_body)))))

File diff suppressed because it is too large Load Diff

@ -1,103 +0,0 @@
================================================================================
Comments
================================================================================
1 + 2
// 1 + 2
/* Hello world */
/** I am a doc comment */
--------------------------------------------------------------------------------
(source_file
(additive_expression
(integer_literal)
(integer_literal))
(comment)
(multiline_comment)
(multiline_comment))
================================================================================
Nested Comments
================================================================================
/*
This is how comments work: //
Also like this: /* */
func doesNotExist() {
// This should not show up in the AST
}
*/
/*
This is the same but with different whitespace: /*
*/
func alsoDoesNotExist() { }
*/
// /*
/* * */
func doesExist() { }
/*/*/* triple nested */*/*/
/****
/****
nested with extra stars
****/
****/
--------------------------------------------------------------------------------
(source_file
(multiline_comment)
(multiline_comment)
(comment)
(multiline_comment)
(function_declaration
(simple_identifier)
(function_body))
(multiline_comment)
(multiline_comment))
================================================================================
Almost nested comments
================================================================================
/*
This is allowed in a comment but does not nest: /
*/
/*
Same with this: *
*/
/*
And even this: / *
*/
--------------------------------------------------------------------------------
(source_file
(multiline_comment)
(multiline_comment)
(multiline_comment))
================================================================================
Single line comment at the end of a non-empty file
================================================================================
class SwiftExamples {
}
// Some comment
--------------------------------------------------------------------------------
(source_file
(class_declaration
(type_identifier)
(class_body))
(comment))

@ -1,91 +0,0 @@
================================================================================
Emojis in variable names
================================================================================
let ⭐️ = "star"
let 🌙 = "moon"
let ☁️☀️☁️ = "clouds and sun"
--------------------------------------------------------------------------------
(source_file
(property_declaration
(pattern
(simple_identifier))
(line_string_literal
(line_str_text)))
(property_declaration
(pattern
(simple_identifier))
(line_string_literal
(line_str_text)))
(property_declaration
(pattern
(simple_identifier))
(line_string_literal
(line_str_text))))
================================================================================
Multi-codepoint emojis
================================================================================
func 🏃🏼‍♂️() {
}
🏃🏼‍♂️()
func 👨‍❤️‍💋‍👨(🙋🏼‍♂️ 🙋‍♂️: Man, 🙋🏻‍♂️ 🙋2: Man) {
}
👨‍❤️‍💋‍👨(🙋🏼‍♂️: a, 🙋🏻‍♂️: b)
--------------------------------------------------------------------------------
(source_file
(function_declaration
(simple_identifier)
(function_body))
(call_expression
(simple_identifier)
(call_suffix
(value_arguments)))
(function_declaration
(simple_identifier)
(parameter
(simple_identifier)
(simple_identifier)
(user_type
(type_identifier)))
(parameter
(simple_identifier)
(simple_identifier)
(user_type
(type_identifier)))
(function_body))
(call_expression
(simple_identifier)
(call_suffix
(value_arguments
(value_argument
(simple_identifier)
(simple_identifier))
(value_argument
(simple_identifier)
(simple_identifier))))))
================================================================================
Emojis with numbers in them
================================================================================
let number4⃣ = nummber2⃣ + number2
--------------------------------------------------------------------------------
(source_file
(property_declaration
(pattern
(simple_identifier))
(additive_expression
(simple_identifier)
(simple_identifier))))

File diff suppressed because it is too large Load Diff

@ -1,834 +0,0 @@
================================================================================
Top-level functions
================================================================================
func main() {}
--------------------------------------------------------------------------------
(source_file
(function_declaration
(simple_identifier)
(function_body)))
================================================================================
Generic functions
================================================================================
func test<T>(t: T) {}
--------------------------------------------------------------------------------
(source_file
(function_declaration
(simple_identifier)
(type_parameters
(type_parameter
(type_identifier)))
(parameter
(simple_identifier)
(user_type
(type_identifier)))
(function_body)))
================================================================================
Static functions
================================================================================
static func help() {}
static func === (lhs: MyType, rhs: MyType) { }
--------------------------------------------------------------------------------
(source_file
(function_declaration
(modifiers
(property_modifier))
(simple_identifier)
(function_body))
(function_declaration
(modifiers
(property_modifier))
(parameter
(simple_identifier)
(user_type
(type_identifier)))
(parameter
(simple_identifier)
(user_type
(type_identifier)))
(function_body)))
================================================================================
Functions with parameters
================================================================================
func main(args: [String]) {}
func maybe_main(args: Maybe<String>) {}
func convert(@Arg args: [String: Int]) {}
func sum(a: Int, b: Int!) { return a + b }
--------------------------------------------------------------------------------
(source_file
(function_declaration
(simple_identifier)
(parameter
(simple_identifier)
(array_type
(user_type
(type_identifier))))
(function_body))
(function_declaration
(simple_identifier)
(parameter
(simple_identifier)
(user_type
(type_identifier)
(type_arguments
(user_type
(type_identifier)))))
(function_body))
(function_declaration
(simple_identifier)
(attribute
(user_type
(type_identifier)))
(parameter
(simple_identifier)
(dictionary_type
(user_type
(type_identifier))
(user_type
(type_identifier))))
(function_body))
(function_declaration
(simple_identifier)
(parameter
(simple_identifier)
(user_type
(type_identifier)))
(parameter
(simple_identifier)
(user_type
(type_identifier)))
(function_body
(statements
(control_transfer_statement
(additive_expression
(simple_identifier)
(simple_identifier)))))))
================================================================================
Functions with renamed parameters
================================================================================
func sum(_ a: Int, with b: Int) { return a + b }
sum(1, with: 2)
--------------------------------------------------------------------------------
(source_file
(function_declaration
(simple_identifier)
(parameter
(simple_identifier)
(simple_identifier)
(user_type
(type_identifier)))
(parameter
(simple_identifier)
(simple_identifier)
(user_type
(type_identifier)))
(function_body
(statements
(control_transfer_statement
(additive_expression
(simple_identifier)
(simple_identifier))))))
(call_expression
(simple_identifier)
(call_suffix
(value_arguments
(value_argument
(integer_literal))
(value_argument
(simple_identifier)
(integer_literal))))))
================================================================================
Functions with return types
================================================================================
func answerToTheUltimateQuestionOfLifeTheUniverseAndEverything() -> Int { return 42 }
func getConfig() -> [String: Int] {
return [
"TimeoutMillis": 1000,
"RetryCount": 5,
"RetryBackoffMillis": 5000
]
}
func returnGetsImplicitlyUnwrapped() -> String! {
return nil
}
--------------------------------------------------------------------------------
(source_file
(function_declaration
(simple_identifier)
(user_type
(type_identifier))
(function_body
(statements
(control_transfer_statement
(integer_literal)))))
(function_declaration
(simple_identifier)
(dictionary_type
(user_type
(type_identifier))
(user_type
(type_identifier)))
(function_body
(statements
(control_transfer_statement
(dictionary_literal
(line_string_literal
(line_str_text))
(integer_literal)
(line_string_literal
(line_str_text))
(integer_literal)
(line_string_literal
(line_str_text))
(integer_literal))))))
(function_declaration
(simple_identifier)
(user_type
(type_identifier))
(function_body
(statements
(control_transfer_statement)))))
================================================================================
Variadic functions
================================================================================
func toUpperCaseAll(strings: String ...) -> [String] { }
--------------------------------------------------------------------------------
(source_file
(function_declaration
(simple_identifier)
(parameter
(simple_identifier)
(user_type
(type_identifier)))
(array_type
(user_type
(type_identifier)))
(function_body)))
================================================================================
Operator overrides
================================================================================
public static func < (lhs: Wrapped<F>, rhs: Wrapped<F>) -> Bool {
return false
}
public func ??<V : Value>(optional: Expression<V?>, defaultValue: V) -> Expression<V> {
return Expression(optional.inner() ?? defaultValue)
}
public prefix func ! (value: Wrapped<F>) -> Bool {
return false
}
--------------------------------------------------------------------------------
(source_file
(function_declaration
(modifiers
(visibility_modifier)
(property_modifier))
(parameter
(simple_identifier)
(user_type
(type_identifier)
(type_arguments
(user_type
(type_identifier)))))
(parameter
(simple_identifier)
(user_type
(type_identifier)
(type_arguments
(user_type
(type_identifier)))))
(user_type
(type_identifier))
(function_body
(statements
(control_transfer_statement
(boolean_literal)))))
(function_declaration
(modifiers
(visibility_modifier))
(custom_operator)
(type_parameters
(type_parameter
(type_identifier)
(user_type
(type_identifier))))
(parameter
(simple_identifier)
(user_type
(type_identifier)
(type_arguments
(optional_type
(user_type
(type_identifier))))))
(parameter
(simple_identifier)
(user_type
(type_identifier)))
(user_type
(type_identifier)
(type_arguments
(user_type
(type_identifier))))
(function_body
(statements
(control_transfer_statement
(call_expression
(simple_identifier)
(call_suffix
(value_arguments
(value_argument
(nil_coalescing_expression
(call_expression
(navigation_expression
(simple_identifier)
(navigation_suffix
(simple_identifier)))
(call_suffix
(value_arguments)))
(simple_identifier))))))))))
(function_declaration
(modifiers
(visibility_modifier)
(function_modifier))
(bang)
(parameter
(simple_identifier)
(user_type
(type_identifier)
(type_arguments
(user_type
(type_identifier)))))
(user_type
(type_identifier))
(function_body
(statements
(control_transfer_statement
(boolean_literal))))))
================================================================================
Custom operators
================================================================================
precedencegroup MyPrecedence {
associativity: left
assignment: true
lowerThan: AdditionPrecedence
}
infix operator -=- : MyPrecedence
infix operator •
--------------------------------------------------------------------------------
(source_file
(precedence_group_declaration
(simple_identifier)
(precedence_group_attributes
(precedence_group_attribute
(simple_identifier)
(simple_identifier))
(precedence_group_attribute
(simple_identifier)
(boolean_literal))
(precedence_group_attribute
(simple_identifier)
(simple_identifier))))
(operator_declaration
(custom_operator)
(simple_identifier))
(operator_declaration
(custom_operator)))
================================================================================
Custom operator with another operator as a prefix
================================================================================
let messageCoerced = error ??? "nil"
--------------------------------------------------------------------------------
(source_file
(property_declaration
(pattern
(simple_identifier))
(infix_expression
(simple_identifier)
(custom_operator)
(line_string_literal
(line_str_text)))))
================================================================================
Functions that throw
================================================================================
func anythingYouCanDo() throws -> Int { return -1 }
func iCanDoBetter()
throws
-> Int { return -2 }
--------------------------------------------------------------------------------
(source_file
(function_declaration
(simple_identifier)
(throws)
(user_type
(type_identifier))
(function_body
(statements
(control_transfer_statement
(prefix_expression
(integer_literal))))))
(function_declaration
(simple_identifier)
(throws)
(user_type
(type_identifier))
(function_body
(statements
(control_transfer_statement
(prefix_expression
(integer_literal)))))))
================================================================================
Async functions
================================================================================
func eventually() async -> Int { return -1 }
func maybe()
async
throws
-> Int { return -2 }
--------------------------------------------------------------------------------
(source_file
(function_declaration
(simple_identifier)
(user_type
(type_identifier))
(function_body
(statements
(control_transfer_statement
(prefix_expression
(integer_literal))))))
(function_declaration
(simple_identifier)
(throws)
(user_type
(type_identifier))
(function_body
(statements
(control_transfer_statement
(prefix_expression
(integer_literal)))))))
================================================================================
Higher-order functions - pt 1
================================================================================
func test(i: Int = 0, block: (Int) throws -> Void) {}
--------------------------------------------------------------------------------
(source_file
(function_declaration
(simple_identifier)
(parameter
(simple_identifier)
(user_type
(type_identifier)))
(integer_literal)
(parameter
(simple_identifier)
(function_type
(tuple_type
(tuple_type_item
(user_type
(type_identifier))))
(throws)
(user_type
(type_identifier))))
(function_body)))
================================================================================
Higher-order functions - pt 2
================================================================================
test { value in /* does nothing */ }
--------------------------------------------------------------------------------
(source_file
(call_expression
(simple_identifier)
(call_suffix
(lambda_literal
(lambda_function_type
(lambda_function_type_parameters
(lambda_parameter
(simple_identifier))))
(multiline_comment)))))
================================================================================
Higher-order functions - pt 3
================================================================================
test(2) { $0.doSomething() }
--------------------------------------------------------------------------------
(source_file
(call_expression
(simple_identifier)
(call_suffix
(value_arguments
(value_argument
(integer_literal)))
(lambda_literal
(statements
(call_expression
(navigation_expression
(simple_identifier)
(navigation_suffix
(simple_identifier)))
(call_suffix
(value_arguments))))))))
================================================================================
Higher-order functions - pt 4
================================================================================
test { (a) -> Void in }
--------------------------------------------------------------------------------
(source_file
(call_expression
(simple_identifier)
(call_suffix
(lambda_literal
(lambda_function_type
(lambda_function_type_parameters
(lambda_parameter
(simple_identifier)))
(user_type
(type_identifier)))))))
================================================================================
Higher-order functions - pt 5
================================================================================
test { (a: inout Int) in }
--------------------------------------------------------------------------------
(source_file
(call_expression
(simple_identifier)
(call_suffix
(lambda_literal
(lambda_function_type
(lambda_function_type_parameters
(lambda_parameter
(simple_identifier)
(parameter_modifiers
(parameter_modifier))
(user_type
(type_identifier)))))))))
================================================================================
Higher-order functions - pt 6
================================================================================
test { @Special [weak self, otherSelf] (a) in }
--------------------------------------------------------------------------------
(source_file
(call_expression
(simple_identifier)
(call_suffix
(lambda_literal
(attribute
(user_type
(type_identifier)))
(capture_list
(capture_list_item
(ownership_modifier)
(simple_identifier))
(capture_list_item
(simple_identifier)))
(lambda_function_type
(lambda_function_type_parameters
(lambda_parameter
(simple_identifier))))))))
================================================================================
Higher-order functions - pt 7
================================================================================
test(block: ===)
--------------------------------------------------------------------------------
(source_file
(call_expression
(simple_identifier)
(call_suffix
(value_arguments
(value_argument
(simple_identifier))))))
================================================================================
Higher-order functions - pt 8
================================================================================
test { ($0, someVariable) }
--------------------------------------------------------------------------------
(source_file
(call_expression
(simple_identifier)
(call_suffix
(lambda_literal
(statements
(tuple_expression
(simple_identifier)
(simple_identifier)))))))
================================================================================
Higher-order functions - pt 9
================================================================================
test { (self, a) -> Void in }
--------------------------------------------------------------------------------
(source_file
(call_expression
(simple_identifier)
(call_suffix
(lambda_literal
(lambda_function_type
(lambda_function_type_parameters
(lambda_parameter
(self_expression))
(lambda_parameter
(simple_identifier)))
(user_type
(type_identifier)))))))
================================================================================
Higher-order functions - pt 10
================================================================================
test { (a: Any?) in foo(a) }
--------------------------------------------------------------------------------
(source_file
(call_expression
(simple_identifier)
(call_suffix
(lambda_literal
(lambda_function_type
(lambda_function_type_parameters
(lambda_parameter
(simple_identifier)
(optional_type
(user_type
(type_identifier))))))
(statements
(call_expression
(simple_identifier)
(call_suffix
(value_arguments
(value_argument
(simple_identifier))))))))))
================================================================================
Higher-order functions - pt 11
================================================================================
types.flatMap { [abc, 1] }
--------------------------------------------------------------------------------
(source_file
(call_expression
(navigation_expression
(simple_identifier)
(navigation_suffix
(simple_identifier)))
(call_suffix
(lambda_literal
(statements
(array_literal
(simple_identifier)
(integer_literal)))))))
================================================================================
Function type with wildcard
================================================================================
private lazy var onCatClosure: (_ cat: Cat) throws -> Void = { _ in
}
--------------------------------------------------------------------------------
(source_file
(property_declaration
(modifiers
(visibility_modifier)
(property_behavior_modifier))
(pattern
(simple_identifier))
(type_annotation
(function_type
(tuple_type
(tuple_type_item
(wildcard_pattern)
(simple_identifier)
(user_type
(type_identifier))))
(throws)
(user_type
(type_identifier))))
(lambda_literal
(lambda_function_type
(lambda_function_type_parameters
(lambda_parameter
(simple_identifier)))))))
================================================================================
Multiple trailing lambdas
================================================================================
myInstance.registerCallbacks { } onCancelled: { }
--------------------------------------------------------------------------------
(source_file
(call_expression
(navigation_expression
(simple_identifier)
(navigation_suffix
(simple_identifier)))
(call_suffix
(lambda_literal)
(simple_identifier)
(lambda_literal))))
================================================================================
Return type fun
================================================================================
func opaqueType() -> some Equatable { return "" }
func multipleType() -> Foo & Bar { return Foo() }
--------------------------------------------------------------------------------
(source_file
(function_declaration
(simple_identifier)
(opaque_type
(user_type
(type_identifier)))
(function_body
(statements
(control_transfer_statement
(line_string_literal)))))
(function_declaration
(simple_identifier)
(protocol_composition_type
(user_type
(type_identifier))
(user_type
(type_identifier)))
(function_body
(statements
(control_transfer_statement
(call_expression
(simple_identifier)
(call_suffix
(value_arguments))))))))
================================================================================
Lambdas with annotations
================================================================================
types.flatMap { @Sendable _ in }
let mainClosure = { @MainActor in print("Running on main") }
--------------------------------------------------------------------------------
(source_file
(call_expression
(navigation_expression
(simple_identifier)
(navigation_suffix
(simple_identifier)))
(call_suffix
(lambda_literal
(attribute
(user_type
(type_identifier)))
(lambda_function_type
(lambda_function_type_parameters
(lambda_parameter
(simple_identifier)))))))
(property_declaration
(pattern
(simple_identifier))
(lambda_literal
(attribute
(user_type
(type_identifier)))
(statements
(call_expression
(simple_identifier)
(call_suffix
(value_arguments
(value_argument
(line_string_literal
(line_str_text))))))))))

@ -1,736 +0,0 @@
================================================================================
Simple identifiers
================================================================================
helloWorld
--------------------------------------------------------------------------------
(source_file
(simple_identifier))
================================================================================
Boolean literals
================================================================================
true
false
--------------------------------------------------------------------------------
(source_file
(boolean_literal)
(boolean_literal))
================================================================================
String literals
================================================================================
"Hello World!"
"""
This is a "multiline"
string.
"""
"This string has a // comment (except not!)"
--------------------------------------------------------------------------------
(source_file
(line_string_literal
(line_str_text))
(multi_line_string_literal
(multi_line_str_text)
(multi_line_str_text)
(multi_line_str_text))
(line_string_literal
(line_str_text)))
================================================================================
String interpolation
================================================================================
"Sample \("string.interpolation") literal"
"""
Multiline
\("""string interpolation""") literal
"""
"This is a string with // a comment in it"
"""
And so is this! /*
#if qwertyuiop
And yet neither of those comments should register
""" // This comment is valid
--------------------------------------------------------------------------------
(source_file
(line_string_literal
(line_str_text)
(interpolated_expression
(line_string_literal
(line_str_text)))
(line_str_text))
(multi_line_string_literal
(multi_line_str_text)
(interpolated_expression
(multi_line_string_literal
(multi_line_str_text)))
(multi_line_str_text))
(line_string_literal
(line_str_text))
(multi_line_string_literal
(multi_line_str_text))
(comment))
================================================================================
Custom interpolation
================================================================================
"Hi, I'm \(format: age)"
--------------------------------------------------------------------------------
(source_file
(line_string_literal
(line_str_text)
(interpolated_expression
(simple_identifier)
(simple_identifier))))
================================================================================
Strings with newline escaping
================================================================================
"""
This is a string that acts as though it \
is all on one line
"""
--------------------------------------------------------------------------------
(source_file
(multi_line_string_literal
(multi_line_str_text)
(str_escaped_char)
(multi_line_str_text)))
================================================================================
Integer literals
================================================================================
0
8
23
9847
0xf00
0o774
0b01
--------------------------------------------------------------------------------
(source_file
(integer_literal)
(integer_literal)
(integer_literal)
(integer_literal)
(hex_literal)
(oct_literal)
(bin_literal))
================================================================================
Real literals
================================================================================
0.0
-23.434
1e-10
4.3
+53.9e-3
--------------------------------------------------------------------------------
(source_file
(real_literal)
(prefix_expression
(real_literal))
(real_literal)
(real_literal)
(prefix_expression
(real_literal)))
================================================================================
Collections
================================================================================
let numbers = [1, 2, 3]
let numerals = [1: "I", 4: "IV", 5: "V", 10: "X"]
--------------------------------------------------------------------------------
(source_file
(property_declaration
(pattern
(simple_identifier))
(array_literal
(integer_literal)
(integer_literal)
(integer_literal)))
(property_declaration
(pattern
(simple_identifier))
(dictionary_literal
(integer_literal)
(line_string_literal
(line_str_text))
(integer_literal)
(line_string_literal
(line_str_text))
(integer_literal)
(line_string_literal
(line_str_text))
(integer_literal)
(line_string_literal
(line_str_text)))))
================================================================================
Trailing commas
================================================================================
[
"Time": Date.now(),
"Success": true,
]
[1, 2, 3, 4, 5,]
--------------------------------------------------------------------------------
(source_file
(dictionary_literal
(line_string_literal
(line_str_text))
(call_expression
(navigation_expression
(simple_identifier)
(navigation_suffix
(simple_identifier)))
(call_suffix
(value_arguments)))
(line_string_literal
(line_str_text))
(boolean_literal))
(array_literal
(integer_literal)
(integer_literal)
(integer_literal)
(integer_literal)
(integer_literal)))
================================================================================
Nil
================================================================================
let _ = nil
--------------------------------------------------------------------------------
(source_file
(property_declaration
(pattern
(wildcard_pattern))))
================================================================================
Raw strings
================================================================================
let _ = #"Hello, world!"#
let _ = ##"Hello, so-called "world"!"##
--------------------------------------------------------------------------------
(source_file
(property_declaration
(pattern
(wildcard_pattern))
(raw_string_literal
(raw_str_end_part)))
(property_declaration
(pattern
(wildcard_pattern))
(raw_string_literal
(raw_str_end_part))))
================================================================================
Doesn't hang for incomplete raw strings (issue #146)
================================================================================
let _ = #"Foo"
--------------------------------------------------------------------------------
(source_file
(property_declaration
(pattern
(wildcard_pattern))
(ERROR
(UNEXPECTED '"'))
(line_string_literal
(line_str_text))))
================================================================================
Raw strings with interpolation
================================================================================
extension URL {
func html(withTitle title: String) -> String {
return #"<a href="\#(absoluteString)">\#(title)</a>"#
}
}
--------------------------------------------------------------------------------
(source_file
(class_declaration
(user_type
(type_identifier))
(class_body
(function_declaration
(simple_identifier)
(parameter
(simple_identifier)
(simple_identifier)
(user_type
(type_identifier)))
(user_type
(type_identifier))
(function_body
(statements
(control_transfer_statement
(raw_string_literal
(raw_str_part)
(raw_str_interpolation
(raw_str_interpolation_start)
(interpolated_expression
(simple_identifier)))
(raw_str_part)
(raw_str_interpolation
(raw_str_interpolation_start)
(interpolated_expression
(simple_identifier)))
(raw_str_end_part)))))))))
================================================================================
Raw strings interpolation edge cases
================================================================================
print(#"Hello \#(world /* commented out)"#) */ )"#)
let _ = ##"Multiple pound signs \##(interpolated): still one part "# not done yet "##
let _ = ##"Fake \#(interpolation) and unused # pound signs "##
let _ = ##"\##(a)\#(b)\##(c)\#(d)"# ##"##
let _ = #"""
\\#(12)\#
"""#
--------------------------------------------------------------------------------
(source_file
(call_expression
(simple_identifier)
(call_suffix
(value_arguments
(value_argument
(raw_string_literal
(raw_str_part)
(raw_str_interpolation
(raw_str_interpolation_start)
(interpolated_expression
(simple_identifier))
(multiline_comment))
(raw_str_end_part))))))
(property_declaration
(pattern
(wildcard_pattern))
(raw_string_literal
(raw_str_part)
(raw_str_interpolation
(raw_str_interpolation_start)
(interpolated_expression
(simple_identifier)))
(raw_str_end_part)))
(property_declaration
(pattern
(wildcard_pattern))
(raw_string_literal
(raw_str_end_part)))
(property_declaration
(pattern
(wildcard_pattern))
(raw_string_literal
(raw_str_part)
(raw_str_interpolation
(raw_str_interpolation_start)
(interpolated_expression
(simple_identifier)))
(raw_str_part)
(raw_str_interpolation
(raw_str_interpolation_start)
(interpolated_expression
(simple_identifier)))
(raw_str_end_part)))
(property_declaration
(pattern
(wildcard_pattern))
(raw_string_literal
(raw_str_part)
(raw_str_interpolation
(raw_str_interpolation_start)
(interpolated_expression
(integer_literal)))
(raw_str_end_part))))
================================================================================
Unicode escape sequences
================================================================================
let unicodeEscaping = "\u{8}"
let anotherUnicode = "…\u{2060}"
let infinity = "\u{221E}"
--------------------------------------------------------------------------------
(source_file
(property_declaration
(pattern
(simple_identifier))
(line_string_literal
(str_escaped_char)))
(property_declaration
(pattern
(simple_identifier))
(line_string_literal
(line_str_text)
(str_escaped_char)))
(property_declaration
(pattern
(simple_identifier))
(line_string_literal
(str_escaped_char))))
================================================================================
Playground literals
================================================================================
let playgroundLiteral = #imageLiteral(resourceName: "heart")
--------------------------------------------------------------------------------
(source_file
(property_declaration
(pattern
(simple_identifier))
(simple_identifier)
(line_string_literal
(line_str_text))))
================================================================================
Single line regex literals
================================================================================
let regex1 = /([ab])?/
let regex2 = /([ab])|\d+/
--------------------------------------------------------------------------------
(source_file
(property_declaration
(pattern
(simple_identifier))
(regex_literal))
(property_declaration
(pattern
(simple_identifier))
(regex_literal)))
================================================================================
Multiline regex literals
================================================================================
let regex = #/
# Match a line of the format e.g "DEBIT 03/03/2022 Totally Legit Shell Corp $2,000,000.00"
(?<kind> \w+) \s\s+
(?<date> \S+) \s\s+
(?<account> (?: (?!\s\s) . )+) \s\s+ # Note that account names may contain spaces.
(?<amount> .*)
/#
--------------------------------------------------------------------------------
(source_file
(property_declaration
(pattern
(simple_identifier))
(regex_literal)))
================================================================================
Parse ambiguity in regex liteal and comment
================================================================================
/*
let regex = /[0-9]*/
--------------------------------------------------------------------------------
(source_file
(multiline_comment))
================================================================================
Regex-like custom operator not in expression position
================================================================================
infix operator /^/
func /^/ (lhs: Int, rhs: Int) -> Int { 0 }
let b = 0 /^/ 1
--------------------------------------------------------------------------------
(source_file
(operator_declaration
(custom_operator))
(function_declaration
(custom_operator)
(parameter
(simple_identifier)
(user_type
(type_identifier)))
(parameter
(simple_identifier)
(user_type
(type_identifier)))
(user_type
(type_identifier))
(function_body
(statements
(integer_literal))))
(property_declaration
(pattern
(simple_identifier))
(infix_expression
(integer_literal)
(custom_operator)
(integer_literal))))
================================================================================
Unapplied `/` that is not a regex literal
================================================================================
let x = array.reduce(1, /) / 5
let y = array.reduce(1, /) + otherArray.reduce(1, /)
--------------------------------------------------------------------------------
(source_file
(property_declaration
(pattern
(simple_identifier))
(multiplicative_expression
(call_expression
(navigation_expression
(simple_identifier)
(navigation_suffix
(simple_identifier)))
(call_suffix
(value_arguments
(value_argument
(integer_literal))
(value_argument))))
(integer_literal)))
(property_declaration
(pattern
(simple_identifier))
(call_expression
(navigation_expression
(additive_expression
(call_expression
(navigation_expression
(simple_identifier)
(navigation_suffix
(simple_identifier)))
(call_suffix
(value_arguments
(value_argument
(integer_literal))
(value_argument))))
(simple_identifier))
(navigation_suffix
(simple_identifier)))
(call_suffix
(value_arguments
(value_argument
(integer_literal))
(value_argument))))))
================================================================================
Unapplied custom operators
================================================================================
baz(!/, 1) / 2
qux(/, /)
qux(/^, /)
qux(!/, /)
--------------------------------------------------------------------------------
(source_file
(multiplicative_expression
(call_expression
(simple_identifier)
(call_suffix
(value_arguments
(value_argument
(custom_operator))
(value_argument
(integer_literal)))))
(integer_literal))
(call_expression
(simple_identifier)
(call_suffix
(value_arguments
(value_argument)
(value_argument))))
(call_expression
(simple_identifier)
(call_suffix
(value_arguments
(value_argument
(custom_operator))
(value_argument))))
(call_expression
(simple_identifier)
(call_suffix
(value_arguments
(value_argument
(custom_operator))
(value_argument)))))
================================================================================
More operator not-regex edge cases
================================================================================
let d = hasSubscript[/] / 2 // Unapplied infix '/' and infix '/'
let e = !/y / .foo() // Prefix '!/' with infix '/' and operand '.foo()'
--------------------------------------------------------------------------------
(source_file
(property_declaration
(pattern
(simple_identifier))
(multiplicative_expression
(call_expression
(simple_identifier)
(call_suffix
(value_arguments
(value_argument))))
(integer_literal)))
(comment)
(property_declaration
(pattern
(simple_identifier))
(call_expression
(prefix_expression
(custom_operator)
(multiplicative_expression
(simple_identifier)
(prefix_expression
(simple_identifier))))
(call_suffix
(value_arguments))))
(comment))
================================================================================
Ambiguous parse cases that now are regexes
================================================================================
foo(/a, b/) // Will become regex literal '/a, b/'
qux(/, !/) // Will become regex literal '/, !/'
qux(/,/) // Will become regex literal '/,/'
--------------------------------------------------------------------------------
(source_file
(call_expression
(simple_identifier)
(call_suffix
(value_arguments
(value_argument
(regex_literal)))))
(comment)
(call_expression
(simple_identifier)
(call_suffix
(value_arguments
(value_argument
(regex_literal)))))
(comment)
(call_expression
(simple_identifier)
(call_suffix
(value_arguments
(value_argument
(regex_literal)))))
(comment))
================================================================================
Unapplied division operator
================================================================================
class Operator {
var perform: (Double, Double) -> Double {
return (/)
}
}
--------------------------------------------------------------------------------
(source_file
(class_declaration
(type_identifier)
(class_body
(property_declaration
(pattern
(simple_identifier))
(type_annotation
(function_type
(tuple_type
(tuple_type_item
(user_type
(type_identifier)))
(tuple_type_item
(user_type
(type_identifier))))
(user_type
(type_identifier))))
(computed_property
(statements
(control_transfer_statement
(tuple_expression))))))))
================================================================================
Single-line regex on multiple lines
================================================================================
doOperation(on: a, /)
/// That was fun! We ran `/`
--------------------------------------------------------------------------------
(source_file
(call_expression
(simple_identifier)
(call_suffix
(value_arguments
(value_argument
(simple_identifier)
(simple_identifier))
(value_argument))))
(comment))

File diff suppressed because it is too large Load Diff

@ -1,360 +0,0 @@
================================================================================
Type references
================================================================================
something as Int
something as? A
something as! A
--------------------------------------------------------------------------------
(source_file
(as_expression
(simple_identifier)
(as_operator)
(user_type
(type_identifier)))
(as_expression
(simple_identifier)
(as_operator)
(user_type
(type_identifier)))
(as_expression
(simple_identifier)
(as_operator)
(user_type
(type_identifier))))
================================================================================
Nested types
================================================================================
something as Some.NestedType
--------------------------------------------------------------------------------
(source_file
(as_expression
(simple_identifier)
(as_operator)
(user_type
(type_identifier)
(type_identifier))))
================================================================================
Deeply nested types
================================================================================
somethingElse as A.Deeply.Nested.Type
--------------------------------------------------------------------------------
(source_file
(as_expression
(simple_identifier)
(as_operator)
(user_type
(type_identifier)
(type_identifier)
(type_identifier)
(type_identifier))))
================================================================================
Generic parameterized types
================================================================================
something as Generic<T>
something as Generic<A, Type>
--------------------------------------------------------------------------------
(source_file
(as_expression
(simple_identifier)
(as_operator)
(user_type
(type_identifier)
(type_arguments
(user_type
(type_identifier)))))
(as_expression
(simple_identifier)
(as_operator)
(user_type
(type_identifier)
(type_arguments
(user_type
(type_identifier))
(user_type
(type_identifier))))))
================================================================================
Function types
================================================================================
unitFunction as () -> Unit
consumer as (Int) -> Unit
configurator as (inout Config) -> Unit
--------------------------------------------------------------------------------
(source_file
(as_expression
(simple_identifier)
(as_operator)
(function_type
(tuple_type)
(user_type
(type_identifier))))
(as_expression
(simple_identifier)
(as_operator)
(function_type
(tuple_type
(tuple_type_item
(user_type
(type_identifier))))
(user_type
(type_identifier))))
(as_expression
(simple_identifier)
(as_operator)
(function_type
(tuple_type
(tuple_type_item
(parameter_modifiers
(parameter_modifier))
(user_type
(type_identifier))))
(user_type
(type_identifier)))))
================================================================================
Function types with multiple parameters
================================================================================
a as (Int, Generic<T>, Boolean) -> Unit
b as (Nested.Type, (Int)) -> Unit
--------------------------------------------------------------------------------
(source_file
(as_expression
(simple_identifier)
(as_operator)
(function_type
(tuple_type
(tuple_type_item
(user_type
(type_identifier)))
(tuple_type_item
(user_type
(type_identifier)
(type_arguments
(user_type
(type_identifier)))))
(tuple_type_item
(user_type
(type_identifier))))
(user_type
(type_identifier))))
(as_expression
(simple_identifier)
(as_operator)
(function_type
(tuple_type
(tuple_type_item
(user_type
(type_identifier)
(type_identifier)))
(tuple_type_item
(tuple_type
(tuple_type_item
(user_type
(type_identifier))))))
(user_type
(type_identifier)))))
================================================================================
Types with named parameters (function or tuple)
================================================================================
a as (first: A, second: B)
-> Unit
let c: (third: C, fourth: D)
--------------------------------------------------------------------------------
(source_file
(as_expression
(simple_identifier)
(as_operator)
(function_type
(tuple_type
(tuple_type_item
(simple_identifier)
(user_type
(type_identifier)))
(tuple_type_item
(simple_identifier)
(user_type
(type_identifier))))
(user_type
(type_identifier))))
(property_declaration
(pattern
(simple_identifier))
(type_annotation
(tuple_type
(tuple_type_item
(simple_identifier)
(user_type
(type_identifier)))
(tuple_type_item
(simple_identifier)
(user_type
(type_identifier)))))))
================================================================================
Nested optional types
================================================================================
private var dictionary: [String: Any?]?
--------------------------------------------------------------------------------
(source_file
(property_declaration
(modifiers
(visibility_modifier))
(pattern
(simple_identifier))
(type_annotation
(optional_type
(dictionary_type
(user_type
(type_identifier))
(optional_type
(user_type
(type_identifier))))))))
================================================================================
Implicitly unwrapped optional types
================================================================================
private var dictionary: [String: Any?]!
--------------------------------------------------------------------------------
(source_file
(property_declaration
(modifiers
(visibility_modifier))
(pattern
(simple_identifier))
(type_annotation
(dictionary_type
(user_type
(type_identifier))
(optional_type
(user_type
(type_identifier)))))))
================================================================================
Type aliases
================================================================================
public typealias Callback<T> = (T) -> Void
public typealias IntCallback = Callback<T>
--------------------------------------------------------------------------------
(source_file
(typealias_declaration
(modifiers
(visibility_modifier))
(type_identifier)
(type_parameters
(type_parameter
(type_identifier)))
(function_type
(tuple_type
(tuple_type_item
(user_type
(type_identifier))))
(user_type
(type_identifier))))
(typealias_declaration
(modifiers
(visibility_modifier))
(type_identifier)
(user_type
(type_identifier)
(type_arguments
(user_type
(type_identifier))))))
================================================================================
Metatypes
================================================================================
_ = foo as [String].Type
protocol GetType {
func getType() -> AnyObject.Type
}
--------------------------------------------------------------------------------
(source_file
(assignment
(directly_assignable_expression
(simple_identifier))
(navigation_expression
(as_expression
(simple_identifier)
(as_operator)
(array_type
(user_type
(type_identifier))))
(navigation_suffix
(simple_identifier))))
(protocol_declaration
(type_identifier)
(protocol_body
(protocol_function_declaration
(simple_identifier)
(user_type
(type_identifier)
(type_identifier))))))
================================================================================
Existential types
================================================================================
let p: any P = S()
func q(using p: any P) { }
--------------------------------------------------------------------------------
(source_file
(property_declaration
(pattern
(simple_identifier))
(type_annotation
(existential_type
(user_type
(type_identifier))))
(call_expression
(simple_identifier)
(call_suffix
(value_arguments))))
(function_declaration
(simple_identifier)
(parameter
(simple_identifier)
(simple_identifier)
(existential_type
(user_type
(type_identifier))))
(function_body)))

@ -1,29 +0,0 @@
import Cocoa
// ^ include
import GRDB
@NSApplicationMain
// ^ type
class AppDelegate: NSObject, NSApplicationDelegate {
// ^ keyword
// ^ type
// ^ punctuation.delimiter
// ^ type
// ^ punctuation.delimiter
// ^ punctuation.bracket
func applicationDidFinishLaunching(_ aNotification: Notification) {
// ^ keyword.function
// ^ method
// ^ parameter
// ^ parameter
_ = try! DatabaseQueue()
// ^ operator
// ^ operator
// ^ function.call
_ = FTS5()
_ = sqlite3_preupdate_new(nil, 0, nil)
// ^ variable.builtin
// ^ number
}
// ^ punctuation.bracket
}

@ -1,201 +0,0 @@
//
// Bag.swift
// Platform
//
// Created by Krunoslav Zaher on 2/28/15.
// Copyright © 2015 Krunoslav Zaher. All rights reserved.
//
import Swift
let arrayDictionaryMaxSize = 30
struct BagKey {
// ^ keyword
/**
Unique identifier for object added to `Bag`.
It's underlying type is UInt64. If we assume there in an idealized CPU that works at 4GHz,
it would take ~150 years of continuous running time for it to overflow.
*/
// ^ comment
fileprivate let rawValue: UInt64
// ^ keyword
// ^ keyword
// ^ property
}
/**
Data structure that represents a bag of elements typed `T`.
Single element can be stored multiple times.
Time and space complexity of insertion and deletion is O(n).
It is suitable for storing small number of elements.
*/
struct Bag<T> : CustomDebugStringConvertible {
// ^ type
/// Type of identifier for inserted elements.
// ^ comment
typealias KeyType = BagKey
typealias Entry = (key: BagKey, value: T)
private var _nextKey: BagKey = BagKey(rawValue: 0)
// ^ keyword
// ^ keyword
// ^ property
// data
// first fill inline variables
var _key0: BagKey?
var _value0: T?
// then fill "array dictionary"
var _pairs = ContiguousArray<Entry>()
// last is sparse dictionary
var _dictionary: [BagKey: T]?
var _onlyFastPath = true
/// Creates new empty `Bag`.
init() {
// ^ constructor
}
/**
Inserts `value` into bag.
- parameter element: Element to insert.
- returns: Key that can be used to remove element from bag.
*/
mutating func insert(_ element: T) -> BagKey {
// ^ operator
let key = _nextKey
_nextKey = BagKey(rawValue: _nextKey.rawValue &+ 1)
// ^ operator
if _key0 == nil {
// ^ conditional
_key0 = key
_value0 = element
return key
// ^ keyword.return
}
_onlyFastPath = false
if _dictionary != nil {
_dictionary![key] = element
return key
}
if _pairs.count < arrayDictionaryMaxSize {
_pairs.append((key: key, value: element))
return key
}
_dictionary = [key: element]
return key
}
/// - returns: Number of elements in bag.
var count: Int {
let dictionaryCount: Int = _dictionary?.count ?? 0
return (_value0 != nil ? 1 : 0) + _pairs.count + dictionaryCount
}
/// Removes all elements from bag and clears capacity.
mutating func removeAll() {
_key0 = nil
_value0 = nil
_pairs.removeAll(keepingCapacity: false)
_dictionary?.removeAll(keepingCapacity: false)
}
/**
Removes element with a specific `key` from bag.
- parameter key: Key that identifies element to remove from bag.
- returns: Element that bag contained, or nil in case element was already removed.
*/
mutating func removeKey(_ key: BagKey) -> T? {
if _key0 == key {
_key0 = nil
let value = _value0!
_value0 = nil
return value
}
if let existingObject = _dictionary?.removeValue(forKey: key) {
return existingObject
}
for i in 0 ..< _pairs.count where _pairs[i].key == key {
let value = _pairs[i].value
_pairs.remove(at: i)
return value
}
return nil
}
}
extension Bag {
// ^ keyword
// ^ type
/// A textual representation of `self`, suitable for debugging.
var debugDescription : String {
"\(self.count) elements in Bag"
// ^ string
// ^ punctuation.bracket
// ^ variable.builtin
}
}
extension Bag {
/// Enumerates elements inside the bag.
///
/// - parameter action: Enumeration closure.
func forEach(_ action: (T) -> Void) {
if _onlyFastPath {
if let value0 = _value0 {
action(value0)
}
return
}
let value0 = _value0
let dictionary = _dictionary
if let value0 = value0 {
action(value0)
}
for i in 0 ..< _pairs.count {
action(_pairs[i].value)
}
if dictionary?.count ?? 0 > 0 {
for element in dictionary!.values {
action(element)
}
}
}
}
extension BagKey: Hashable {
func hash(into hasher: inout Hasher) {
hasher.combine(rawValue)
}
}
func ==(lhs: BagKey, rhs: BagKey) -> Bool {
lhs.rawValue == rhs.rawValue
}

@ -1,65 +0,0 @@
// The MIT License (MIT)
//
// Copyright (c) 2016 Luke Zhao <me@lkzhao.com>
//
// 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.
import Foundation
public protocol HeroStringConvertible {
static func from(node: ExprNode) -> Self?
// ^ keyword
}
extension String {
func parse<T: HeroStringConvertible>() -> [T]? {
// ^ punctuation.delimiter
// ^ type
let lexer = Lexer(input: self)
let parser = Parser(tokens: lexer.tokenize())
// ^ punctuation.delimiter
// ^ function.call
do {
// ^ keyword
let nodes = try parser.parse()
// ^ operator
var results = [T]()
// ^ punctuation.bracket
for node in nodes {
if let modifier = T.from(node: node) {
results.append(modifier)
} else {
print("\(node.name) doesn't exist in \(T.self)")
// ^ string
}
}
return results
} catch let error {
// ^ keyword
// ^ keyword
// ^ variable
print("failed to parse \"\(self)\", error: \(error)")
}
return nil
}
func parseOne<T: HeroStringConvertible>() -> T? {
return parse()?.last
}
}

@ -1,114 +0,0 @@
/*
MIT License
Copyright (c) 2017-2019 MessageKit
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.
*/
import UIKit
/// A subclass of `MessageContentCell` used to display video and audio messages.
open class MediaMessageCell: MessageContentCell {
// ^ keyword
/// The play button view to display on video messages.
open lazy var playButtonView: PlayButtonView = {
// ^ keyword
// ^ punctuation.bracket
let playButtonView = PlayButtonView()
return playButtonView
}()
// ^ punctuation.bracket
// ^ punctuation.bracket
/// The image view display the media content.
open var imageView: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFill
return imageView
}()
// MARK: - Methods
/// Responsible for setting up the constraints of the cell's subviews.
open func setupConstraints() {
imageView.fillSuperview()
playButtonView.centerInSuperview()
playButtonView.constraint(equalTo: CGSize(width: 35, height: 35))
}
open override func setupSubviews() {
super.setupSubviews()
messageContainerView.addSubview(imageView)
messageContainerView.addSubview(playButtonView)
setupConstraints()
}
open override func prepareForReuse() {
super.prepareForReuse()
self.imageView.image = nil
}
open override func configure(with message: MessageType, at indexPath: IndexPath, and messagesCollectionView: MessagesCollectionView) {
super.configure(with: message, at: indexPath, and: messagesCollectionView)
guard let displayDelegate = messagesCollectionView.messagesDisplayDelegate else {
// ^ conditional
// ^ keyword
// ^ keyword
fatalError(MessageKitError.nilMessagesDisplayDelegate)
}
switch message.kind {
// ^ conditional
case .photo(let mediaItem):
// ^ keyword
// ^ punctuation.delimiter
// ^ variable
imageView.image = mediaItem.image ?? mediaItem.placeholderImage
// ^ operator
playButtonView.isHidden = true
// ^ boolean
case .video(let mediaItem):
imageView.image = mediaItem.image ?? mediaItem.placeholderImage
playButtonView.isHidden = false
// ^ boolean
default:
// ^ keyword
break
// ^ repeat
}
displayDelegate.configureMediaMessageImageView(imageView, for: message, at: indexPath, in: messagesCollectionView)
}
/// Handle tap gesture on contentView and its subviews.
open override func handleTapGesture(_ gesture: UIGestureRecognizer) {
let touchLocation = gesture.location(in: imageView)
guard imageView.frame.contains(touchLocation) else {
super.handleTapGesture(gesture)
return
}
delegate?.didTapImage(in: self)
}
}

@ -1,34 +0,0 @@
public struct OperatorUsageWhitespaceConfiguration: RuleConfiguration, Equatable {
private(set) var severityConfiguration = SeverityConfiguration(.warning)
// ^ keyword
// ^ keyword
private(set) var linesLookAround = 2
private(set) var skipAlignedConstants = true
private(set) var allowedNoSpaceOperators: [String] = ["...", "..<"]
public var consoleDescription: String {
return severityConfiguration.consoleDescription
+ ", lines_look_around: \(linesLookAround)"
+ ", skip_aligned_constants: \(skipAlignedConstants)"
+ ", allowed_no_space_operators: \(allowedNoSpaceOperators)"
}
public mutating func apply(configuration: Any) throws {
// ^ keyword
guard let configuration = configuration as? [String: Any] else {
// ^ keyword
// ^ keyword
throw ConfigurationError.unknownConfiguration
// ^ keyword
}
linesLookAround = configuration["lines_look_around"] as? Int ?? 2
skipAlignedConstants = configuration["skip_aligned_constants"] as? Bool ?? true
allowedNoSpaceOperators =
configuration["allowed_no_space_operators"] as? [String] ?? ["...", "..<"]
if let severityString = configuration["severity"] as? String {
try severityConfiguration.apply(configuration: severityString)
}
}
}

@ -1,59 +0,0 @@
//
// PlayerWindowController.swift
// iina
//
// Created by Yuze Jiang on 2/15/20.
// Copyright © 2020 lhc. All rights reserved.
//
import Cocoa
class PlayerWindowController: NSWindowController, NSWindowDelegate {
unowned var player: PlayerCore
var videoView: VideoView {
fatalError("Subclass must implement")
}
var menuActionHandler: MainMenuActionHandler!
var isOntop = false {
didSet {
player.mpv.setFlag(MPVOption.Window.ontop, isOntop)
}
}
var loaded = false
init(playerCore: PlayerCore) {
self.player = playerCore
super.init(window: nil)
if #available(macOS 10.15, *) {
// ^ number
// ^ number
// ^ operator
player.refreshEdrMode()
}
}
required init?(coder: NSCoder) {
// ^ keyword
// ^ constructor
fatalError("init(coder:) has not been implemented")
}
@IBOutlet weak var volumeSlider: NSSlider!
// ^ type
deinit {
ObjcUtils.silenced {
for key in self.observedPrefKeys {
// ^ repeat
// ^ repeat
UserDefaults.standard.removeObserver(self, forKeyPath: key.rawValue)
}
}
}
}