difftastic/vendored_parsers/tree-sitter-swift/grammar.js

1835 lines
60 KiB
JavaScript

"use strict";
/*
* MIT License
*
* Copyright (c) 2021 alex-pinkus
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
const PRECS = {
multiplication: 11,
addition: 10,
infix_operations: 9,
nil_coalescing: 8,
check: 7,
prefix_operations: 7,
comparison: 6,
postfix_operations: 6,
equality: 5,
conjunction: 4,
disjunction: 3,
block: 2,
loop: 1,
keypath: 1,
control_transfer: 0,
as: -1,
tuple: -1,
if: -1,
switch: -1,
do: -1,
fully_open_range: -1,
range: -1,
navigation: -1,
expr: -1,
ty: -1,
call: -2,
ternary: -2,
try: -2,
call_suffix: -2,
range_suffix: -2,
ternary_binary_suffix: -2,
await: -2,
assignment: -3,
comment: -3,
lambda: -3,
regex: -4,
};
const DYNAMIC_PRECS = {
call: 1,
};
const DEC_DIGITS = token(sep1(/[0-9]+/, /_+/));
const HEX_DIGITS = token(sep1(/[0-9a-fA-F]+/, /_+/));
const OCT_DIGITS = token(sep1(/[0-7]+/, /_+/));
const BIN_DIGITS = token(sep1(/[01]+/, /_+/));
const REAL_EXPONENT = token(seq(/[eE]/, optional(/[+-]/), DEC_DIGITS));
var LEXICAL_IDENTIFIER;
if (tree_sitter_version_supports_emoji()) {
LEXICAL_IDENTIFIER =
/[_\p{XID_Start}\p{Emoji}&&[^0-9#*]](\p{EMod}|\x{FE0F}\x{20E3}?)?([_\p{XID_Continue}\p{Emoji}\x{200D}](\p{EMod}|\x{FE0F}\x{20E3}?)?)*/;
} else {
LEXICAL_IDENTIFIER = /[_\p{XID_Start}][_\p{XID_Continue}]*/;
}
module.exports = grammar({
name: "swift",
conflicts: ($) => [
// @Type(... could either be an annotation constructor invocation or an annotated expression
[$.attribute],
[$._attribute_argument],
// Is `foo { ... }` a constructor invocation or function invocation?
[$._simple_user_type, $._expression],
// To support nested types A.B not being interpreted as `(navigation_expression ... (type_identifier)) (navigation_suffix)`
[$.user_type],
// How to tell the difference between Foo.bar(with:and:), and Foo.bar(with: smth, and: other)? You need GLR
[$.value_argument],
// { (foo, bar) ...
[$._expression, $.lambda_parameter],
[$._primary_expression, $.lambda_parameter],
// (start: start, end: end)
[$._tuple_type_item_identifier, $.tuple_expression],
// After a `{` in a function or switch context, it's ambigous whether we're starting a set of local statements or
// applying some modifiers to a capture or pattern.
[$.modifiers],
// `+(...)` is ambigously either "call the function produced by a reference to the operator `+`" or "use the unary
// operator `+` on the result of the parenthetical expression."
[$._additive_operator, $._prefix_unary_operator],
[$._referenceable_operator, $._prefix_unary_operator],
// `{ [self, b, c] ...` could be a capture list or an array literal depending on what else happens.
[$.capture_list_item, $.self_expression],
[$.capture_list_item, $._expression],
[$.capture_list_item, $._expression, $._simple_user_type],
[$._primary_expression, $.capture_list_item],
// a ? b : c () could be calling c(), or it could be calling a function that's produced by the result of
// `(a ? b : c)`. We have a small hack to force it to be the former of these by intentionally introducing a
// conflict.
[$.call_suffix, $.expr_hack_at_ternary_binary_call_suffix],
// try {expression} is a bit magic and applies quite broadly: `try foo()` and `try foo { }` show that this is right
// associative, and `try foo ? bar() : baz` even more so. But it doesn't always win: something like
// `if try foo { } ...` should award its braces to the `if`. In order to make this actually happen, we need to parse
// all the options and pick the best one that doesn't error out.
[$.try_expression, $._unary_expression],
[$.try_expression, $._expression],
// await {expression} has the same special cases as `try`.
[$.await_expression, $._unary_expression],
[$.await_expression, $._expression],
// In a computed property, when you see an @attribute, it's not yet clear if that's going to be for a
// locally-declared class or a getter / setter specifier.
[
$._local_property_declaration,
$._local_typealias_declaration,
$._local_function_declaration,
$._local_class_declaration,
$.computed_getter,
$.computed_modify,
$.computed_setter,
],
// In a lambda literal's capture list, same problem with class attributes vs capture specifier attributes.
[
$.capture_list,
$._local_property_declaration,
$._local_typealias_declaration,
$._local_function_declaration,
$._local_class_declaration,
],
// 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,
$.multiline_comment,
$.directive,
$.diagnostic,
/\s+/, // Whitespace
],
externals: ($) => [
// Comments and raw strings are parsed in a custom scanner because they require us to carry forward state to
// maintain symmetry. For instance, parsing a multiline comment requires us to increment a counter whenever we see
// `/*`, and decrement it whenever we see `*/`. A standard grammar would only be able to exit the comment at the
// first `*/` (like C does). Similarly, when you start a string with `##"`, you're required to include the same
// number of `#` symbols to end it.
$.multiline_comment,
$.raw_str_part,
$.raw_str_continuing_indicator,
$.raw_str_end_part,
// Because Swift doesn't have explicit semicolons, we also do some whitespace handling in a custom scanner. Line
// breaks are _sometimes_ meaningful as the end of a statement: try to write `let foo: Foo let bar: Bar`, for
// instance and the compiler will complain, but add either a newline or a semicolon and it's fine. We borrow the
// idea from the Kotlin grammar that a newline is sometimes a "semicolon". By including `\n` in both `_semi` and
// an anonymous `whitespace` extras, we _should_ be able to let the parser decide if a newline is meaningful. If the
// parser sees something like `foo.bar(1\n)`, it knows that a "semicolon" would not be valid there, so it parses
// that as whitespace. On the other hand, `let foo: Foo\n let bar: Bar` has a meaningful newline.
// Unfortunately, we can't simply stop at that. There are some expressions and statements that remain valid if you
// end them early, but are expected to be parsed across multiple lines. One particular nefarious example is a
// function declaration, where you might have something like `func foo<A>(args: A) -> Foo throws where A: Hashable`.
// This would still be a valid declaration even if it ended after the `)`, the `Foo`, or the `throws`, so a grammar
// that simply interprets a newline as "sometimes a semi" would parse those incorrectly.
// To solve that case, our custom scanner must do a bit of extra lookahead itself. If we're about to generate a
// `_semi`, we advance a bit further to see if the next non-whitespace token would be one of these other operators.
// If so, we ignore the `_semi` and just produce the operator; if not, we produce the `_semi` and let the rest of
// the grammar sort it out. This isn't perfect, but it works well enough most of the time.
$._implicit_semi,
$._explicit_semi,
// Every one of the below operators will suppress a `_semi` if we encounter it after a newline.
$._arrow_operator_custom,
$._dot_custom,
$._conjunction_operator_custom,
$._disjunction_operator_custom,
$._nil_coalescing_operator_custom,
$._eq_custom,
$._eq_eq_custom,
$._plus_then_ws,
$._minus_then_ws,
$.bang,
$._throws_keyword,
$._rethrows_keyword,
$.default_keyword,
$.where_keyword,
$["else"],
$.catch_keyword,
$._as_custom,
$._as_quest_custom,
$._as_bang_custom,
$._async_keyword_custom,
$._custom_operator,
],
inline: ($) => [$._locally_permitted_modifiers],
rules: {
////////////////////////////////
// File Structure
////////////////////////////////
source_file: ($) =>
seq(
optional($.shebang_line),
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
////////////////////////////////
comment: ($) => token(prec(PRECS.comment, seq("//", /.*/))),
// Identifiers
simple_identifier: ($) =>
choice(
LEXICAL_IDENTIFIER,
/`[^\r\n` ]*`/,
/\$[0-9]+/,
token(seq("$", LEXICAL_IDENTIFIER)),
"actor"
),
identifier: ($) => sep1($.simple_identifier, $._dot),
// Literals
_basic_literal: ($) =>
choice(
$.integer_literal,
$.hex_literal,
$.oct_literal,
$.bin_literal,
$.real_literal,
$.boolean_literal,
$._string_literal,
$.regex_literal,
"nil"
),
// TODO: Hex exponents
real_literal: ($) =>
token(
choice(
seq(DEC_DIGITS, REAL_EXPONENT),
seq(optional(DEC_DIGITS), ".", DEC_DIGITS, optional(REAL_EXPONENT))
)
),
integer_literal: ($) => token(seq(optional(/[1-9]/), DEC_DIGITS)),
hex_literal: ($) => token(seq("0", /[xX]/, HEX_DIGITS)),
oct_literal: ($) => token(seq("0", /[oO]/, OCT_DIGITS)),
bin_literal: ($) => token(seq("0", /[bB]/, BIN_DIGITS)),
boolean_literal: ($) => choice("true", "false"),
// String literals
_string_literal: ($) =>
choice(
$.line_string_literal,
$.multi_line_string_literal,
$.raw_string_literal
),
line_string_literal: ($) =>
seq(
'"',
repeat(choice(field("text", $._line_string_content), $._interpolation)),
'"'
),
_line_string_content: ($) => choice($.line_str_text, $.str_escaped_char),
line_str_text: ($) => /[^\\"]+/,
str_escaped_char: ($) =>
choice($._escaped_identifier, $._uni_character_literal),
_uni_character_literal: ($) => seq("\\", "u", /\{[0-9a-fA-F]+\}/),
multi_line_string_literal: ($) =>
seq(
'"""',
repeat(
choice(field("text", $._multi_line_string_content), $._interpolation)
),
'"""'
),
raw_string_literal: ($) =>
seq(
repeat(
seq(
field("text", $.raw_str_part),
field("interpolation", $.raw_str_interpolation),
optional($.raw_str_continuing_indicator)
)
),
field("text", $.raw_str_end_part)
),
raw_str_interpolation: ($) =>
seq($.raw_str_interpolation_start, $._interpolation_contents, ")"),
raw_str_interpolation_start: ($) => /\\#*\(/,
_multi_line_string_content: ($) =>
choice($.multi_line_str_text, $.str_escaped_char, '"'),
_interpolation: ($) => seq("\\(", $._interpolation_contents, ")"),
_interpolation_contents: ($) =>
sep1(
field(
"interpolation",
alias($.value_argument, $.interpolated_expression)
),
","
),
_escaped_identifier: ($) => /\\[0\\tnr"'\n]/,
multi_line_str_text: ($) => /[^\\"]+/,
// Based on https://gitlab.com/woolsweater/tree-sitter-swifter/-/blob/3d47c85bd47ce54cdf2023a9c0e01eb90adfcc1d/grammar.js#L1019
// But required modifications to hit all of the cases in SE-354
regex_literal: ($) =>
choice(
$._extended_regex_literal,
$._multiline_regex_literal,
$._oneline_regex_literal
),
_extended_regex_literal: ($) => /#\/((\/[^#])|[^\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
////////////////////////////////
type_annotation: ($) =>
seq(":", field("type", $._possibly_implicitly_unwrapped_type)),
_possibly_implicitly_unwrapped_type: ($) =>
seq($._type, optional(token.immediate("!"))),
_type: ($) =>
prec.right(
PRECS.ty,
seq(optional($.type_modifiers), field("name", $._unannotated_type))
),
_unannotated_type: ($) =>
prec.right(
PRECS.ty,
choice(
$.user_type,
$.tuple_type,
$.function_type,
$.array_type,
$.dictionary_type,
$.optional_type,
$.metatype,
$.opaque_type,
$.existential_type,
$.protocol_composition_type
)
),
// The grammar just calls this whole thing a `type-identifier` but that's a bit confusing.
user_type: ($) => sep1($._simple_user_type, $._dot),
_simple_user_type: ($) =>
prec.right(
PRECS.ty,
seq(
alias($.simple_identifier, $.type_identifier),
optional($.type_arguments)
)
),
tuple_type: ($) =>
seq("(", optional(sep1(field("element", $.tuple_type_item), ",")), ")"),
tuple_type_item: ($) =>
prec(
PRECS.expr,
seq(
optional($._tuple_type_item_identifier),
optional($.parameter_modifiers),
field("type", $._type)
)
),
_tuple_type_item_identifier: ($) =>
prec(
PRECS.expr,
seq(
optional($.wildcard_pattern),
field("name", $.simple_identifier),
":"
)
),
function_type: ($) =>
seq(
field("params", choice($.tuple_type, $._unannotated_type)),
optional($._async_keyword),
optional($.throws),
$._arrow_operator,
field("return_type", $._type)
),
array_type: ($) => seq("[", field("element", $._type), "]"),
dictionary_type: ($) =>
seq("[", field("key", $._type), ":", field("value", $._type), "]"),
optional_type: ($) =>
prec.left(
seq(
field(
"wrapped",
choice($.user_type, $.tuple_type, $.array_type, $.dictionary_type)
),
repeat1(alias($._immediate_quest, "?"))
)
),
metatype: ($) => seq($._unannotated_type, ".", choice("Type", "Protocol")),
_quest: ($) => "?",
_immediate_quest: ($) => token.immediate("?"),
opaque_type: ($) => prec.right(seq("some", $._unannotated_type)),
existential_type: ($) => prec.right(seq("any", $._unannotated_type)),
protocol_composition_type: ($) =>
prec.left(
seq(
$._unannotated_type,
repeat1(seq("&", prec.right($._unannotated_type)))
)
),
////////////////////////////////
// Expressions - https://docs.swift.org/swift-book/ReferenceManual/Expressions.html
////////////////////////////////
_expression: ($) =>
prec(
PRECS.expr,
choice(
$.simple_identifier,
$._unary_expression,
$._binary_expression,
$.ternary_expression,
$._primary_expression,
$.assignment,
seq($._expression, alias($._immediate_quest, "?")),
alias("async", $.simple_identifier)
)
),
// Unary expressions
_unary_expression: ($) =>
choice(
$.postfix_expression,
$.call_expression,
$.constructor_expression,
$.navigation_expression,
$.prefix_expression,
$.as_expression,
$.selector_expression,
$.open_start_range_expression,
$.open_end_range_expression
),
postfix_expression: ($) =>
prec.left(
PRECS.postfix_operations,
seq(
field("target", $._expression),
field("operation", $._postfix_unary_operator)
)
),
constructor_expression: ($) =>
prec(
PRECS.call,
seq(
field(
"constructed_type",
choice($.array_type, $.dictionary_type, $.user_type)
),
$.constructor_suffix
)
),
navigation_expression: ($) =>
prec.left(
PRECS.navigation,
seq(
field("target", choice($._navigable_type_expression, $._expression)),
field("suffix", $.navigation_suffix)
)
),
_navigable_type_expression: ($) =>
choice($.user_type, $.array_type, $.dictionary_type),
open_start_range_expression: ($) =>
prec.right(
PRECS.range,
seq(
$._range_operator,
prec.right(PRECS.range_suffix, field("end", $._expression))
)
),
_range_operator: ($) =>
choice($._open_ended_range_operator, $._three_dot_operator),
open_end_range_expression: ($) =>
prec.right(
PRECS.range,
seq(field("start", $._expression), $._three_dot_operator)
),
prefix_expression: ($) =>
prec.left(
PRECS.prefix_operations,
seq(
field("operation", $._prefix_unary_operator),
field("target", $._expression)
)
),
as_expression: ($) =>
prec.left(
PRECS.as,
seq(field("expr", $._expression), $.as_operator, field("type", $._type))
),
selector_expression: ($) =>
seq(
"#selector",
"(",
optional(choice("getter:", "setter:")),
$._expression,
")"
),
// Binary expressions
_binary_expression: ($) =>
choice(
$.multiplicative_expression,
$.additive_expression,
$.range_expression,
$.infix_expression,
$.nil_coalescing_expression,
$.check_expression,
$.equality_expression,
$.comparison_expression,
$.conjunction_expression,
$.disjunction_expression,
$.bitwise_operation
),
multiplicative_expression: ($) =>
prec.left(
PRECS.multiplication,
seq(
field("lhs", $._expression),
field("op", $._multiplicative_operator),
field("rhs", $._expression)
)
),
additive_expression: ($) =>
prec.left(
PRECS.addition,
seq(
field("lhs", $._expression),
field("op", $._additive_operator),
field("rhs", $._expression)
)
),
range_expression: ($) =>
prec.right(
PRECS.range,
seq(
field("start", $._expression),
field("op", $._range_operator),
field("end", $._expr_hack_at_ternary_binary_suffix)
)
),
infix_expression: ($) =>
prec.left(
PRECS.infix_operations,
seq(
field("lhs", $._expression),
field("op", $.custom_operator),
field("rhs", $._expr_hack_at_ternary_binary_suffix)
)
),
nil_coalescing_expression: ($) =>
prec.right(
PRECS.nil_coalescing,
seq(
field("value", $._expression),
$._nil_coalescing_operator,
field("if_nil", $._expr_hack_at_ternary_binary_suffix)
)
),
check_expression: ($) =>
prec.left(
PRECS.check,
seq(
field("target", $._expression),
field("op", $._is_operator),
field("type", $._type)
)
),
comparison_expression: ($) =>
prec.left(
seq(
field("lhs", $._expression),
field("op", $._comparison_operator),
field("rhs", $._expr_hack_at_ternary_binary_suffix)
)
),
equality_expression: ($) =>
prec.left(
PRECS.equality,
seq(
field("lhs", $._expression),
field("op", $._equality_operator),
field("rhs", $._expr_hack_at_ternary_binary_suffix)
)
),
conjunction_expression: ($) =>
prec.left(
PRECS.conjunction,
seq(
field("lhs", $._expression),
field("op", $._conjunction_operator),
field("rhs", $._expr_hack_at_ternary_binary_suffix)
)
),
disjunction_expression: ($) =>
prec.left(
PRECS.disjunction,
seq(
field("lhs", $._expression),
field("op", $._disjunction_operator),
field("rhs", $._expr_hack_at_ternary_binary_suffix)
)
),
bitwise_operation: ($) =>
prec.left(
seq(
field("lhs", $._expression),
field("op", $._bitwise_binary_operator),
field("rhs", $._expr_hack_at_ternary_binary_suffix)
)
),
custom_operator: ($) => choice(token(/[\/]+[*]+/), $._custom_operator),
// Suffixes
navigation_suffix: ($) =>
seq(
$._dot,
field("suffix", choice($.simple_identifier, $.integer_literal))
),
call_suffix: ($) =>
prec(
PRECS.call_suffix,
choice(
$.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,
choice(
alias($._constructor_value_arguments, $.value_arguments),
prec.dynamic(-1, $._fn_call_lambda_arguments), // As above
seq(
alias($._constructor_value_arguments, $.value_arguments),
$._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(
choice(
seq("(", optional(sep1($.value_argument, ",")), ")"),
seq("[", optional(sep1($.value_argument, ",")), "]")
)
),
value_argument: ($) =>
prec.left(
seq(
optional($.type_modifiers),
choice(
repeat1(
seq(field("reference_specifier", $.simple_identifier), ":")
),
seq(
optional(
seq(
field(
"name",
choice(
$.simple_identifier,
alias("async", $.simple_identifier)
)
),
":"
)
),
field("value", $._expression)
)
)
)
),
try_expression: ($) =>
prec.right(
PRECS["try"],
seq(
$._try_operator,
field(
"expr",
choice(
// Prefer direct calls, e.g. `try foo()`, over indirect like `try a ? b() : c`. This allows us to have
// left associativity for the direct calls, which is technically wrong but is the only way to resolve the
// ambiguity of `if foo { ... }` in the correct direction.
prec.right(-2, $._expression),
prec.left(0, $._binary_expression),
prec.left(0, $.call_expression),
// Similarly special case the ternary expression, where `try` may come earlier than it is actually needed.
// When the parser just encounters some identifier after a `try`, it should prefer the `call_expression` (so
// this should be lower in priority than that), but when we encounter an ambiguous expression that might be
// either `try (foo() ? ...)` or `(try foo()) ? ...`, we should prefer the former. We accomplish that by
// giving it a _static precedence_ of -1 but a _dynamic precedence_ of 1.
prec.dynamic(1, prec.left(-1, $.ternary_expression))
)
)
)
),
await_expression: ($) =>
prec.right(
PRECS.await,
seq(
$._await_operator,
field(
"expr",
choice(
// Prefer direct calls over indirect (same as with `try`).
prec.right(-2, $._expression),
prec.left(0, $.call_expression),
// Special case ternary to `await` the whole thing (same as with `try`).
prec.dynamic(1, prec.left(-1, $.ternary_expression))
)
)
)
),
_await_operator: ($) => alias("await", "await"),
ternary_expression: ($) =>
prec.right(
PRECS.ternary,
seq(
field("condition", $._expression),
$._quest,
field("if_true", $._expression),
":",
field("if_false", $._expr_hack_at_ternary_binary_suffix)
)
),
_expr_hack_at_ternary_binary_suffix: ($) =>
prec.left(
PRECS.ternary_binary_suffix,
choice(
$._expression,
alias($.expr_hack_at_ternary_binary_call, $.call_expression)
)
),
expr_hack_at_ternary_binary_call: ($) =>
seq(
$._expression,
alias($.expr_hack_at_ternary_binary_call_suffix, $.call_suffix)
),
expr_hack_at_ternary_binary_call_suffix: ($) =>
prec(PRECS.call_suffix, $.value_arguments),
call_expression: ($) =>
prec(
PRECS.call,
prec.dynamic(DYNAMIC_PRECS.call, seq($._expression, $.call_suffix))
),
_primary_expression: ($) =>
choice(
$.tuple_expression,
$._basic_literal,
$.lambda_literal,
$._special_literal,
$._playground_literal,
$.array_literal,
$.dictionary_literal,
$.self_expression,
$.super_expression,
$.try_expression,
$.await_expression,
$._referenceable_operator,
$.key_path_expression,
$.key_path_string_expression,
prec.right(
PRECS.fully_open_range,
alias($._three_dot_operator, $.fully_open_range)
)
),
tuple_expression: ($) =>
prec.right(
PRECS.tuple,
seq(
"(",
sep1(
seq(
optional(seq(field("name", $.simple_identifier), ":")),
field("value", $._expression)
),
","
),
")"
)
),
array_literal: ($) =>
seq(
"[",
optional(sep1(field("element", $._expression), ",")),
optional(","),
"]"
),
dictionary_literal: ($) =>
seq(
"[",
choice(":", sep1($._dictionary_literal_item, ",")),
optional(","),
"]"
),
_dictionary_literal_item: ($) =>
seq(field("key", $._expression), ":", field("value", $._expression)),
_special_literal: ($) =>
choice(
"#file",
"#fileID",
"#filePath",
"#line",
"#column",
"#function",
"#dsohandle"
),
_playground_literal: ($) =>
seq(
choice("#colorLiteral", "#fileLiteral", "#imageLiteral"),
"(",
sep1(seq($.simple_identifier, ":", $._expression), ","),
")"
),
lambda_literal: ($) =>
prec.left(
PRECS.lambda,
seq(
choice("{", "^{"),
optional($._lambda_type_declaration),
optional($.statements),
"}"
)
),
_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),
prec(
PRECS.expr,
seq(
optional($.ownership_modifier),
field("name", $.simple_identifier),
optional(seq($._equal_sign, field("value", $._expression)))
)
)
),
lambda_function_type: ($) =>
prec(
PRECS.expr,
seq(
choice(
$.lambda_function_type_parameters,
seq("(", optional($.lambda_function_type_parameters), ")")
),
optional($._async_keyword),
optional($.throws),
optional(
seq(
$._arrow_operator,
field("return_type", $._possibly_implicitly_unwrapped_type)
)
)
)
),
lambda_function_type_parameters: ($) => sep1($.lambda_parameter, ","),
lambda_parameter: ($) =>
seq(
choice(
$.self_expression,
prec(PRECS.expr, field("name", $.simple_identifier)),
prec(
PRECS.expr,
seq(
optional(field("external_name", $.simple_identifier)),
field("name", $.simple_identifier),
":",
optional($.parameter_modifiers),
field("type", $._possibly_implicitly_unwrapped_type)
)
)
)
),
self_expression: ($) => "self",
super_expression: ($) => seq("super"),
_else_options: ($) => choice($._block, $.if_statement),
if_statement: ($) =>
prec.right(
PRECS["if"],
seq(
"if",
sep1(field("condition", $._if_condition_sequence_item), ","),
$._block,
optional(seq($["else"], $._else_options))
)
),
_if_condition_sequence_item: ($) =>
choice($._if_let_binding, $._expression, $.availability_condition),
_if_let_binding: ($) =>
seq(
$._direct_or_indirect_binding,
optional(seq($._equal_sign, $._expression)),
optional($.where_clause)
),
guard_statement: ($) =>
prec.right(
PRECS["if"],
seq(
"guard",
sep1(field("condition", $._if_condition_sequence_item), ","),
$["else"],
$._block
)
),
switch_statement: ($) =>
prec.right(
PRECS["switch"],
seq(
"switch",
field("expr", $._expression),
"{",
repeat($.switch_entry),
"}"
)
),
switch_entry: ($) =>
seq(
optional($.modifiers),
choice(
seq(
"case",
seq(
$.switch_pattern,
optional(seq($.where_keyword, $._expression))
),
repeat(seq(",", $.switch_pattern))
),
$.default_keyword
),
":",
$.statements,
optional("fallthrough")
),
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(alias($._binding_pattern_no_expr, $.pattern))),
optional($.where_clause),
$._block
),
where_clause: ($) => prec.left(seq($.where_keyword, $._expression)),
key_path_expression: ($) =>
prec.right(
PRECS.keypath,
seq(
"\\",
optional(
choice($._simple_user_type, $.array_type, $.dictionary_type)
),
repeat(seq(".", $._key_path_component))
)
),
key_path_string_expression: ($) =>
prec.left(seq("#keyPath", "(", $._expression, ")")),
_key_path_component: ($) =>
prec.left(
choice(
seq($.simple_identifier, repeat($._key_path_postfixes)),
repeat1($._key_path_postfixes)
)
),
_key_path_postfixes: ($) =>
choice(
"?",
$.bang,
"self",
seq("[", optional(sep1($.value_argument, ",")), "]")
),
_try_operator: ($) => choice("try", "try!", "try?"),
_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(
alias($._plus_then_ws, "+"),
alias($._minus_then_ws, "-"),
"+",
"-"
),
// The `/` operator conflicts with a regex literal (which itself appears to conflict with a
// comment, for some reason), so we must give it equivalent token precedence.
_multiplicative_operator: ($) =>
choice("*", alias(token(prec(PRECS.regex, "/")), "/"), "%"),
as_operator: ($) => choice($._as, $._as_quest, $._as_bang),
_prefix_unary_operator: ($) =>
prec.right(
choice(
"++",
"--",
"-",
"+",
$.bang,
"&",
"~",
$._dot,
$.custom_operator
)
),
_bitwise_binary_operator: ($) => choice("&", "|", "^", "<<", ">>"),
_postfix_unary_operator: ($) => choice("++", "--", $.bang),
directly_assignable_expression: ($) =>
choice(
$.simple_identifier,
$.navigation_expression,
$.call_expression,
$.tuple_expression,
$.self_expression,
$.postfix_expression // Since `x[...]! = y` is legal
),
////////////////////////////////
// Statements - https://docs.swift.org/swift-book/ReferenceManual/Statements.html
////////////////////////////////
statements: ($) =>
prec.left(
// Left precedence is required in switch statements
seq(
$._local_statement,
repeat(seq($._semi, $._local_statement)),
optional($._semi)
)
),
_local_statement: ($) =>
choice(
$._expression,
$._local_declaration,
$._labeled_statement,
$.control_transfer_statement
),
_top_level_statement: ($) =>
choice(
$._expression,
$._global_declaration,
$._labeled_statement,
$._throw_statement
),
_block: ($) => prec(PRECS.block, seq("{", optional($.statements), "}")),
_labeled_statement: ($) =>
seq(
optional($.statement_label),
choice(
$.for_statement,
$.while_statement,
$.repeat_while_statement,
$.do_statement,
$.if_statement,
$.guard_statement,
$.switch_statement
)
),
statement_label: ($) => token(/[a-zA-Z_][a-zA-Z_0-9]*:/),
for_statement: ($) =>
prec(
PRECS.loop,
seq(
"for",
optional($._try_operator),
optional($._await_operator),
field("item", alias($._binding_pattern_no_expr, $.pattern)),
optional($.type_annotation),
"in",
field("collection", $._expression),
optional($.where_clause),
$._block
)
),
while_statement: ($) =>
prec(
PRECS.loop,
seq(
"while",
sep1(field("condition", $._if_condition_sequence_item), ","),
"{",
optional($.statements),
"}"
)
),
repeat_while_statement: ($) =>
prec(
PRECS.loop,
seq(
"repeat",
"{",
optional($.statements),
"}",
"while",
sep1(field("condition", $._if_condition_sequence_item), ",")
)
),
control_transfer_statement: ($) =>
choice(
prec.right(PRECS.control_transfer, $._throw_statement),
prec.right(
PRECS.control_transfer,
seq(
$._optionally_valueful_control_keyword,
field("result", optional($._expression))
)
)
),
_throw_statement: ($) => seq($.throw_keyword, $._expression),
throw_keyword: ($) => "throw",
_optionally_valueful_control_keyword: ($) =>
choice("return", "continue", "break", "yield"),
assignment: ($) =>
prec.left(
PRECS.assignment,
seq(
field("target", $.directly_assignable_expression),
field("operator", $._assignment_and_operator),
field("result", $._expression)
)
),
availability_condition: ($) =>
seq("#available", "(", sep1($._availability_argument, ","), ")"),
_availability_argument: ($) =>
choice(seq($.identifier, sep1($.integer_literal, ".")), "*"),
////////////////////////////////
// Declarations - https://docs.swift.org/swift-book/ReferenceManual/Declarations.html
////////////////////////////////
_global_declaration: ($) =>
choice(
$.import_declaration,
$.property_declaration,
$.typealias_declaration,
$.function_declaration,
$.class_declaration,
$.protocol_declaration,
$.operator_declaration,
$.precedence_group_declaration,
$.associatedtype_declaration
),
_type_level_declaration: ($) =>
choice(
$.import_declaration,
$.property_declaration,
$.typealias_declaration,
$.function_declaration,
$.class_declaration,
$.protocol_declaration,
$.deinit_declaration,
$.subscript_declaration,
$.operator_declaration,
$.precedence_group_declaration,
$.associatedtype_declaration
),
_local_declaration: ($) =>
choice(
alias($._local_property_declaration, $.property_declaration),
alias($._local_typealias_declaration, $.typealias_declaration),
alias($._local_function_declaration, $.function_declaration),
alias($._local_class_declaration, $.class_declaration)
),
_local_property_declaration: ($) =>
seq(
optional($._locally_permitted_modifiers),
$._modifierless_property_declaration
),
_local_typealias_declaration: ($) =>
seq(
optional($._locally_permitted_modifiers),
$._modifierless_typealias_declaration
),
_local_function_declaration: ($) =>
seq(
optional($._locally_permitted_modifiers),
$._modifierless_function_declaration
),
_local_class_declaration: ($) =>
seq(
optional($._locally_permitted_modifiers),
$._modifierless_class_declaration
),
import_declaration: ($) =>
seq(
optional($.modifiers),
"import",
optional($._import_kind),
$.identifier
),
_import_kind: ($) =>
choice(
"typealias",
"struct",
"class",
"enum",
"protocol",
"let",
"var",
"func"
),
protocol_property_declaration: ($) =>
prec.right(
seq(
optional($.modifiers),
field("name", alias($._binding_kind_and_pattern, $.pattern)),
optional($.type_annotation),
optional($.type_constraints),
$.protocol_property_requirements
)
),
protocol_property_requirements: ($) =>
seq("{", repeat(choice($.getter_specifier, $.setter_specifier)), "}"),
property_declaration: ($) =>
seq(optional($.modifiers), $._modifierless_property_declaration),
_modifierless_property_declaration: ($) =>
prec.right(
seq(
$._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)
)
)
),
typealias_declaration: ($) =>
seq(optional($.modifiers), $._modifierless_typealias_declaration),
_modifierless_typealias_declaration: ($) =>
seq(
"typealias",
field("name", alias($.simple_identifier, $.type_identifier)),
optional($.type_parameters),
$._equal_sign,
field("value", $._type)
),
function_declaration: ($) =>
prec.right(
seq($._bodyless_function_declaration, field("body", $.function_body))
),
_modifierless_function_declaration: ($) =>
prec.right(
seq(
$._modifierless_function_declaration_no_body,
field("body", $.function_body)
)
),
_bodyless_function_declaration: ($) =>
seq(
optional($.modifiers),
optional("class"), // XXX: This should be possible in non-last position, but that creates parsing ambiguity
$._modifierless_function_declaration_no_body
),
_modifierless_function_declaration_no_body: ($) =>
prec.right(
seq(
choice(
$._constructor_function_decl,
$._non_constructor_function_decl
),
optional($.type_parameters),
$._function_value_parameters,
optional($._async_keyword),
optional($.throws),
optional(
seq(
$._arrow_operator,
field("return_type", $._possibly_implicitly_unwrapped_type)
)
),
optional($.type_constraints)
)
),
function_body: ($) => $._block,
class_declaration: ($) =>
seq(optional($.modifiers), $._modifierless_class_declaration),
_modifierless_class_declaration: ($) =>
prec.right(
choice(
seq(
field("declaration_kind", choice("class", "struct", "actor")),
field("name", alias($.simple_identifier, $.type_identifier)),
optional($.type_parameters),
optional(seq(":", $._inheritance_specifiers)),
optional($.type_constraints),
field("body", $.class_body)
),
seq(
field("declaration_kind", "extension"),
field("name", $._unannotated_type),
optional($.type_parameters),
optional(seq(":", $._inheritance_specifiers)),
optional($.type_constraints),
field("body", $.class_body)
),
seq(
optional("indirect"),
field("declaration_kind", "enum"),
field("name", alias($.simple_identifier, $.type_identifier)),
optional($.type_parameters),
optional(seq(":", $._inheritance_specifiers)),
optional($.type_constraints),
field("body", $.enum_class_body)
)
)
),
class_body: ($) => seq("{", optional($._class_member_declarations), "}"),
_inheritance_specifiers: ($) =>
prec.left(sep1($._annotated_inheritance_specifier, choice(",", "&"))),
inheritance_specifier: ($) =>
prec.left(field("inherits_from", choice($.user_type, $.function_type))),
_annotated_inheritance_specifier: ($) =>
seq(repeat($.attribute), $.inheritance_specifier),
type_parameters: ($) =>
seq("<", sep1($.type_parameter, ","), optional($.type_constraints), ">"),
type_parameter: ($) =>
seq(
optional($.type_parameter_modifiers),
alias($.simple_identifier, $.type_identifier),
optional(seq(":", $._type))
),
type_constraints: ($) =>
prec.right(seq($.where_keyword, sep1($.type_constraint, ","))),
type_constraint: ($) =>
choice($.inheritance_constraint, $.equality_constraint),
inheritance_constraint: ($) =>
seq(
repeat($.attribute),
field("constrained_type", $.identifier),
":",
field("inherits_from", $._possibly_implicitly_unwrapped_type)
),
equality_constraint: ($) =>
seq(
repeat($.attribute),
field("constrained_type", $.identifier),
choice($._equal_sign, $._eq_eq),
field("must_equal", $._type)
),
_class_member_separator: ($) => choice($._semi, $.multiline_comment),
_class_member_declarations: ($) =>
seq(
sep1($._type_level_declaration, $._class_member_separator),
optional($._class_member_separator)
),
_function_value_parameters: ($) =>
repeat1(seq("(", optional(sep1($._function_value_parameter, ",")), ")")),
_function_value_parameter: ($) =>
seq(
optional($.attribute),
$.parameter,
optional(seq($._equal_sign, field("default_value", $._expression)))
),
parameter: ($) =>
seq(
optional(field("external_name", $.simple_identifier)),
field("name", $.simple_identifier),
":",
optional($.parameter_modifiers),
field("type", $._possibly_implicitly_unwrapped_type),
optional($._three_dot_operator)
),
_constructor_function_decl: ($) =>
seq(field("name", "init"), optional(choice($._quest, $.bang))),
_non_constructor_function_decl: ($) =>
seq(
"func",
field("name", choice($.simple_identifier, $._referenceable_operator))
),
_referenceable_operator: ($) =>
choice(
$.custom_operator,
$._comparison_operator,
$._additive_operator,
$._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
// noisy) but allows callers to refer to them as nodes by their text form like with any
// operator.
_equal_sign: ($) => alias($._eq_custom, "="),
_eq_eq: ($) => alias($._eq_eq_custom, "=="),
_dot: ($) => alias($._dot_custom, "."),
_arrow_operator: ($) => alias($._arrow_operator_custom, "->"),
_conjunction_operator: ($) => alias($._conjunction_operator_custom, "&&"),
_disjunction_operator: ($) => alias($._disjunction_operator_custom, "||"),
_nil_coalescing_operator: ($) =>
alias($._nil_coalescing_operator_custom, "??"),
_as: ($) => alias($._as_custom, "as"),
_as_quest: ($) => alias($._as_quest_custom, "as?"),
_as_bang: ($) => alias($._as_bang_custom, "as!"),
_async_keyword: ($) => alias($._async_keyword_custom, "async"),
_async_modifier: ($) => token("async"),
throws: ($) => choice($._throws_keyword, $._rethrows_keyword),
enum_class_body: ($) =>
seq("{", repeat(choice($.enum_entry, $._type_level_declaration)), "}"),
enum_entry: ($) =>
seq(
optional($.modifiers),
optional("indirect"),
"case",
sep1(
seq(
field("name", $.simple_identifier),
optional($._enum_entry_suffix)
),
","
),
optional(";")
),
_enum_entry_suffix: ($) =>
choice(
field("data_contents", $.enum_type_parameters),
seq($._equal_sign, field("raw_value", $._expression))
),
enum_type_parameters: ($) =>
seq(
"(",
optional(
sep1(
seq(
optional(
seq(optional($.wildcard_pattern), $.simple_identifier, ":")
),
$._type,
optional(seq($._equal_sign, $._expression))
),
","
)
),
")"
),
protocol_declaration: ($) =>
prec.right(
seq(
optional($.modifiers),
field("declaration_kind", "protocol"),
field("name", alias($.simple_identifier, $.type_identifier)),
optional($.type_parameters),
optional(seq(":", $._inheritance_specifiers)),
optional($.type_constraints),
field("body", $.protocol_body)
)
),
protocol_body: ($) =>
seq("{", optional($._protocol_member_declarations), "}"),
_protocol_member_declarations: ($) =>
seq(sep1($._protocol_member_declaration, $._semi), optional($._semi)),
_protocol_member_declaration: ($) =>
choice(
alias(
seq(
$._bodyless_function_declaration,
optional(field("body", $.function_body))
),
$.protocol_function_declaration
),
$.deinit_declaration,
$.protocol_property_declaration,
$.typealias_declaration,
$.associatedtype_declaration,
$.subscript_declaration
),
deinit_declaration: ($) =>
prec.right(
seq(optional($.modifiers), "deinit", field("body", $.function_body))
),
subscript_declaration: ($) =>
prec.right(
seq(
optional($.modifiers),
"subscript",
optional($.type_parameters),
$._function_value_parameters,
optional(
seq(
$._arrow_operator,
field("return_type", $._possibly_implicitly_unwrapped_type)
)
),
optional($.type_constraints),
$.computed_property
)
),
computed_property: ($) =>
seq(
"{",
choice(
optional($.statements),
repeat(
choice($.computed_getter, $.computed_setter, $.computed_modify)
)
),
"}"
),
computed_getter: ($) =>
seq(repeat($.attribute), $.getter_specifier, optional($._block)),
computed_modify: ($) =>
seq(repeat($.attribute), $.modify_specifier, optional($._block)),
computed_setter: ($) =>
seq(
repeat($.attribute),
$.setter_specifier,
optional(seq("(", $.simple_identifier, ")")),
optional($._block)
),
getter_specifier: ($) =>
seq(optional($.mutation_modifier), "get", optional($._getter_effects)),
setter_specifier: ($) => seq(optional($.mutation_modifier), "set"),
modify_specifier: ($) => seq(optional($.mutation_modifier), "_modify"),
_getter_effects: ($) => repeat1(choice($._async_keyword, $.throws)),
operator_declaration: ($) =>
seq(
choice("prefix", "infix", "postfix"),
"operator",
$._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",
$.simple_identifier,
"{",
optional($.precedence_group_attributes),
"}"
),
precedence_group_attributes: ($) => repeat1($.precedence_group_attribute),
precedence_group_attribute: ($) =>
seq(
$.simple_identifier,
":",
choice($.simple_identifier, $.boolean_literal)
),
associatedtype_declaration: ($) =>
seq(
optional($.modifiers),
"associatedtype",
field("name", alias($.simple_identifier, $.type_identifier)),
optional(seq(":", field("must_inherit", $._type))),
optional($.type_constraints),
optional(seq($._equal_sign, field("default_value", $._type)))
),
////////////////////////////////
// Attributes - https://docs.swift.org/swift-book/ReferenceManual/Attributes.html
////////////////////////////////
attribute: ($) =>
seq(
"@",
$.user_type,
// attribute arguments are a mess of special cases, maybe this is good enough?
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
////////////////////////////////
_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)
),
_binding_pattern_with_expr: ($) =>
seq(
choice(
$._universally_allowed_pattern,
$._binding_pattern,
$._expression
),
optional($._quest)
),
_non_binding_pattern_with_expr: ($) =>
seq(
choice($._universally_allowed_pattern, $._expression),
optional($._quest)
),
_direct_or_indirect_binding: ($) =>
seq(
choice(
$._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: ($) => "_",
_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
// ==========
modifiers: ($) =>
repeat1(
choice($._non_local_scope_modifier, $._locally_permitted_modifiers)
),
_locally_permitted_modifiers: ($) =>
repeat1(choice($.attribute, $._locally_permitted_modifier)),
parameter_modifiers: ($) => repeat1($.parameter_modifier),
_modifier: ($) =>
choice($._non_local_scope_modifier, $._locally_permitted_modifier),
_non_local_scope_modifier: ($) =>
choice(
$.member_modifier,
$.visibility_modifier,
$.function_modifier,
$.mutation_modifier,
$.property_modifier,
$.parameter_modifier,
$.property_behavior_modifier
),
_locally_permitted_modifier: ($) =>
choice($.ownership_modifier, $.inheritance_modifier),
property_behavior_modifier: ($) => "lazy",
type_modifiers: ($) => repeat1($.attribute),
member_modifier: ($) =>
choice("override", "convenience", "required", "nonisolated"),
visibility_modifier: ($) =>
seq(
choice("public", "private", "internal", "fileprivate", "open"),
optional(seq("(", "set", ")"))
),
type_parameter_modifiers: ($) => repeat1($.attribute),
function_modifier: ($) => choice("infix", "postfix", "prefix"),
mutation_modifier: ($) => choice("mutating", "nonmutating"),
property_modifier: ($) => choice("static", "dynamic", "optional", "class"),
inheritance_modifier: ($) => choice("final"),
parameter_modifier: ($) => choice("inout", "@escaping", "@autoclosure"),
ownership_modifier: ($) =>
choice("weak", "unowned", "unowned(safe)", "unowned(unsafe)"),
use_site_target: ($) =>
seq(
choice(
"property",
"get",
"set",
"receiver",
"param",
"setparam",
"delegate"
),
":"
),
directive: ($) =>
token(
prec(
PRECS.comment,
choice(
seq("#if", /.*/),
seq("#elseif", /.*/),
seq("#else", /.*/),
seq("#endif", /.*/),
seq(/#sourceLocation([^\r\n]*)/)
)
)
),
diagnostic: ($) =>
token(
prec(
PRECS.comment,
choice(
// Using regexes here, rather than actually validating the string literal, because complex string literals
// cannot be used inside `token()` and we need that to ensure we get the right precedence.
seq(/#error([^\r\n]*)/),
seq(/#warning([^\r\n]*)/)
)
)
),
},
});
function sep1(rule, separator) {
return seq(rule, repeat(seq(separator, rule)));
}
function tree_sitter_version_supports_emoji() {
try {
return (
TREE_SITTER_CLI_VERSION_MAJOR > 0 ||
TREE_SITTER_CLI_VERSION_MINOR > 20 ||
TREE_SITTER_CLI_VERSION_PATCH >= 5
);
} catch (err) {
if (err instanceof ReferenceError) {
return false;
} else {
throw err;
}
}
}