tree-sitters/rust/grammar.js

1543 lines
34 KiB
JavaScript

/**
* @file Rust grammar for tree-sitter
* @author Maxim Sokolov <maxim0xff@gmail.com>
* @author Max Brunsfeld
* @author Amaan Qureshi <amaanq12@gmail.com>
* @license MIT
*/
/* eslint-disable arrow-parens */
/* eslint-disable camelcase */
/* eslint-disable-next-line spaced-comment */
/// <reference types="tree-sitter-cli/dsl" />
// @ts-check
// https://doc.rust-lang.org/reference/expressions.html#expression-precedence
const PREC = {
call: 15,
field: 14,
try: 13,
unary: 12,
cast: 11,
multiplicative: 10,
additive: 9,
shift: 8,
bitand: 7,
bitxor: 6,
bitor: 5,
comparative: 4,
and: 3,
or: 2,
range: 1,
assign: 0,
closure: -1,
};
const numeric_types = [
'u8',
'i8',
'u16',
'i16',
'u32',
'i32',
'u64',
'i64',
'u128',
'i128',
'isize',
'usize',
'f32',
'f64',
];
const TOKEN_TREE_NON_SPECIAL_TOKENS = [
'/', '_', '\\', '-',
'=', '->', ',', ';',
':', '::', '!', '?',
'.', '@', '*', '&',
'#', '%', '^', '+',
'<', '>', '|', '~',
];
const primitive_types = numeric_types.concat(['bool', 'str', 'char']);
module.exports = grammar({
name: 'rust',
extras: $ => [/\s/, $.line_comment, $.block_comment],
externals: $ => [
$._string_content,
$.raw_string_literal,
$.float_literal,
$.block_comment,
],
supertypes: $ => [
$._expression,
$._type,
$._literal,
$._literal_pattern,
$._declaration_statement,
$._pattern,
],
inline: $ => [
$._path,
$._type_identifier,
$._tokens,
$._field_identifier,
$._non_special_token,
$._declaration_statement,
$._reserved_identifier,
$._expression_ending_with_block,
],
conflicts: $ => [
// Local ambiguity due to anonymous types:
// See https://internals.rust-lang.org/t/pre-rfc-deprecating-anonymous-parameters/3710
[$._type, $._pattern],
[$.unit_type, $.tuple_pattern],
[$.scoped_identifier, $.scoped_type_identifier],
[$.parameters, $._pattern],
[$.parameters, $.tuple_struct_pattern],
[$.type_parameters, $.for_lifetimes],
],
word: $ => $.identifier,
rules: {
source_file: $ => seq(
optional($.shebang),
repeat($._statement),
),
_statement: $ => choice(
$.expression_statement,
$._declaration_statement,
),
empty_statement: _ => ';',
expression_statement: $ => choice(
seq($._expression, ';'),
prec(1, $._expression_ending_with_block),
),
_declaration_statement: $ => choice(
$.const_item,
$.macro_invocation,
$.macro_definition,
$.empty_statement,
$.attribute_item,
$.inner_attribute_item,
$.mod_item,
$.foreign_mod_item,
$.struct_item,
$.union_item,
$.enum_item,
$.type_item,
$.function_item,
$.function_signature_item,
$.impl_item,
$.trait_item,
$.associated_type,
$.let_declaration,
$.use_declaration,
$.extern_crate_declaration,
$.static_item,
),
// Section - Macro definitions
macro_definition: $ => {
const rules = seq(
repeat(seq($.macro_rule, ';')),
optional($.macro_rule),
);
return seq(
'macro_rules!',
field('name', choice(
$.identifier,
$._reserved_identifier,
)),
choice(
seq('(', rules, ')', ';'),
seq('{', rules, '}'),
),
);
},
macro_rule: $ => seq(
field('left', $.token_tree_pattern),
'=>',
field('right', $.token_tree),
),
_token_pattern: $ => choice(
$.token_tree_pattern,
$.token_repetition_pattern,
$.token_binding_pattern,
$.metavariable,
$._non_special_token,
),
token_tree_pattern: $ => choice(
seq('(', repeat($._token_pattern), ')'),
seq('[', repeat($._token_pattern), ']'),
seq('{', repeat($._token_pattern), '}'),
),
token_binding_pattern: $ => prec(1, seq(
field('name', $.metavariable),
':',
field('type', $.fragment_specifier),
)),
token_repetition_pattern: $ => seq(
'$', '(', repeat($._token_pattern), ')', optional(/[^+*?]+/), choice('+', '*', '?'),
),
fragment_specifier: _ => choice(
'block', 'expr', 'ident', 'item', 'lifetime', 'literal', 'meta', 'pat',
'path', 'stmt', 'tt', 'ty', 'vis',
),
_tokens: $ => choice(
$.token_tree,
$.token_repetition,
$.metavariable,
$._non_special_token,
),
token_tree: $ => choice(
seq('(', repeat($._tokens), ')'),
seq('[', repeat($._tokens), ']'),
seq('{', repeat($._tokens), '}'),
),
token_repetition: $ => seq(
'$', '(', repeat($._tokens), ')', optional(/[^+*?]+/), choice('+', '*', '?'),
),
// Matches non-delimiter tokens common to both macro invocations and
// definitions. This is everything except $ and metavariables (which begin
// with $).
_non_special_token: $ => choice(
$._literal, $.identifier, $.mutable_specifier, $.self, $.super, $.crate,
alias(choice(...primitive_types), $.primitive_type),
prec.right(repeat1(choice(...TOKEN_TREE_NON_SPECIAL_TOKENS))),
'\'',
'as', 'async', 'await', 'break', 'const', 'continue', 'default', 'enum', 'fn', 'for', 'if', 'impl',
'let', 'loop', 'match', 'mod', 'pub', 'return', 'static', 'struct', 'trait', 'type',
'union', 'unsafe', 'use', 'where', 'while',
),
// Section - Declarations
attribute_item: $ => seq(
'#',
'[',
$.attribute,
']',
),
inner_attribute_item: $ => seq(
'#',
'!',
'[',
$.attribute,
']',
),
attribute: $ => seq(
$._path,
optional(choice(
seq('=', field('value', $._expression)),
field('arguments', alias($.delim_token_tree, $.token_tree)),
)),
),
mod_item: $ => seq(
optional($.visibility_modifier),
'mod',
field('name', $.identifier),
choice(
';',
field('body', $.declaration_list),
),
),
foreign_mod_item: $ => seq(
optional($.visibility_modifier),
$.extern_modifier,
choice(
';',
field('body', $.declaration_list),
),
),
declaration_list: $ => seq(
'{',
repeat($._declaration_statement),
'}',
),
struct_item: $ => seq(
optional($.visibility_modifier),
'struct',
field('name', $._type_identifier),
field('type_parameters', optional($.type_parameters)),
choice(
seq(
optional($.where_clause),
field('body', $.field_declaration_list),
),
seq(
field('body', $.ordered_field_declaration_list),
optional($.where_clause),
';',
),
';',
),
),
union_item: $ => seq(
optional($.visibility_modifier),
'union',
field('name', $._type_identifier),
field('type_parameters', optional($.type_parameters)),
optional($.where_clause),
field('body', $.field_declaration_list),
),
enum_item: $ => seq(
optional($.visibility_modifier),
'enum',
field('name', $._type_identifier),
field('type_parameters', optional($.type_parameters)),
optional($.where_clause),
field('body', $.enum_variant_list),
),
enum_variant_list: $ => seq(
'{',
sepBy(',', seq(repeat($.attribute_item), $.enum_variant)),
optional(','),
'}',
),
enum_variant: $ => seq(
optional($.visibility_modifier),
field('name', $.identifier),
field('body', optional(choice(
$.field_declaration_list,
$.ordered_field_declaration_list,
))),
optional(seq(
'=',
field('value', $._expression),
)),
),
field_declaration_list: $ => seq(
'{',
sepBy(',', seq(repeat($.attribute_item), $.field_declaration)),
optional(','),
'}',
),
field_declaration: $ => seq(
optional($.visibility_modifier),
field('name', $._field_identifier),
':',
field('type', $._type),
),
ordered_field_declaration_list: $ => seq(
'(',
sepBy(',', seq(
repeat($.attribute_item),
optional($.visibility_modifier),
field('type', $._type),
)),
optional(','),
')',
),
extern_crate_declaration: $ => seq(
optional($.visibility_modifier),
'extern',
$.crate,
field('name', $.identifier),
optional(seq(
'as',
field('alias', $.identifier),
)),
';',
),
const_item: $ => seq(
optional($.visibility_modifier),
'const',
field('name', $.identifier),
':',
field('type', $._type),
optional(
seq(
'=',
field('value', $._expression),
),
),
';',
),
static_item: $ => seq(
optional($.visibility_modifier),
'static',
// Not actual rust syntax, but made popular by the lazy_static crate.
optional('ref'),
optional($.mutable_specifier),
field('name', $.identifier),
':',
field('type', $._type),
optional(seq(
'=',
field('value', $._expression),
)),
';',
),
type_item: $ => seq(
optional($.visibility_modifier),
'type',
field('name', $._type_identifier),
field('type_parameters', optional($.type_parameters)),
'=',
field('type', $._type),
optional($.where_clause),
';',
),
function_item: $ => seq(
optional($.visibility_modifier),
optional($.function_modifiers),
'fn',
field('name', choice($.identifier, $.metavariable)),
field('type_parameters', optional($.type_parameters)),
field('parameters', $.parameters),
optional(seq('->', field('return_type', $._type))),
optional($.where_clause),
field('body', $.block),
),
function_signature_item: $ => seq(
optional($.visibility_modifier),
optional($.function_modifiers),
'fn',
field('name', choice($.identifier, $.metavariable)),
field('type_parameters', optional($.type_parameters)),
field('parameters', $.parameters),
optional(seq('->', field('return_type', $._type))),
optional($.where_clause),
';',
),
function_modifiers: $ => repeat1(choice(
'async',
'default',
'const',
'unsafe',
$.extern_modifier,
)),
where_clause: $ => seq(
'where',
sepBy1(',', $.where_predicate),
optional(','),
),
where_predicate: $ => seq(
field('left', choice(
$.lifetime,
$._type_identifier,
$.scoped_type_identifier,
$.generic_type,
$.reference_type,
$.pointer_type,
$.tuple_type,
$.array_type,
$.higher_ranked_trait_bound,
alias(choice(...primitive_types), $.primitive_type),
)),
field('bounds', $.trait_bounds),
),
impl_item: $ => seq(
optional('unsafe'),
'impl',
field('type_parameters', optional($.type_parameters)),
optional(seq(
field('trait', choice(
$._type_identifier,
$.scoped_type_identifier,
$.generic_type,
)),
'for',
)),
field('type', $._type),
optional($.where_clause),
choice(field('body', $.declaration_list), ';'),
),
trait_item: $ => seq(
optional($.visibility_modifier),
optional('unsafe'),
'trait',
field('name', $._type_identifier),
field('type_parameters', optional($.type_parameters)),
field('bounds', optional($.trait_bounds)),
optional($.where_clause),
field('body', $.declaration_list),
),
associated_type: $ => seq(
'type',
field('name', $._type_identifier),
field('type_parameters', optional($.type_parameters)),
field('bounds', optional($.trait_bounds)),
';',
),
trait_bounds: $ => seq(
':',
sepBy1('+', choice(
$._type,
$.lifetime,
$.higher_ranked_trait_bound,
$.removed_trait_bound,
)),
),
higher_ranked_trait_bound: $ => seq(
'for',
field('type_parameters', $.type_parameters),
field('type', $._type),
),
removed_trait_bound: $ => seq(
'?',
$._type,
),
type_parameters: $ => prec(1, seq(
'<',
sepBy1(',', choice(
$.lifetime,
$.metavariable,
$._type_identifier,
$.constrained_type_parameter,
$.optional_type_parameter,
$.const_parameter,
)),
optional(','),
'>',
)),
const_parameter: $ => seq(
'const',
field('name', $.identifier),
':',
field('type', $._type),
),
constrained_type_parameter: $ => seq(
field('left', choice($.lifetime, $._type_identifier)),
field('bounds', $.trait_bounds),
),
optional_type_parameter: $ => seq(
field('name', choice(
$._type_identifier,
$.constrained_type_parameter,
)),
'=',
field('default_type', $._type),
),
let_declaration: $ => seq(
'let',
optional($.mutable_specifier),
field('pattern', $._pattern),
optional(seq(
':',
field('type', $._type),
)),
optional(seq(
'=',
field('value', $._expression),
)),
optional(seq(
'else',
field('alternative', $.block),
)),
';',
),
use_declaration: $ => seq(
optional($.visibility_modifier),
'use',
field('argument', $._use_clause),
';',
),
_use_clause: $ => choice(
$._path,
$.use_as_clause,
$.use_list,
$.scoped_use_list,
$.use_wildcard,
),
scoped_use_list: $ => seq(
field('path', optional($._path)),
'::',
field('list', $.use_list),
),
use_list: $ => seq(
'{',
sepBy(',', choice(
$._use_clause,
)),
optional(','),
'}',
),
use_as_clause: $ => seq(
field('path', $._path),
'as',
field('alias', $.identifier),
),
use_wildcard: $ => seq(
optional(seq($._path, '::')),
'*',
),
parameters: $ => seq(
'(',
sepBy(',', seq(
optional($.attribute_item),
choice(
$.parameter,
$.self_parameter,
$.variadic_parameter,
'_',
$._type,
))),
optional(','),
')',
),
self_parameter: $ => seq(
optional('&'),
optional($.lifetime),
optional($.mutable_specifier),
$.self,
),
variadic_parameter: _ => '...',
parameter: $ => seq(
optional($.mutable_specifier),
field('pattern', choice(
$._pattern,
$.self,
)),
':',
field('type', $._type),
),
extern_modifier: $ => seq(
'extern',
optional($.string_literal),
),
visibility_modifier: $ => prec.right(
choice(
$.crate,
seq(
'pub',
optional(seq(
'(',
choice(
$.self,
$.super,
$.crate,
seq('in', $._path),
),
')',
)),
),
)),
// Section - Types
_type: $ => choice(
$.abstract_type,
$.reference_type,
$.metavariable,
$.pointer_type,
$.generic_type,
$.scoped_type_identifier,
$.tuple_type,
$.unit_type,
$.array_type,
$.function_type,
$._type_identifier,
$.macro_invocation,
$.empty_type,
$.dynamic_type,
$.bounded_type,
alias(choice(...primitive_types), $.primitive_type),
),
bracketed_type: $ => seq(
'<',
choice(
$._type,
$.qualified_type,
),
'>',
),
qualified_type: $ => seq(
field('type', $._type),
'as',
field('alias', $._type),
),
lifetime: $ => seq('\'', $.identifier),
array_type: $ => seq(
'[',
field('element', $._type),
optional(seq(
';',
field('length', $._expression),
)),
']',
),
for_lifetimes: $ => seq(
'for',
'<',
sepBy1(',', $.lifetime),
optional(','),
'>',
),
function_type: $ => seq(
optional($.for_lifetimes),
prec(PREC.call, seq(
choice(
field('trait', choice(
$._type_identifier,
$.scoped_type_identifier,
)),
seq(
optional($.function_modifiers),
'fn',
),
),
field('parameters', $.parameters),
)),
optional(seq('->', field('return_type', $._type))),
),
tuple_type: $ => seq(
'(',
sepBy1(',', $._type),
optional(','),
')',
),
unit_type: _ => seq('(', ')'),
generic_function: $ => prec(1, seq(
field('function', choice(
$.identifier,
$.scoped_identifier,
$.field_expression,
)),
'::',
field('type_arguments', $.type_arguments),
)),
generic_type: $ => prec(1, seq(
field('type', choice(
$._type_identifier,
$._reserved_identifier,
$.scoped_type_identifier,
)),
field('type_arguments', $.type_arguments),
)),
generic_type_with_turbofish: $ => seq(
field('type', choice(
$._type_identifier,
$.scoped_identifier,
)),
'::',
field('type_arguments', $.type_arguments),
),
bounded_type: $ => prec.left(-1, choice(
seq($.lifetime, '+', $._type),
seq($._type, '+', $._type),
seq($._type, '+', $.lifetime),
)),
type_arguments: $ => seq(
token(prec(1, '<')),
sepBy1(',', choice(
$._type,
$.type_binding,
$.lifetime,
$._literal,
$.block,
)),
optional(','),
'>',
),
type_binding: $ => seq(
field('name', $._type_identifier),
field('type_arguments', optional($.type_arguments)),
'=',
field('type', $._type),
),
reference_type: $ => seq(
'&',
optional($.lifetime),
optional($.mutable_specifier),
field('type', $._type),
),
pointer_type: $ => seq(
'*',
choice('const', $.mutable_specifier),
field('type', $._type),
),
empty_type: _ => '!',
abstract_type: $ => seq(
'impl',
optional(seq('for', $.type_parameters)),
field('trait', choice(
$._type_identifier,
$.scoped_type_identifier,
$.generic_type,
$.function_type,
)),
),
dynamic_type: $ => seq(
'dyn',
field('trait', choice(
$._type_identifier,
$.scoped_type_identifier,
$.generic_type,
$.function_type,
)),
),
mutable_specifier: _ => 'mut',
// Section - Expressions
_expression_except_range: $ => choice(
$.unary_expression,
$.reference_expression,
$.try_expression,
$.binary_expression,
$.assignment_expression,
$.compound_assignment_expr,
$.type_cast_expression,
$.call_expression,
$.return_expression,
$.yield_expression,
$._literal,
prec.left($.identifier),
alias(choice(...primitive_types), $.identifier),
prec.left($._reserved_identifier),
$.self,
$.scoped_identifier,
$.generic_function,
$.await_expression,
$.field_expression,
$.array_expression,
$.tuple_expression,
prec(1, $.macro_invocation),
$.unit_expression,
$.break_expression,
$.continue_expression,
$.index_expression,
$.metavariable,
$.closure_expression,
$.parenthesized_expression,
$.struct_expression,
$._expression_ending_with_block,
),
_expression: $ => choice(
$._expression_except_range,
$.range_expression,
),
_expression_ending_with_block: $ => choice(
$.unsafe_block,
$.async_block,
$.block,
$.if_expression,
$.match_expression,
$.while_expression,
$.loop_expression,
$.for_expression,
$.const_block,
),
macro_invocation: $ => seq(
field('macro', choice(
$.scoped_identifier,
$.identifier,
$._reserved_identifier,
)),
'!',
alias($.delim_token_tree, $.token_tree),
),
delim_token_tree: $ => choice(
seq('(', repeat($._delim_tokens), ')'),
seq('[', repeat($._delim_tokens), ']'),
seq('{', repeat($._delim_tokens), '}'),
),
_delim_tokens: $ => choice(
$._non_delim_token,
alias($.delim_token_tree, $.token_tree),
),
// Should match any token other than a delimiter.
_non_delim_token: $ => choice(
$._non_special_token,
'$',
),
scoped_identifier: $ => seq(
field('path', optional(choice(
$._path,
$.bracketed_type,
alias($.generic_type_with_turbofish, $.generic_type),
))),
'::',
field('name', choice($.identifier, $.super)),
),
scoped_type_identifier_in_expression_position: $ => prec(-2, seq(
field('path', optional(choice(
$._path,
alias($.generic_type_with_turbofish, $.generic_type),
))),
'::',
field('name', $._type_identifier),
)),
scoped_type_identifier: $ => seq(
field('path', optional(choice(
$._path,
alias($.generic_type_with_turbofish, $.generic_type),
$.bracketed_type,
$.generic_type,
))),
'::',
field('name', $._type_identifier),
),
range_expression: $ => prec.left(PREC.range, choice(
seq($._expression, choice('..', '...', '..='), $._expression),
seq($._expression, '..'),
seq('..', $._expression),
'..',
)),
unary_expression: $ => prec(PREC.unary, seq(
choice('-', '*', '!'),
$._expression,
)),
try_expression: $ => prec(PREC.try, seq(
$._expression,
'?',
)),
reference_expression: $ => prec(PREC.unary, seq(
'&',
optional($.mutable_specifier),
field('value', $._expression),
)),
binary_expression: $ => {
const table = [
[PREC.and, '&&'],
[PREC.or, '||'],
[PREC.bitand, '&'],
[PREC.bitor, '|'],
[PREC.bitxor, '^'],
[PREC.comparative, choice('==', '!=', '<', '<=', '>', '>=')],
[PREC.shift, choice('<<', '>>')],
[PREC.additive, choice('+', '-')],
[PREC.multiplicative, choice('*', '/', '%')],
];
// @ts-ignore
return choice(...table.map(([precedence, operator]) => prec.left(precedence, seq(
field('left', $._expression),
// @ts-ignore
field('operator', operator),
field('right', $._expression),
))));
},
assignment_expression: $ => prec.left(PREC.assign, seq(
field('left', $._expression),
'=',
field('right', $._expression),
)),
compound_assignment_expr: $ => prec.left(PREC.assign, seq(
field('left', $._expression),
field('operator', choice('+=', '-=', '*=', '/=', '%=', '&=', '|=', '^=', '<<=', '>>=')),
field('right', $._expression),
)),
type_cast_expression: $ => prec.left(PREC.cast, seq(
field('value', $._expression),
'as',
field('type', $._type),
)),
return_expression: $ => choice(
prec.left(seq('return', $._expression)),
prec(-1, 'return'),
),
yield_expression: $ => choice(
prec.left(seq('yield', $._expression)),
prec(-1, 'yield'),
),
call_expression: $ => prec(PREC.call, seq(
field('function', $._expression_except_range),
field('arguments', $.arguments),
)),
arguments: $ => seq(
'(',
sepBy(',', seq(repeat($.attribute_item), $._expression)),
optional(','),
')',
),
array_expression: $ => seq(
'[',
repeat($.attribute_item),
choice(
seq(
$._expression,
';',
field('length', $._expression),
),
seq(
sepBy(',', $._expression),
optional(','),
),
),
']',
),
parenthesized_expression: $ => seq(
'(',
$._expression,
')',
),
tuple_expression: $ => seq(
'(',
repeat($.attribute_item),
seq($._expression, ','),
repeat(seq($._expression, ',')),
optional($._expression),
')',
),
unit_expression: _ => seq('(', ')'),
struct_expression: $ => seq(
field('name', choice(
$._type_identifier,
alias($.scoped_type_identifier_in_expression_position, $.scoped_type_identifier),
$.generic_type_with_turbofish,
)),
field('body', $.field_initializer_list),
),
field_initializer_list: $ => seq(
'{',
sepBy(',', choice(
$.shorthand_field_initializer,
$.field_initializer,
$.base_field_initializer,
)),
optional(','),
'}',
),
shorthand_field_initializer: $ => seq(
repeat($.attribute_item),
$.identifier,
),
field_initializer: $ => seq(
repeat($.attribute_item),
field('name', $._field_identifier),
':',
field('value', $._expression),
),
base_field_initializer: $ => seq(
'..',
$._expression,
),
if_expression: $ => prec.right(seq(
'if',
field('condition', $._condition),
field('consequence', $.block),
optional(field('alternative', $.else_clause)),
)),
let_condition: $ => seq(
'let',
field('pattern', $._pattern),
'=',
field('value', prec.left(PREC.and, $._expression)),
),
_let_chain: $ => prec.left(PREC.and, choice(
seq($._let_chain, '&&', $.let_condition),
seq($._let_chain, '&&', $._expression),
seq($.let_condition, '&&', $._expression),
seq($.let_condition, '&&', $.let_condition),
seq($._expression, '&&', $.let_condition),
)),
_condition: $ => choice(
$._expression,
$.let_condition,
alias($._let_chain, $.let_chain),
),
else_clause: $ => seq(
'else',
choice(
$.block,
$.if_expression,
),
),
match_expression: $ => seq(
'match',
field('value', $._expression),
field('body', $.match_block),
),
match_block: $ => seq(
'{',
optional(seq(
repeat($.match_arm),
alias($.last_match_arm, $.match_arm),
)),
'}',
),
match_arm: $ => prec.right(seq(
repeat($.attribute_item),
field('pattern', $.match_pattern),
'=>',
choice(
seq(field('value', $._expression), ','),
field('value', prec(1, $._expression_ending_with_block)),
),
)),
last_match_arm: $ => seq(
repeat($.attribute_item),
field('pattern', $.match_pattern),
'=>',
field('value', $._expression),
optional(','),
),
match_pattern: $ => seq(
choice($._pattern, alias($.closure_expression, $.closure_pattern)),
optional(seq('if', field('condition', $._condition))),
),
while_expression: $ => seq(
optional(seq($.loop_label, ':')),
'while',
field('condition', $._condition),
field('body', $.block),
),
loop_expression: $ => seq(
optional(seq($.loop_label, ':')),
'loop',
field('body', $.block),
),
for_expression: $ => seq(
optional(seq($.loop_label, ':')),
'for',
field('pattern', $._pattern),
'in',
field('value', $._expression),
field('body', $.block),
),
const_block: $ => seq(
'const',
field('body', $.block),
),
closure_expression: $ => prec(PREC.closure, seq(
optional('static'),
optional('move'),
field('parameters', $.closure_parameters),
choice(
seq(
optional(seq('->', field('return_type', $._type))),
field('body', $.block),
),
field('body', choice($._expression, '_')),
),
)),
closure_parameters: $ => seq(
'|',
sepBy(',', choice(
$._pattern,
$.parameter,
)),
'|',
),
loop_label: $ => seq('\'', $.identifier),
break_expression: $ => prec.left(seq('break', optional($.loop_label), optional($._expression))),
continue_expression: $ => prec.left(seq('continue', optional($.loop_label))),
index_expression: $ => prec(PREC.call, seq($._expression, '[', $._expression, ']')),
await_expression: $ => prec(PREC.field, seq(
$._expression,
'.',
'await',
)),
field_expression: $ => prec(PREC.field, seq(
field('value', $._expression),
'.',
field('field', choice(
$._field_identifier,
$.integer_literal,
)),
)),
unsafe_block: $ => seq(
'unsafe',
$.block,
),
async_block: $ => seq(
'async',
optional('move'),
$.block,
),
block: $ => seq(
'{',
repeat($._statement),
optional($._expression),
'}',
),
// Section - Patterns
_pattern: $ => choice(
$._literal_pattern,
alias(choice(...primitive_types), $.identifier),
$.identifier,
$.scoped_identifier,
$.tuple_pattern,
$.tuple_struct_pattern,
$.struct_pattern,
$._reserved_identifier,
$.ref_pattern,
$.slice_pattern,
$.captured_pattern,
$.reference_pattern,
$.remaining_field_pattern,
$.mut_pattern,
$.range_pattern,
$.or_pattern,
$.const_block,
$.macro_invocation,
'_',
),
tuple_pattern: $ => seq(
'(',
sepBy(',', choice($._pattern, $.closure_expression)),
optional(','),
')',
),
slice_pattern: $ => seq(
'[',
sepBy(',', $._pattern),
optional(','),
']',
),
tuple_struct_pattern: $ => seq(
field('type', choice(
$.identifier,
$.scoped_identifier,
)),
'(',
sepBy(',', $._pattern),
optional(','),
')',
),
struct_pattern: $ => seq(
field('type', choice(
$._type_identifier,
$.scoped_type_identifier,
)),
'{',
sepBy(',', choice($.field_pattern, $.remaining_field_pattern)),
optional(','),
'}',
),
field_pattern: $ => seq(
optional('ref'),
optional($.mutable_specifier),
choice(
field('name', alias($.identifier, $.shorthand_field_identifier)),
seq(
field('name', $._field_identifier),
':',
field('pattern', $._pattern),
),
),
),
remaining_field_pattern: _ => '..',
mut_pattern: $ => prec(-1, seq(
$.mutable_specifier,
$._pattern,
)),
range_pattern: $ => seq(
choice(
$._literal_pattern,
$._path,
),
choice('...', '..='),
choice(
$._literal_pattern,
$._path,
),
),
ref_pattern: $ => seq(
'ref',
$._pattern,
),
captured_pattern: $ => seq(
$.identifier,
'@',
$._pattern,
),
reference_pattern: $ => seq(
'&',
optional($.mutable_specifier),
$._pattern,
),
or_pattern: $ => prec.left(-2, seq(
$._pattern,
'|',
$._pattern,
)),
// Section - Literals
_literal: $ => choice(
$.string_literal,
$.raw_string_literal,
$.char_literal,
$.boolean_literal,
$.integer_literal,
$.float_literal,
),
_literal_pattern: $ => choice(
$.string_literal,
$.raw_string_literal,
$.char_literal,
$.boolean_literal,
$.integer_literal,
$.float_literal,
$.negative_literal,
),
negative_literal: $ => seq('-', choice($.integer_literal, $.float_literal)),
integer_literal: _ => token(seq(
choice(
/[0-9][0-9_]*/,
/0x[0-9a-fA-F_]+/,
/0b[01_]+/,
/0o[0-7_]+/,
),
optional(choice(...numeric_types)),
)),
string_literal: $ => seq(
alias(/b?"/, '"'),
repeat(choice(
$.escape_sequence,
$._string_content,
)),
token.immediate('"'),
),
char_literal: _ => token(seq(
optional('b'),
'\'',
optional(choice(
seq('\\', choice(
/[^xu]/,
/u[0-9a-fA-F]{4}/,
/u{[0-9a-fA-F]+}/,
/x[0-9a-fA-F]{2}/,
)),
/[^\\']/,
)),
'\'',
)),
escape_sequence: _ => token.immediate(
seq('\\',
choice(
/[^xu]/,
/u[0-9a-fA-F]{4}/,
/u{[0-9a-fA-F]+}/,
/x[0-9a-fA-F]{2}/,
),
)),
boolean_literal: _ => choice('true', 'false'),
comment: $ => choice(
$.line_comment,
$.block_comment,
),
line_comment: _ => token(seq(
'//', /.*/,
)),
_path: $ => choice(
$.self,
alias(choice(...primitive_types), $.identifier),
$.metavariable,
$.super,
$.crate,
$.identifier,
$.scoped_identifier,
$._reserved_identifier,
),
identifier: _ => /(r#)?[_\p{XID_Start}][_\p{XID_Continue}]*/,
shebang: _ => /#!.*/,
_reserved_identifier: $ => alias(choice(
'default',
'union',
), $.identifier),
_type_identifier: $ => alias($.identifier, $.type_identifier),
_field_identifier: $ => alias($.identifier, $.field_identifier),
self: _ => 'self',
super: _ => 'super',
crate: _ => 'crate',
metavariable: _ => /\$[a-zA-Z_]\w*/,
},
});
/**
* Creates a rule to match one or more of the rules separated by the separator.
*
* @param {RuleOrLiteral} sep - The separator to use.
* @param {RuleOrLiteral} rule
*
* @return {SeqRule}
*
*/
function sepBy1(sep, rule) {
return seq(rule, repeat(seq(sep, rule)));
}
/**
* Creates a rule to optionally match one or more of the rules separated by the separator.
*
* @param {RuleOrLiteral} sep - The separator to use.
* @param {RuleOrLiteral} rule
*
* @return {ChoiceRule}
*
*/
function sepBy(sep, rule) {
return optional(sepBy1(sep, rule));
}