mirror of https://github.com/Wilfred/difftastic/
726 lines
19 KiB
JavaScript
726 lines
19 KiB
JavaScript
const PREC = {
|
|
ASSIGNMENT: 0,
|
|
LOGICAL_XOR: 1,
|
|
LOGICAL_OR: 2,
|
|
LOGICAL_AND: 3,
|
|
BITWISE_OR: 4,
|
|
BITWISE_XOR: 5,
|
|
BITWISE_AND: 6,
|
|
EQUALITY: 7,
|
|
COMPARISON: 8,
|
|
SHIFT: 9,
|
|
ADD: 10,
|
|
MULTIPLY: 11,
|
|
CAST: 12,
|
|
UNARY: 13,
|
|
}
|
|
|
|
module.exports = grammar ({
|
|
|
|
name: 'hare',
|
|
|
|
extras: $ => [
|
|
/\s|\\\r?\n/,
|
|
$.comment,
|
|
],
|
|
|
|
conflicts: $ => [
|
|
[$.integer_constant, $.floating_constant],
|
|
[$.identifier], // enum
|
|
[$.bindings], // parenthesized expressions in array/slice specifiers
|
|
[$.for_predicate, $.expression], // second/third production rules in for predicate.
|
|
[$.if_expression]
|
|
],
|
|
|
|
rules: {
|
|
|
|
// The Translation Unit.
|
|
unit: $ => seq(
|
|
optional($.imports),
|
|
optional($.declarations),
|
|
),
|
|
|
|
// Imports.
|
|
imports: $ => repeat1($.use_statement),
|
|
|
|
use_statement: $ => seq(
|
|
'use',
|
|
choice(
|
|
seq($.identifier, ';'),
|
|
seq($.name, '=', $.identifier, ';'),
|
|
seq($.identifier, '::', '{', $.name_list, '}', ';')
|
|
),
|
|
),
|
|
|
|
name_list: $ => choice(
|
|
seq($.name, optional(',')),
|
|
seq($.name,',', $.name_list)
|
|
),
|
|
|
|
// Declarations.
|
|
declarations: $ => repeat1(seq(optional('export'), $.declaration, ';')),
|
|
|
|
declaration: $ => choice(
|
|
$.global_declaration,
|
|
$.constant_declaration,
|
|
$.type_declaration,
|
|
$.function_declaration
|
|
),
|
|
|
|
global_declaration: $ => choice(
|
|
seq('let', $.global_bindings),
|
|
seq('const', $.global_bindings)
|
|
),
|
|
|
|
global_bindings: $ =>
|
|
seq($.global_binding, optional(seq(',', $.global_bindings))),
|
|
|
|
global_binding: $ => seq(
|
|
optional($.decl_attr),
|
|
$.identifier, ':', $.type, optional(seq('=', $.expression))
|
|
),
|
|
|
|
decl_attr: $ => seq(
|
|
'@symbol', '(', $.string_constant, ')'
|
|
),
|
|
|
|
constant_declaration: $ => seq('def', $.constant_bindings),
|
|
|
|
constant_bindings: $ =>
|
|
seq($.constant_binding, optional(seq(',', $.constant_bindings))),
|
|
|
|
constant_binding: $ => seq(
|
|
$.identifier, ':', $.type, '=', $.expression
|
|
),
|
|
|
|
|
|
type_declaration: $ => seq('type', $.type_bindings),
|
|
|
|
type_bindings: $ => choice(
|
|
seq($.identifier, '=', $.type, optional(',')),
|
|
seq($.identifier, '=', $.type, ',', $.type_bindings)
|
|
),
|
|
|
|
function_declaration: $ =>
|
|
seq(optional($.fndec_attrs), 'fn',
|
|
field('name', $.identifier), field('type', $.prototype),
|
|
optional(seq('=', field('body', $.expression)))
|
|
),
|
|
|
|
fndec_attrs: $ => repeat1($.fndec_attr),
|
|
|
|
fndec_attr: $ => choice(
|
|
'@fini',
|
|
'@init',
|
|
'@test',
|
|
$.fntype_attr,
|
|
$.decl_attr
|
|
),
|
|
|
|
fntype_attr: $ => choice(
|
|
'@noreturn',
|
|
),
|
|
|
|
// Types.
|
|
type: $ => seq($._inner_type, optional('!')),
|
|
|
|
_inner_type: $ => seq( optional('const'), $.storage_class),
|
|
|
|
storage_class: $ => choice(
|
|
$.scalar_type,
|
|
$.struct_type,
|
|
$.union_type,
|
|
$.tuple_type,
|
|
$.tagged_union_type,
|
|
$.slice_array_type,
|
|
$.function_type,
|
|
$.alias_type,
|
|
$.unwrapped_alias,
|
|
),
|
|
|
|
scalar_type: $ => choice(
|
|
$.integer_type,
|
|
$.floating_type,
|
|
$.enum_type,
|
|
$.pointer_type,
|
|
'rune',
|
|
'str',
|
|
'bool',
|
|
'void'
|
|
),
|
|
|
|
integer_type: $ => choice(
|
|
'i8',
|
|
'i16',
|
|
'i32',
|
|
'i64',
|
|
'u8',
|
|
'u16',
|
|
'u32',
|
|
'u64',
|
|
'int',
|
|
'uint',
|
|
'size',
|
|
'uintptr',
|
|
'char',
|
|
),
|
|
|
|
floating_type: $ => choice(
|
|
'f32',
|
|
'f64',
|
|
),
|
|
|
|
enum_type: $ => choice(
|
|
seq('enum', '{', $.enum_values, '}'),
|
|
seq('enum', $.integer_type, '{', $.enum_values, '}'),
|
|
),
|
|
|
|
enum_values: $ => choice(
|
|
seq($.enum_value, optional(',')),
|
|
seq($.enum_value, ',', $.enum_values),
|
|
),
|
|
|
|
enum_value: $ => choice(
|
|
$.name,
|
|
seq($.name, '=', $.expression)
|
|
),
|
|
|
|
pointer_type: $ => choice(
|
|
seq('*', $._inner_type),
|
|
seq('nullable', '*', $._inner_type)
|
|
),
|
|
|
|
struct_type: $ =>seq('struct', '{', $.struct_union_fields, '}'),
|
|
union_type: $ =>seq('union', '{', $.struct_union_fields, '}'),
|
|
|
|
struct_union_fields: $ => choice(
|
|
seq($.struct_union_field, optional(',')),
|
|
seq($.struct_union_field, ',', $.struct_union_fields)
|
|
),
|
|
|
|
struct_union_field: $ => seq(
|
|
optional($.offset_specifier),
|
|
choice(
|
|
seq($.name, ':', $.type),
|
|
$.struct_type,
|
|
$.union_type,
|
|
$.identifier
|
|
)
|
|
),
|
|
|
|
offset_specifier: $ => seq('@offset', '(', $.expression, ')'),
|
|
|
|
tuple_type: $ => seq('(', $.tuple_types, ')'),
|
|
|
|
tuple_types: $ => choice(
|
|
seq($.type, ',', $.type, optional(',')),
|
|
seq($.type, ',', $.tuple_types),
|
|
),
|
|
|
|
tagged_union_type: $ => seq('(', $.tagged_types, ')'),
|
|
|
|
tagged_types: $ => seq($.type, '|', $.type, repeat(seq('|', $.type))),
|
|
|
|
slice_array_type: $ => choice(
|
|
seq('[',']', $._inner_type),
|
|
seq('[', $.logical_or_expression, ']', $._inner_type),
|
|
seq('[', '*', ']', $._inner_type),
|
|
seq('[', '_', ']', $._inner_type)
|
|
),
|
|
|
|
function_type: $ => seq(optional($.fntype_attr), 'fn', $.prototype),
|
|
|
|
prototype: $ => seq('(', optional($.parameter_list), ')', $._inner_type),
|
|
|
|
parameter_list: $ => choice(
|
|
seq($.parameters, optional(',')),
|
|
seq($.parameters, '...', optional(',')),
|
|
seq($.parameters, ',', '...', optional(',')),
|
|
),
|
|
|
|
parameters: $ => choice(
|
|
$.parameter,
|
|
seq($.parameters, ',', $.parameter)
|
|
),
|
|
|
|
parameter: $ => choice(
|
|
seq($.name, ':', $.type),
|
|
seq('_', ':', $.type)
|
|
),
|
|
|
|
|
|
alias_type: $ => $.identifier,
|
|
|
|
unwrapped_alias: $ => seq('...', $.identifier),
|
|
|
|
|
|
// Expressions.
|
|
constant: $ => choice(
|
|
$.integer_constant,
|
|
$.floating_constant,
|
|
$.rune_constant,
|
|
$.string_constant,
|
|
'true',
|
|
'false',
|
|
'null',
|
|
'void'
|
|
),
|
|
|
|
integer_constant: $ => choice(
|
|
seq('0x', $.hex_digits, optional($.integer_suffix)),
|
|
seq('0o', $.octal_digits, optional($.integer_suffix)),
|
|
seq('0b', $.binary_digits, optional($.integer_suffix)),
|
|
seq($.decimal_digits, optional($.exponent), optional($.integer_suffix)),
|
|
),
|
|
|
|
hex_digits: $ => repeat1($.hex_digit),
|
|
|
|
hex_digit: $ => choice(
|
|
'0',
|
|
'1',
|
|
'2',
|
|
'3',
|
|
'4',
|
|
'5',
|
|
'6',
|
|
'7',
|
|
'8',
|
|
'9',
|
|
'A',
|
|
'B',
|
|
'C',
|
|
'D',
|
|
'E',
|
|
'F',
|
|
'a',
|
|
'b',
|
|
'c',
|
|
'd',
|
|
'e',
|
|
'f'
|
|
),
|
|
|
|
octal_digits: $ => repeat1($.octal_digit),
|
|
octal_digit: $ => choice(
|
|
'0',
|
|
'1',
|
|
'2',
|
|
'3',
|
|
'4',
|
|
'5',
|
|
'6',
|
|
'7',
|
|
),
|
|
|
|
binary_digits: $ => repeat1($.binary_digit),
|
|
binary_digit: $ => choice('0', '1'),
|
|
|
|
decimal_digits: $ => repeat1($.decimal_digit),
|
|
decimal_digit: $ => choice('0','1', '2', '3', '4', '5', '6', '7', '8', '9'),
|
|
|
|
integer_suffix: $ => choice(
|
|
'i',
|
|
'u',
|
|
'z',
|
|
'i8',
|
|
'i16',
|
|
'i32',
|
|
'i64',
|
|
'u8',
|
|
'u16',
|
|
'u32',
|
|
'u64',
|
|
),
|
|
|
|
floating_constant: $ => choice(
|
|
seq($.decimal_digits, '.', $.decimal_digits, optional($.exponent), optional($.floating_suffix)),
|
|
seq($.decimal_digits, optional($.exponent), $.floating_suffix),
|
|
),
|
|
|
|
exponent: $ => seq('e', $.decimal_digits),
|
|
|
|
floating_suffix: $ => choice(
|
|
'f32',
|
|
'f64'
|
|
),
|
|
|
|
rune_constant: $ => seq("'", $.rune, "'"),
|
|
|
|
rune: $ => choice(
|
|
token.immediate(/[^\']/),
|
|
$.escape_sequence
|
|
),
|
|
|
|
escape_sequence: $ => choice(
|
|
$.named_escape,
|
|
seq(
|
|
"\\",
|
|
token.immediate(
|
|
choice(
|
|
/x[0-9a-fA-F]{2}/,
|
|
/u[0-9a-fA-F]{4}/,
|
|
/U[0-9a-fA-F]{8}/
|
|
)
|
|
)
|
|
)
|
|
),
|
|
|
|
named_escape: $ => seq(
|
|
'\\',
|
|
token.immediate(
|
|
choice(
|
|
'0',
|
|
'n',
|
|
'r',
|
|
't',
|
|
'b',
|
|
'f',
|
|
'a',
|
|
'v',
|
|
'\\',
|
|
'\'',
|
|
'\"',
|
|
))
|
|
),
|
|
|
|
string_constant: $ => repeat1(seq('"', optional($.string_chars), '"')),
|
|
|
|
string_chars: $ => repeat1($.string_char),
|
|
string_char: $ => choice(
|
|
token.immediate(/[^\n"]/),
|
|
$.escape_sequence
|
|
),
|
|
|
|
array_literal: $ => seq('[', optional($.array_members), ']'),
|
|
array_members: $ => choice(
|
|
seq($.expression, optional(',')),
|
|
seq($.expression, '...', optional(',')),
|
|
seq($.expression, ',', $.array_members),
|
|
),
|
|
|
|
enum_literal: $ => seq($.identifier, '::', $.name),
|
|
|
|
struct_literal: $ => choice(
|
|
seq('struct', '{', seq($.field_values, optional(',')), '}'),
|
|
seq($.identifier, '{', $.struct_initializer, '}'),
|
|
),
|
|
|
|
struct_initializer: $ => choice(
|
|
'...',
|
|
seq($.field_values, optional(seq(',', optional('...')))),
|
|
),
|
|
|
|
field_values: $ => choice(
|
|
$.field_value,
|
|
seq($.field_values, ',', $.field_value),
|
|
),
|
|
|
|
field_value: $ => choice(
|
|
seq($.name, '=', $.expression),
|
|
seq($.name, ':', $.type, '=', $.expression),
|
|
$.struct_literal
|
|
),
|
|
|
|
plain_expression: $ => choice(
|
|
$.identifier,
|
|
$.constant,
|
|
$.array_literal,
|
|
$.enum_literal,
|
|
$.struct_literal,
|
|
),
|
|
|
|
nested_expression: $ => choice(
|
|
$.plain_expression,
|
|
seq('(', $.expression, ')'),
|
|
seq('(', $.tuple_items, ')'),
|
|
),
|
|
|
|
tuple_items: $ => choice(
|
|
seq($.expression, ',', $.expression, optional(',')),
|
|
seq($.expression, ',', $.tuple_items),
|
|
),
|
|
|
|
allocation_expression: $ => choice(
|
|
seq('alloc','(', $.expression, ')'),
|
|
seq('alloc','(', $.expression, ',', $.expression, ')'),
|
|
seq('append', '(', $.object_selector, ',', $.append_values, ')'),
|
|
seq('append','(', '*', $.unary_expression, ',', $.append_values,')'),
|
|
seq('free', '(', $.expression, ')'),
|
|
seq('delete', '(', $.slicing_expression, ')'),
|
|
seq('delete', '(', $.indexing_expression, ')')
|
|
),
|
|
|
|
append_values: $ => choice(
|
|
seq($.expression, optional(',')),
|
|
seq('...', $.expression, optional(',')),
|
|
seq($.expression, ',', $.append_values)
|
|
),
|
|
|
|
|
|
assertion_expression: $ => choice(
|
|
seq('assert', '(', $.expression, ')'),
|
|
seq('assert', '(', $.expression, ',', $.string_constant, ')'),
|
|
seq('static', 'assert', '(', $.expression, ')'),
|
|
seq('static', 'assert', '(', $.expression ,',', $.string_constant, ')'),
|
|
seq('abort', '(', optional($.string_constant), ')'),
|
|
),
|
|
|
|
call_expression: $ => seq($.postfix_expression, '(', optional($.argument_list), ')'),
|
|
|
|
argument_list: $ => choice(
|
|
seq($.expression, optional(',')),
|
|
seq($.expression, '...', optional(',')),
|
|
seq($.expression, ',', $.argument_list),
|
|
),
|
|
|
|
measurement_expression: $ => choice(
|
|
$.size_expression,
|
|
$.length_expression,
|
|
$.offset_expression
|
|
),
|
|
|
|
size_expression: $ => seq('size', '(', $.type, ')'),
|
|
|
|
length_expression: $ => seq('len', '(', $.expression, ')'),
|
|
|
|
offset_expression: $ => seq('offset', '(', $.field_access_expression, ')'),
|
|
|
|
field_access_expression: $ => choice(
|
|
seq($.postfix_expression, field('selector', seq('.', $.name))),
|
|
seq($.postfix_expression, field('selector', seq('.', $.integer_constant)))
|
|
),
|
|
|
|
indexing_expression: $ => seq($.postfix_expression, '[', $.expression, ']'),
|
|
|
|
slicing_expression: $ => seq(
|
|
$.postfix_expression, '[', optional($.expression),
|
|
'..', optional($.expression), ']'
|
|
),
|
|
|
|
error_propagation: $ => seq($.postfix_expression, '?'),
|
|
|
|
postfix_expression: $ => choice(
|
|
$.nested_expression,
|
|
$.allocation_expression,
|
|
$.assertion_expression,
|
|
$.call_expression,
|
|
$.field_access_expression,
|
|
$.indexing_expression,
|
|
$.measurement_expression,
|
|
$.slicing_expression,
|
|
$.error_propagation,
|
|
),
|
|
|
|
object_selector: $ => choice(
|
|
$.identifier,
|
|
$.indexing_expression,
|
|
$.field_access_expression
|
|
),
|
|
|
|
unary_expression: $ => choice(
|
|
$.postfix_expression,
|
|
prec.right(PREC.UNARY,
|
|
seq(
|
|
field('operator', choice('+', '-', '~', '!', '*')),
|
|
field('argument', $.unary_expression)
|
|
)
|
|
),
|
|
prec.right(PREC.UNARY,
|
|
seq(
|
|
field('address', '&'),
|
|
field('argument', $.object_selector)
|
|
)
|
|
)
|
|
),
|
|
|
|
cast_expression: $ => choice(
|
|
$.unary_expression,
|
|
prec.left(PREC.CAST, field('type_cast', seq( $.cast_expression, ':', $.type))),
|
|
prec.left(PREC.CAST, field('as_cast', seq( $.cast_expression, 'as', $.type))),
|
|
prec.left(PREC.CAST, field('is_cast', seq( $.cast_expression, 'is', $.type)))
|
|
),
|
|
|
|
multiplicative_expression: $ => choice(
|
|
$.cast_expression,
|
|
prec.left(PREC.MULTIPLY, seq($.multiplicative_expression, '*', $.cast_expression)),
|
|
prec.left(PREC.MULTIPLY, seq($.multiplicative_expression, '/', $.cast_expression)),
|
|
prec.left(PREC.MULTIPLY, seq($.multiplicative_expression, '%', $.cast_expression))
|
|
),
|
|
|
|
additive_expression: $ => choice(
|
|
$.multiplicative_expression,
|
|
prec.left(PREC.ADD, seq($.additive_expression, '+', $.multiplicative_expression)),
|
|
prec.left(PREC.ADD, seq($.additive_expression, '-', $.multiplicative_expression))
|
|
),
|
|
|
|
shift_expression: $ => choice(
|
|
$.additive_expression,
|
|
prec.left(PREC.SHIFT, seq($.multiplicative_expression, '<<', $.cast_expression)),
|
|
prec.left(PREC.SHIFT, seq($.multiplicative_expression, '>>', $.cast_expression))
|
|
),
|
|
|
|
and_expression: $ => choice(
|
|
$.shift_expression,
|
|
prec.left(PREC.BITWISE_AND, seq($.and_expression, '&', $.shift_expression)),
|
|
),
|
|
|
|
exclusive_or_expression: $ => choice(
|
|
$.and_expression,
|
|
prec.left(PREC.BITWISE_XOR, seq($.exclusive_or_expression, '^', $.and_expression)),
|
|
),
|
|
inclusive_or_expression: $ => choice(
|
|
$.exclusive_or_expression,
|
|
prec.left(PREC.BITWISE_OR, seq($.inclusive_or_expression, '|', $.exclusive_or_expression)),
|
|
),
|
|
|
|
comparison_expression: $ => choice(
|
|
$.inclusive_or_expression,
|
|
prec.left(PREC.COMPARISON, seq($.comparison_expression, '<', $.inclusive_or_expression)),
|
|
prec.left(PREC.COMPARISON, seq($.comparison_expression, '>', $.inclusive_or_expression)),
|
|
prec.left(PREC.COMPARISON, seq($.comparison_expression, '<=', $.inclusive_or_expression)),
|
|
prec.left(PREC.COMPARISON, seq($.comparison_expression, '>=', $.inclusive_or_expression))
|
|
),
|
|
|
|
equality_expression: $ => choice(
|
|
$.comparison_expression,
|
|
prec.left(PREC.EQUALITY, seq($.equality_expression, '==', $.comparison_expression)),
|
|
prec.left(PREC.EQUALITY, seq($.equality_expression, '!=', $.comparison_expression)),
|
|
),
|
|
|
|
logical_and_expression: $ => choice(
|
|
$.equality_expression,
|
|
prec.left(PREC.LOGICAL_AND, seq($.logical_and_expression, '&&', $.equality_expression)),
|
|
),
|
|
|
|
logical_xor_expression: $ => choice(
|
|
$.logical_and_expression,
|
|
prec.left(PREC.LOGICAL_XOR, seq($.logical_xor_expression, '^^', $.logical_and_expression)),
|
|
),
|
|
|
|
logical_or_expression: $ => choice(
|
|
$.logical_xor_expression,
|
|
prec.left(PREC.LOGICAL_OR, seq($.logical_or_expression, '||', $.logical_xor_expression)),
|
|
),
|
|
|
|
if_expression: $ => choice(
|
|
seq('if', $.conditional_branch),
|
|
seq('if', $.conditional_branch, 'else', $.expression)
|
|
),
|
|
|
|
conditional_branch: $ => seq('(' , $.expression, ')', $.expression),
|
|
|
|
for_loop: $ => seq(
|
|
optional($.label),
|
|
'for', '(', $.for_predicate, ')', $.expression
|
|
),
|
|
|
|
for_predicate: $ => choice(
|
|
$.expression,
|
|
seq(field('binding', $.binding_list), ';', $.expression),
|
|
seq($.expression, ';', field('afterthought', $.expression)),
|
|
seq($.binding_list, ';', $.expression, ';', $.expression),
|
|
),
|
|
|
|
label: $ => seq(':', $.name),
|
|
|
|
switch_expression: $ => seq(
|
|
'switch', '(', $.expression, ')', '{', $.switch_cases, '}'
|
|
),
|
|
|
|
switch_cases: $ => choice(
|
|
seq($.switch_case, optional(',')),
|
|
seq($.switch_case, ',', $.switch_cases)
|
|
),
|
|
|
|
switch_case: $ => choice(
|
|
seq($.case_options, '=>', $.expression),
|
|
seq('*', '=>', $.expression),
|
|
),
|
|
|
|
case_options: $ => choice(
|
|
seq($.expression, optional(',')),
|
|
seq($.expression, ',', $.case_options)
|
|
),
|
|
|
|
match_expression: $ =>
|
|
seq('match', '(', $.expression, ')', '{', $.match_cases, '}'),
|
|
|
|
match_cases: $ => choice(
|
|
seq($.match_case, optional(',')),
|
|
seq($.match_case, ',', $.match_cases)
|
|
),
|
|
|
|
match_case: $ => choice(
|
|
seq($.name, ':', $.type, '=>', $.expression),
|
|
seq($.type, '=>', $.expression),
|
|
seq('*', '=>', $.expression)
|
|
),
|
|
|
|
assignment: $ => prec.left(PREC.ASSIGNMENT,
|
|
choice(
|
|
seq($.object_selector, $.assignment_op, $.expression),
|
|
seq('*', $.unary_expression, $.assignment_op, $.expression),
|
|
seq($.slicing_expression, '=', $.expression)
|
|
)),
|
|
|
|
assignment_op: $ => choice(
|
|
'=', '+=', '-=', '*=', '/=', '%=', '<<=', '>>=', '&=', '|=', '^='
|
|
),
|
|
|
|
binding_list: $ => choice(
|
|
seq(optional('static'), 'let', $.bindings),
|
|
seq(optional('static'), 'const', $.bindings),
|
|
),
|
|
|
|
bindings: $ => seq($.binding, optional(seq(',', $.bindings))),
|
|
|
|
binding: $ => choice(
|
|
seq($.name, '=', $.expression),
|
|
seq($.name, ':', $.type, '=', $.expression),
|
|
seq($.binding_names, '=', $.expression),
|
|
seq($.binding_names, ':', $.type, '=', $.expression),
|
|
),
|
|
|
|
binding_names: $ => choice(
|
|
seq($.name, ',', $.name),
|
|
seq($.name, ',', $.binding_names)
|
|
),
|
|
|
|
deferred_expression: $ => seq('defer', $.expression),
|
|
|
|
expression_list: $ => choice(
|
|
seq($.expression, ';'),
|
|
seq($.expression, ';', $.expression_list)
|
|
),
|
|
|
|
control_statement: $ => choice(
|
|
seq('break', optional($.label)),
|
|
seq('continue', optional($.label)),
|
|
seq('return', optional($.expression))
|
|
),
|
|
|
|
expression: $ => choice(
|
|
$.assignment,
|
|
$.binding_list,
|
|
$.deferred_expression,
|
|
$.logical_or_expression,
|
|
$.if_expression,
|
|
$.for_loop,
|
|
$.switch_expression,
|
|
$.match_expression,
|
|
$.control_statement,
|
|
$.compound_expression,
|
|
),
|
|
|
|
compound_expression: $ => seq('{', $.expression_list, '}'),
|
|
|
|
identifier: $ =>
|
|
seq($.name, optional(seq('::', $.identifier))),
|
|
|
|
name: $ => /[a-zA-Z_]\w*/,
|
|
|
|
comment: $ => token(seq('//', /(\\(.|\r?\n)|[^\\\n])*/)),
|
|
|
|
}
|
|
})
|