difftastic/vendor/tree-sitter-julia/grammar.js

903 lines
21 KiB
JavaScript

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

const PREC = [
'assign',
'pair',
'conditional',
'lazy_or',
'lazy_and',
'arrow',
'comparison',
'pipe_left',
'pipe_right',
'colon_quote',
'colon_range',
'plus',
'times',
'rational',
'bitshift',
'power',
'call',
'decl',
'dot',
'postfix',
'prefix',
].reduce((result, name, index) => {
result[name] = index + 10;
return result;
}, {});
const ASSIGN_OPERATORS = `
= += -= *= /= //= \\= ^= ÷= %= <<= >>= >>>= |= &= ⊻= ≔ ⩴ ≕
`;
const ARROW_OPERATORS = `
← → ↔ ↚ ↛ ↞ ↠ ↢ ↣ ↦ ↤ ↮ ⇎ ⇍ ⇏ ⇐ ⇒ ⇔ ⇴ ⇶
⇷ ⇸ ⇹ ⇺ ⇻ ⇼ ⇽ ⇾ ⇿ ⟵ ⟶ ⟷ ⟹ ⟺ ⟻ ⟼ ⟽ ⟾
⟿ ⤀ ⤁ ⤂ ⤃ ⤄ ⤅ ⤆ ⤇ ⤌ ⤍ ⤎ ⤏ ⤐ ⤑ ⤔ ⤕ ⤖ ⤗ ⤘
⤝ ⤞ ⤟ ⤠ ⥄ ⥅ ⥆ ⥇ ⥈ ⥊ ⥋ ⥎ ⥐ ⥒ ⥓ ⥖ ⥗ ⥚ ⥛ ⥞ ⥟
⥢ ⥤ ⥦ ⥧ ⥨ ⥩ ⥪ ⥫ ⥬ ⥭ ⥰ ⧴ ⬱ ⬰ ⬲ ⬳ ⬴ ⬵ ⬶ ⬷
⬸ ⬹ ⬺ ⬻ ⬼ ⬽ ⬾ ⬿ ⭀ ⭁ ⭂ ⭃ ⭄ ⭇ ⭈ ⭉ ⭊ ⭋ ⭌ ← →
⇜ ⇝ ↜ ↝ ↩ ↪ ↫ ↬ ↼ ↽ ⇀ ⇁ ⇄ ⇆ ⇇ ⇉ ⇋ ⇌ ⇚ ⇛ ⇠ ⇢
`;
const COMPARISON_OPERATORS = `
> < >= ≥ <= ≤ == === ≡ != ≠ !== ≢ ∈ ∉ ∋ ∌ ⊆ ⊈ ⊂ ⊄ ⊊ ∝ ∊ ∍ ∥ ∦ ∷ ∺ ∻ ∽ ∾ ≁
≃ ≂ ≄ ≅ ≆ ≇ ≈ ≉ ≊ ≋ ≌ ≍ ≎ ≐ ≑ ≒ ≓ ≖ ≗ ≘ ≙ ≚ ≛ ≜ ≝ ≞ ≟ ≣ ≦ ≧ ≨ ≩ ≪ ≫ ≬ ≭
≮ ≯ ≰ ≱ ≲ ≳ ≴ ≵ ≶ ≷ ≸ ≹ ≺ ≻ ≼ ≽ ≾ ≿ ⊀ ⊁ ⊃ ⊅ ⊇ ⊉ ⊋ ⊏ ⊐ ⊑ ⊒ ⊜ ⊩ ⊬ ⊮ ⊰ ⊱
⊲ ⊳ ⊴ ⊵ ⊶ ⊷ ⋍ ⋐ ⋑ ⋕ ⋖ ⋗ ⋘ ⋙ ⋚ ⋛ ⋜ ⋝ ⋞ ⋟ ⋠ ⋡ ⋢ ⋣ ⋤ ⋥ ⋦ ⋧ ⋨ ⋩ ⋪ ⋫
⋬ ⋭ ⋲ ⋳ ⋴ ⋵ ⋶ ⋷ ⋸ ⋹ ⋺ ⋻ ⋼ ⋽ ⋾ ⟈ ⟉ ⟒ ⦷ ⧀ ⧁ ⧡ ⧣ ⧤ ⧥ ⩦ ⩧ ⩪ ⩫ ⩬ ⩭ ⩮ ⩯
⩰ ⩱ ⩲ ⩳ ⩵ ⩶ ⩷ ⩸ ⩹ ⩺ ⩻ ⩼ ⩽ ⩾ ⩿ ⪀ ⪁ ⪂ ⪃ ⪄ ⪅ ⪆ ⪇ ⪈ ⪉ ⪊ ⪋ ⪌ ⪍ ⪎ ⪏ ⪐ ⪑ ⪒ ⪓ ⪔
⪕ ⪖ ⪗ ⪘ ⪙ ⪚ ⪛ ⪜ ⪝ ⪞ ⪟ ⪠ ⪡ ⪢ ⪣ ⪤ ⪥ ⪦ ⪧ ⪨ ⪩ ⪪ ⪫ ⪬ ⪭ ⪮ ⪯ ⪰ ⪱ ⪲ ⪳ ⪴ ⪵ ⪶ ⪷ ⪸
⪹ ⪺ ⪻ ⪼ ⪽ ⪾ ⪿ ⫀ ⫁ ⫂ ⫃ ⫄ ⫅ ⫆ ⫇ ⫈ ⫉ ⫊ ⫋ ⫌ ⫍ ⫎ ⫏ ⫐ ⫑ ⫒ ⫓ ⫔ ⫕ ⫖ ⫗ ⫘ ⫙ ⫷ ⫸
⫹ ⫺ ⊢ ⊣ ⟂
`;
const DOTTY_OPERATORS = '… ⁝ ⋮ ⋱ ⋰ ⋯';
const PLUS_OPERATORS = `
+ - | ⊕ ⊖ ⊞ ⊟ ++ ⊔ ± ∓ ∔ ∸ ≂ ≏ ⊎ ⊻ ⊽ ⋎ ⋓ ⧺ ⧻ ⨈
⨢ ⨣ ⨤ ⨥ ⨦ ⨧ ⨨ ⨩ ⨪ ⨫ ⨬ ⨭ ⨮ ⨹ ⨺ ⩁ ⩂ ⩅ ⩊ ⩌ ⩏ ⩐ ⩒ ⩔ ⩖ ⩗ ⩛ ⩝ ⩡ ⩢ ⩣
`;
const TIMES_OPERATORS = `
* / ÷ % & ⋅ ∘ × \\ ∩ ∧ ⊗ ⊘ ⊙ ⊚ ⊛ ⊠ ⊡ ⊓
∤ ⅋ ≀ ⊼ ⋄ ⋆ ⋇ ⋉ ⋊ ⋋ ⋌ ⋏ ⋒ ⟑ ⦸ ⦼ ⦾ ⦿ ⧶ ⧷ ⨇ ⨰
⨱ ⨲ ⨳ ⨴ ⨵ ⨶ ⨷ ⨸ ⨻ ⨼ ⨽ ⩀ ⩃ ⩄ ⩋ ⩍ ⩎ ⩑ ⩓ ⩕ ⩘
⩚ ⩜ ⩞ ⩟ ⩠ ⫛ ⊍ ▷ ⨝ ⟕ ⟖ ⟗
`;
const BITSHIFT_OPERATORS = '<< >> >>>';
const POWER_OPERATORS = `
^ ↑ ↓ ⇵ ⟰ ⟱ ⤈ ⤉ ⤊ ⤋ ⤒ ⤓ ⥉ ⥌ ⥍ ⥏ ⥑ ⥔ ⥕ ⥘ ⥙ ⥜ ⥝ ⥠ ⥡ ⥣ ⥥ ⥮ ⥯ ↑ ↓
`;
module.exports =
grammar({
name: 'julia',
word: $ => $.identifier,
inline: $ => [
$._terminator,
$._definition,
$._statement,
],
supertypes: $ => [
$._statement,
$._definition,
$._expression,
$._primary_expression,
],
externals: $ => [
$.block_comment,
$._immediate_paren,
$._string_start,
$._command_start,
$._immediate_string_start,
$._immediate_command_start,
$._string_end,
$._command_end,
$._string_content,
$._string_content_no_interp,
],
conflicts: $ => [
// Arrow functions vs tuples
[$._primary_expression, $.parameter_list],
[$._primary_expression, $.spread_parameter],
[$._primary_expression, $.typed_parameter],
[$._primary_expression, $.named_field],
[$._primary_expression, $.named_field, $.optional_parameter],
[$.named_field, $.optional_parameter],
],
supertypes: $ => [
$._expression,
$._statement,
$._definition,
],
extras: $ => [
/\s/,
$.line_comment,
$.block_comment,
],
rules: {
source_file: $ => optional($._expression_list),
_expression_list: $ => seq(
sep1($._terminator, choice(
$._expression,
$.assignment_expression,
$.bare_tuple_expression
)),
optional($._terminator)
),
// Definitions
_definition: $ => choice(
$.abstract_definition,
$.primitive_definition,
$.struct_definition,
$.module_definition,
$.function_definition,
$.macro_definition
),
function_definition: $ => seq(
'function',
field('name', $.identifier),
field('type_parameters', optional($.type_parameter_list)),
field('parameters', $.parameter_list),
optional($._expression_list),
'end'
),
abstract_definition: $ => seq(
'abstract',
'type',
field('name', $.identifier),
field('type_parameters', optional($.type_parameter_list)),
optional($.subtype_clause),
'end'
),
primitive_definition: $ => seq(
'primitive',
'type',
field('name', $.identifier),
field('type_parameters', optional($.type_parameter_list)),
optional($.subtype_clause),
alias(numeral('0-9'), $.integer_literal),
'end'
),
struct_definition: $ => seq(
optional('mutable'),
'struct',
field('name', $.identifier),
field('type_parameters', optional($.type_parameter_list)),
optional($.subtype_clause),
optional($._expression_list),
'end'
),
module_definition: $ => seq(
'module',
field('name', $.identifier),
optional($._expression_list),
'end'
),
macro_definition: $ => seq(
'macro',
field('name', choice($.identifier, $.operator)),
field('parameters', $.parameter_list),
optional($._expression_list),
'end'
),
parameter_list: $ => seq(
'(',
sep(',', choice(
$.identifier,
$.spread_parameter,
$.optional_parameter,
$.typed_parameter
)),
optional($.keyword_parameters),
')'
),
keyword_parameters: $ => seq(
';',
sep1(',', choice(
$.identifier,
$.spread_parameter,
$.optional_parameter,
$.typed_parameter
))
),
optional_parameter: $ => seq(
choice($.identifier, $.typed_parameter),
'=',
$._expression
),
spread_parameter: $ => seq($.identifier, '...'),
typed_parameter: $ => seq(
$.identifier,
'::',
choice($.identifier, $.parameterized_identifier)
),
type_parameter_list: $ => seq(
'{',
sep1(',', choice($.identifier, $.constrained_parameter)),
'}'
),
constrained_parameter: $ => seq(
field('name', $.identifier),
'<:',
field('value', $._expression)
),
subtype_clause: $ => seq(
'<:',
$._expression
),
// Statements
_statement: $ => choice(
$.if_statement,
$.try_statement,
$.for_statement,
$.while_statement,
$.let_statement,
$.const_statement,
$.quote_statement,
$.break_statement,
$.continue_statement,
$.return_statement,
$.import_statement,
$.export_statement
),
if_statement: $ => seq(
'if',
field('condition', $._expression),
optional($._terminator),
optional($._expression_list),
field('alternative', repeat($.elseif_clause)),
field('alternative', optional($.else_clause)),
'end'
),
elseif_clause: $ => seq(
'elseif',
field('condition', $._expression),
optional($._terminator),
optional($._expression_list)
),
else_clause: $ => seq(
'else',
optional($._expression_list)
),
try_statement: $ => seq(
'try',
optional($._expression_list),
optional($.catch_clause),
optional($.finally_clause),
'end'
),
catch_clause: $ => prec(1, seq(
'catch',
optional($.identifier),
optional($._terminator),
optional($._expression_list),
)),
finally_clause: $ => seq(
'finally',
optional($._terminator),
optional($._expression_list),
),
for_statement: $ => seq(
'for',
sep1(',', $.for_binding),
optional($._terminator),
optional($._expression_list),
'end'
),
while_statement: $ => seq(
'while',
field('condition', $._expression),
optional($._terminator),
optional($._expression_list),
'end'
),
break_statement: $ => 'break',
continue_statement: $ => 'continue',
return_statement: $ => prec.right(-2, seq(
'return',
optional(choice(
$._expression,
$.bare_tuple_expression
))
)),
let_statement: $ => seq(
'let',
sep1(',', $.variable_declaration),
optional($._terminator),
optional($._expression_list),
'end'
),
const_statement: $ => seq(
'const',
prec.right(sep1(',', $.variable_declaration))
),
variable_declaration: $ => prec.right(seq(
$.identifier,
optional(seq('=', $._expression))
)),
quote_statement: $ => seq(
'quote',
optional($._expression_list),
'end'
),
import_statement: $ => prec.right(seq(
choice('using', 'import'),
sep1(',', choice(
$.identifier,
$.scoped_identifier,
$.selected_import
))
)),
selected_import: $ => seq(
choice($.identifier, $.scoped_identifier),
token.immediate(':'),
prec.right(sep1(',', choice(
$.identifier,
$.macro_identifier
)))
),
scoped_identifier: $ => prec(PREC.dot, seq(
optional(choice($.identifier, $.scoped_identifier)),
'.',
$.identifier
)),
export_statement: $ => prec.right(seq(
'export',
sep1(',', $.identifier)
)),
// Expressions
_expression: $ => choice(
$._statement,
$._definition,
$.typed_expression,
$.compound_expression,
$.pair_expression,
alias(':', $.operator),
$.macro_expression,
$.unary_expression,
$.binary_expression,
$.ternary_expression,
$.generator_expression,
$.function_expression,
$.coefficient_expression,
$.spread_expression,
$.range_expression,
$.quote_expression,
$.interpolation_expression,
$._primary_expression,
$._literal,
$.operator,
),
_primary_expression: $ => choice(
$.identifier,
$.array_expression,
$.array_comprehension_expression,
$.matrix_expression,
$.call_expression,
$.field_expression,
$.parenthesized_expression,
$.subscript_expression,
$.parameterized_identifier,
$.tuple_expression,
$.broadcast_call_expression,
),
bare_tuple_expression: $ => prec(-1, seq(
$._expression,
repeat1(prec(-1, seq(',', $._expression)))
)),
operator: $ => choice(
$._comparison_operator,
$._dotty_operator,
$._plus_operator,
$._times_operator,
$._rational_operator,
$._bitshift_operator,
$._power_operator,
$._unary_operator,
),
parenthesized_expression: $ => prec(1, seq(
'(', choice($._expression_list, $.spread_expression), ')'
)),
field_expression: $ => prec(PREC.dot, seq(
$._primary_expression,
'.',
$.identifier
)),
subscript_expression: $ => seq(
choice(
$._primary_expression,
$._literal,
),
token.immediate('['),
sep(',', $._expression),
optional(','),
']'
),
typed_expression: $ => prec(PREC.decl, seq(
$._expression,
choice('::', '<:'),
choice($.identifier, $.parameterized_identifier)
)),
parameterized_identifier: $ => seq(
choice($.identifier, $.field_expression),
$.type_argument_list
),
type_argument_list: $ => seq(
'{',
sep1(',', choice($._expression)),
'}'
),
compound_expression: $ => seq(
'begin',
$._expression_list,
'end'
),
call_expression: $ => prec(PREC.call, seq(
choice($._primary_expression, $.operator),
$._immediate_paren,
choice($.argument_list, $.generator_expression),
optional($.do_clause)
)),
broadcast_call_expression: $ => prec(PREC.call, seq(
$._primary_expression,
'.',
$._immediate_paren,
choice($.argument_list, $.generator_expression),
optional($.do_clause)
)),
macro_expression: $ => prec.right(seq(
$.macro_identifier,
optional(choice(
seq($._immediate_paren, $.argument_list),
$.macro_argument_list
))
)),
macro_argument_list: $ => prec(-1, repeat1(prec(-1, $._expression))),
argument_list: $ => seq(
'(',
sep(',', choice(
$._expression,
alias($.named_field, $.named_argument)
)),
optional(seq(
';',
sep1(',', alias($.named_field, $.named_argument))
)),
optional(','),
')'
),
do_clause: $ => seq(
'do',
$._expression_list,
'end'
),
named_field: $ => seq(
$.identifier,
'=',
$._expression
),
spread_expression: $ => prec(PREC.dot, seq($._expression, '...')),
assignment_expression: $ => prec.right(PREC.assign, seq(
choice(
$._expression,
$.bare_tuple_expression
),
alias(choice($._assign_operator, '='), $.operator),
choice(
$._expression,
$.assignment_expression,
$.bare_tuple_expression
)
)),
unary_expression: $ => choice(
prec(PREC.prefix, seq(
alias($._unary_operator, $.operator),
$._expression,
)),
prec(PREC.postfix, seq($._expression, alias("'", $.operator))),
),
binary_expression: $ => {
const table = [
[prec.left, PREC.power, $._power_operator],
[prec.left, PREC.rational, $._rational_operator],
[prec.left, PREC.bitshift, $._bitshift_operator],
[prec.left, PREC.times, $._times_operator],
[prec.left, PREC.plus, choice('+', $._plus_operator)],
[prec.left, PREC.colon_range, $._dotty_operator],
[prec.right, PREC.arrow, $._arrow_operator],
[prec.right, PREC.pipe_left, '<|'],
[prec.left, PREC.pipe_right, '|>'],
[prec.left, PREC.comparison, choice('in', 'isa', $._comparison_operator)],
[prec.left, PREC.lazy_or, '||'],
[prec.left, PREC.lazy_and, '&&'],
];
return choice(...table.map(([fn, prec, op]) => fn(prec, seq(
$._expression,
alias(op, $.operator),
$._expression,
))));
},
ternary_expression: $ => prec.right(PREC.conditional, seq(
$._expression,
'?',
$._expression,
':',
$._expression
)),
pair_expression: $ => prec.right(PREC.pair, seq(
$._expression,
'=>',
$._expression
)),
tuple_expression: $ => seq(
'(',
choice(
optional(','),
seq(
choice($._expression, $.named_field),
','
),
seq(
choice($._expression, $.named_field),
repeat1(seq(',', choice($._expression, $.named_field))),
optional(',')
)
),
')'
),
array_expression: $ => seq(
'[',
sep(',', $._expression),
optional(','),
']'
),
matrix_expression: $ => prec(-1, seq(
'[',
sep(';', $.matrix_row),
optional(';'),
']'
)),
matrix_row: $ => repeat1(prec(-1, $._expression)),
generator_expression: $ => seq(
'(',
$._expression,
$._comprehension_clause,
')'
),
array_comprehension_expression: $ => seq(
'[',
$._expression,
$._comprehension_clause,
']'
),
_comprehension_clause: $ => seq(
$.for_clause,
repeat(choice(
$.for_clause,
$.if_clause
))
),
if_clause: $ => seq(
'if',
$._expression
),
for_clause: $ => seq(
'for',
sep1(',', $.for_binding)
),
for_binding: $ => seq(
choice($.identifier, $.tuple_expression),
choice('in', '=', '∈'),
$._expression
),
function_expression: $ => prec.right(PREC.arrow,
choice(
seq(
'function',
$.parameter_list,
choice(
$._expression,
$.assignment_expression
),
'end'
),
seq(
choice(
$.identifier,
$.parameter_list,
),
'->',
choice(
$._expression,
$.assignment_expression
)))),
range_expression: $ => prec.left(PREC.colon_range, seq(
$._expression,
':',
$._expression
)),
coefficient_expression: $ => prec(PREC.call, seq(
choice(
alias(numeral('0-9'), $.integer_literal),
$.float_literal,
),
choice(
$.parenthesized_expression,
$.identifier
)
)),
quote_expression: $ => prec.left(PREC.colon_quote, seq(
':',
$._expression
)),
interpolation_expression: $ => prec.left(PREC.colon_quote, seq(
'$',
$._expression
)),
// Tokens
macro_identifier: $ => seq('@', choice(
$.identifier,
$.operator,
alias('.', $.operator)
)),
identifier: $ => {
const operators = [
',',
';',
':',
'(', ')',
'{', '}',
'&',
'$',
ASSIGN_OPERATORS,
ARROW_OPERATORS,
COMPARISON_OPERATORS,
DOTTY_OPERATORS,
PLUS_OPERATORS,
TIMES_OPERATORS,
BITSHIFT_OPERATORS,
POWER_OPERATORS
];
const operatorCharacters = operators
.join(' ')
.trim()
.replace(/\s+/g, '')
.replace(/-/g, '')
.replace(/\\/g, '\\\\')
.replace(/!/g, '');
const start = "[_\\p{L}\\p{Nl}∇]"
const rest = `[^"'\`\\s\\.\\-\\[\\]${operatorCharacters}]*`
return new RegExp(start + rest)
},
// Literals
_literal: $ => choice(
$.integer_literal,
$.float_literal,
$.character_literal,
$.string_literal,
$.command_literal,
$.prefixed_string_literal,
$.prefixed_command_literal,
),
integer_literal: $ => choice(
token(seq('0b', numeral('01'))),
token(seq('0o', numeral('0-7'))),
token(seq('0x', numeral('0-9a-fA-F'))),
numeral('0-9'),
),
float_literal: $ => {
const dec = numeral('0-9');
const hex = numeral('0-9a-fA-F');
const float = seq(
choice(
seq(dec, optional('.'), optional(dec)),
seq('.', dec),
),
optional(/[eEf][+-]?\d+/), // the exponent doesn't allow underscores
)
const hex_float = seq(
choice(
seq('0x', hex, optional('.'), optional(hex)),
seq('0x.', hex),
),
/p[+-]?\d+/, // hex floats must always have an exponent
)
return token(choice(float, hex_float))
},
escape_sequence: $ => token(seq(
'\\',
token.immediate(choice(
/[uU][0-9a-fA-F]{1,6}/, // unicode codepoints
/x[0-9a-fA-F]{2}/,
/["'`$\\abfnrtv]/,
/[0-7]{1,3}/,
)),
)),
character_literal: $ => seq(
"'",
choice(
$.escape_sequence,
/[^'\\]/,
),
"'",
),
string_literal: $ => seq(
$._string_start,
repeat(choice($._string_content, $.string_interpolation, $.escape_sequence)),
$._string_end,
),
command_literal: $ => seq(
$._command_start,
repeat(choice($._string_content, $.string_interpolation, $.escape_sequence)),
$._command_end,
),
prefixed_string_literal: $ => seq(
field('prefix', $.identifier),
$._immediate_string_start,
repeat(choice($._string_content_no_interp, $.escape_sequence)),
$._string_end,
),
prefixed_command_literal: $ => seq(
field('prefix', $.identifier),
$._immediate_command_start,
repeat(choice($._string_content_no_interp, $.escape_sequence)),
$._command_end,
),
string_interpolation: $ => seq(
'$',
choice(
$.identifier,
seq('(', $._expression, ')'),
),
),
_unary_operator: $ => token(addDots('+ - ! ~ ¬ √ ∛ ∜')),
_power_operator: $ => token(addDots(POWER_OPERATORS)),
_bitshift_operator: $ => token(addDots(BITSHIFT_OPERATORS)),
_rational_operator: $ => token(addDots('//')),
_times_operator: $ => token(addDots(TIMES_OPERATORS)),
_plus_operator: $ => token(choice('$', addDots(PLUS_OPERATORS))),
_dotty_operator: $ => token(choice('..', addDots(DOTTY_OPERATORS))),
_comparison_operator: $ => token(choice('<:', '>:', addDots(COMPARISON_OPERATORS))),
_arrow_operator: $ => token(choice('<--', '-->', '<-->', addDots(ARROW_OPERATORS))),
_assign_operator: $ => token(choice(':=', '~', '$=', addDots(ASSIGN_OPERATORS))),
_terminator: $ => choice('\n', ';'),
line_comment: $ => token(seq('#', /.*/))
}
});
function sep(separator, rule) {
return optional(sep1(separator, rule));
}
function sep1(separator, rule) {
return seq(rule, repeat(seq(separator, rule)));
}
function addDots(operatorString) {
const operators = operatorString.trim().split(/\s+/)
return seq(optional('.'), choice(...operators))
}
function numeral(range) {
return RegExp(`[${range}]|([${range}][${range}_]*[${range}])`)
}