Make grammar rules more tree-sitter-like

pull/70/head
Arthur Baars 2021-11-12 12:01:18 +07:00
parent 00d4cdc038
commit f7528122d6
1 changed files with 129 additions and 82 deletions

@ -34,8 +34,6 @@ const ALPHA_CHAR = /[^\x00-\x1F\s0-9:;`"'@$#.,|^&<=>+\-*/\\%?!~()\[\]{}]/;
module.exports = grammar({
name: 'ruby',
inline: $ => [$.p_kwarg, $.p_args_post],
externals: $ => [
$._line_break,
@ -351,124 +349,176 @@ module.exports = grammar({
in_clause: $ => seq(
'in',
$.p_top_expr,
field('pattern', $._pattern_top_expr_body),
field('guard', optional($._guard)),
choice($._terminator, field('body', $.then))
),
pattern: $ => choice($._arg, $.splat_argument),
p_top_expr: $ => choice($.p_top_expr_body,
seq($.p_top_expr_body, 'if', $._expression),
seq($.p_top_expr_body, 'unless', $._expression)
_guard: $ => choice(
$.if_guard,
$.unless_guard
),
p_top_expr_body: $ => choice(
$.p_expr,
seq($.p_expr, ',', optional($.p_args)),
$.p_find,
$.p_args_tail,
$.p_kwargs
if_guard: $ => seq(
'if',
field('condition', $._expression)
),
p_expr: $ => $.p_as,
unless_guard: $ => seq(
'unless',
field('condition', $._expression)
),
p_as: $ => choice(
seq($.p_expr, '=>', $.p_variable),
$.p_alt
_pattern_top_expr_body: $ => choice(
$._pattern_expr,
alias($._array_pattern_n, $.array_pattern),
alias($._find_pattern_body, $.find_pattern),
alias($._hash_pattern_body, $.hash_pattern),
),
p_alt: $ => sep1($.p_expr_basic, '|'),
_array_pattern_n: $ => choice(
seq($._pattern_expr, alias(',', $.array_pattern_rest)),
seq($._pattern_expr, ',', choice($._pattern_expr, $._array_pattern_n)),
seq($.array_pattern_rest, repeat(seq(',', $._pattern_expr))),
),
p_expr_basic: $ => choice(
$.p_value,
seq($.p_const,
choice(
seq('(', optional(choice($.p_args, $.p_find, $.p_kwargs)), ')'),
seq('[', optional(choice($.p_args, $.p_find, $.p_kwargs)), ']'),
)
),
seq('(', $.p_expr, ')'),
seq('[', optional(choice($.p_args, $.p_find)), ']'),
seq('{', optional($.p_kwargs), '}'),
_pattern_expr: $ => choice(
$.as_pattern,
$._pattern_expr_alt,
),
p_args: $ => choice(
$.p_expr,
seq(
repeat1(seq($.p_arg, ',')),
optional(
choice(
$.p_arg,
seq(
$.p_rest,
optional($.p_args_post)
)
)
)
),
$.p_args_tail
as_pattern: $ => seq(field('value', $._pattern_expr), '=>', field('name', $.identifier)),
_pattern_expr_alt: $ => choice(
$.alternative_pattern,
$._pattern_expr_basic,
),
p_args_tail: $ => seq($.p_rest, optional($.p_args_post)),
alternative_pattern: $ => seq(field('alternatives', $._pattern_expr_basic), repeat1(seq('|', field('alternatives', $._pattern_expr_basic)))),
p_find: $ => seq($.p_rest, $.p_args_post, ',', $.p_rest),
_array_pattern_body: $ => choice(
$._pattern_expr,
$._array_pattern_n,
),
p_rest: $ => seq('*', optional($.identifier)),
array_pattern: $ => choice(
seq('[', optional($._array_pattern_body), ']'),
seq(field('class', $._pattern_constant), token.immediate('['), optional($._array_pattern_body), ']'),
seq(field('class', $._pattern_constant), token.immediate('('), optional($._array_pattern_body), ')')
),
p_args_post: $ => repeat1(seq(',', $.p_arg)),
_find_pattern_body: $ => seq($.array_pattern_rest, repeat1(seq(',', $._pattern_expr)), ',', $.array_pattern_rest),
find_pattern: $ => choice(
seq('[', $._find_pattern_body, ']'),
seq(field('class', $._pattern_constant), token.immediate('['), $._find_pattern_body, ']'),
seq(field('class', $._pattern_constant), token.immediate('('), $._find_pattern_body, ')')
),
p_arg: $ => $.p_expr,
_hash_pattern_body: $ => choice(
seq(commaSep1($.pattern_pair), optional(',')),
seq(commaSep1($.pattern_pair), ',', $._hash_pattern_any_rest),
$._hash_pattern_any_rest
),
p_kwargs: $ => choice(
seq(optional(seq($.p_kwarg, ',')), choice($.p_kwrest, $.p_kwnorest)),
seq($.p_kwarg, optional(','))
pattern_pair: $ => seq(
field('key',
choice(
alias($.identifier, $.hash_key_symbol),
alias($.constant, $.hash_key_symbol),
$.string
)
),
token.immediate(':'),
optional(field('value', $._pattern_expr))
),
p_kwarg: $ => commaSep1($.p_kw),
_hash_pattern_any_rest: $ => choice($.hash_pattern_rest, $.hash_pattern_norest),
p_kw: $ => seq($.p_kw_label, optional($.p_expr)),
hash_pattern_rest: $ => seq('**', field('name', optional($.identifier))),
p_kw_label: $ => seq(
choice(
alias($.identifier, $.hash_key_symbol),
alias($.constant, $.hash_key_symbol),
$.string
),
token.immediate(':')
hash_pattern_norest: $ => seq('**', 'nil'),
hash_pattern: $ => choice(
seq('{', optional($._hash_pattern_body), '}'),
seq(field('class', $._pattern_constant), token.immediate('['), $._hash_pattern_body, ']'),
seq(field('class', $._pattern_constant), token.immediate('('), $._hash_pattern_body, ')')
),
p_kwrest: $ => seq('**', optional($.identifier)),
_pattern_expr_basic: $ => choice(
$._pattern_value,
$.array_pattern,
$.find_pattern,
$.hash_pattern,
),
array_pattern_rest: $ => seq('*', field('name', optional($.identifier))),
p_kwnorest: $ => seq('**', 'nil'),
_pattern_value: $ => choice(
$._pattern_primitive,
$.pattern_range,
$.pattern_variable,
$.variable_reference_pattern,
$._pattern_constant
),
pattern_range: $ => {
const begin = field('begin', $._pattern_primitive);
const end = field('end', $._pattern_primitive);
const operator = field('operator', choice('..', '...'));
return choice(
seq(begin, operator, end),
seq(operator, end),
seq(begin, operator)
);
},
p_value: $ => choice(
$.p_primitive,
seq($.p_primitive, choice('..', '...'), optional($.p_primitive)),
seq(choice('..', '...'), $.p_primitive),
$.p_variable,
$.p_var_ref,
$.p_const
_pattern_primitive: $ => choice(
$._pattern_literal,
$._pattern_lambda
),
p_primitive: $ => choice(
_pattern_lambda: $ => $.lambda,
_pattern_literal: $ => choice(
$._literal,
$.string,
$.regex,
$.string_array,
$.symbol_array,
$.keyword_variable,
$.lambda
$._keyword_variable
),
keyword_variable: $ => choice($.nil, $.self, $.true, $.false, '__LINE__', '__FILE__', '__ENCODING__'),
_keyword_variable: $ => choice(
$.nil,
$.self,
$.true,
$.false,
$.line,
$.file,
$.encoding,
),
p_variable: $ => $.identifier,
line: $ => '__LINE__',
file: $ => '__FILE__',
encoding: $ => '__ENCODING__',
p_var_ref: $ => seq('^', $.identifier),
pattern_variable: $ => field('name', $.identifier),
p_const: $ => choice(
seq($.constant, repeat(seq('::', $._cname))),
repeat1(seq('::', $._cname))
variable_reference_pattern: $ => seq('^', field('name', $.identifier)),
_pattern_constant: $ => choice(
$.pattern_constant,
$.pattern_constant_resolution
),
pattern_constant: $ => field('name', $.constant),
pattern_constant_resolution: $ => seq(
optional(field('scope', $._pattern_constant)),
'::',
field('name', $.constant)
),
if: $ => seq(
@ -626,11 +676,9 @@ module.exports = grammar({
'::',
seq(field('scope', $._primary), token.immediate('::'))
),
field('name', $._cname)
field('name', choice($.identifier, $.constant))
)),
_cname: $ => choice($.identifier, $.constant),
_call: $ => prec.left(PREC.CALL, seq(
field('receiver', $._primary),
choice('.', '&.'),
@ -866,7 +914,6 @@ module.exports = grammar({
$.float,
$.complex,
$.rational
),
right_assignment_list: $ => prec(-1, commaSep1(choice($._arg, $.splat_argument))),