difftastic/common/define-grammar.js

1111 lines
32 KiB
JavaScript

const JavaScript = require('tree-sitter-javascript/grammar');
module.exports = function defineGrammar(dialect) {
return grammar(JavaScript, {
name: dialect,
externals: ($, previous) => previous.concat([
$._function_signature_automatic_semicolon,
]),
supertypes: ($, previous) => previous.concat([
$._primary_type,
]),
precedences: ($, previous) => previous.concat([
[
'call',
'instantiation',
'unary',
'binary',
$.await_expression,
$.arrow_function,
],
[
'extends',
'instantiation',
],
[
$.intersection_type,
$.union_type,
$.conditional_type,
$.function_type,
'binary',
$.type_predicate,
$.readonly_type,
],
[$.mapped_type_clause, $.primary_expression],
[$.accessibility_modifier, $.primary_expression],
['unary_void', $.expression],
[$.extends_clause, $.primary_expression],
['unary', 'assign'],
['declaration', $.expression],
[$.predefined_type, $.unary_expression],
[$._type, $.flow_maybe_type],
[$.tuple_type, $.array_type, $.pattern, $._type],
[$.readonly_type, $.pattern],
[$.readonly_type, $.primary_expression],
[$.type_query, $.subscript_expression, $.expression],
[$.type_query, $._type_query_subscript_expression],
[$.nested_type_identifier, $.generic_type, $._primary_type, $.lookup_type, $.index_type_query, $._type],
[$.as_expression, $.satisfies_expression, $._primary_type],
[$._type_query_member_expression, $.member_expression],
[$.member_expression, $._type_query_member_expression_in_type_annotation],
[$._type_query_member_expression, $.primary_expression],
[$._type_query_subscript_expression, $.subscript_expression],
[$._type_query_subscript_expression, $.primary_expression],
[$._type_query_call_expression, $.primary_expression],
[$._type_query_instantiation_expression, $.primary_expression],
[$.type_query, $.primary_expression],
[$.override_modifier, $.primary_expression],
[$.decorator_call_expression, $.decorator],
[$.literal_type, $.pattern],
[$.predefined_type, $.pattern],
[$.call_expression, $._type_query_call_expression],
[$.call_expression, $._type_query_call_expression_in_type_annotation],
[$.new_expression, $.primary_expression],
[$.meta_property, $.primary_expression],
[$.construct_signature, $._property_name],
]),
conflicts: ($, previous) => previous.concat([
[$.call_expression, $.instantiation_expression, $.binary_expression],
[$.call_expression, $.instantiation_expression, $.binary_expression, $.unary_expression],
[$.call_expression, $.instantiation_expression, $.binary_expression, $.update_expression],
[$.call_expression, $.instantiation_expression, $.binary_expression, $.await_expression],
// This appears to be necessary to parse a parenthesized class expression
[$.class],
[$.nested_identifier, $.nested_type_identifier, $.primary_expression],
[$.nested_identifier, $.nested_type_identifier],
[$._call_signature, $.function_type],
[$._call_signature, $.constructor_type],
[$._primary_type, $.type_parameter],
[$.jsx_opening_element, $.type_parameter],
[$.jsx_namespace_name, $._primary_type],
[$.primary_expression, $._parameter_name],
[$.primary_expression, $._parameter_name, $._primary_type],
[$.primary_expression, $.literal_type],
[$.primary_expression, $.literal_type, $.rest_pattern],
[$.primary_expression, $.predefined_type, $.rest_pattern],
[$.primary_expression, $._primary_type],
[$.primary_expression, $.generic_type],
[$.primary_expression, $.predefined_type],
[$.primary_expression, $.pattern, $._primary_type],
[$._parameter_name, $._primary_type],
[$.pattern, $._primary_type],
[$.optional_tuple_parameter, $._primary_type],
[$.rest_pattern, $._primary_type, $.primary_expression],
[$.object, $.object_type],
[$.object, $.object_pattern, $.object_type],
[$.object, $.object_pattern, $._property_name],
[$.object_pattern, $.object_type],
[$.object_pattern, $.object_type],
[$.array, $.tuple_type],
[$.array, $.array_pattern, $.tuple_type],
[$.array_pattern, $.tuple_type],
[$.template_literal_type, $.template_string],
]),
inline: ($, previous) => previous
.filter((rule) => ![
'_formal_parameter',
'_call_signature',
].includes(rule.name))
.concat([
$._type_identifier,
$._jsx_start_opening_element,
]),
rules: {
public_field_definition: ($) => seq(
repeat(field('decorator', $.decorator)),
optional(choice(
seq('declare', optional($.accessibility_modifier)),
seq($.accessibility_modifier, optional('declare')),
)),
choice(
seq(optional('static'), optional($.override_modifier), optional('readonly')),
seq(optional('abstract'), optional('readonly')),
seq(optional('readonly'), optional('abstract')),
),
field('name', $._property_name),
optional(choice('?', '!')),
field('type', optional($.type_annotation)),
optional($._initializer),
),
// override original catch_clause, add optional type annotation
catch_clause: ($) => seq(
'catch',
optional(
seq(
'(',
field(
'parameter',
choice($.identifier, $._destructuring_pattern),
),
optional(
// only types that resolve to 'any' or 'unknown' are supported
// by the language but it's simpler to accept any type here.
field('type', $.type_annotation),
),
')',
),
),
field('body', $.statement_block),
),
call_expression: ($) => choice(
prec('call', seq(
field('function', choice($.expression, $.import)),
field('type_arguments', optional($.type_arguments)),
field('arguments', choice($.arguments, $.template_string)),
)),
prec('member', seq(
field('function', $.primary_expression),
'?.',
field('type_arguments', optional($.type_arguments)),
field('arguments', $.arguments),
)),
),
new_expression: ($) => prec.right('new', seq(
'new',
field('constructor', $.primary_expression),
field('type_arguments', optional($.type_arguments)),
field('arguments', optional($.arguments)),
)),
assignment_expression: ($) => prec.right('assign', seq(
optional('using'),
field('left', choice($.parenthesized_expression, $._lhs_expression)),
'=',
field('right', $.expression),
)),
_augmented_assignment_lhs: ($, previous) => choice(previous, $.non_null_expression),
_lhs_expression: ($, previous) => choice(previous, $.non_null_expression),
primary_expression: ($, previous) => choice(
previous,
$.non_null_expression,
),
// If the dialect is regular typescript, we exclude JSX expressions and
// include type assertions. If the dialect is TSX, we do the opposite.
expression: ($, previous) => {
const choices = [
$.as_expression,
$.satisfies_expression,
$.instantiation_expression,
$.internal_module,
];
if (dialect === 'typescript') {
choices.push($.type_assertion);
choices.push(...previous.members.filter((member) =>
member.name !== '_jsx_element',
));
} else if (dialect === 'tsx') {
choices.push(...previous.members);
} else {
throw new Error(`Unknown dialect ${dialect}`);
}
return choice(...choices);
},
_jsx_start_opening_element: ($) => seq(
'<',
optional(
seq(
choice(
field('name', choice(
$._jsx_identifier,
$.jsx_namespace_name,
)),
seq(
field('name', choice(
$.identifier,
alias($.nested_identifier, $.member_expression),
)),
field('type_arguments', optional($.type_arguments)),
),
),
repeat(field('attribute', $._jsx_attribute)),
),
),
),
// This rule is only referenced by expression when the dialect is 'tsx'
jsx_opening_element: ($) => prec.dynamic(-1, seq(
$._jsx_start_opening_element,
'>',
)),
// tsx only. See jsx_opening_element.
jsx_self_closing_element: ($) => prec.dynamic(-1, seq(
$._jsx_start_opening_element,
'/>',
)),
export_specifier: (_, previous) => seq(
optional(choice('type', 'typeof')),
previous,
),
_import_identifier: ($) => choice($.identifier, alias('type', $.identifier)),
import_specifier: ($) => seq(
optional(choice('type', 'typeof')),
choice(
field('name', $._import_identifier),
seq(
field('name', choice($._module_export_name, alias('type', $.identifier))),
'as',
field('alias', $._import_identifier),
),
)),
import_clause: ($) => choice(
$.namespace_import,
$.named_imports,
seq(
$._import_identifier,
optional(seq(
',',
choice(
$.namespace_import,
$.named_imports,
),
)),
),
),
import_statement: ($) => seq(
'import',
optional(choice('type', 'typeof')),
choice(
seq($.import_clause, $._from_clause),
$.import_require_clause,
field('source', $.string),
),
optional($.import_attribute),
$._semicolon,
),
export_statement: ($, previous) => choice(
previous,
seq(
'export',
'type',
$.export_clause,
optional($._from_clause),
$._semicolon,
),
seq('export', '=', $.expression, $._semicolon),
seq('export', 'as', 'namespace', $.identifier, $._semicolon),
),
non_null_expression: ($) => prec.left('unary', seq(
$.expression, '!',
)),
variable_declarator: ($) => choice(
seq(
field('name', choice($.identifier, $._destructuring_pattern)),
field('type', optional($.type_annotation)),
optional($._initializer),
),
prec('declaration', seq(
field('name', $.identifier),
'!',
field('type', $.type_annotation),
)),
),
method_signature: ($) => seq(
optional($.accessibility_modifier),
optional('static'),
optional($.override_modifier),
optional('readonly'),
optional('async'),
optional(choice('get', 'set', '*')),
field('name', $._property_name),
optional('?'),
$._call_signature,
),
abstract_method_signature: ($) => seq(
optional($.accessibility_modifier),
'abstract',
optional($.override_modifier),
optional(choice('get', 'set', '*')),
field('name', $._property_name),
optional('?'),
$._call_signature,
),
parenthesized_expression: ($) => seq(
'(',
choice(
seq($.expression, field('type', optional($.type_annotation))),
$.sequence_expression,
),
')',
),
_formal_parameter: ($) => choice(
$.required_parameter,
$.optional_parameter,
),
function_signature: ($) => seq(
optional('async'),
'function',
field('name', $.identifier),
$._call_signature,
choice($._semicolon, $._function_signature_automatic_semicolon),
),
class_body: ($) => seq(
'{',
repeat(choice(
seq(
repeat(field('decorator', $.decorator)),
$.method_definition,
optional($._semicolon),
),
// As it happens for functions, the semicolon insertion should not
// happen if a block follows the closing paren, because then it's a
// *definition*, not a declaration. Example:
// public foo()
// { <--- this brace made the method signature become a definition
// }
// The same rule applies for functions and that's why we use
// "_function_signature_automatic_semicolon".
seq($.method_signature, choice($._function_signature_automatic_semicolon, ',')),
$.class_static_block,
seq(
choice(
$.abstract_method_signature,
$.index_signature,
$.method_signature,
$.public_field_definition,
),
choice($._semicolon, ','),
),
';',
)),
'}',
),
method_definition: ($) => prec.left(seq(
optional($.accessibility_modifier),
optional('static'),
optional($.override_modifier),
optional('readonly'),
optional('async'),
optional(choice('get', 'set', '*')),
field('name', $._property_name),
optional('?'),
$._call_signature,
field('body', $.statement_block),
)),
declaration: ($, previous) => choice(
previous,
$.function_signature,
$.abstract_class_declaration,
$.module,
prec('declaration', $.internal_module),
$.type_alias_declaration,
$.enum_declaration,
$.interface_declaration,
$.import_alias,
$.ambient_declaration,
),
type_assertion: ($) => prec.left('unary', seq(
$.type_arguments,
$.expression,
)),
as_expression: ($) => prec.left('binary', seq(
$.expression,
'as',
choice('const', $._type),
)),
satisfies_expression: ($) => prec.left('binary', seq(
$.expression,
'satisfies',
$._type,
)),
instantiation_expression: ($) => prec('instantiation', seq(
$.expression,
field('type_arguments', $.type_arguments),
)),
class_heritage: ($) => choice(
seq($.extends_clause, optional($.implements_clause)),
$.implements_clause,
),
import_require_clause: ($) => seq(
$.identifier,
'=',
'require',
'(',
field('source', $.string),
')',
),
extends_clause: ($) => seq(
'extends',
commaSep1($._extends_clause_single),
),
_extends_clause_single: ($) => prec('extends', seq(
field('value', $.expression),
field('type_arguments', optional($.type_arguments)),
)),
implements_clause: ($) => seq(
'implements',
commaSep1($._type),
),
ambient_declaration: ($) => seq(
'declare',
choice(
$.declaration,
seq('global', $.statement_block),
seq('module', '.', alias($.identifier, $.property_identifier), ':', $._type, $._semicolon),
),
),
class: ($) => prec('literal', seq(
repeat(field('decorator', $.decorator)),
'class',
field('name', optional($._type_identifier)),
field('type_parameters', optional($.type_parameters)),
optional($.class_heritage),
field('body', $.class_body),
)),
abstract_class_declaration: ($) => prec('declaration', seq(
repeat(field('decorator', $.decorator)),
'abstract',
'class',
field('name', $._type_identifier),
field('type_parameters', optional($.type_parameters)),
optional($.class_heritage),
field('body', $.class_body),
)),
class_declaration: ($) => prec.left('declaration', seq(
repeat(field('decorator', $.decorator)),
'class',
field('name', $._type_identifier),
field('type_parameters', optional($.type_parameters)),
optional($.class_heritage),
field('body', $.class_body),
optional($._automatic_semicolon),
)),
module: ($) => seq(
'module',
$._module,
),
internal_module: ($) => seq(
'namespace',
$._module,
),
_module: ($) => prec.right(seq(
field('name', choice($.string, $.identifier, $.nested_identifier)),
// On .d.ts files "declare module foo" desugars to "declare module foo {}",
// hence why it is optional here
field('body', optional($.statement_block)),
)),
import_alias: ($) => seq(
'import',
$.identifier,
'=',
choice($.identifier, $.nested_identifier),
$._semicolon,
),
nested_type_identifier: ($) => prec('member', seq(
field('module', choice($.identifier, $.nested_identifier)),
'.',
field('name', $._type_identifier),
)),
interface_declaration: ($) => seq(
'interface',
field('name', $._type_identifier),
field('type_parameters', optional($.type_parameters)),
optional($.extends_type_clause),
field('body', alias($.object_type, $.interface_body)),
),
extends_type_clause: ($) => seq(
'extends',
commaSep1(field('type', choice(
$._type_identifier,
$.nested_type_identifier,
$.generic_type,
))),
),
enum_declaration: ($) => seq(
optional('const'),
'enum',
field('name', $.identifier),
field('body', $.enum_body),
),
enum_body: ($) => seq(
'{',
optional(seq(
sepBy1(',', choice(
field('name', $._property_name),
$.enum_assignment,
)),
optional(','),
)),
'}',
),
enum_assignment: ($) => seq(
field('name', $._property_name),
$._initializer,
),
type_alias_declaration: ($) => seq(
'type',
field('name', $._type_identifier),
field('type_parameters', optional($.type_parameters)),
'=',
field('value', $._type),
$._semicolon,
),
accessibility_modifier: (_) => choice(
'public',
'private',
'protected',
),
override_modifier: (_) => 'override',
required_parameter: ($) => seq(
$._parameter_name,
field('type', optional($.type_annotation)),
optional($._initializer),
),
optional_parameter: ($) => seq(
$._parameter_name,
'?',
field('type', optional($.type_annotation)),
optional($._initializer),
),
_parameter_name: ($) => seq(
repeat(field('decorator', $.decorator)),
optional($.accessibility_modifier),
optional($.override_modifier),
optional('readonly'),
field('pattern', choice($.pattern, $.this)),
),
omitting_type_annotation: ($) => seq('-?:', $._type),
adding_type_annotation: ($) => seq('+?:', $._type),
opting_type_annotation: ($) => seq('?:', $._type),
type_annotation: ($) => seq(
':',
choice(
$._type,
alias($._type_query_member_expression_in_type_annotation, $.member_expression),
alias($._type_query_call_expression_in_type_annotation, $.call_expression),
),
),
// Oh boy
// The issue is these special type queries need a lower relative precedence than the normal ones,
// since these are used in type annotations whereas the other ones are used where `typeof` is
// required beforehand. This allows for parsing of annotations such as
// foo: import('x').y.z;
// but was a nightmare to get working.
_type_query_member_expression_in_type_annotation: ($) => seq(
field('object', choice(
$.import,
alias($._type_query_member_expression_in_type_annotation, $.member_expression),
alias($._type_query_call_expression_in_type_annotation, $.call_expression),
)),
'.',
field('property', choice(
$.private_property_identifier,
alias($.identifier, $.property_identifier),
)),
),
_type_query_call_expression_in_type_annotation: ($) => seq(
field('function', choice(
$.import,
alias($._type_query_member_expression_in_type_annotation, $.member_expression),
)),
field('arguments', $.arguments),
),
asserts: ($) => seq(
'asserts',
choice($.type_predicate, $.identifier, $.this),
),
asserts_annotation: ($) => seq(
seq(':', $.asserts),
),
_type: ($) => choice(
$._primary_type,
$.function_type,
$.readonly_type,
$.constructor_type,
$.infer_type,
),
tuple_parameter: ($) => seq(
field('name', choice($.identifier, $.rest_pattern)),
field('type', $.type_annotation),
),
optional_tuple_parameter: ($) => seq(
field('name', $.identifier),
'?',
field('type', $.type_annotation),
),
optional_type: ($) => seq($._type, '?'),
rest_type: ($) => seq('...', $._type),
_tuple_type_member: ($) => choice(
alias($.tuple_parameter, $.required_parameter),
alias($.optional_tuple_parameter, $.optional_parameter),
$.optional_type,
$.rest_type,
$._type,
),
constructor_type: ($) => prec.left(seq(
optional('abstract'),
'new',
field('type_parameters', optional($.type_parameters)),
field('parameters', $.formal_parameters),
'=>',
field('type', $._type),
)),
_primary_type: ($) => choice(
$.parenthesized_type,
$.predefined_type,
$._type_identifier,
$.nested_type_identifier,
$.generic_type,
$.object_type,
$.array_type,
$.tuple_type,
$.flow_maybe_type,
$.type_query,
$.index_type_query,
alias($.this, $.this_type),
$.existential_type,
$.literal_type,
$.lookup_type,
$.conditional_type,
$.template_literal_type,
$.intersection_type,
$.union_type,
'const',
),
template_type: ($) => seq('${', choice($._primary_type, $.infer_type), '}'),
template_literal_type: ($) => seq(
'`',
repeat(choice(
$._template_chars,
$.template_type,
)),
'`',
),
infer_type: ($) => prec.right(seq(
'infer',
$._type_identifier,
optional(seq(
'extends',
$._type,
)),
)),
conditional_type: ($) => prec.right(seq(
field('left', $._type),
'extends',
field('right', $._type),
'?',
field('consequence', $._type),
':',
field('alternative', $._type),
)),
generic_type: ($) => prec('call', seq(
field('name', choice(
$._type_identifier,
$.nested_type_identifier,
)),
field('type_arguments', $.type_arguments),
)),
type_predicate: ($) => seq(
field('name', choice(
$.identifier,
$.this,
// Sometimes tree-sitter contextual lexing is not good enough to know
// that 'object' in ':object is foo' is really an identifier and not
// a predefined_type, so we must explicitely list all possibilities.
// TODO: should we use '_reserved_identifier'? Should all the element in
// 'predefined_type' be added to '_reserved_identifier'?
alias($.predefined_type, $.identifier),
)),
'is',
field('type', $._type),
),
type_predicate_annotation: ($) => seq(
seq(':', $.type_predicate),
),
// Type query expressions are more restrictive than regular expressions
_type_query_member_expression: ($) => seq(
field('object', choice(
$.identifier,
alias($._type_query_subscript_expression, $.subscript_expression),
alias($._type_query_member_expression, $.member_expression),
alias($._type_query_call_expression, $.call_expression),
)),
choice('.', '?.'),
field('property', choice(
$.private_property_identifier,
alias($.identifier, $.property_identifier),
)),
),
_type_query_subscript_expression: ($) => seq(
field('object', choice(
$.identifier,
alias($._type_query_subscript_expression, $.subscript_expression),
alias($._type_query_member_expression, $.member_expression),
alias($._type_query_call_expression, $.call_expression),
)),
optional('?.'),
'[', field('index', choice($.predefined_type, $.string, $.number)), ']',
),
_type_query_call_expression: ($) => seq(
field('function', choice(
$.import,
$.identifier,
alias($._type_query_member_expression, $.member_expression),
alias($._type_query_subscript_expression, $.subscript_expression),
)),
field('arguments', $.arguments),
),
_type_query_instantiation_expression: ($) => seq(
field('function', choice(
$.import,
$.identifier,
alias($._type_query_member_expression, $.member_expression),
alias($._type_query_subscript_expression, $.subscript_expression),
)),
field('type_arguments', $.type_arguments),
),
type_query: ($) => prec.right(seq(
'typeof',
choice(
alias($._type_query_subscript_expression, $.subscript_expression),
alias($._type_query_member_expression, $.member_expression),
alias($._type_query_call_expression, $.call_expression),
alias($._type_query_instantiation_expression, $.instantiation_expression),
$.identifier,
),
)),
index_type_query: ($) => seq(
'keyof',
$._primary_type,
),
lookup_type: ($) => seq(
$._primary_type,
'[',
$._type,
']',
),
mapped_type_clause: ($) => seq(
field('name', $._type_identifier),
'in',
field('type', $._type),
optional(seq('as', field('alias', $._type))),
),
literal_type: ($) => choice(
alias($._number, $.unary_expression),
$.number,
$.string,
$.true,
$.false,
$.null,
$.undefined,
),
_number: ($) => prec.left(1, seq(
field('operator', choice('-', '+')),
field('argument', $.number),
)),
existential_type: (_) => '*',
flow_maybe_type: ($) => prec.right(seq('?', $._primary_type)),
parenthesized_type: ($) => seq('(', $._type, ')'),
predefined_type: (_) => choice(
'any',
'number',
'boolean',
'string',
'symbol',
alias(seq('unique', 'symbol'), 'unique symbol'),
'void',
'unknown',
'string',
'never',
'object',
),
type_arguments: ($) => seq(
'<',
commaSep1(choice(
$._type,
alias($._type_query_member_expression_in_type_annotation, $.member_expression),
alias($._type_query_call_expression_in_type_annotation, $.call_expression),
)),
optional(','),
'>',
),
object_type: ($) => seq(
choice('{', '{|'),
optional(seq(
optional(choice(',', ';')),
sepBy1(
choice(',', $._semicolon),
choice(
$.export_statement,
$.property_signature,
$.call_signature,
$.construct_signature,
$.index_signature,
$.method_signature,
),
),
optional(choice(',', $._semicolon)),
)),
choice('}', '|}'),
),
call_signature: ($) => $._call_signature,
property_signature: ($) => seq(
optional($.accessibility_modifier),
optional('static'),
optional($.override_modifier),
optional('readonly'),
field('name', $._property_name),
optional('?'),
field('type', optional($.type_annotation)),
),
_call_signature: ($) => seq(
field('type_parameters', optional($.type_parameters)),
field('parameters', $.formal_parameters),
field('return_type', optional(
choice($.type_annotation, $.asserts_annotation, $.type_predicate_annotation),
)),
),
type_parameters: ($) => seq(
'<', commaSep1($.type_parameter), optional(','), '>',
),
type_parameter: ($) => seq(
optional('const'),
field('name', $._type_identifier),
field('constraint', optional($.constraint)),
field('value', optional($.default_type)),
),
default_type: ($) => seq(
'=',
$._type,
),
constraint: ($) => seq(
choice('extends', ':'),
$._type,
),
construct_signature: ($) => seq(
optional('abstract'),
'new',
field('type_parameters', optional($.type_parameters)),
field('parameters', $.formal_parameters),
field('type', optional($.type_annotation)),
),
index_signature: ($) => seq(
optional(
seq(
field('sign', optional(choice('-', '+'))),
'readonly',
),
),
'[',
choice(
seq(
field('name', choice(
$.identifier,
alias($._reserved_identifier, $.identifier),
)),
':',
field('index_type', $._type),
),
$.mapped_type_clause,
),
']',
field('type', choice(
$.type_annotation,
$.omitting_type_annotation,
$.adding_type_annotation,
$.opting_type_annotation,
)),
),
array_type: ($) => seq($._primary_type, '[', ']'),
tuple_type: ($) => seq(
'[', commaSep($._tuple_type_member), optional(','), ']',
),
readonly_type: ($) => seq('readonly', $._type),
union_type: ($) => prec.left(seq(optional($._type), '|', $._type)),
intersection_type: ($) => prec.left(seq(optional($._type), '&', $._type)),
function_type: ($) => prec.left(seq(
field('type_parameters', optional($.type_parameters)),
field('parameters', $.formal_parameters),
'=>',
field('return_type', choice($._type, $.asserts, $.type_predicate)),
)),
_type_identifier: ($) => alias($.identifier, $.type_identifier),
_reserved_identifier: (_, previous) => choice(
'declare',
'namespace',
'type',
'public',
'private',
'protected',
'override',
'readonly',
'module',
'any',
'number',
'boolean',
'string',
'symbol',
'export',
'object',
'new',
'readonly',
previous,
),
},
});
};
/**
* Creates a rule to match one or more of the rules separated by a comma
*
* @param {RuleOrLiteral} rule
*
* @return {SeqRule}
*
*/
function commaSep1(rule) {
return sepBy1(',', rule);
}
/**
* Creates a rule to optionally match one or more of the rules separated by a comma
*
* @param {RuleOrLiteral} rule
*
* @return {SeqRule}
*
*/
function commaSep(rule) {
return sepBy(',', rule);
}
/**
* Creates a rule to optionally match one or more of the rules separated by a separator
*
* @param {RuleOrLiteral} sep
*
* @param {RuleOrLiteral} rule
*
* @return {ChoiceRule}
*/
function sepBy(sep, rule) {
return optional(sepBy1(sep, rule));
}
/**
* Creates a rule to match one or more of the rules separated by a separator
*
* @param {RuleOrLiteral} sep
*
* @param {RuleOrLiteral} rule
*
* @return {SeqRule}
*/
function sepBy1(sep, rule) {
return seq(rule, repeat(seq(sep, rule)));
}