mirror of https://github.com/Wilfred/difftastic/
Update Swift parser to use crate
parent
97bab83730
commit
1b04d17c4d
@ -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,3 +0,0 @@
|
||||
build
|
||||
coverage
|
||||
src
|
||||
@ -1 +0,0 @@
|
||||
{}
|
||||
@ -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 @@
|
||||

|
||||
[](https://crates.io/crates/tree-sitter-swift)
|
||||
[](https://www.npmjs.com/package/tree-sitter-swift)
|
||||
[](https://github.com/alex-pinkus/tree-sitter-swift/actions/workflows/top-repos.yml)
|
||||
|
||||
# tree-sitter-swift
|
||||
|
||||
This contains a [`tree-sitter`](https://tree-sitter.github.io/tree-sitter) grammar for the Swift programming language.
|
||||
|
||||
## Getting started
|
||||
|
||||
To use this parser to parse Swift code, you'll want to depend on either the Rust crate or the NPM package.
|
||||
|
||||
### Rust
|
||||
To use the Rust crate, you'll add this to your `Cargo.toml`:
|
||||
```
|
||||
tree-sitter = "0.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))
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue