Sync tree-sitter-swift with upstream

Fixes #277

The upstream parser has added new support for a variety of constructs,
including better tracking for `await`. Query load time has also been
substantially improved by simplifying the rules that match patterns.
pull/404/head
Alex Pinkus 2022-10-09 12:06:04 +07:00
parent dd0c78fefa
commit c191f5cf47
40 changed files with 334844 additions and 460350 deletions

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

@ -11,17 +11,12 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x, 14.x, 16.x]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
- name: Use Node.js 16.x
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
node-version: 16.x
cache: 'npm'
- uses: actions-rs/toolchain@v1
with:

@ -0,0 +1,25 @@
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

@ -55,6 +55,16 @@ jobs:
- 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 }}

@ -2,7 +2,7 @@ name: Update corpus repository versions
on:
schedule:
- cron: '12 4 * * *'
- cron: '12 4 * * 0'
jobs:
update_repository_versions:

@ -1,11 +1,8 @@
node_modules
/src/*
!/src/scanner.c
!/src/parser.c
!/src/tree_sitter
*.swp
/build
/test
Cargo.lock
/target/*
*.a
@ -14,3 +11,5 @@ Cargo.lock
*.o
bindings/c/*.h
bindings/c/tree-sitter-*.pc
.vscode/
/.build

@ -1,7 +1,7 @@
[package]
name = "tree-sitter-swift"
description = "swift grammar for the tree-sitter parsing library"
version = "0.2.0"
version = "0.3.4"
keywords = ["incremental", "parsing", "swift"]
categories = ["parsing", "text-editors"]
repository = "https://github.com/alex-pinkus/tree-sitter-swift"

@ -1,4 +1,4 @@
VERSION := 0.2.0
VERSION := 0.3.4
# Repository
SRC_DIR := src
@ -107,6 +107,10 @@ install: all
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

@ -15,7 +15,7 @@ To use this parser to parse Swift code, you'll want to depend on either the Rust
To use the Rust crate, you'll add this to your `Cargo.toml`:
```
tree-sitter = "0.20.0"
tree-sitter-swift = "=0.2.0"
tree-sitter-swift = "=0.3.4"
```
Then you can use a `tree-sitter` parser with the language declared here:
@ -35,7 +35,7 @@ let tree = parser.parse(&my_source_code, None)
To use this from NPM, you'll add similar dependencies to `package.json`:
```
"dependencies: {
"tree-sitter-swift": "0.2.0",
"tree-sitter-swift": "0.3.4",
"tree-sitter": "^0.20.0"
}
```
@ -71,6 +71,38 @@ started this parser to teach myself how `tree-sitter` works, and how to write a
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`?

@ -35,10 +35,10 @@ 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 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");
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 {

@ -1,65 +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))
(value_binding_pattern (non_binding_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)))))

@ -58,7 +58,13 @@ const PRECS = {
assignment: -3,
comment: -3,
lambda: -3,
regex: -4,
};
const DYNAMIC_PRECS = {
call: 1,
};
const DEC_DIGITS = token(sep1(/[0-9]+/, /_+/));
const HEX_DIGITS = token(sep1(/[0-9a-fA-F]+/, /_+/));
const OCT_DIGITS = token(sep1(/[0-7]+/, /_+/));
@ -74,27 +80,12 @@ if (tree_sitter_version_supports_emoji()) {
LEXICAL_IDENTIFIER = /[_\p{XID_Start}][_\p{XID_Continue}]*/;
}
const CUSTOM_OPERATORS = token(
choice(
// https://docs.swift.org/swift-book/ReferenceManual/LexicalStructure.html#ID418
// This supports a subset of the operators that Swift does but I'm really not concerned about the esoteric ones.
// Someone who wants unicode support can add it. What this does do is:
// * Avoid the reserved operators by saying that certain characters are only available if you don't start with them.
// * Entirely forbid `<` as the last char because it creates ambiguity with type arguments
/[\\<>&?=][\/=\-+!*%<>&|^?~\.]*[\/=\-+!*%>&|^?~]+/,
/[\-+!*%|^~]+[\/=\-+!*%<>&|^?~]*[\/=\-+!*%>&|^?~]+/,
/[\-+!*%|^~\.]+[\/=\-+!*%<>&|^?~\.]*[\/=\-+!*%>&|^?~\.]+/,
/[\/]+[=\-+!*%<>&|^?~]*[=\-+!*%>&|^?~]+/,
/[\/]+[=\-+!*%<>&|^?~\.]*[=\-+!*%>&|^?~\.]+/
)
);
// XXX need custom scanner for:
// * Custom operators and `<` for type arguments
module.exports = grammar({
name: "swift",
conflicts: ($) => [
// @Type(... could either be an annotation constructor invocation or an annotated expression
[$.attribute],
[$._attribute_argument],
// Is `foo { ... }` a constructor invocation or function invocation?
[$._simple_user_type, $._expression],
// To support nested types A.B not being interpreted as `(navigation_expression ... (type_identifier)) (navigation_suffix)`
@ -109,12 +100,10 @@ module.exports = grammar({
// After a `{` in a function or switch context, it's ambigous whether we're starting a set of local statements or
// applying some modifiers to a capture or pattern.
[$.modifiers],
// Custom operators get weird special handling for `<` characters in silly stuff like `func =<<<<T>(...)`
[$.custom_operator],
[$._prefix_unary_operator, $._referenceable_operator],
// `+(...)` is ambigously either "call the function produced by a reference to the operator `+`" or "use the unary
// operator `+` on the result of the parenthetical expression."
[$._additive_operator, $._prefix_unary_operator],
[$._referenceable_operator, $._prefix_unary_operator],
// `{ [self, b, c] ...` could be a capture list or an array literal depending on what else happens.
[$.capture_list_item, $.self_expression],
[$.capture_list_item, $._expression],
@ -155,6 +144,35 @@ module.exports = grammar({
// The `class` modifier is legal in many of the same positions that a class declaration itself would be.
[$._bodyless_function_declaration, $.property_modifier],
[$._local_class_declaration, $.modifiers],
// Patterns, man
[$._navigable_type_expression, $._case_pattern],
[$._no_expr_pattern_already_bound, $._binding_pattern_with_expr],
[$._no_expr_pattern_already_bound, $._expression],
[$._no_expr_pattern_already_bound, $._binding_pattern_no_expr],
// On encountering a closure starting with `{ @Foo ...`, we don't yet know if that attribute applies to the closure
// type or to a declaration within the closure. What a mess! We just have to hope that if we keep going, only one of
// those will parse (because there will be an `in` or a `let`).
[
$._lambda_type_declaration,
$._local_property_declaration,
$._local_typealias_declaration,
$._local_function_declaration,
$._local_class_declaration,
],
// We want `foo() { }` to be treated as one function call, but we _also_ want `if foo() { ... }` to be treated as a
// full if-statement. This means we have to treat it as a conflict rather than purely a left or right associative
// construct, and let the parser realize that the second expression won't parse properly with the `{ ... }` as a
// lambda.
[$.constructor_suffix],
[$.call_suffix],
// `actor` is allowed to be an identifier, even though it is also a locally permitted declaration. If we encounter
// it, the only way to know what it's meant to be is to keep going.
[$._modifierless_class_declaration, $.property_modifier],
[$._modifierless_class_declaration, $.simple_identifier],
[$._fn_call_lambda_arguments],
],
extras: ($) => [
$.comment,
@ -189,12 +207,11 @@ module.exports = grammar({
// `_semi`, we advance a bit further to see if the next non-whitespace token would be one of these other operators.
// If so, we ignore the `_semi` and just produce the operator; if not, we produce the `_semi` and let the rest of
// the grammar sort it out. This isn't perfect, but it works well enough most of the time.
$._semi,
$._implicit_semi,
$._explicit_semi,
// Every one of the below operators will suppress a `_semi` if we encounter it after a newline.
$._arrow_operator_custom,
$._dot_custom,
$._three_dot_operator_custom,
$._open_ended_range_operator_custom,
$._conjunction_operator_custom,
$._disjunction_operator_custom,
$._nil_coalescing_operator_custom,
@ -213,6 +230,7 @@ module.exports = grammar({
$._as_quest_custom,
$._as_bang_custom,
$._async_keyword_custom,
$._custom_operator,
],
inline: ($) => [$._locally_permitted_modifiers],
rules: {
@ -222,8 +240,15 @@ module.exports = grammar({
source_file: ($) =>
seq(
optional($.shebang_line),
repeat(seq($._top_level_statement, $._semi))
optional(
seq(
$._top_level_statement,
repeat(seq($._semi, $._top_level_statement)),
optional($._semi)
)
)
),
_semi: ($) => choice($._implicit_semi, $._explicit_semi),
shebang_line: ($) => seq("#!", /[^\r\n]*/),
////////////////////////////////
// Lexical Structure - https://docs.swift.org/swift-book/ReferenceManual/LexicalStructure.html
@ -235,7 +260,8 @@ module.exports = grammar({
LEXICAL_IDENTIFIER,
/`[^\r\n` ]*`/,
/\$[0-9]+/,
token(seq("$", LEXICAL_IDENTIFIER))
token(seq("$", LEXICAL_IDENTIFIER)),
"actor"
),
identifier: ($) => sep1($.simple_identifier, $._dot),
// Literals
@ -248,6 +274,7 @@ module.exports = grammar({
$.real_literal,
$.boolean_literal,
$._string_literal,
$.regex_literal,
"nil"
),
// TODO: Hex exponents
@ -316,6 +343,30 @@ module.exports = grammar({
),
_escaped_identifier: ($) => /\\[0\\tnr"'\n]/,
multi_line_str_text: ($) => /[^\\"]+/,
// Based on https://gitlab.com/woolsweater/tree-sitter-swifter/-/blob/3d47c85bd47ce54cdf2023a9c0e01eb90adfcc1d/grammar.js#L1019
// But required modifications to hit all of the cases in SE-354
regex_literal: ($) =>
choice(
$._extended_regex_literal,
$._multiline_regex_literal,
$._oneline_regex_literal
),
_extended_regex_literal: ($) => /#\/((\/[^#])|[^\n])+\/#/,
_multiline_regex_literal: ($) => seq(/#\/\n/, /(\/[^#]|[^/])*?\n\/#/),
_oneline_regex_literal: ($) =>
token(
prec(
PRECS.regex,
seq(
"/",
token.immediate(/[^ \t\n]?[^/\n]*[^ \t\n/]/),
token.immediate("/")
)
)
),
////////////////////////////////
// Types - https://docs.swift.org/swift-book/ReferenceManual/Types.html
////////////////////////////////
@ -340,6 +391,7 @@ module.exports = grammar({
$.optional_type,
$.metatype,
$.opaque_type,
$.existential_type,
$.protocol_composition_type
)
),
@ -375,7 +427,7 @@ module.exports = grammar({
),
function_type: ($) =>
seq(
field("params", $.tuple_type),
field("params", choice($.tuple_type, $._unannotated_type)),
optional($._async_keyword),
optional($.throws),
$._arrow_operator,
@ -394,13 +446,13 @@ module.exports = grammar({
repeat1(alias($._immediate_quest, "?"))
)
),
metatype: ($) =>
prec.left(seq($._unannotated_type, ".", choice("Type", "Protocol"))),
metatype: ($) => seq($._unannotated_type, ".", choice("Type", "Protocol")),
_quest: ($) => "?",
_immediate_quest: ($) => token.immediate("?"),
opaque_type: ($) => seq("some", $.user_type),
opaque_type: ($) => prec.right(seq("some", $._unannotated_type)),
existential_type: ($) => prec.right(seq("any", $._unannotated_type)),
protocol_composition_type: ($) =>
prec.right(
prec.left(
seq(
$._unannotated_type,
repeat1(seq("&", prec.right($._unannotated_type)))
@ -540,7 +592,7 @@ module.exports = grammar({
seq(
field("start", $._expression),
field("op", $._range_operator),
field("end", $._expression)
field("end", $._expr_hack_at_ternary_binary_suffix)
)
),
infix_expression: ($) =>
@ -549,7 +601,7 @@ module.exports = grammar({
seq(
field("lhs", $._expression),
field("op", $.custom_operator),
field("rhs", $._expression)
field("rhs", $._expr_hack_at_ternary_binary_suffix)
)
),
nil_coalescing_expression: ($) =>
@ -558,7 +610,7 @@ module.exports = grammar({
seq(
field("value", $._expression),
$._nil_coalescing_operator,
field("if_nil", $._expression)
field("if_nil", $._expr_hack_at_ternary_binary_suffix)
)
),
check_expression: ($) =>
@ -575,7 +627,7 @@ module.exports = grammar({
seq(
field("lhs", $._expression),
field("op", $._comparison_operator),
field("rhs", $._expression)
field("rhs", $._expr_hack_at_ternary_binary_suffix)
)
),
equality_expression: ($) =>
@ -584,7 +636,7 @@ module.exports = grammar({
seq(
field("lhs", $._expression),
field("op", $._equality_operator),
field("rhs", $._expression)
field("rhs", $._expr_hack_at_ternary_binary_suffix)
)
),
conjunction_expression: ($) =>
@ -593,16 +645,7 @@ module.exports = grammar({
seq(
field("lhs", $._expression),
field("op", $._conjunction_operator),
prec.left(
PRECS.ternary_binary_suffix,
field(
"rhs",
choice(
$._expression,
alias($.expr_hack_at_ternary_binary_call, $.call_expression)
)
)
)
field("rhs", $._expr_hack_at_ternary_binary_suffix)
)
),
disjunction_expression: ($) =>
@ -611,7 +654,7 @@ module.exports = grammar({
seq(
field("lhs", $._expression),
field("op", $._disjunction_operator),
field("rhs", $._expression)
field("rhs", $._expr_hack_at_ternary_binary_suffix)
)
),
bitwise_operation: ($) =>
@ -619,10 +662,10 @@ module.exports = grammar({
seq(
field("lhs", $._expression),
field("op", $._bitwise_binary_operator),
field("rhs", $._expression)
field("rhs", $._expr_hack_at_ternary_binary_suffix)
)
),
custom_operator: ($) => seq(CUSTOM_OPERATORS, optional("<")),
custom_operator: ($) => choice(token(/[\/]+[*]+/), $._custom_operator),
// Suffixes
navigation_suffix: ($) =>
seq(
@ -632,25 +675,28 @@ module.exports = grammar({
call_suffix: ($) =>
prec(
PRECS.call_suffix,
seq(
choice(
$.value_arguments,
sep1($.lambda_literal, seq(field("name", $.simple_identifier), ":"))
)
choice(
$.value_arguments,
prec.dynamic(-1, $._fn_call_lambda_arguments), // Prefer to treat `foo() { }` as one call not two
seq($.value_arguments, $._fn_call_lambda_arguments)
)
),
constructor_suffix: ($) =>
prec(
PRECS.call_suffix,
seq(
choice(
choice(
alias($._constructor_value_arguments, $.value_arguments),
prec.dynamic(-1, $._fn_call_lambda_arguments), // As above
seq(
alias($._constructor_value_arguments, $.value_arguments),
$.lambda_literal
$._fn_call_lambda_arguments
)
)
),
_constructor_value_arguments: ($) =>
seq("(", optional(sep1($.value_argument, ",")), ")"),
_fn_call_lambda_arguments: ($) =>
sep1($.lambda_literal, seq(field("name", $.simple_identifier), ":")),
type_arguments: ($) => prec.left(seq("<", sep1($._type, ","), ">")),
value_arguments: ($) =>
seq(
@ -726,7 +772,7 @@ module.exports = grammar({
)
)
),
_await_operator: ($) => "await",
_await_operator: ($) => alias("await", "await"),
ternary_expression: ($) =>
prec.right(
PRECS.ternary,
@ -735,16 +781,15 @@ module.exports = grammar({
$._quest,
field("if_true", $._expression),
":",
prec.left(
PRECS.ternary_binary_suffix,
field(
"if_false",
choice(
$._expression,
alias($.expr_hack_at_ternary_binary_call, $.call_expression)
)
)
)
field("if_false", $._expr_hack_at_ternary_binary_suffix)
)
),
_expr_hack_at_ternary_binary_suffix: ($) =>
prec.left(
PRECS.ternary_binary_suffix,
choice(
$._expression,
alias($.expr_hack_at_ternary_binary_call, $.call_expression)
)
),
expr_hack_at_ternary_binary_call: ($) =>
@ -754,7 +799,11 @@ module.exports = grammar({
),
expr_hack_at_ternary_binary_call_suffix: ($) =>
prec(PRECS.call_suffix, $.value_arguments),
call_expression: ($) => prec(PRECS.call, seq($._expression, $.call_suffix)),
call_expression: ($) =>
prec(
PRECS.call,
prec.dynamic(DYNAMIC_PRECS.call, seq($._expression, $.call_suffix))
),
_primary_expression: ($) =>
choice(
$.tuple_expression,
@ -828,15 +877,20 @@ module.exports = grammar({
prec.left(
PRECS.lambda,
seq(
"{",
prec(PRECS.expr, optional(field("captures", $.capture_list))),
optional(seq(optional(field("type", $.lambda_function_type)), "in")),
choice("{", "^{"),
optional($._lambda_type_declaration),
optional($.statements),
"}"
)
),
capture_list: ($) =>
seq(repeat($.attribute), "[", sep1($.capture_list_item, ","), "]"),
_lambda_type_declaration: ($) =>
seq(
repeat($.attribute),
prec(PRECS.expr, optional(field("captures", $.capture_list))),
optional(field("type", $.lambda_function_type)),
"in"
),
capture_list: ($) => seq("[", sep1($.capture_list_item, ","), "]"),
capture_list_item: ($) =>
choice(
field("name", $.self_expression),
@ -870,7 +924,6 @@ module.exports = grammar({
lambda_function_type_parameters: ($) => sep1($.lambda_parameter, ","),
lambda_parameter: ($) =>
seq(
optional($.attribute),
choice(
$.self_expression,
prec(PRECS.expr, field("name", $.simple_identifier)),
@ -902,7 +955,11 @@ module.exports = grammar({
_if_condition_sequence_item: ($) =>
choice($._if_let_binding, $._expression, $.availability_condition),
_if_let_binding: ($) =>
seq($._direct_or_indirect_binding, $._equal_sign, $._expression),
seq(
$._direct_or_indirect_binding,
optional(seq($._equal_sign, $._expression)),
optional($.where_clause)
),
guard_statement: ($) =>
prec.right(
PRECS["if"],
@ -942,16 +999,13 @@ module.exports = grammar({
$.statements,
optional("fallthrough")
),
switch_pattern: ($) => generate_pattern_matching_rule($, true, false, true),
switch_pattern: ($) => alias($._binding_pattern_with_expr, $.pattern),
do_statement: ($) =>
prec.right(PRECS["do"], seq("do", $._block, repeat($.catch_block))),
catch_block: ($) =>
seq(
$.catch_keyword,
field(
"error",
optional(generate_pattern_matching_rule($, true, false))
),
field("error", optional(alias($._binding_pattern_no_expr, $.pattern))),
optional($.where_clause),
$._block
),
@ -987,6 +1041,8 @@ module.exports = grammar({
_assignment_and_operator: ($) => choice("+=", "-=", "*=", "/=", "%=", "="),
_equality_operator: ($) => choice("!=", "!==", $._eq_eq, "==="),
_comparison_operator: ($) => choice("<", ">", "<=", ">="),
_three_dot_operator: ($) => alias("...", "..."), // Weird alias to satisfy highlight queries
_open_ended_range_operator: ($) => alias("..<", "..<"),
_is_operator: ($) => "is",
_additive_operator: ($) =>
choice(
@ -995,7 +1051,10 @@ module.exports = grammar({
"+",
"-"
),
_multiplicative_operator: ($) => choice("*", "/", "%"),
// The `/` operator conflicts with a regex literal (which itself appears to conflict with a
// comment, for some reason), so we must give it equivalent token precedence.
_multiplicative_operator: ($) =>
choice("*", alias(token(prec(PRECS.regex, "/")), "/"), "%"),
as_operator: ($) => choice($._as, $._as_quest, $._as_bang),
_prefix_unary_operator: ($) =>
prec.right(
@ -1019,7 +1078,8 @@ module.exports = grammar({
$.navigation_expression,
$.call_expression,
$.tuple_expression,
$.self_expression
$.self_expression,
$.postfix_expression // Since `x[...]! = y` is legal
),
////////////////////////////////
// Statements - https://docs.swift.org/swift-book/ReferenceManual/Statements.html
@ -1069,7 +1129,7 @@ module.exports = grammar({
"for",
optional($._try_operator),
optional($._await_operator),
field("item", generate_pattern_matching_rule($, true, true, false)),
field("item", alias($._binding_pattern_no_expr, $.pattern)),
optional($.type_annotation),
"in",
field("collection", $._expression),
@ -1138,7 +1198,6 @@ module.exports = grammar({
$.typealias_declaration,
$.function_declaration,
$.class_declaration,
// TODO actor declaration
$.protocol_declaration,
$.operator_declaration,
$.precedence_group_declaration,
@ -1207,7 +1266,7 @@ module.exports = grammar({
prec.right(
seq(
optional($.modifiers),
field("name", $.value_binding_pattern),
field("name", alias($._binding_kind_and_pattern, $.pattern)),
optional($.type_annotation),
optional($.type_constraints),
$.protocol_property_requirements
@ -1220,28 +1279,22 @@ module.exports = grammar({
_modifierless_property_declaration: ($) =>
prec.right(
seq(
choice(seq(optional($._async_modifier), "let"), "var"),
sep1(
seq(
field(
"name",
alias($.property_binding_pattern, $.value_binding_pattern)
),
optional($.type_annotation),
optional($.type_constraints),
optional(
choice(
seq($._equal_sign, field("value", $._expression)),
field("computed_value", $.computed_property)
)
)
),
","
$._possibly_async_binding_pattern_kind,
sep1($._single_modifierless_property_declaration, ",")
)
),
_single_modifierless_property_declaration: ($) =>
seq(
field("name", alias($._no_expr_pattern_already_bound, $.pattern)),
optional($.type_annotation),
optional($.type_constraints),
optional(
choice(
seq($._equal_sign, field("value", $._expression)),
field("computed_value", $.computed_property)
)
)
),
property_binding_pattern: ($) =>
generate_pattern_matching_rule($, false, false),
typealias_declaration: ($) =>
seq(optional($.modifiers), $._modifierless_typealias_declaration),
_modifierless_typealias_declaration: ($) =>
@ -1296,7 +1349,7 @@ module.exports = grammar({
prec.right(
choice(
seq(
field("declaration_kind", choice("class", "struct")),
field("declaration_kind", choice("class", "struct", "actor")),
field("name", alias($.simple_identifier, $.type_identifier)),
optional($.type_parameters),
optional(seq(":", $._inheritance_specifiers)),
@ -1305,7 +1358,7 @@ module.exports = grammar({
),
seq(
field("declaration_kind", "extension"),
field("name", $.user_type),
field("name", $._unannotated_type),
optional($.type_parameters),
optional(seq(":", $._inheritance_specifiers)),
optional($.type_constraints),
@ -1329,7 +1382,8 @@ module.exports = grammar({
prec.left(field("inherits_from", choice($.user_type, $.function_type))),
_annotated_inheritance_specifier: ($) =>
seq(repeat($.attribute), $.inheritance_specifier),
type_parameters: ($) => seq("<", sep1($.type_parameter, ","), ">"),
type_parameters: ($) =>
seq("<", sep1($.type_parameter, ","), optional($.type_constraints), ">"),
type_parameter: ($) =>
seq(
optional($.type_parameter_modifiers),
@ -1361,7 +1415,7 @@ module.exports = grammar({
optional($._class_member_separator)
),
_function_value_parameters: ($) =>
seq("(", optional(sep1($._function_value_parameter, ",")), ")"),
repeat1(seq("(", optional(sep1($._function_value_parameter, ",")), ")")),
_function_value_parameter: ($) =>
seq(
optional($.attribute),
@ -1382,14 +1436,7 @@ module.exports = grammar({
_non_constructor_function_decl: ($) =>
seq(
"func",
field(
"name",
choice(
$.simple_identifier,
$._referenceable_operator,
$._bitwise_binary_operator
)
)
field("name", choice($.simple_identifier, $._referenceable_operator))
),
_referenceable_operator: ($) =>
choice(
@ -1399,10 +1446,15 @@ module.exports = grammar({
$._multiplicative_operator,
$._equality_operator,
$._comparison_operator,
$._assignment_and_operator,
"++",
"--",
$.bang,
"~"
"~",
"|",
"^",
"<<",
">>"
),
// Hide the fact that certain symbols come from the custom scanner by aliasing them to their
// string variants. This keeps us from having to see them in the syntax tree (which would be
@ -1412,9 +1464,6 @@ module.exports = grammar({
_eq_eq: ($) => alias($._eq_eq_custom, "=="),
_dot: ($) => alias($._dot_custom, "."),
_arrow_operator: ($) => alias($._arrow_operator_custom, "->"),
_three_dot_operator: ($) => alias($._three_dot_operator_custom, "..."),
_open_ended_range_operator: ($) =>
alias($._open_ended_range_operator_custom, "..<"),
_conjunction_operator: ($) => alias($._conjunction_operator_custom, "&&"),
_disjunction_operator: ($) => alias($._disjunction_operator_custom, "||"),
_nil_coalescing_operator: ($) =>
@ -1422,12 +1471,7 @@ module.exports = grammar({
_as: ($) => alias($._as_custom, "as"),
_as_quest: ($) => alias($._as_quest_custom, "as?"),
_as_bang: ($) => alias($._as_bang_custom, "as!"),
_async_keyword: function ($) {
// Backward compatibility: make `async` both a named node and a string node. Remove this once downstream queries
// have all been switched over.
return prec(-1, alias($._async_keyword_internal, $.async));
},
_async_keyword_internal: ($) => alias($._async_keyword_custom, "async"),
_async_keyword: ($) => alias($._async_keyword_custom, "async"),
_async_modifier: ($) => token("async"),
throws: ($) => choice($._throws_keyword, $._rethrows_keyword),
enum_class_body: ($) =>
@ -1551,9 +1595,13 @@ module.exports = grammar({
seq(
choice("prefix", "infix", "postfix"),
"operator",
$.custom_operator,
optional(seq(":", $.simple_identifier))
$._referenceable_operator,
optional(seq(":", $.simple_identifier)),
optional($.deprecated_operator_declaration_body)
),
// The Swift compiler no longer accepts these, but some very old code still uses it.
deprecated_operator_declaration_body: ($) =>
seq("{", repeat(choice($.simple_identifier, $._basic_literal)), "}"),
precedence_group_declaration: ($) =>
seq(
"precedencegroup",
@ -1586,64 +1634,104 @@ module.exports = grammar({
"@",
$.user_type,
// attribute arguments are a mess of special cases, maybe this is good enough?
optional(
seq(
"(",
sep1(
choice(
// labeled function parameters, used in custom property wrappers
seq($.simple_identifier, ":", $._expression),
// Unlabeled function parameters, simple identifiers, or `*`
$._expression,
// References to param names (used in `@objc(foo:bar:)`)
repeat1(seq($.simple_identifier, ":")),
// Version restrictions (iOS 3.4.5, Swift 5.0.0)
seq(repeat1($.simple_identifier), sep1($.integer_literal, "."))
),
","
),
")"
)
)
optional(seq("(", sep1($._attribute_argument, ","), ")"))
),
_attribute_argument: ($) =>
choice(
// labeled function parameters, used in custom property wrappers
seq($.simple_identifier, ":", $._expression),
// Unlabeled function parameters, simple identifiers, or `*`
$._expression,
// References to param names (used in `@objc(foo:bar:)`)
repeat1(seq($.simple_identifier, ":")),
// Version restrictions (iOS 3.4.5, Swift 5.0.0)
seq(repeat1($.simple_identifier), sep1($.integer_literal, "."))
),
////////////////////////////////
// Patterns - https://docs.swift.org/swift-book/ReferenceManual/Patterns.html
////////////////////////////////
// Higher-than-default precedence to resolve `x as SomeType` ambiguity (expression patterns seem not to support
// as-expressions)
binding_pattern: ($) =>
prec.left(1, generate_pattern_matching_rule($, true, false, false, true)),
non_binding_pattern: ($) =>
prec.left(
1,
generate_pattern_matching_rule($, false, false, false, true)
_universally_allowed_pattern: ($) =>
choice(
$.wildcard_pattern,
$._tuple_pattern,
$._type_casting_pattern,
$._case_pattern
),
_bound_identifier: ($) => field("bound_identifier", $.simple_identifier),
_binding_pattern_no_expr: ($) =>
seq(
choice(
$._universally_allowed_pattern,
$._binding_pattern,
$._bound_identifier
),
optional($._quest)
),
_no_expr_pattern_already_bound: ($) =>
seq(
choice($._universally_allowed_pattern, $._bound_identifier),
optional($._quest)
),
// Higher precedence than pattern w/o binding since these are strictly more flexible
_binding_pattern_with_expr: ($) =>
prec.left(2, generate_pattern_matching_rule($, true, false, true, true)),
seq(
choice(
$._universally_allowed_pattern,
$._binding_pattern,
$._expression
),
optional($._quest)
),
_non_binding_pattern_with_expr: ($) =>
prec.left(2, generate_pattern_matching_rule($, false, false, true, true)),
seq(
choice($._universally_allowed_pattern, $._expression),
optional($._quest)
),
_direct_or_indirect_binding: ($) =>
seq(
choice(
$.value_binding_pattern,
seq("case", generate_pattern_matching_rule($, true, false, false))
$._binding_kind_and_pattern,
seq("case", $._binding_pattern_no_expr)
),
optional($.type_annotation)
),
_binding_pattern_kind: ($) => field("mutability", choice("var", "let")),
_possibly_async_binding_pattern_kind: ($) =>
seq(optional($._async_modifier), $._binding_pattern_kind),
_binding_kind_and_pattern: ($) =>
seq(
$._possibly_async_binding_pattern_kind,
$._no_expr_pattern_already_bound
),
wildcard_pattern: ($) => "_",
binding_pattern_kind: ($) => choice("var", "let"),
value_binding_pattern: ($) =>
prec.left(
choice(
seq("var", generate_pattern_matching_rule($, false, false)),
seq(
optional($._async_modifier),
"let",
generate_pattern_matching_rule($, false, false)
)
)
_tuple_pattern_item: ($) =>
choice(
seq(
$.simple_identifier,
seq(":", alias($._binding_pattern_with_expr, $.pattern))
),
alias($._binding_pattern_with_expr, $.pattern)
),
_tuple_pattern: ($) => seq("(", sep1($._tuple_pattern_item, ","), ")"),
_case_pattern: ($) =>
seq(
optional("case"),
optional($.user_type), // XXX this should just be _type but that creates ambiguity
$._dot,
$.simple_identifier,
optional($._tuple_pattern)
),
_type_casting_pattern: ($) =>
choice(
seq("is", $._type),
seq(alias($._binding_pattern_no_expr, $.pattern), $._as, $._type)
),
_binding_pattern: ($) =>
seq(
seq(optional("case"), $._binding_pattern_kind),
$._no_expr_pattern_already_bound
),
// ==========
// Modifiers
// ==========
@ -1663,17 +1751,15 @@ module.exports = grammar({
$.function_modifier,
$.mutation_modifier,
$.property_modifier,
$.parameter_modifier
$.parameter_modifier,
$.property_behavior_modifier
),
_locally_permitted_modifier: ($) =>
choice(
$.ownership_modifier,
$.property_behavior_modifier,
$.inheritance_modifier
),
choice($.ownership_modifier, $.inheritance_modifier),
property_behavior_modifier: ($) => "lazy",
type_modifiers: ($) => repeat1($.attribute),
member_modifier: ($) => choice("override", "convenience", "required"),
member_modifier: ($) =>
choice("override", "convenience", "required", "nonisolated"),
visibility_modifier: ($) =>
seq(
choice("public", "private", "internal", "fileprivate", "open"),
@ -1730,87 +1816,6 @@ module.exports = grammar({
function sep1(rule, separator) {
return seq(rule, repeat(seq(separator, rule)));
}
function generate_tuple_pattern($, allows_binding, allows_expressions) {
var pattern_rule = generate_pattern_matching_rule(
$,
allows_binding,
false,
allows_expressions
);
var tuple_pattern_item = choice(
seq($.simple_identifier, seq(":", pattern_rule)),
pattern_rule
);
return seq("(", sep1(tuple_pattern_item, ","), ")", optional($._quest));
}
function generate_case_pattern($, allows_binding, force) {
return seq(
optional($.user_type), // XXX this should just be _type but that creates ambiguity
$._dot,
$.simple_identifier,
optional(generate_tuple_pattern($, allows_binding, true)),
optional($._quest)
);
}
function generate_type_casting_pattern($, allows_binding) {
return choice(
seq("is", $._type),
seq(
generate_pattern_matching_rule($, allows_binding, false),
$._as,
$._type
)
);
}
function generate_pattern_matching_rule(
$,
allows_binding,
allows_case_keyword,
allows_expressions,
force
) {
if (!force && !allows_case_keyword) {
if (allows_binding && !allows_expressions) {
return $.binding_pattern;
}
if (!allows_binding && !allows_expressions) {
return $.non_binding_pattern;
}
if (allows_binding && allows_expressions) {
return $._binding_pattern_with_expr;
}
if (!allows_binding && allows_expressions) {
return $._non_binding_pattern_with_expr;
}
}
var always_allowed_patterns = [
$.wildcard_pattern,
generate_tuple_pattern($, allows_binding, allows_expressions || false),
generate_type_casting_pattern($, allows_binding),
];
var binding_pattern_prefix = allows_case_keyword
? seq(optional("case"), $.binding_pattern_kind)
: $.binding_pattern_kind;
var binding_pattern_if_allowed = allows_binding
? [
seq(
binding_pattern_prefix,
generate_pattern_matching_rule($, false, false, false)
),
]
: [];
var case_pattern = allows_case_keyword
? seq("case", generate_case_pattern($, allows_binding))
: generate_case_pattern($, allows_binding);
var expression_pattern = allows_expressions
? $._expression
: field("bound_identifier", $.simple_identifier);
var all_patterns = always_allowed_patterns
.concat(binding_pattern_if_allowed)
.concat(case_pattern)
.concat(expression_pattern);
return seq(choice.apply(void 0, all_patterns), optional($._quest));
}
function tree_sitter_version_supports_emoji() {
try {

@ -0,0 +1,41 @@
{
"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,6 +1,6 @@
{
"name": "tree-sitter-swift",
"version": "0.2.0",
"version": "0.3.4",
"description": "A tree-sitter grammar for the Swift programming language.",
"main": "bindings/node/index.js",
"scripts": {
@ -14,6 +14,15 @@
"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"
@ -26,7 +35,7 @@
"homepage": "https://github.com/alex-pinkus/tree-sitter-swift#readme",
"dependencies": {
"nan": "^2.15.0",
"tree-sitter-cli": "^0.20.6",
"tree-sitter-cli": "=0.20.6",
"which": "2.0.2"
},
"devDependencies": {

@ -21,22 +21,28 @@
(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))
(non_binding_pattern bound_identifier: (simple_identifier)) @variable
(pattern bound_identifier: (simple_identifier)) @variable
[
"typealias"
"struct"
"class"
"actor"
"enum"
"protocol"
"extension"
"indirect"
"nonisolated"
"override"
"convenience"
"required"
"some"
] @keyword
@ -46,18 +52,18 @@
(modify_specifier)
] @keyword
(class_body (property_declaration (value_binding_pattern (non_binding_pattern (simple_identifier) @property))))
(protocol_property_declaration (value_binding_pattern (non_binding_pattern (simple_identifier) @property)))
(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) ; foo()
(call_expression (simple_identifier) @function.call) ; foo()
(call_expression ; foo.bar.baz(): highlight the baz()
(navigation_expression
(navigation_suffix (simple_identifier) @function)))
(navigation_suffix (simple_identifier) @function.call)))
((navigation_expression
(simple_identifier) @type) ; SomeType.method(): highlight SomeType as a type
(#match? @type "^[A-Z]"))
@ -68,14 +74,13 @@
; Statements
(for_statement ["for" @repeat])
(for_statement ["in" @repeat])
(for_statement item: (simple_identifier) @variable)
(for_statement (pattern) @variable)
(else) @keyword
(as_operator) @keyword
["while" "repeat" "continue" "break"] @repeat
["let" "var"] @keyword
(non_binding_pattern (simple_identifier) @variable)
(guard_statement ["guard" @conditional])
(if_statement ["if" @conditional])
@ -92,8 +97,10 @@
(statement_label) @label
; Comments
(comment) @comment
(multiline_comment) @comment
[
(comment)
(multiline_comment)
] @comment @spell
; String literals
(line_str_text) @string
@ -118,6 +125,9 @@
(boolean_literal) @boolean
"nil" @variable.builtin
; Regex literals
(regex_literal) @string.regex
; Operators
(custom_operator) @operator
[

@ -15,4 +15,4 @@
(function_declaration)
(class_declaration)
(protocol_declaration)
] @scope
] @local.scope

@ -0,0 +1,51 @@
(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,4 +1 @@
firefox-ios/Shared/Functions.swift
RxSwift/RxExample/RxExample/Examples/GitHubSearchRepositories/GitHubSearchRepositories.swift
SwiftLint/Source/SwiftLintFramework/Rules/Lint/ExpiringTodoRule.swift
GRDB/GRDB/Core/Row.swift
ReactKit/ReactKitTests/OperationTests.swift

@ -1,7 +1,7 @@
Alamofire Alamofire/Alamofire 5.6.1
iina iina/iina v1.2.0
Charts danielgindi/Charts v4.0.2
lottie-ios airbnb/lottie-ios 3.3.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
@ -13,31 +13,41 @@ 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.1
Kingfisher onevcat/Kingfisher 7.2.1
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.47.0 0 2
SwiftLint realm/SwiftLint 0.47.0 1 2
ClashX yichengchen/clashX 1.91.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.53
PromiseKit mxcl/PromiseKit 6.17.0
Moya Moya/Moya 15.0.0
MonitorControl MonitorControl/MonitorControl v4.0.2
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.29.2
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.4.0
AudioKit AudioKit/AudioKit 5.5.6
Starscream daltoniam/Starscream 4.0.4
MessageKit MessageKit/MessageKit 3.7.0
MessageKit MessageKit/MessageKit 4.0.0
KeychainAccess kishikawakatsumi/KeychainAccess v4.2.2
Nuke kean/Nuke 10.8.0
Swinject Swinject/Swinject 2.8.1
GRDB groue/GRDB.swift v5.23.0 0 2
GRDB groue/GRDB.swift v5.23.0 1 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

@ -8,17 +8,4 @@ if [[ "$1" == "--install-valgrind" ]]; then
shift
fi
# Query tests hang forever when run with valgrind, so move them out of
# the way.
mv ./queries ./queries.bak
trap "mv ./queries.bak ./queries || true" EXIT
valgrind tree-sitter test
# Now move the query tests back, and move the corpus tests out of the
# way.
mv ./queries.bak ./queries
mv ./corpus ./corpus.bak
trap "mv ./corpus.bak ./corpus || true" EXIT
tree-sitter test

@ -19,6 +19,13 @@ git reset HEAD@{1}
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
@ -28,8 +35,10 @@ git add ./src/tree_sitter/* --force
git add ./src/*.json --force
git add grammar.js
git add package.json
git add corpus
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"

File diff suppressed because it is too large Load Diff

@ -1,4 +1,5 @@
#include <tree_sitter/parser.h>
#include <string.h>
#include <wctype.h>
enum TokenType {
@ -6,11 +7,10 @@ enum TokenType {
RAW_STR_PART,
RAW_STR_CONTINUING_INDICATOR,
RAW_STR_END_PART,
SEMI,
IMPLICIT_SEMI,
EXPLICIT_SEMI,
ARROW_OPERATOR,
DOT_OPERATOR,
THREE_DOT_OPERATOR,
OPEN_ENDED_RANGE_OPERATOR,
CONJUNCTION_OPERATOR,
DISJUNCTION_OPERATOR,
NIL_COALESCING_OPERATOR,
@ -28,16 +28,15 @@ enum TokenType {
AS_KEYWORD,
AS_QUEST,
AS_BANG,
ASYNC_KEYWORD
ASYNC_KEYWORD,
CUSTOM_OPERATOR,
};
#define OPERATOR_COUNT 22
#define OPERATOR_COUNT 20
const char* OPERATORS[OPERATOR_COUNT] = {
"->",
".",
"...",
"..<",
"&&",
"||",
"??",
@ -68,8 +67,6 @@ enum IllegalTerminatorGroup {
const enum IllegalTerminatorGroup OP_ILLEGAL_TERMINATORS[OPERATOR_COUNT] = {
OPERATOR_SYMBOLS, // ->
OPERATOR_OR_DOT, // .
OPERATOR_OR_DOT, // ...
OPERATOR_OR_DOT, // ..<
OPERATOR_SYMBOLS, // &&
OPERATOR_SYMBOLS, // ||
OPERATOR_SYMBOLS, // ??
@ -93,8 +90,6 @@ const enum IllegalTerminatorGroup OP_ILLEGAL_TERMINATORS[OPERATOR_COUNT] = {
const enum TokenType OP_SYMBOLS[OPERATOR_COUNT] = {
ARROW_OPERATOR,
DOT_OPERATOR,
THREE_DOT_OPERATOR,
OPEN_ENDED_RANGE_OPERATOR,
CONJUNCTION_OPERATOR,
DISJUNCTION_OPERATOR,
NIL_COALESCING_OPERATOR,
@ -115,12 +110,46 @@ const enum TokenType OP_SYMBOLS[OPERATOR_COUNT] = {
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 THREE_DOT_OPERATOR:
case OPEN_ENDED_RANGE_OPERATOR:
case CONJUNCTION_OPERATOR:
case DISJUNCTION_OPERATOR:
case NIL_COALESCING_OPERATOR:
@ -138,6 +167,7 @@ bool is_cross_semi_token(enum TokenType op) {
case AS_QUEST:
case AS_BANG:
case ASYNC_KEYWORD:
case CUSTOM_OPERATOR:
return true;
case BANG:
default:
@ -162,8 +192,10 @@ const uint32_t NON_CONSUMING_CROSS_SEMI_CHARS[NON_CONSUMING_CROSS_SEMI_CHAR_COUN
enum ParseDirective {
CONTINUE_PARSING_NOTHING_FOUND,
CONTINUE_PARSING_TOKEN_FOUND,
CONTINUE_PARSING_SLASH_CONSUMED,
STOP_PARSING_NOTHING_FOUND,
STOP_PARSING_TOKEN_FOUND
STOP_PARSING_TOKEN_FOUND,
STOP_PARSING_END_OF_FILE
};
struct ScannerState {
@ -231,18 +263,106 @@ static int32_t encountered_op_count(bool *encountered_operator) {
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]];
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;
}
int32_t str_idx = 0;
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++) {
@ -304,12 +424,53 @@ static bool eat_operators(
}
}
if (encountered_op_count(possible_operators) == 0) {
break;
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) {
@ -317,61 +478,72 @@ static bool eat_operators(
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 bool eat_comment(
static enum ParseDirective eat_comment(
TSLexer *lexer,
const bool *valid_symbols,
bool mark_end,
enum TokenType *symbol_result
) {
// This is from https://github.com/tree-sitter/tree-sitter-rust/blob/f1c5c4b1d7b98a0288c1e4e6094cfcc3f6213cc0/src/scanner.c
if (lexer->lookahead == '/') {
advance(lexer);
if (lexer->lookahead != '*') return false;
advance(lexer);
bool after_star = false;
unsigned nesting_depth = 1;
for (;;) {
switch (lexer->lookahead) {
case '\0':
return false;
case '*':
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 = 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 true;
}
} else {
advance(lexer);
after_star = false;
if (lexer->lookahead == '*') {
nesting_depth++;
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;
}
break;
default:
} else {
advance(lexer);
after_star = false;
break;
if (lexer->lookahead == '*') {
nesting_depth++;
advance(lexer);
}
}
break;
default:
advance(lexer);
after_star = false;
break;
}
}
return false;
}
static enum ParseDirective eat_whitespace(
@ -380,33 +552,37 @@ static enum ParseDirective eat_whitespace(
enum TokenType *symbol_result
) {
enum ParseDirective ws_directive = CONTINUE_PARSING_NOTHING_FOUND;
bool semi_is_valid = valid_symbols[SEMI];
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) {
break;
if (semi_is_valid) {
ws_directive = STOP_PARSING_TOKEN_FOUND;
lexer->advance(lexer, false);
}
ws_directive = STOP_PARSING_TOKEN_FOUND;
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;
}
}
lexer->mark_end(lexer);
if (true && ws_directive == CONTINUE_PARSING_TOKEN_FOUND && lookahead == '/') {
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;
bool saw_multiline_comment = eat_comment(lexer, valid_symbols, /* mark_end */ false, &multiline_comment_result);
if (saw_multiline_comment) {
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.
@ -415,6 +591,12 @@ static enum ParseDirective eat_whitespace(
*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
@ -432,18 +614,25 @@ static enum ParseDirective eat_whitespace(
// 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, &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 = SEMI;
*symbol_result = IMPLICIT_SEMI;
ws_directive = STOP_PARSING_TOKEN_FOUND;
}
}
@ -459,7 +648,7 @@ static enum ParseDirective eat_whitespace(
}
if (semi_is_valid && ws_directive != CONTINUE_PARSING_NOTHING_FOUND) {
*symbol_result = SEMI;
*symbol_result = lookahead == ';' ? EXPLICIT_SEMI : IMPLICIT_SEMI;
return ws_directive;
}
@ -515,9 +704,11 @@ static bool eat_raw_str_part(
while (lexer->lookahead != '#' && lexer->lookahead != '\0') {
last_char = lexer->lookahead;
advance(lexer);
if (last_char != '\\') {
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.
// 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);
}
}
@ -569,23 +760,37 @@ bool tree_sitter_swift_external_scanner_scan(
return true;
}
if (ws_directive == STOP_PARSING_NOTHING_FOUND) {
if (ws_directive == STOP_PARSING_NOTHING_FOUND || ws_directive == STOP_PARSING_END_OF_FILE) {
return false;
}
bool has_ws_result = (ws_directive != CONTINUE_PARSING_NOTHING_FOUND);
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 */ true,
/* 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;
}
@ -595,14 +800,6 @@ bool tree_sitter_swift_external_scanner_scan(
return true;
}
enum TokenType comment_result;
bool saw_comment = eat_comment(lexer, valid_symbols, /* mark_end */ true, &comment_result);
if (saw_comment) {
lexer->mark_end(lexer);
lexer->result_symbol = comment_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;

@ -15,7 +15,7 @@
},
"..": {
"name": "tree-sitter-swift",
"version": "0.2.0",
"version": "0.3.4",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {

@ -0,0 +1,75 @@
================================================================================
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)))))

@ -117,18 +117,16 @@ internal open class Test {
(property_declaration
(modifiers
(visibility_modifier))
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(type_annotation
(user_type
(type_identifier))))
(property_declaration
(modifiers
(visibility_modifier))
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(type_annotation
(user_type
(type_identifier))))
@ -400,17 +398,15 @@ class SomethingElse: ThingProvider {
(type_identifier)
(class_body
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(type_annotation
(user_type
(type_identifier)))
(integer_literal))
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(type_annotation
(optional_type
(user_type
@ -418,17 +414,15 @@ class SomethingElse: ThingProvider {
(property_declaration
(modifiers
(property_behavior_modifier))
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(type_annotation
(user_type
(type_identifier)))
(simple_identifier))
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(type_annotation
(user_type
(type_identifier)))
@ -436,9 +430,8 @@ class SomethingElse: ThingProvider {
(statements
(simple_identifier))))
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(type_annotation
(user_type
(type_identifier)))
@ -451,9 +444,8 @@ class SomethingElse: ThingProvider {
(setter_specifier)
(simple_identifier))))
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(type_annotation
(user_type
(type_identifier)))
@ -477,18 +469,15 @@ class SomethingElse: ThingProvider {
(type_identifier)))
(class_body
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(type_annotation
(user_type
(type_identifier)))
(computed_property
(statements
(guard_statement
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(simple_identifier)
(simple_identifier)
(else)
(statements
@ -499,9 +488,9 @@ class SomethingElse: ThingProvider {
(control_transfer_statement
(simple_identifier)))))
(function_declaration
(modifiers
(property_modifier)
(member_modifier))
(modifiers
(property_modifier)
(member_modifier))
(simple_identifier)
(function_body)))))
@ -522,16 +511,14 @@ class Alphabet {
(type_identifier)
(class_body
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(type_annotation
(user_type
(type_identifier)))
(computed_property
(computed_getter
(getter_specifier
(async))
(getter_specifier)
(statements
(integer_literal))))))))
@ -549,9 +536,8 @@ class Cat { let noise: String = "meow"; let claws: String = "retractable" }
(type_identifier)
(class_body
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(type_annotation
(user_type
(type_identifier)))
@ -561,18 +547,16 @@ class Cat { let noise: String = "meow"; let claws: String = "retractable" }
(type_identifier)
(class_body
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(type_annotation
(user_type
(type_identifier)))
(line_string_literal
(line_str_text)))
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(type_annotation
(user_type
(type_identifier)))
@ -591,9 +575,8 @@ var propertyMap: NodePropertyMap & KeypathSearchable {
(source_file
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(type_annotation
(protocol_composition_type
(user_type
@ -624,9 +607,8 @@ struct Adder {
(type_identifier)
(class_body
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(type_annotation
(user_type
(type_identifier))))
@ -696,9 +678,8 @@ protocol Wrapper {
(type_identifier)
(protocol_body
(protocol_property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(type_annotation
(user_type
(type_identifier)))
@ -808,16 +789,14 @@ class Test {
(type_identifier)
(class_body
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(type_annotation
(user_type
(type_identifier))))
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(type_annotation
(user_type
(type_identifier))))
@ -983,9 +962,8 @@ enum CStyle {
(property_declaration
(modifiers
(property_modifier))
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(type_annotation
(user_type
(type_identifier)))
@ -1077,6 +1055,9 @@ extension SpecialDecorator where Self: Decorator, Self.DecoratedType == SpecialT
public extension Foo where T == (arg1: Arg1, arg2: Arg2) { }
extension [SpecialItem] {
}
--------------------------------------------------------------------------------
(source_file
@ -1088,17 +1069,15 @@ public extension Foo where T == (arg1: Arg1, arg2: Arg2) { }
(property_declaration
(modifiers
(property_modifier))
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(line_string_literal
(line_str_text)))
(property_declaration
(modifiers
(property_modifier))
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(type_annotation
(user_type
(type_identifier)))
@ -1143,6 +1122,11 @@ public extension Foo where T == (arg1: Arg1, arg2: Arg2) { }
(simple_identifier)
(user_type
(type_identifier)))))))
(class_body))
(class_declaration
(array_type
(user_type
(type_identifier)))
(class_body)))
================================================================================
@ -1196,9 +1180,8 @@ enum ComputeType {
(simple_identifier)
(line_string_literal
(line_str_text))))
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(type_annotation
(user_type
(type_identifier))))
@ -1248,9 +1231,8 @@ let result: HasGeneric<P1 & P2> = HasGeneric<P1 & P2>(t: "Hello")
(source_file
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(type_annotation
(user_type
(type_identifier)
@ -1347,9 +1329,8 @@ let result = greet("me") as P1 & P2
(source_file
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(as_expression
(call_expression
(simple_identifier)
@ -1393,18 +1374,16 @@ public final class Foo {
(property_declaration
(modifiers
(visibility_modifier))
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(type_annotation
(user_type
(type_identifier))))
(property_declaration
(modifiers
(visibility_modifier))
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(type_annotation
(user_type
(type_identifier)))
@ -1438,9 +1417,8 @@ public var someVar: String {
(property_declaration
(modifiers
(visibility_modifier))
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(type_annotation
(user_type
(type_identifier)))
@ -1474,3 +1452,103 @@ extension TrustMe: @unchecked Sendable { }
(user_type
(type_identifier)))
(class_body)))
================================================================================
Actors
================================================================================
private actor CounterActor {
private var count = 0
func next() -> Int {
count += 1
return count
}
nonisolated func eventuallyIncrement() {
Task {
await next()
}
}
}
--------------------------------------------------------------------------------
(source_file
(class_declaration
(modifiers
(visibility_modifier))
(type_identifier)
(class_body
(property_declaration
(modifiers
(visibility_modifier))
(pattern
(simple_identifier))
(integer_literal))
(function_declaration
(simple_identifier)
(user_type
(type_identifier))
(function_body
(statements
(assignment
(directly_assignable_expression
(simple_identifier))
(integer_literal))
(control_transfer_statement
(simple_identifier)))))
(function_declaration
(modifiers
(member_modifier))
(simple_identifier)
(function_body
(statements
(call_expression
(simple_identifier)
(call_suffix
(lambda_literal
(statements
(await_expression
(call_expression
(simple_identifier)
(call_suffix
(value_arguments))))))))))))))
================================================================================
Lazy is usable as a computed property
================================================================================
extension Array {
var stringified: some RandomAccessCollection {
lazy.map { "\($0)" }
}
}
--------------------------------------------------------------------------------
(source_file
(class_declaration
(user_type
(type_identifier))
(class_body
(property_declaration
(pattern
(simple_identifier))
(type_annotation
(opaque_type
(user_type
(type_identifier))))
(computed_property
(statements
(call_expression
(navigation_expression
(simple_identifier)
(navigation_suffix
(simple_identifier)))
(call_suffix
(lambda_literal
(statements
(line_string_literal
(interpolated_expression
(simple_identifier)))))))))))))

@ -10,21 +10,18 @@ let ☁️☀️☁️ = "clouds and sun"
(source_file
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(line_string_literal
(line_str_text)))
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(line_string_literal
(line_str_text)))
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(line_string_literal
(line_str_text))))
@ -87,9 +84,8 @@ let number4⃣ = nummber2⃣ + number2
(source_file
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(additive_expression
(simple_identifier)
(simple_identifier))))

@ -84,18 +84,18 @@ a
(conjunction_expression
(simple_identifier)
(call_expression
(simple_identifier)
(call_suffix
(value_arguments))))
(simple_identifier)
(call_suffix
(value_arguments))))
(conjunction_expression
(simple_identifier)
(call_expression
(navigation_expression
(simple_identifier)
(navigation_suffix
(simple_identifier)))
(call_suffix
(value_arguments)))))
(navigation_expression
(simple_identifier)
(navigation_suffix
(simple_identifier)))
(call_suffix
(value_arguments)))))
================================================================================
Bitwise operations
@ -242,9 +242,8 @@ let e = array[...]
(source_file
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(call_expression
(simple_identifier)
(call_suffix
@ -261,9 +260,8 @@ let e = array[...]
(integer_literal))))))
(simple_identifier))
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(call_expression
(simple_identifier)
(call_suffix
@ -272,9 +270,8 @@ let e = array[...]
(simple_identifier)
(simple_identifier))))))
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(call_expression
(simple_identifier)
(call_suffix
@ -285,9 +282,8 @@ let e = array[...]
(simple_identifier)
(simple_identifier))))))
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(call_expression
(simple_identifier)
(call_suffix
@ -322,14 +318,12 @@ _ = someCall()
(source_file
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(integer_literal))
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(type_annotation
(user_type
(type_identifier)))
@ -368,9 +362,8 @@ let a: SomeClass = .someInstance
(source_file
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(type_annotation
(user_type
(type_identifier)))
@ -394,9 +387,8 @@ func math() {
(function_body
(statements
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(type_annotation
(tuple_type
(tuple_type_item
@ -463,9 +455,8 @@ var result2 = [String: [Complex<[String: Any]>]]()
(source_file
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(constructor_expression
(user_type
(type_identifier)
@ -475,9 +466,8 @@ var result2 = [String: [Complex<[String: Any]>]]()
(constructor_suffix
(value_arguments))))
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(constructor_expression
(dictionary_type
(user_type
@ -521,9 +511,8 @@ modifyThis(&this)
(type_identifier))))
(function_body))
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(dictionary_literal))
(call_expression
(simple_identifier)
@ -545,9 +534,8 @@ let setterSelector = #selector(setter: self.bar)
(source_file
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(selector_expression
(call_expression
(navigation_expression
@ -559,18 +547,16 @@ let setterSelector = #selector(setter: self.bar)
(value_argument
(simple_identifier)))))))
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(selector_expression
(navigation_expression
(self_expression)
(navigation_suffix
(simple_identifier)))))
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(selector_expression
(navigation_expression
(self_expression)
@ -607,9 +593,8 @@ let result: MyEnumType = condition ? .someEnumCase : .someOtherEnum
(source_file
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(ternary_expression
(tuple_expression
(equality_expression
@ -619,9 +604,8 @@ let result: MyEnumType = condition ? .someEnumCase : .someOtherEnum
(simple_identifier)))
(array_literal)))
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(type_annotation
(user_type
(type_identifier)))
@ -673,7 +657,8 @@ for i in 0 ..< something.count {
(source_file
(for_statement
(simple_identifier)
(pattern
(simple_identifier))
(range_expression
(integer_literal)
(navigation_expression
@ -780,18 +765,16 @@ let keyPathStringExpression = #keyPath(someProperty)
(source_file
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(navigation_expression
(key_path_expression
(type_identifier))
(navigation_suffix
(simple_identifier))))
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(call_expression
(simple_identifier)
(call_suffix
@ -800,19 +783,17 @@ let keyPathStringExpression = #keyPath(someProperty)
(simple_identifier)
(integer_literal))))))
(call_expression
(call_expression
(navigation_expression
(simple_identifier)
(navigation_suffix
(simple_identifier)))
(call_suffix
(value_arguments
(value_argument
(navigation_expression
(key_path_expression)
(navigation_suffix
(simple_identifier)))))))
(navigation_expression
(simple_identifier)
(navigation_suffix
(simple_identifier)))
(call_suffix
(value_arguments
(value_argument
(navigation_expression
(key_path_expression)
(navigation_suffix
(simple_identifier)))))
(lambda_literal
(lambda_function_type
(lambda_function_type_parameters
@ -839,9 +820,8 @@ let keyPathStringExpression = #keyPath(someProperty)
(simple_identifier)
(integer_literal)))
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(navigation_expression
(navigation_expression
(key_path_expression
@ -851,9 +831,8 @@ let keyPathStringExpression = #keyPath(someProperty)
(navigation_suffix
(simple_identifier))))
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(key_path_string_expression
(simple_identifier))))
@ -978,9 +957,8 @@ let two = 2
(source_file
(property_declaration
(value_binding_pattern
(non_binding_pattern
(wildcard_pattern)))
(pattern
(wildcard_pattern))
(multiplicative_expression
(tuple_expression
(additive_expression
@ -988,9 +966,8 @@ let two = 2
(integer_literal)))
(integer_literal)))
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(equality_expression
(tuple_expression
(additive_expression
@ -998,9 +975,8 @@ let two = 2
(integer_literal)))
(integer_literal)))
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(additive_expression
(additive_expression
(integer_literal)
@ -1108,7 +1084,8 @@ for try await value in values {
(source_file
(for_statement
(simple_identifier)
(pattern
(simple_identifier))
(simple_identifier)
(statements
(call_expression
@ -1131,11 +1108,12 @@ let a = false
(source_file
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(boolean_literal))
(simple_identifier))
(prefix_expression
(bang)
(simple_identifier)))
================================================================================
Calling `async` in positions where it could be a keyword
@ -1148,23 +1126,94 @@ async(async: async, qos: qos, flags: flags) {
(source_file
(call_expression
(call_expression
(simple_identifier)
(call_suffix
(value_arguments
(value_argument
(simple_identifier)
(simple_identifier))
(value_argument
(simple_identifier)
(simple_identifier))
(value_argument
(simple_identifier)
(simple_identifier)))))
(simple_identifier)
(call_suffix
(value_arguments
(value_argument
(simple_identifier)
(simple_identifier))
(value_argument
(simple_identifier)
(simple_identifier))
(value_argument
(simple_identifier)
(simple_identifier)))
(lambda_literal
(statements
(call_expression
(simple_identifier)
(call_suffix
(value_arguments))))))))
================================================================================
Assigning to the result of a force unwrap
================================================================================
stat[lang]! += 1
--------------------------------------------------------------------------------
(source_file
(assignment
(directly_assignable_expression
(postfix_expression
(call_expression
(simple_identifier)
(call_suffix
(value_arguments
(value_argument
(simple_identifier)))))
(bang)))
(integer_literal)))
================================================================================
Tricky operators
================================================================================
/!5;
prefix operator /!;
prefix func /!(x: Int) {
print(x)
}
--------------------------------------------------------------------------------
(source_file
(prefix_expression
(custom_operator)
(integer_literal))
(operator_declaration
(custom_operator))
(function_declaration
(modifiers
(function_modifier))
(custom_operator)
(parameter
(simple_identifier)
(user_type
(type_identifier)))
(function_body
(statements
(call_expression
(simple_identifier)
(call_suffix
(value_arguments
(value_argument
(simple_identifier)))))))))
================================================================================
Three dot operator after newline
================================================================================
foo()
...
--------------------------------------------------------------------------------
(source_file
(call_expression
(simple_identifier)
(call_suffix
(value_arguments)))
(fully_open_range))

@ -354,6 +354,8 @@ precedencegroup MyPrecedence {
infix operator -=- : MyPrecedence
infix operator •
--------------------------------------------------------------------------------
(source_file
@ -371,7 +373,9 @@ infix operator -=- : MyPrecedence
(simple_identifier))))
(operator_declaration
(custom_operator)
(simple_identifier)))
(simple_identifier))
(operator_declaration
(custom_operator)))
================================================================================
Custom operator with another operator as a prefix
@ -383,9 +387,8 @@ let messageCoerced = error ??? "nil"
(source_file
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(infix_expression
(simple_identifier)
(custom_operator)
@ -440,7 +443,6 @@ func maybe()
(source_file
(function_declaration
(simple_identifier)
(async)
(user_type
(type_identifier))
(function_body
@ -450,7 +452,6 @@ func maybe()
(integer_literal))))))
(function_declaration
(simple_identifier)
(async)
(throws)
(user_type
(type_identifier))
@ -517,13 +518,11 @@ test(2) { $0.doSomething() }
(source_file
(call_expression
(call_expression
(simple_identifier)
(call_suffix
(value_arguments
(value_argument
(integer_literal)))))
(simple_identifier)
(call_suffix
(value_arguments
(value_argument
(integer_literal)))
(lambda_literal
(statements
(call_expression
@ -589,10 +588,10 @@ test { @Special [weak self, otherSelf] (a) in }
(simple_identifier)
(call_suffix
(lambda_literal
(attribute
(user_type
(type_identifier)))
(capture_list
(attribute
(user_type
(type_identifier)))
(capture_list_item
(ownership_modifier)
(simple_identifier))
@ -722,9 +721,8 @@ private lazy var onCatClosure: (_ cat: Cat) throws -> Void = { _ in
(modifiers
(visibility_modifier)
(property_behavior_modifier))
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(type_annotation
(function_type
(tuple_type
@ -796,10 +794,11 @@ func multipleType() -> Foo & Bar { return Foo() }
(value_arguments))))))))
================================================================================
Annotated function parameters in lambdas
Lambdas with annotations
================================================================================
types.flatMap { @Sendable _ in }
let mainClosure = { @MainActor in print("Running on main") }
--------------------------------------------------------------------------------
@ -811,10 +810,25 @@ types.flatMap { @Sendable _ in }
(simple_identifier)))
(call_suffix
(lambda_literal
(attribute
(user_type
(type_identifier)))
(lambda_function_type
(lambda_function_type_parameters
(lambda_parameter
(attribute
(user_type
(type_identifier)))
(simple_identifier))))))))
(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))))))))))

@ -168,17 +168,15 @@ let numerals = [1: "I", 4: "IV", 5: "V", 10: "X"]
(source_file
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(array_literal
(integer_literal)
(integer_literal)
(integer_literal)))
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(dictionary_literal
(integer_literal)
(line_string_literal
@ -237,9 +235,8 @@ let _ = nil
(source_file
(property_declaration
(value_binding_pattern
(non_binding_pattern
(wildcard_pattern)))))
(pattern
(wildcard_pattern))))
================================================================================
Raw strings
@ -252,15 +249,13 @@ let _ = ##"Hello, so-called "world"!"##
(source_file
(property_declaration
(value_binding_pattern
(non_binding_pattern
(wildcard_pattern)))
(pattern
(wildcard_pattern))
(raw_string_literal
(raw_str_end_part)))
(property_declaration
(value_binding_pattern
(non_binding_pattern
(wildcard_pattern)))
(pattern
(wildcard_pattern))
(raw_string_literal
(raw_str_end_part))))
@ -270,13 +265,12 @@ Doesn't hang for incomplete raw strings (issue #146)
let _ = #"Foo"
---
--------------------------------------------------------------------------------
(source_file
(property_declaration
(value_binding_pattern
(non_binding_pattern
(wildcard_pattern)))
(pattern
(wildcard_pattern))
(ERROR
(UNEXPECTED '"'))
(line_string_literal
@ -333,6 +327,9 @@ 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)\#
"""#
--------------------------------------------------------------------------------
@ -351,9 +348,8 @@ let _ = ##"\##(a)\#(b)\##(c)\#(d)"# ##"##
(multiline_comment))
(raw_str_end_part))))))
(property_declaration
(value_binding_pattern
(non_binding_pattern
(wildcard_pattern)))
(pattern
(wildcard_pattern))
(raw_string_literal
(raw_str_part)
(raw_str_interpolation
@ -362,15 +358,13 @@ let _ = ##"\##(a)\#(b)\##(c)\#(d)"# ##"##
(simple_identifier)))
(raw_str_end_part)))
(property_declaration
(value_binding_pattern
(non_binding_pattern
(wildcard_pattern)))
(pattern
(wildcard_pattern))
(raw_string_literal
(raw_str_end_part)))
(property_declaration
(value_binding_pattern
(non_binding_pattern
(wildcard_pattern)))
(pattern
(wildcard_pattern))
(raw_string_literal
(raw_str_part)
(raw_str_interpolation
@ -382,6 +376,16 @@ let _ = ##"\##(a)\#(b)\##(c)\#(d)"# ##"##
(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))))
================================================================================
@ -396,22 +400,19 @@ let infinity = "\u{221E}"
(source_file
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(line_string_literal
(str_escaped_char)))
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(line_string_literal
(line_str_text)
(str_escaped_char)))
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(line_string_literal
(str_escaped_char))))
@ -425,9 +426,311 @@ let playgroundLiteral = #imageLiteral(resourceName: "heart")
(source_file
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(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))

@ -10,24 +10,21 @@ let `default` = 0
(source_file
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(integer_literal))
(property_declaration
(value_binding_pattern
(non_binding_pattern
(non_binding_pattern
(simple_identifier))
(non_binding_pattern
(simple_identifier))))
(pattern
(pattern
(simple_identifier))
(pattern
(simple_identifier)))
(tuple_expression
(integer_literal)
(integer_literal)))
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(integer_literal)))
================================================================================
@ -40,21 +37,17 @@ var one = 1, two = 2, four = 4, eight = 8
(source_file
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(integer_literal)
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(integer_literal)
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(integer_literal)
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(integer_literal)))
================================================================================
@ -77,7 +70,8 @@ for var value in values where value.isExcellent() {
(source_file
(for_statement
(simple_identifier)
(pattern
(simple_identifier))
(type_annotation
(user_type
(type_identifier)))
@ -90,19 +84,26 @@ for var value in values where value.isExcellent() {
(value_argument
(simple_identifier)))))))
(for_statement
(simple_identifier)
(simple_identifier)
(pattern
(simple_identifier)
(pattern
(simple_identifier)))
(simple_identifier))
(for_statement
(simple_identifier)
(simple_identifier)
(integer_literal)
(simple_identifier)
(integer_literal)
(pattern
(simple_identifier)
(pattern
(pattern
(simple_identifier)
(pattern
(integer_literal)))
(pattern
(simple_identifier)
(pattern
(integer_literal)))))
(simple_identifier))
(for_statement
(binding_pattern_kind)
(non_binding_pattern
(pattern
(simple_identifier))
(simple_identifier)
(where_clause
@ -138,28 +139,28 @@ outerLoop: for outerObject in dataArray {
(source_file
(for_statement
(binding_pattern_kind)
(non_binding_pattern
(non_binding_pattern
(pattern
(pattern
(simple_identifier))
(user_type
(type_identifier)))
(simple_identifier))
(for_statement
(binding_pattern_kind)
(non_binding_pattern
(non_binding_pattern
(pattern
(pattern
(simple_identifier))
(non_binding_pattern
(pattern
(simple_identifier)))
(simple_identifier))
(statement_label)
(for_statement
(simple_identifier)
(pattern
(simple_identifier))
(simple_identifier)
(statements
(for_statement
(simple_identifier)
(pattern
(simple_identifier))
(simple_identifier)
(statements
(if_statement
@ -205,10 +206,9 @@ repeat {
(integer_literal))
(comment))
(while_statement
(value_binding_pattern
(non_binding_pattern
(simple_identifier)
(simple_identifier)))
(simple_identifier)
(pattern
(simple_identifier))
(call_expression
(simple_identifier)
(call_suffix
@ -239,22 +239,25 @@ switch something {
(simple_identifier)
(switch_entry
(switch_pattern
(simple_identifier))
(pattern
(simple_identifier)))
(statements
(control_transfer_statement
(line_string_literal
(line_str_text)))))
(switch_entry
(switch_pattern
(simple_identifier))
(pattern
(simple_identifier)))
(statements
(control_transfer_statement
(line_string_literal
(line_str_text)))))
(switch_entry
(switch_pattern
(line_string_literal
(line_str_text)))
(pattern
(line_string_literal
(line_str_text))))
(statements
(control_transfer_statement
(line_string_literal
@ -290,20 +293,23 @@ case let .isExecutable(path?):
(simple_identifier)
(switch_entry
(switch_pattern
(binding_pattern_kind)
(non_binding_pattern
(pattern
(simple_identifier)
(wildcard_pattern)
(simple_identifier)))
(pattern
(wildcard_pattern))
(pattern
(simple_identifier))))
(statements
(simple_identifier)))
(switch_entry
(switch_pattern
(simple_identifier))
(pattern
(simple_identifier)))
(where_keyword)
(simple_identifier)
(switch_pattern
(simple_identifier))
(pattern
(simple_identifier)))
(statements
(simple_identifier)))
(switch_entry
@ -320,10 +326,10 @@ case let .isExecutable(path?):
(self_expression)
(switch_entry
(switch_pattern
(simple_identifier)
(binding_pattern_kind)
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier)
(pattern
(simple_identifier))))
(statements
(control_transfer_statement
(line_string_literal
@ -332,10 +338,10 @@ case let .isExecutable(path?):
(simple_identifier))))))
(switch_entry
(switch_pattern
(binding_pattern_kind)
(non_binding_pattern
(pattern
(simple_identifier)
(simple_identifier)))
(pattern
(simple_identifier))))
(statements
(control_transfer_statement
(line_string_literal
@ -343,6 +349,31 @@ case let .isExecutable(path?):
(interpolated_expression
(simple_identifier))))))))
================================================================================
Switch with extra parentheses
================================================================================
switch result {
case let .success((successfulResult)):
return successfulResult
}
--------------------------------------------------------------------------------
(source_file
(switch_statement
(simple_identifier)
(switch_entry
(switch_pattern
(pattern
(simple_identifier)
(pattern
(pattern
(simple_identifier)))))
(statements
(control_transfer_statement
(simple_identifier))))))
================================================================================
Imports
================================================================================
@ -395,32 +426,27 @@ do {
(do_statement
(statements
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(integer_literal)))
(catch_block
(catch_keyword)
(binding_pattern
(binding_pattern
(binding_pattern_kind)
(non_binding_pattern
(simple_identifier)))
(pattern
(pattern
(simple_identifier))
(user_type
(type_identifier))))
(catch_block
(catch_keyword)
(binding_pattern
(pattern
(user_type
(type_identifier))
(simple_identifier)))
(catch_block
(catch_keyword)
(binding_pattern
(binding_pattern
(binding_pattern_kind)
(non_binding_pattern
(simple_identifier)))
(pattern
(pattern
(simple_identifier))
(user_type
(type_identifier)))
(where_clause
@ -433,31 +459,28 @@ do {
(integer_literal))))
(catch_block
(catch_keyword)
(binding_pattern
(binding_pattern_kind)
(non_binding_pattern
(user_type
(type_identifier))
(simple_identifier)
(pattern
(user_type
(type_identifier))
(simple_identifier)
(pattern
(simple_identifier))))
(catch_block
(catch_keyword)
(binding_pattern
(pattern
(user_type
(type_identifier))
(simple_identifier)
(simple_identifier)
(binding_pattern_kind)
(non_binding_pattern
(pattern
(simple_identifier))))
(catch_block
(catch_keyword)))
(do_statement
(statements
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(integer_literal)))))
================================================================================
@ -481,9 +504,7 @@ someLabel: if a.isEmpty, let b = getB() {
(source_file
(if_statement
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(simple_identifier)
(call_expression
(simple_identifier)
(call_suffix
@ -494,17 +515,15 @@ someLabel: if a.isEmpty, let b = getB() {
(call_suffix
(value_arguments)))))
(if_statement
(binding_pattern
(simple_identifier)
(simple_identifier)
(pattern
(wildcard_pattern))
(call_expression
(simple_identifier)
(call_suffix
(value_arguments))))
(if_statement
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(simple_identifier)
(type_annotation
(user_type
(type_identifier)))
@ -518,9 +537,7 @@ someLabel: if a.isEmpty, let b = getB() {
(simple_identifier)
(navigation_suffix
(simple_identifier)))
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(simple_identifier)
(call_expression
(simple_identifier)
(call_suffix
@ -545,9 +562,7 @@ func doSomething() {
(function_body
(statements
(if_statement
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(simple_identifier)
(try_expression
(call_expression
(navigation_expression
@ -581,9 +596,7 @@ if let something = doThing(), let somethingElse = something.somethingElse() {
(source_file
(if_statement
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(simple_identifier)
(call_expression
(simple_identifier)
(call_suffix
@ -601,16 +614,12 @@ if let something = doThing(), let somethingElse = something.somethingElse() {
(call_suffix
(value_arguments)))))
(if_statement
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(simple_identifier)
(call_expression
(simple_identifier)
(call_suffix
(value_arguments)))
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(simple_identifier)
(call_expression
(navigation_expression
(simple_identifier)
@ -637,15 +646,11 @@ else if let cPrime = c {
(source_file
(if_statement
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(simple_identifier)
(simple_identifier)
(else)
(if_statement
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(simple_identifier)
(simple_identifier)))
(if_statement
(equality_expression
@ -653,9 +658,7 @@ else if let cPrime = c {
(simple_identifier))
(else)
(if_statement
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(simple_identifier)
(simple_identifier))))
================================================================================
@ -696,19 +699,19 @@ If try
--------------------------------------------------------------------------------
(source_file
(if_statement
(if_statement
(try_expression
(equality_expression
(simple_identifier)
(conjunction_expression
(try_expression
(equality_expression
(simple_identifier)))
(conjunction_expression
(simple_identifier)
(prefix_expression
(bang)
(simple_identifier))))
(statements
(control_transfer_statement
(simple_identifier)))))
(simple_identifier))))))
(statements
(control_transfer_statement
(simple_identifier)))))
================================================================================
Guard statements
@ -727,13 +730,15 @@ guard case .someCase(ident: let foo)? = otherThing() else {
guard case justIdentifier = bound else { }
guard let pattern else {
return
}
--------------------------------------------------------------------------------
(source_file
(guard_statement
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(simple_identifier)
(call_expression
(simple_identifier)
(call_suffix
@ -756,22 +761,24 @@ guard case justIdentifier = bound else { }
(call_suffix
(value_arguments)))))
(guard_statement
(binding_pattern
(simple_identifier)
(simple_identifier)
(binding_pattern_kind)
(non_binding_pattern
(simple_identifier)))
(simple_identifier)
(simple_identifier)
(pattern
(simple_identifier))
(call_expression
(simple_identifier)
(call_suffix
(value_arguments)))
(else))
(guard_statement
(binding_pattern
(simple_identifier))
(simple_identifier)
(else)))
(simple_identifier)
(else))
(guard_statement
(simple_identifier)
(else)
(statements
(control_transfer_statement))))
================================================================================
Compound guard
@ -785,9 +792,7 @@ guard let something = doThing(), something.isSpecial() else {
(source_file
(guard_statement
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(simple_identifier)
(call_expression
(simple_identifier)
(call_suffix
@ -818,10 +823,7 @@ guard case let size: Int = variable.size else {
(source_file
(guard_statement
(binding_pattern
(binding_pattern_kind)
(non_binding_pattern
(simple_identifier)))
(simple_identifier)
(type_annotation
(user_type
(type_identifier)))
@ -886,9 +888,8 @@ let ø = unicode()
(source_file
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(call_expression
(simple_identifier)
(call_suffix
@ -927,9 +928,8 @@ public init() {
(comment)
(property_declaration
(ownership_modifier)
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(simple_identifier))
(class_declaration
(inheritance_modifier)
@ -977,12 +977,32 @@ async let bar = 66
(source_file
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(integer_literal))
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(integer_literal)))
================================================================================
Actor is a legal identifier
================================================================================
let actor = 5
actor.increment()
--------------------------------------------------------------------------------
(source_file
(property_declaration
(pattern
(simple_identifier))
(integer_literal))
(call_expression
(navigation_expression
(simple_identifier)
(navigation_suffix
(simple_identifier)))
(call_suffix
(value_arguments))))

@ -202,9 +202,8 @@ let c: (third: C, fourth: D)
(user_type
(type_identifier))))
(property_declaration
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(type_annotation
(tuple_type
(tuple_type_item
@ -228,9 +227,8 @@ private var dictionary: [String: Any?]?
(property_declaration
(modifiers
(visibility_modifier))
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(type_annotation
(optional_type
(dictionary_type
@ -252,9 +250,8 @@ private var dictionary: [String: Any?]!
(property_declaration
(modifiers
(visibility_modifier))
(value_binding_pattern
(non_binding_pattern
(simple_identifier)))
(pattern
(simple_identifier))
(type_annotation
(dictionary_type
(user_type
@ -330,3 +327,34 @@ protocol GetType {
(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)))

@ -0,0 +1,29 @@
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
}

@ -0,0 +1,201 @@
//
// 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
}

@ -0,0 +1,65 @@
// 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
}
}

@ -0,0 +1,114 @@
/*
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)
}
}

@ -0,0 +1,34 @@
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)
}
}
}

@ -0,0 +1,59 @@
//
// 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)
}
}
}
}