mirror of https://github.com/Wilfred/difftastic/
1350 lines
27 KiB
JavaScript
1350 lines
27 KiB
JavaScript
/*
|
|
* MIT License
|
|
*
|
|
* Copyright (c) 2019 fwcd
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
// Using an adapted version of https://kotlinlang.org/docs/reference/grammar.html
|
|
|
|
module.exports = grammar({
|
|
name: "kotlin",
|
|
rules: {
|
|
// TODO: Hide common elements such as "identifier"
|
|
// or "expression" from the syntax tree by prepending
|
|
// an underscore
|
|
|
|
// Note that all rules marked with "modified" have
|
|
// been modified from the original grammar to prevent
|
|
// zero-width matches. See https://gist.github.com/Aerijo/df27228d70c633e088b0591b8857eeef#general-tips
|
|
// for an explanation.
|
|
|
|
// ====================
|
|
// Syntax grammar
|
|
// ====================
|
|
|
|
// ==========
|
|
// General
|
|
// ==========
|
|
|
|
// start
|
|
program: $ => choice(
|
|
// kotlin_file
|
|
seq(
|
|
optional($.shebang_line),
|
|
repeat($.file_annotation),
|
|
optional($.package_header),
|
|
repeat($.import_header),
|
|
repeat($.top_level_object)
|
|
),
|
|
// script
|
|
seq(
|
|
optional($.shebang_line),
|
|
repeat($.file_annotation),
|
|
optional($.package_header),
|
|
repeat($.import_header),
|
|
repeat(seq($.statement, $.semi))
|
|
)
|
|
),
|
|
|
|
shebang_line: $ => seq("#!", /[^\r\n]*/),
|
|
|
|
file_annotation: $ => seq(
|
|
choice("@", $.at_pre_ws),
|
|
"file",
|
|
":",
|
|
choice(
|
|
seq("[", repeat1($.unescaped_annotation), "]"),
|
|
$.unescaped_annotation
|
|
)
|
|
),
|
|
|
|
// modified
|
|
package_header: $ => seq("package", $.identifier, optional($.semi)),
|
|
|
|
// modified
|
|
import_list: $ => seq($.import_header),
|
|
|
|
import_header: $ => seq(
|
|
"import",
|
|
$.identifier,
|
|
optional(choice(seq(".", "*"), $.import_alias)),
|
|
optional($.semi)
|
|
),
|
|
|
|
import_alias: $ => seq("as", $.simple_identifier),
|
|
|
|
top_level_object: $ => seq($.declaration, optional($.semis)),
|
|
|
|
type_alias: $ => seq(
|
|
optional($.modifiers),
|
|
"typealias",
|
|
$.simple_identifier,
|
|
optional($.type_parameters),
|
|
"=",
|
|
$.type
|
|
),
|
|
|
|
declaration: $ => choice(
|
|
$.class_declaration,
|
|
$.object_declaration,
|
|
$.function_declaration,
|
|
$.property_declaration,
|
|
$.type_alias
|
|
),
|
|
|
|
// ==========
|
|
// Classes
|
|
// ==========
|
|
|
|
class_declaration: $ => seq(
|
|
optional($.modifiers),
|
|
choice("class", "interface"),
|
|
$.simple_identifier,
|
|
optional($.type_parameters),
|
|
optional($.primary_constructor),
|
|
optional(seq(":", $.delegation_specifiers)),
|
|
optional($.type_constraints),
|
|
optional(choice($.class_body, $.enum_class_body))
|
|
),
|
|
|
|
primary_constructor: $ => seq(
|
|
optional(seq(optional($.modifiers), "constructor")),
|
|
$.class_parameters
|
|
),
|
|
|
|
// modified
|
|
class_body: $ => seq("{", optional($.class_member_declarations), "}"),
|
|
|
|
class_parameters: $ => seq(
|
|
"(",
|
|
optional(seq($.class_parameter, repeat(seq(",", $.class_parameter)))),
|
|
")"
|
|
),
|
|
|
|
class_parameter: $ => seq(
|
|
optional($.modifiers),
|
|
optional(choice("val", "var")),
|
|
$.simple_identifier,
|
|
":",
|
|
$.type,
|
|
optional(seq("=", $.expression))
|
|
),
|
|
|
|
delegation_specifiers: $ => seq(
|
|
$.annotated_delegation_specifier,
|
|
repeat(seq(",", $.annotated_delegation_specifier))
|
|
),
|
|
|
|
delegation_specifier: $ => choice(
|
|
$.constructor_invocation,
|
|
$.explicit_delegation,
|
|
$.user_type,
|
|
$.function_type
|
|
),
|
|
|
|
constructor_invocation: $ => seq($.user_type, $.value_arguments),
|
|
|
|
annotated_delegation_specifier: $ => seq(repeat($.annotation), $.delegation_specifier),
|
|
|
|
explicit_delegation: $ => seq(
|
|
choice($.user_type, $.function_type),
|
|
"by",
|
|
$.expression
|
|
),
|
|
|
|
type_parameters: $ => seq(
|
|
"<",
|
|
$.type_parameter,
|
|
repeat(seq(",", $.type_parameter)),
|
|
">"
|
|
),
|
|
|
|
type_parameter: $ => seq(
|
|
optional($.type_parameter_modifiers),
|
|
$.simple_identifier,
|
|
optional(seq(":", $.type))
|
|
),
|
|
|
|
type_constraints: $ => seq(
|
|
"where",
|
|
$.type_constraint,
|
|
repeat(seq(",", $.type_constraint))
|
|
),
|
|
|
|
type_constraint: $ => seq(
|
|
repeat($.annotation),
|
|
$.simple_identifier,
|
|
":",
|
|
$.type
|
|
),
|
|
|
|
// ==========
|
|
// Class members
|
|
// ==========
|
|
|
|
// modified
|
|
class_member_declarations: $ => repeat1(seq($.class_member_declaration, optional($.semis))),
|
|
|
|
class_member_declaration: $ => choice(
|
|
$.declaration,
|
|
$.companion_object,
|
|
$.anonymous_initializer,
|
|
$.secondary_constructor
|
|
),
|
|
|
|
anonymous_initializer: $ => seq("init", $.block),
|
|
|
|
companion_object: $ => seq(
|
|
optional($.modifiers),
|
|
"companion",
|
|
"object",
|
|
optional($.simple_identifier),
|
|
optional(seq(":", $.delegation_specifiers)),
|
|
optional($.class_body)
|
|
),
|
|
|
|
function_value_parameters: $ => seq(
|
|
"(",
|
|
optional(seq(
|
|
$.function_value_parameter,
|
|
repeat(seq(",", $.function_value_parameter))
|
|
)),
|
|
")"
|
|
),
|
|
|
|
function_value_parameter: $ => seq(
|
|
optional($.parameter_modifiers),
|
|
$.parameter,
|
|
optional(seq("=", $.expression))
|
|
),
|
|
|
|
function_declaration: $ => seq(
|
|
optional($.modifiers),
|
|
"fun",
|
|
optional($.type_parameters),
|
|
optional(seq($.receiver_type, ".")),
|
|
$.simple_identifier,
|
|
$.function_value_parameters,
|
|
optional(seq(":", $.type)),
|
|
optional($.type_constraints),
|
|
optional($.function_body)
|
|
),
|
|
|
|
function_body: $ => choice($.block, seq("=", $.expression)),
|
|
|
|
variable_declaration: $ => seq(
|
|
repeat($.annotation),
|
|
$.simple_identifier,
|
|
optional(seq(":", $.type))
|
|
),
|
|
|
|
multi_variable_declaration: $ => seq(
|
|
"(",
|
|
$.variable_declaration,
|
|
repeat(seq(",", $.variable_declaration)),
|
|
")"
|
|
),
|
|
|
|
property_declaration: $ => seq(
|
|
optional($.modifiers),
|
|
choice("val", "var"),
|
|
optional($.type_parameters),
|
|
optional(seq($.receiver_type, ".")),
|
|
choice($.multi_variable_declaration, $.variable_declaration),
|
|
optional($.type_constraints),
|
|
optional(choice(seq("=", $.expression), $.property_delegate)),
|
|
choice(";"),
|
|
choice(
|
|
seq(
|
|
optional($.getter),
|
|
optional(seq(optional($.semi), $.setter))
|
|
),
|
|
seq(
|
|
optional($.setter),
|
|
optional(seq(optional($.semi), $.getter))
|
|
)
|
|
)
|
|
),
|
|
|
|
property_delegate: $ => seq("by", $.expression),
|
|
|
|
getter: $ => choice(
|
|
seq(optional($.modifiers), "get"),
|
|
seq(optional($.modifiers), "get", "(", ")", optional(seq(":", $.type)), $.function_body)
|
|
),
|
|
|
|
setter: $ => choice(
|
|
seq(optional($.modifiers), "set"),
|
|
seq(optional($.modifiers), "set", "(", $.parameter_with_optional_type, ")", optional(seq(":", $.type)), $.function_body)
|
|
),
|
|
|
|
parameters_with_optional_type: $ => seq(
|
|
"(",
|
|
optional(seq(
|
|
$.parameter_with_optional_type,
|
|
repeat(seq(",", $.parameter_with_optional_type))
|
|
)),
|
|
")"
|
|
),
|
|
|
|
parameter_with_optional_type: $ => seq(
|
|
optional($.parameter_modifiers),
|
|
$.simple_identifier,
|
|
optional(seq(":", $.type))
|
|
),
|
|
|
|
parameter: $ => seq($.simple_identifier, ":", $.type),
|
|
|
|
object_declaration: $ => seq(
|
|
optional($.modifiers),
|
|
"object",
|
|
$.simple_identifier,
|
|
optional(seq(":", $.delegation_specifiers)),
|
|
optional($.class_body)
|
|
),
|
|
|
|
secondary_constructor: $ => seq(
|
|
optional($.modifiers),
|
|
"constructor",
|
|
$.function_value_parameters,
|
|
optional(seq(":", $.constructor_delegation_call)),
|
|
optional($.block)
|
|
),
|
|
|
|
constructor_delegation_call: $ => choice(
|
|
seq("this", $.value_arguments),
|
|
seq("super", $.value_arguments)
|
|
),
|
|
|
|
// ==========
|
|
// Enum classes
|
|
// ==========
|
|
|
|
// modified
|
|
enum_class_body: $ => seq(
|
|
"{",
|
|
optional($.enum_entries),
|
|
optional(seq(";", optional($.class_member_declarations))),
|
|
"}"
|
|
),
|
|
|
|
enum_entries: $ => seq(
|
|
$.enum_entry,
|
|
repeat(seq(",", $.enum_entry)),
|
|
optional(",")
|
|
),
|
|
|
|
enum_entry: $ => seq(
|
|
optional($.modifiers),
|
|
$.simple_identifier,
|
|
optional($.value_arguments),
|
|
optional($.class_body)
|
|
),
|
|
|
|
// ==========
|
|
// Types
|
|
// ==========
|
|
|
|
type: $ => seq(
|
|
optional($.type_modifiers),
|
|
choice(
|
|
$.parenthesized_type,
|
|
$.nullable_type,
|
|
$.type_reference,
|
|
$.function_type
|
|
)
|
|
),
|
|
|
|
type_reference: $ => choice(
|
|
$.user_type,
|
|
"dynamic"
|
|
),
|
|
|
|
nullable_type: $ => seq(
|
|
choice($.type_reference, $.parenthesized_type),
|
|
repeat1($.quest)
|
|
),
|
|
|
|
quest: $ => choice("?", $.quest_ws),
|
|
|
|
user_type: $ => seq(
|
|
$.simple_user_type,
|
|
repeat(seq(".", $.simple_user_type))
|
|
),
|
|
|
|
simple_user_type: $ => seq(
|
|
$.simple_identifier,
|
|
optional($.type_arguments)
|
|
),
|
|
|
|
type_projection: $ => choice(
|
|
seq(optional($.type_projection_modifiers), $.type),
|
|
"*"
|
|
),
|
|
|
|
type_projection_modifiers: $ => repeat1($.type_projection_modifier),
|
|
|
|
type_projection_modifier: $ => choice(
|
|
$.variance_modifier,
|
|
$.annotation
|
|
),
|
|
|
|
function_type: $ => seq(
|
|
optional(seq($.receiver_type, ".")),
|
|
$.function_type_parameters,
|
|
"->",
|
|
$.type
|
|
),
|
|
|
|
function_type_parameters: $ => seq(
|
|
"(",
|
|
optional(choice($.parameter, $.type)),
|
|
repeat(seq(
|
|
",",
|
|
choice($.parameter, $.type)
|
|
)),
|
|
")"
|
|
),
|
|
|
|
parenthesized_type: $ => seq("(", $.type, ")"),
|
|
|
|
receiver_type: $ => seq(
|
|
optional($.type_modifiers),
|
|
choice(
|
|
$.parenthesized_type,
|
|
$.nullable_type,
|
|
$.type_reference
|
|
)
|
|
),
|
|
|
|
parenthesized_user_type: $ => choice(
|
|
seq("(", $.user_type, ")"),
|
|
seq("(", $.parenthesized_user_type, ")")
|
|
),
|
|
|
|
// ==========
|
|
// Statements
|
|
// ==========
|
|
|
|
// modified
|
|
statements: $ => seq(
|
|
$.statement,
|
|
repeat(seq($.semis, $.statement)),
|
|
optional($.semis)
|
|
),
|
|
|
|
statement: $ => seq(
|
|
repeat(choice($.label, $.annotation)),
|
|
choice(
|
|
$.declaration,
|
|
$.assignment,
|
|
$.loop_statement,
|
|
$.expression
|
|
)
|
|
),
|
|
|
|
label: $ => seq(
|
|
$.simple_identifier,
|
|
choice("@", $.at_post_ws)
|
|
),
|
|
|
|
control_structure_body: $ => choice($.block, $.statement),
|
|
|
|
// modified
|
|
block: $ => seq("{", optional($.statements), "}"),
|
|
|
|
loop_statement: $ => choice(
|
|
$.for_statement,
|
|
$.while_statement,
|
|
$.do_while_statement
|
|
),
|
|
|
|
for_statement: $ => seq(
|
|
"for",
|
|
"(",
|
|
repeat($.annotation),
|
|
choice($.variable_declaration, $.multi_variable_declaration),
|
|
"in",
|
|
$.expression,
|
|
")",
|
|
optional($.control_structure_body)
|
|
),
|
|
|
|
while_statement: $ => choice(
|
|
seq(
|
|
"while",
|
|
"(",
|
|
$.expression,
|
|
")",
|
|
$.control_structure_body
|
|
),
|
|
seq(
|
|
"while",
|
|
"(",
|
|
$.expression,
|
|
")",
|
|
";"
|
|
)
|
|
),
|
|
|
|
do_while_statement: $ => seq(
|
|
"do",
|
|
optional($.control_structure_body),
|
|
"while",
|
|
"(",
|
|
$.expression,
|
|
")"
|
|
),
|
|
|
|
assignment: $ => choice(
|
|
seq($.directly_assignable_expression, "=", $.expression),
|
|
seq($.assignable_expression, $.assignment_and_operator, $.expression)
|
|
),
|
|
|
|
// See also https://github.com/tree-sitter/tree-sitter/issues/160
|
|
// for discussion of a generic EOF/newline token
|
|
semi: $ => /[\r\n]+/,
|
|
|
|
semis: $ => /[\r\n]+/,
|
|
|
|
// ==========
|
|
// Expressions
|
|
// ==========
|
|
|
|
// Note how the following rules directly encode
|
|
// predence and associativity rather than using
|
|
// Tree-Sitters prec function. This might be
|
|
// changed in the future (though it reflects how
|
|
// the Kotlin compiler generates its syntax tree).
|
|
|
|
expression: $ => $.disjunction,
|
|
|
|
disjunction: $ => seq($.conjunction, repeat(seq("||", $.conjunction))),
|
|
|
|
conjunction: $ => seq($.equality, repeat(seq("&&", $.equality))),
|
|
|
|
equality: $ => seq($.comparison, repeat(seq($.equality_operator, $.comparison))),
|
|
|
|
comparison: $ => seq($.infix_operation, optional(seq($.comparison_operator, $.infix_operation))),
|
|
|
|
infix_operation: $ => seq($.elvis_expression, repeat(choice(
|
|
seq($.in_operator, $.elvis_expression),
|
|
seq($.is_operator, $.type)
|
|
))),
|
|
|
|
elvis_expression: $ => seq($.infix_function_call, repeat(seq($.elvis, $.infix_function_call))),
|
|
|
|
elvis: $ => seq("?", ":"),
|
|
|
|
infix_function_call: $ => seq($.range_expression, repeat(seq($.simple_identifier, $.range_expression))),
|
|
|
|
range_expression: $ => seq($.additive_expression, repeat(seq("..", $.additive_expression))),
|
|
|
|
additive_expression: $ => seq($.multiplicative_expression, repeat(seq($.additive_operator, $.multiplicative_expression))),
|
|
|
|
multiplicative_expression: $ => seq($.as_expression, repeat(seq($.multiplicative_operator, $.as_expression))),
|
|
|
|
as_expression: $ => seq($.prefix_unary_expression, optional(seq($.as_operator, $.type))),
|
|
|
|
prefix_unary_expression: $ => seq(repeat($.unary_prefix), $.postfix_unary_expression),
|
|
|
|
unary_prefix: $ => choice(
|
|
$.annotation,
|
|
$.label,
|
|
$.prefix_unary_operator
|
|
),
|
|
|
|
postfix_unary_expression: $ => choice(
|
|
$.primary_expression,
|
|
seq($.primary_expression, repeat1($.postfix_unary_suffix))
|
|
),
|
|
|
|
postfix_unary_suffix: $ => choice(
|
|
$.postfix_unary_operator,
|
|
$.type_arguments,
|
|
$.call_suffix,
|
|
$.indexing_suffix,
|
|
$.navigation_suffix
|
|
),
|
|
|
|
directly_assignable_expression: $ => choice(
|
|
seq($.postfix_unary_expression, $.assignable_suffix),
|
|
$.simple_identifier,
|
|
$.parenthesized_directly_assignable_expression
|
|
),
|
|
|
|
parenthesized_directly_assignable_expression: $ => seq("(", $.directly_assignable_expression, ")"),
|
|
|
|
assignable_expression: $ => choice(
|
|
$.prefix_unary_expression,
|
|
$.parenthesized_assignable_expression
|
|
),
|
|
|
|
parenthesized_assignable_expression: $ => seq("(", $.assignable_expression, ")"),
|
|
|
|
assignable_suffix: $ => choice(
|
|
$.type_arguments,
|
|
$.indexing_suffix,
|
|
$.navigation_suffix
|
|
),
|
|
|
|
indexing_suffix: $ => seq("[", $.expression, repeat(seq(",", $.expression)), "]"),
|
|
|
|
navigation_suffix: $ => seq(
|
|
$.member_access_operator,
|
|
choice(
|
|
$.simple_identifier,
|
|
$.parenthesized_expression,
|
|
"class"
|
|
)
|
|
),
|
|
|
|
call_suffix: $ => choice(
|
|
seq(
|
|
optional($.type_arguments),
|
|
optional($.value_arguments),
|
|
$.annotated_lambda
|
|
),
|
|
seq(
|
|
optional($.type_arguments),
|
|
$.value_arguments
|
|
)
|
|
),
|
|
|
|
annotated_lambda: $ => seq(
|
|
repeat($.annotation),
|
|
optional($.label),
|
|
$.lambda_literal
|
|
),
|
|
|
|
type_arguments: $ => seq(
|
|
"<",
|
|
$.type_projection,
|
|
repeat(seq(",", $.type_projection)),
|
|
">"
|
|
),
|
|
|
|
value_arguments: $ => choice(
|
|
seq("(", ")"),
|
|
seq(
|
|
"(",
|
|
$.value_argument,
|
|
repeat(seq(",", $.value_argument)),
|
|
")"
|
|
)
|
|
),
|
|
|
|
value_argument: $ => seq(
|
|
optional($.annotation),
|
|
optional(seq($.simple_identifier, "=")),
|
|
optional("*"),
|
|
$.expression
|
|
),
|
|
|
|
primary_expression: $ => choice(
|
|
$.parenthesized_expression,
|
|
$.simple_identifier,
|
|
$.literal_constant,
|
|
$.string_literal,
|
|
$.callable_reference,
|
|
$.function_literal,
|
|
$.object_literal,
|
|
$.collection_literal,
|
|
$.this_expression,
|
|
$.super_expression,
|
|
$.if_expression,
|
|
$.when_expression,
|
|
$.try_expression,
|
|
$.jump_expression
|
|
),
|
|
|
|
parenthesized_expression: $ => seq("(", $.expression, ")"),
|
|
|
|
collection_literal: $ => seq(
|
|
"[",
|
|
$.expression,
|
|
repeat(seq(",", $.expression)),
|
|
"]"
|
|
),
|
|
|
|
literal_constant: $ => choice(
|
|
$.boolean_literal,
|
|
$.integer_literal,
|
|
$.hex_literal,
|
|
$.bin_literal,
|
|
$.character_literal,
|
|
$.real_literal,
|
|
"null",
|
|
$.long_literal,
|
|
$.unsigned_literal
|
|
),
|
|
|
|
string_literal: $ => choice(
|
|
$.line_string_literal,
|
|
$.multi_line_string_literal
|
|
),
|
|
|
|
line_string_literal: $ => seq(
|
|
'"',
|
|
repeat(choice($.line_string_content, $.line_string_expression)),
|
|
'"'
|
|
),
|
|
|
|
multi_line_string_literal: $ => seq(
|
|
'"""',
|
|
repeat(choice(
|
|
$.multi_line_string_content,
|
|
$.multi_line_string_expression,
|
|
'"'
|
|
)),
|
|
$.triple_quote_close
|
|
),
|
|
|
|
line_string_content: $ => choice(
|
|
$.line_str_text,
|
|
$.line_str_escaped_char,
|
|
$.line_str_ref
|
|
),
|
|
|
|
line_string_expression: $ => seq("${", $.expression, "}"),
|
|
|
|
multi_line_string_content: $ => choice(
|
|
$.multi_line_str_text,
|
|
'"',
|
|
$.multi_line_str_ref
|
|
),
|
|
|
|
multi_line_string_expression: $ => seq("${", $.expression, "}"),
|
|
|
|
// modified
|
|
lambda_literal: $ => choice(
|
|
seq("{", optional($.statements), "}"),
|
|
seq(
|
|
"{",
|
|
optional($.lambda_parameters),
|
|
"->",
|
|
optional($.statements)
|
|
)
|
|
),
|
|
|
|
lambda_parameters: $ => seq(
|
|
$.lambda_parameter,
|
|
repeat(seq(",", $.lambda_parameter))
|
|
),
|
|
|
|
lambda_parameter: $ => choice(
|
|
$.variable_declaration,
|
|
seq(
|
|
$.multi_variable_declaration,
|
|
optional(seq(":", $.type))
|
|
)
|
|
),
|
|
|
|
anonymous_function: $ => seq(
|
|
"fun",
|
|
optional(seq($.type, ".")),
|
|
$.parameters_with_optional_type,
|
|
optional(seq(":", $.type)),
|
|
optional($.type_constraints),
|
|
optional($.function_body)
|
|
),
|
|
|
|
function_literal: $ => choice(
|
|
$.lambda_literal,
|
|
$.anonymous_function
|
|
),
|
|
|
|
object_literal: $ => choice(
|
|
seq("object", ":", $.delegation_specifiers, $.class_body),
|
|
seq("object", $.class_body)
|
|
),
|
|
|
|
this_expression: $ => choice("this", $.this_at),
|
|
|
|
super_expression: $ => choice(
|
|
seq(
|
|
"super",
|
|
optional(seq("<", $.type, ">")),
|
|
optional(seq("@", $.simple_identifier))
|
|
),
|
|
$.super_at
|
|
),
|
|
|
|
if_expression: $ => choice(
|
|
seq(
|
|
"if",
|
|
"(",
|
|
$.expression,
|
|
")",
|
|
choice($.control_structure_body, ";")
|
|
),
|
|
seq(
|
|
"if",
|
|
"(",
|
|
$.expression,
|
|
")",
|
|
optional($.control_structure_body),
|
|
optional(";"),
|
|
"else",
|
|
choice($.control_structure_body, ";")
|
|
)
|
|
),
|
|
|
|
when_subject: $ => seq(
|
|
"(",
|
|
optional(seq(
|
|
repeat($.annotation),
|
|
"val",
|
|
$.variable_declaration,
|
|
"="
|
|
)),
|
|
$.expression,
|
|
")"
|
|
),
|
|
|
|
when_expression: $ => seq(
|
|
"when",
|
|
optional($.when_subject),
|
|
"{",
|
|
repeat($.when_entry),
|
|
"}"
|
|
),
|
|
|
|
when_entry: $ => choice(
|
|
seq(
|
|
$.when_condition,
|
|
repeat(seq(",", $.when_condition)),
|
|
"->",
|
|
$.control_structure_body,
|
|
optional($.semi)
|
|
),
|
|
seq(
|
|
"else",
|
|
"->",
|
|
$.control_structure_body,
|
|
optional($.semi)
|
|
)
|
|
),
|
|
|
|
when_condition: $ => choice(
|
|
$.expression,
|
|
$.range_test,
|
|
$.type_test
|
|
),
|
|
|
|
range_test: $ => seq($.in_operator, $.expression),
|
|
|
|
type_test: $ => seq($.is_operator, $.type),
|
|
|
|
try_expression: $ => seq(
|
|
"try",
|
|
$.block,
|
|
choice(
|
|
seq(repeat1($.catch_block), optional($.finally_block)),
|
|
$.finally_block
|
|
)
|
|
),
|
|
|
|
catch_block: $ => seq(
|
|
"catch",
|
|
"(",
|
|
repeat($.annotation),
|
|
$.simple_identifier,
|
|
":",
|
|
$.type,
|
|
")",
|
|
$.block
|
|
),
|
|
|
|
finally_block: $ => seq("finally", $.block),
|
|
|
|
jump_expression: $ => choice(
|
|
seq("throw", $.expression),
|
|
seq(choice("return", $.return_at), optional($.expression)),
|
|
"continue",
|
|
$.continue_at,
|
|
"break",
|
|
$.break_at
|
|
),
|
|
|
|
callable_reference: $ => seq(
|
|
optional($.receiver_type),
|
|
"::",
|
|
choice($.simple_identifier, "class")
|
|
),
|
|
|
|
assignment_and_operator: $ => choice("+=", "-=", "*=", "/=", "%="),
|
|
|
|
equality_operator: $ => choice("!=", "!==", "==", "==="),
|
|
|
|
comparison_operator: $ => choice("<", ">", "<=", ">="),
|
|
|
|
in_operator: $ => choice("in", $.not_in),
|
|
|
|
is_operator: $ => choice("is", $.not_is),
|
|
|
|
additive_operator: $ => choice("+", "-"),
|
|
|
|
multiplicative_operator: $ => choice("*", "/", "%"),
|
|
|
|
as_operator: $ => choice("as", "as?"),
|
|
|
|
prefix_unary_operator: $ => choice("++", "--", "-", "+", $.excl),
|
|
|
|
postfix_unary_operator: $ => choice("++", "--", seq("!,", $.excl)),
|
|
|
|
excl: $ => choice("!", $.excl_ws),
|
|
|
|
member_access_operator: $ => choice(".", $.safe_nav, "::"),
|
|
|
|
safe_nav: $ => seq("?", "."),
|
|
|
|
// ==========
|
|
// Modifiers
|
|
// ==========
|
|
|
|
modifiers: $ => choice($.annotation, repeat1($.modifier)),
|
|
|
|
parameter_modifiers: $ => choice($.annotation, repeat1($.parameter_modifier)),
|
|
|
|
modifier: $ => choice(
|
|
$.class_modifier,
|
|
$.member_modifier,
|
|
$.visibility_modifier,
|
|
$.function_modifier,
|
|
$.property_modifier,
|
|
$.inheritance_modifier,
|
|
$.parameter_modifier,
|
|
$.platform_modifier
|
|
),
|
|
|
|
type_modifiers: $ => repeat1($.type_modifier),
|
|
|
|
type_modifier: $ => choice($.annotation, "suspend"),
|
|
|
|
class_modifier: $ => choice(
|
|
"enum",
|
|
"sealed",
|
|
"annotation",
|
|
"data",
|
|
"inner"
|
|
),
|
|
|
|
member_modifier: $ => choice(
|
|
"override",
|
|
"lateinit"
|
|
),
|
|
|
|
visibility_modifier: $ => choice(
|
|
"public",
|
|
"private",
|
|
"internal",
|
|
"protected"
|
|
),
|
|
|
|
variance_modifier: $ => choice("in", "out"),
|
|
|
|
type_parameter_modifiers: $ => repeat1($.type_parameter_modifier),
|
|
|
|
type_parameter_modifier: $ => choice(
|
|
$.reification_modifier,
|
|
$.variance_modifier,
|
|
$.annotation
|
|
),
|
|
|
|
function_modifier: $ => choice(
|
|
"tailrec",
|
|
"operator",
|
|
"infix",
|
|
"inline",
|
|
"external",
|
|
"suspend"
|
|
),
|
|
|
|
property_modifier: $ => "const",
|
|
|
|
inheritance_modifier: $ => choice(
|
|
"abstract",
|
|
"final",
|
|
"open"
|
|
),
|
|
|
|
parameter_modifier: $ => choice(
|
|
"vararg",
|
|
"noinline",
|
|
"crossinline"
|
|
),
|
|
|
|
reification_modifier: $ => "reified",
|
|
|
|
platform_modifier: $ => choice("expect", "actual"),
|
|
|
|
// ==========
|
|
// Annotations
|
|
// ==========
|
|
|
|
annotation: $ => choice(
|
|
$.single_annotation,
|
|
$.multi_annotation
|
|
),
|
|
|
|
single_annotation: $ => choice(
|
|
seq($.annotation_use_site_target, $.unescaped_annotation),
|
|
seq(
|
|
choice("@", $.at_pre_ws),
|
|
$.unescaped_annotation
|
|
)
|
|
),
|
|
|
|
multi_annotation: $ => choice(
|
|
seq(
|
|
$.annotation_use_site_target,
|
|
"[",
|
|
repeat1($.unescaped_annotation),
|
|
"]"
|
|
),
|
|
seq(
|
|
choice("@", $.at_pre_ws),
|
|
"[",
|
|
repeat1($.unescaped_annotation),
|
|
"]"
|
|
)
|
|
),
|
|
|
|
annotation_use_site_target: $ => seq(
|
|
choice("@", $.at_pre_ws),
|
|
choice(
|
|
"field",
|
|
"property",
|
|
"get",
|
|
"set",
|
|
"receiver",
|
|
"param",
|
|
"setparam",
|
|
"delegate"
|
|
),
|
|
":"
|
|
),
|
|
|
|
unescaped_annotation: $ => choice(
|
|
$.constructor_invocation,
|
|
$.user_type
|
|
),
|
|
|
|
// ==========
|
|
// Identifiers
|
|
// ==========
|
|
|
|
simple_identifier: $ => choice(
|
|
$.lexical_identifier,
|
|
"abstract",
|
|
"annotation",
|
|
"by",
|
|
"catch",
|
|
"companion",
|
|
"constructor",
|
|
"crossinline",
|
|
"data",
|
|
"dynamic",
|
|
"enum",
|
|
"external",
|
|
"final",
|
|
"finally",
|
|
"get",
|
|
"import",
|
|
"infix",
|
|
"init",
|
|
"inline",
|
|
"inner",
|
|
"internal",
|
|
"lateinit",
|
|
"noinline",
|
|
"open",
|
|
"operator",
|
|
"out",
|
|
"override",
|
|
"private",
|
|
"protected",
|
|
"public",
|
|
"reified",
|
|
"sealed",
|
|
"tailrec",
|
|
"set",
|
|
"vararg",
|
|
"where",
|
|
"field",
|
|
"property",
|
|
"receiver",
|
|
"param",
|
|
"setparam",
|
|
"delegate",
|
|
"file",
|
|
"expect",
|
|
"actual",
|
|
"const",
|
|
"suspend"
|
|
),
|
|
|
|
identifier: $ => seq(
|
|
$.simple_identifier,
|
|
repeat(seq(".", $.simple_identifier))
|
|
),
|
|
|
|
// ====================
|
|
// Lexical grammar
|
|
// ====================
|
|
|
|
// ==========
|
|
// General
|
|
// ==========
|
|
|
|
delimited_comment: $ => seq(
|
|
"/*",
|
|
repeat(choice($.delimited_comment, ".")),
|
|
"*/"
|
|
),
|
|
|
|
line_comment: $ => seq("//", /[^\r\n]*/),
|
|
|
|
ws: $ => /[ \t\u000C]/,
|
|
|
|
hidden: $ => choice(
|
|
$.delimited_comment,
|
|
$.line_comment,
|
|
$.ws
|
|
),
|
|
|
|
// ==========
|
|
// Separators and operations
|
|
// ==========
|
|
|
|
reserved: $ => "...",
|
|
|
|
excl_ws: $ => seq("!", $.hidden),
|
|
|
|
double_arrow: $ => "=>",
|
|
|
|
double_semicolon: $ => ";;",
|
|
|
|
hash: $ => "#",
|
|
|
|
at_post_ws: $ => seq("@", $.hidden),
|
|
|
|
at_pre_ws: $ => seq($.hidden, "@"),
|
|
|
|
at_both_ws: $ => seq($.hidden, "@", $.hidden),
|
|
|
|
quest_ws: $ => seq("?", $.hidden),
|
|
|
|
single_quote: $ => "'",
|
|
|
|
// ==========
|
|
// Keywords
|
|
// ==========
|
|
|
|
return_at: $ => seq("return@", $.lexical_identifier),
|
|
|
|
continue_at: $ => seq("continue@", $.lexical_identifier),
|
|
|
|
break_at: $ => seq("break@", $.lexical_identifier),
|
|
|
|
this_at: $ => seq("this@", $.lexical_identifier),
|
|
|
|
super_at: $ => seq("super@", $.lexical_identifier),
|
|
|
|
typeof: $ => "typeof",
|
|
|
|
not_is: $ => seq("!is", $.hidden),
|
|
|
|
not_in: $ => seq("!in", $.hidden),
|
|
|
|
// ==========
|
|
// Literals
|
|
// ==========
|
|
|
|
dec_digit: $ => /[0-9]/,
|
|
|
|
dec_digit_no_zero: $ => /[1-9]/,
|
|
|
|
dec_digit_or_separator: $ => choice($.dec_digit, "_"),
|
|
|
|
dec_digits: $ => choice(
|
|
seq($.dec_digit, repeat($.dec_digit_or_separator), $.dec_digit),
|
|
$.dec_digit
|
|
),
|
|
|
|
double_exponent: $ => seq(/[eE]/, optional(/[+-]/), $.dec_digits),
|
|
|
|
real_literal: $ => choice(
|
|
$.float_literal,
|
|
$.double_literal
|
|
),
|
|
|
|
float_literal: $ => choice(
|
|
seq($.double_literal, /[fF]/),
|
|
seq($.dec_digits, /[fF]/)
|
|
),
|
|
|
|
double_literal: $ => choice(
|
|
seq(optional($.dec_digits), ".", $.dec_digits, optional($.double_exponent)),
|
|
seq($.dec_digits, $.double_exponent)
|
|
),
|
|
|
|
integer_literal: $ => choice(
|
|
seq($.dec_digit_no_zero, repeat($.dec_digit_or_separator), $.dec_digit),
|
|
$.dec_digit
|
|
),
|
|
|
|
hex_digit: $ => /[0-9a-fA-F]/,
|
|
|
|
hex_digit_or_separator: $ => choice($.hex_digit, "_"),
|
|
|
|
hex_literal: $ => choice(
|
|
seq("0", /[xX]/, $.hex_digit, repeat($.hex_digit_or_separator), $.hex_digit),
|
|
seq("0", /[xX]/, $.hex_digit)
|
|
),
|
|
|
|
bin_digit: $ => /[01]/,
|
|
|
|
bin_digit_or_separator: $ => choice($.bin_digit, "_"),
|
|
|
|
bin_literal: $ => choice(
|
|
seq("0", /[bB]/, $.bin_digit, repeat($.bin_digit_or_separator), $.bin_digit),
|
|
seq("0", /[bB]/, $.bin_digit)
|
|
),
|
|
|
|
unsigned_literal: $ => seq(
|
|
choice($.integer_literal, $.hex_literal, $.bin_literal),
|
|
/[uU]/,
|
|
optional("L")
|
|
),
|
|
|
|
long_literal: $ => seq(
|
|
choice($.integer_literal, $.hex_literal, $.bin_literal),
|
|
"L"
|
|
),
|
|
|
|
boolean_literal: $ => choice("true", "false"),
|
|
|
|
character_literal: $ => seq(
|
|
"'",
|
|
choice($.escape_seq, /[^\n\r'\\]/),
|
|
"'"
|
|
),
|
|
|
|
// ==========
|
|
// Identifiers
|
|
// ==========
|
|
|
|
lexical_identifier: $ => choice(
|
|
/[a-zA-Z_][a-zA-Z_0-9]+/,
|
|
/`[^\r\n`]+`/
|
|
),
|
|
|
|
identifier_or_soft_key: $ => choice(
|
|
$.lexical_identifier,
|
|
"abstract",
|
|
"annotation",
|
|
"by",
|
|
"catch",
|
|
"companion",
|
|
"constructor",
|
|
"crossinline",
|
|
"data",
|
|
"dynamic",
|
|
"enum",
|
|
"external",
|
|
"final",
|
|
"finally",
|
|
"import",
|
|
"infix",
|
|
"init",
|
|
"inline",
|
|
"inner",
|
|
"internal",
|
|
"lateinit",
|
|
"noinline",
|
|
"open",
|
|
"operator",
|
|
"out",
|
|
"override",
|
|
"private",
|
|
"protected",
|
|
"public",
|
|
"reified",
|
|
"sealed",
|
|
"tailrec",
|
|
"vararg",
|
|
"where",
|
|
"get",
|
|
"set",
|
|
"field",
|
|
"property",
|
|
"receiver",
|
|
"param",
|
|
"setparam",
|
|
"delegate",
|
|
"file",
|
|
"expect",
|
|
"actual",
|
|
"const",
|
|
"suspend"
|
|
),
|
|
|
|
field_identifier: $ => seq("$", $.identifier_or_soft_key),
|
|
|
|
uni_character_literal: $ => seq(
|
|
"\\",
|
|
"u",
|
|
$.hex_digit,
|
|
$.hex_digit,
|
|
$.hex_digit,
|
|
$.hex_digit
|
|
),
|
|
|
|
escaped_identifier: $ => /\\[tbrn'"\\$]/,
|
|
|
|
escape_seq: $ => choice(
|
|
$.uni_character_literal,
|
|
$.escaped_identifier
|
|
),
|
|
|
|
// ==========
|
|
// Strings
|
|
// ==========
|
|
|
|
line_str_ref: $ => $.field_identifier,
|
|
|
|
line_str_text: $ => choice(/[^\\"$]+/, "$"),
|
|
|
|
line_str_escaped_char: $ => choice(
|
|
$.escaped_identifier,
|
|
$.uni_character_literal
|
|
),
|
|
|
|
triple_quote_close: $ => /"?"""/,
|
|
|
|
multi_line_str_ref: $ => $.field_identifier,
|
|
|
|
multi_line_str_text: $ => choice(/[^"$]+/, "$")
|
|
}
|
|
});
|