From da0005bdf97f23573e008459004c0db70b5e0443 Mon Sep 17 00:00:00 2001
From: Turiiya <34311583+ttytm@users.noreply.github.com>
Date: Mon, 25 Mar 2024 22:41:27 +0100
Subject: [PATCH] ci: add linting and formatting automation to tree-sitter_v
(#68)
---
...st_tree_sitter_v.yml => tree_sitter_v.yml} | 19 +-
tree_sitter_v/.eslintrc.js | 15 +
tree_sitter_v/.gitattributes | 2 -
tree_sitter_v/.prettierrc.js | 5 +
tree_sitter_v/grammar.cjs | 1537 -----------------
tree_sitter_v/grammar.js | 1330 +++++++++++++-
tree_sitter_v/package.json | 11 +-
7 files changed, 1368 insertions(+), 1551 deletions(-)
rename .github/workflows/{test_tree_sitter_v.yml => tree_sitter_v.yml} (69%)
create mode 100644 tree_sitter_v/.eslintrc.js
create mode 100644 tree_sitter_v/.prettierrc.js
delete mode 100644 tree_sitter_v/grammar.cjs
mode change 120000 => 100644 tree_sitter_v/grammar.js
diff --git a/.github/workflows/test_tree_sitter_v.yml b/.github/workflows/tree_sitter_v.yml
similarity index 69%
rename from .github/workflows/test_tree_sitter_v.yml
rename to .github/workflows/tree_sitter_v.yml
index c258676e..9a16c25a 100644
--- a/.github/workflows/test_tree_sitter_v.yml
+++ b/.github/workflows/tree_sitter_v.yml
@@ -16,20 +16,23 @@ concurrency:
jobs:
test:
- name: Test tree-sitter
runs-on: ubuntu-latest
+ defaults:
+ run:
+ working-directory: tree_sitter_v
steps:
- - name: Install Nodejs
- uses: actions/setup-node@v4
- with:
- node-version: 20
-
- name: Checkout v-analyzer
uses: actions/checkout@v4
- name: Install dependencies
- run: cd tree_sitter_v && npm update
+ run: npm update
- name: Run tests
- run: cd tree_sitter_v && npm run test
+ run: npm run test
+
+ - name: Lint
+ run: npm run lint
+
+ - name: Verify formatting
+ run: npm run format:check
diff --git a/tree_sitter_v/.eslintrc.js b/tree_sitter_v/.eslintrc.js
new file mode 100644
index 00000000..5d1ac6ae
--- /dev/null
+++ b/tree_sitter_v/.eslintrc.js
@@ -0,0 +1,15 @@
+module.exports = {
+ env: {
+ commonjs: true,
+ es2024: true,
+ },
+ extends: [
+ 'google',
+ 'prettier', // Use prettier for formatting, disable potentially conflicting rules.
+ ],
+ overrides: [],
+ parserOptions: {
+ ecmaVersion: 'latest',
+ sourceType: 'module',
+ },
+};
diff --git a/tree_sitter_v/.gitattributes b/tree_sitter_v/.gitattributes
index c5f672fe..33b31435 100644
--- a/tree_sitter_v/.gitattributes
+++ b/tree_sitter_v/.gitattributes
@@ -1,5 +1,3 @@
-grammar.js symlink=file
-
src/tree_sitter/* linguist-generated
src/grammar.json linguist-generated
src/node-types.json linguist-generated
diff --git a/tree_sitter_v/.prettierrc.js b/tree_sitter_v/.prettierrc.js
new file mode 100644
index 00000000..169b7296
--- /dev/null
+++ b/tree_sitter_v/.prettierrc.js
@@ -0,0 +1,5 @@
+module.exports = {
+ printWidth: 100,
+ singleQuote: true,
+ useTabs: true,
+};
diff --git a/tree_sitter_v/grammar.cjs b/tree_sitter_v/grammar.cjs
deleted file mode 100644
index a7a72098..00000000
--- a/tree_sitter_v/grammar.cjs
+++ /dev/null
@@ -1,1537 +0,0 @@
-/**
- * @file V grammar for tree-sitter
- */
-
-///
-/// @ts-check
-
-const PREC = {
- attributes: 10,
- match_arm_type: 9,
- type_initializer: 8,
- primary: 7,
- unary: 6,
- multiplicative: 5,
- additive: 4,
- comparative: 3,
- and: 2,
- or: 1,
- resolve: 1,
- composite_literal: -1,
- strictly_expression_list: -2,
-};
-
-const multiplicative_operators = ["*", "/", "%", "<<", ">>", ">>>", "&", "&^"];
-const additive_operators = ["+", "-", "|", "^"];
-const comparative_operators = ["==", "!=", "<", "<=", ">", ">="];
-const assignment_operators = multiplicative_operators
- .concat(additive_operators)
- .map((operator) => operator + "=")
- .concat("=");
-const unary_operators = ["+", "-", "!", "~", "^", "*", "&"];
-const overridable_operators = [
- "+",
- "-",
- "*",
- "/",
- "%",
- "<",
- ">",
- "==",
- "!=",
- "<=",
- ">=",
-].map((operator) => token(operator));
-
-const terminator = choice("\n", "\r", "\r\n");
-
-const unicode_digit = /[0-9]/;
-const unicode_letter = /[a-zA-Zα-ωΑ-Ωµ]/;
-
-const letter = choice(unicode_letter, "_");
-
-const hex_digit = /[0-9a-fA-F]/;
-const octal_digit = /[0-7]/;
-const decimal_digit = /[0-9]/;
-const binary_digit = /[01]/;
-
-const hex_digits = seq(hex_digit, repeat(seq(optional("_"), hex_digit)));
-const octal_digits = seq(octal_digit, repeat(seq(optional("_"), octal_digit)));
-const decimal_digits = seq(
- decimal_digit,
- repeat(seq(optional("_"), decimal_digit)),
-);
-const binary_digits = seq(
- binary_digit,
- repeat(seq(optional("_"), binary_digit)),
-);
-
-const hex_literal = seq("0", choice("x", "X"), optional("_"), hex_digits);
-const octal_literal = seq(
- "0",
- optional(choice("o", "O")),
- optional("_"),
- octal_digits,
-);
-const decimal_literal = choice(
- "0",
- seq(/[1-9]/, optional(seq(optional("_"), decimal_digits))),
-);
-const binary_literal = seq("0", choice("b", "B"), optional("_"), binary_digits);
-
-const int_literal = choice(
- binary_literal,
- decimal_literal,
- octal_literal,
- hex_literal,
-);
-
-const decimal_exponent = seq(
- choice("e", "E"),
- optional(choice("+", "-")),
- decimal_digits,
-);
-const decimal_float_literal = choice(
- seq(decimal_digits, ".", decimal_digits, optional(decimal_exponent)),
- seq(decimal_digits, decimal_exponent),
- seq(".", decimal_digits, optional(decimal_exponent)),
-);
-
-const hex_exponent = seq(
- choice("p", "P"),
- optional(choice("+", "-")),
- decimal_digits,
-);
-const hex_mantissa = choice(
- seq(optional("_"), hex_digits, ".", optional(hex_digits)),
- seq(optional("_"), hex_digits),
- seq(".", hex_digits),
-);
-const hex_float_literal = seq(
- "0",
- choice("x", "X"),
- hex_mantissa,
- hex_exponent,
-);
-const float_literal = choice(decimal_float_literal, hex_float_literal);
-
-const format_flag = token(/[bgGeEfFcdoxXpsS]/);
-
-const semi = choice(terminator, ";");
-const list_separator = choice(semi, ",");
-
-module.exports = grammar({
- name: "v",
-
- extras: ($) => [$.comment, /\s/],
-
- word: ($) => $.identifier,
-
- externals: (_) => [],
-
- inline: ($) => [$._string_literal, $._top_level_declaration, $._array],
-
- supertypes: ($) => [
- $._expression,
- $._statement,
- $._top_level_declaration,
- $._expression_with_blocks,
- ],
-
- conflicts: ($) => [
- [$.fixed_array_type, $._expression_without_blocks],
- [$.qualified_type, $._expression_without_blocks],
- [$.fixed_array_type, $.literal],
- [$.reference_expression, $.type_reference_expression],
- [$.is_expression],
- [$.not_is_expression],
- [$._type_union_list],
- [$._expression_without_blocks, $.element_list],
- ],
-
- rules: {
- source_file: ($) =>
- seq(
- optional($.shebang),
- optional($.module_clause),
- optional($.import_list),
- repeat(
- choice(
- seq($._top_level_declaration, optional(terminator)),
- seq($._statement, optional(terminator)),
- ),
- ),
- ),
-
- shebang: (_) => token(/\#\!([^\\\r\n]+)+/),
-
- // http://stackoverflow.com/questions/13014947/regex-to-match-a-c-style-multiline-comment/36328890#36328890
- comment: (_) =>
- token(
- choice(
- /\/\/[^\n\r]*/,
- /\/\*(?:[^\/][^\*]+\/\*+[^\/][^\*]+)+(?:[^\*][^\/]+\*+\/[^\*][^\/]+)+\//,
- /\/\*[^\*]*\*\//,
- ),
- ),
-
- module_clause: ($) => seq(optional($.attributes), "module", $.identifier),
-
- import_list: ($) => repeat1($.import_declaration),
-
- import_declaration: ($) => seq("import", $.import_spec, semi),
-
- import_spec: ($) =>
- seq(
- $.import_path,
- optional($.import_alias),
- optional($.selective_import_list),
- ),
-
- // foo.bar.baz
- import_path: ($) => seq($.import_name, repeat(seq(".", $.import_name))),
-
- // foo
- import_name: ($) => $.identifier,
-
- // foo as bar
- // ^^^^^^
- import_alias: ($) => seq("as", $.import_name),
-
- // { foo, bar }
- selective_import_list: ($) =>
- seq(
- "{",
- $.reference_expression,
- repeat(seq(choice(",", terminator), optional($.reference_expression))),
- "}",
- ),
-
- // ==================== TOP LEVEL DECLARATIONS ====================
-
- _top_level_declaration: ($) =>
- choice(
- $.const_declaration,
- $.global_var_declaration,
- $.type_declaration,
- $.function_declaration,
- $.static_method_declaration,
- $.struct_declaration,
- $.enum_declaration,
- $.interface_declaration,
- ),
-
- const_declaration: ($) =>
- seq(
- optional(field("attributes", $.attributes)),
- optional($.visibility_modifiers),
- "const",
- choice(
- $.const_definition,
- seq("(", repeat(seq($.const_definition, semi)), ")"),
- ),
- ),
-
- const_definition: ($) =>
- seq(field("name", $.identifier), "=", field("value", $._expression)),
-
- global_var_declaration: ($) =>
- seq(
- optional(field("attributes", $.attributes)),
- "__global",
- choice(
- $.global_var_definition,
- seq("(", repeat(seq($.global_var_definition, semi)), ")"),
- ),
- ),
-
- global_var_definition: ($) =>
- seq(
- field("name", $.identifier),
- choice($.plain_type, $._global_var_value),
- ),
-
- _global_var_value: ($) => seq("=", field("value", $._expression)),
-
- type_declaration: ($) =>
- seq(
- optional($.visibility_modifiers),
- "type",
- field("name", $.identifier),
- optional(field("generic_parameters", $.generic_parameters)),
- "=",
- field("types", $._type_union_list),
- ),
-
- // int | string | Foo
- _type_union_list: ($) =>
- seq($.plain_type, repeat(seq(optional(terminator), "|", $.plain_type))),
-
- function_declaration: ($) =>
- prec.right(
- PREC.resolve,
- seq(
- optional(field("attributes", $.attributes)),
- optional($.visibility_modifiers),
- "fn",
- optional(field("receiver", $.receiver)),
- field("name", $._function_name),
- optional(field("generic_parameters", $.generic_parameters)),
- field("signature", $.signature),
- optional(field("body", $.block)),
- ),
- ),
-
- static_method_declaration: ($) =>
- prec.right(
- PREC.resolve,
- seq(
- optional(field("attributes", $.attributes)),
- optional($.visibility_modifiers),
- "fn",
- field("static_receiver", $.static_receiver),
- ".",
- field("name", $._function_name),
- optional(field("generic_parameters", $.generic_parameters)),
- field("signature", $.signature),
- optional(field("body", $.block)),
- ),
- ),
-
- static_receiver: ($) => $.reference_expression,
-
- _function_name: ($) => choice($.identifier, $.overridable_operator),
-
- overridable_operator: () => choice(...overridable_operators),
-
- receiver: ($) =>
- prec(
- PREC.primary,
- seq(
- "(",
- seq(
- optional(field("mutability", $.mutability_modifiers)),
- field("name", $.identifier),
- field("type", alias($._plain_type_without_special, $.plain_type)),
- ),
- ")",
- ),
- ),
-
- signature: ($) =>
- prec.right(
- seq(
- field("parameters", choice($.parameter_list, $.type_parameter_list)),
- optional(field("result", $.plain_type)),
- ),
- ),
-
- parameter_list: ($) =>
- prec(PREC.resolve, seq("(", comma_sep($.parameter_declaration), ")")),
-
- parameter_declaration: ($) =>
- seq(
- optional(field("mutability", $.mutability_modifiers)),
- field("name", $.identifier),
- optional(field("variadic", "...")),
- field("type", $.plain_type),
- ),
-
- type_parameter_list: ($) =>
- seq("(", comma_sep($.type_parameter_declaration), ")"),
-
- type_parameter_declaration: ($) =>
- prec(
- PREC.primary,
- seq(
- optional($.mutability_modifiers),
- optional(field("variadic", "...")),
- field("type", $.plain_type),
- ),
- ),
-
- // fn foo[T, T2]() {}
- // ^^^^^^^
- generic_parameters: ($) =>
- prec(
- PREC.resolve,
- seq(
- choice(token.immediate("["), token.immediate("<")),
- comma_sep1($.generic_parameter),
- optional(","),
- choice("]", ">"),
- ),
- ),
-
- generic_parameter: ($) => $.identifier,
-
- struct_declaration: ($) =>
- seq(
- optional(field("attributes", $.attributes)),
- optional($.visibility_modifiers),
- choice("struct", "union"),
- field("name", $.identifier),
- optional(field("generic_parameters", $.generic_parameters)),
- $._struct_body,
- ),
-
- _struct_body: ($) =>
- seq(
- "{",
- repeat(
- choice(
- seq($.struct_field_scope, optional(terminator)),
- seq($.struct_field_declaration, optional(terminator)),
- ),
- ),
- "}",
- ),
-
- // pub:
- // mut:
- // pub mut:
- // __global:
- struct_field_scope: () =>
- seq(choice("pub", "mut", seq("pub", "mut"), "__global"), ":"),
-
- struct_field_declaration: ($) =>
- choice($._struct_field_definition, $.embedded_definition),
-
- _struct_field_definition: ($) =>
- prec.right(
- PREC.type_initializer,
- seq(
- field("name", $.identifier),
- field("type", $.plain_type),
- optional(seq("=", field("default_value", $._expression))),
- optional(field("attributes", $.attribute)),
- ),
- ),
-
- embedded_definition: ($) =>
- choice($.type_reference_expression, $.qualified_type, $.generic_type),
-
- enum_declaration: ($) =>
- seq(
- optional(field("attributes", $.attributes)),
- optional($.visibility_modifiers),
- "enum",
- field("name", $.identifier),
- optional($.enum_backed_type),
- $._enum_body,
- ),
-
- enum_backed_type: ($) => seq("as", $.plain_type),
-
- _enum_body: ($) =>
- seq("{", repeat(seq($.enum_field_definition, optional(terminator))), "}"),
-
- enum_field_definition: ($) =>
- seq(
- field("name", $.identifier),
- optional(seq("=", field("value", $._expression))),
- optional(field("attributes", $.attribute)),
- ),
-
- interface_declaration: ($) =>
- seq(
- optional(field("attributes", $.attributes)),
- optional($.visibility_modifiers),
- "interface",
- field("name", $.identifier),
- optional(field("generic_parameters", $.generic_parameters)),
- $._interface_body,
- ),
-
- _interface_body: ($) =>
- seq(
- "{",
- repeat(
- choice(
- seq($.struct_field_scope, optional(terminator)),
- seq($.struct_field_declaration, optional(terminator)),
- seq($.interface_method_definition, optional(terminator)),
- ),
- ),
- "}",
- ),
-
- interface_method_definition: ($) =>
- prec.right(
- seq(
- field("name", $.identifier),
- optional(field("generic_parameters", $.generic_parameters)),
- field("signature", $.signature),
- optional(field("attributes", $.attribute)),
- ),
- ),
-
- // ==================== EXPRESSIONS ====================
-
- _expression: ($) =>
- choice($._expression_without_blocks, $._expression_with_blocks),
-
- _expression_without_blocks: ($) =>
- choice(
- $.parenthesized_expression,
- $.go_expression,
- $.spawn_expression,
- $.call_expression,
- $.function_literal,
- $.reference_expression,
- $._max_group,
- $.array_creation,
- $.fixed_array_creation,
- $.unary_expression,
- $.receive_expression,
- $.binary_expression,
- $.is_expression,
- $.not_is_expression,
- $.in_expression,
- $.not_in_expression,
- $.index_expression,
- $.slice_expression,
- $.as_type_cast_expression,
- $.selector_expression,
- $.enum_fetch,
- $.inc_expression,
- $.dec_expression,
- $.or_block_expression,
- $.option_propagation_expression,
- $.result_propagation_expression,
- ),
-
- _expression_with_blocks: ($) =>
- choice(
- $.type_initializer,
- $.anon_struct_value_expression,
- $.if_expression,
- $.match_expression,
- $.select_expression,
- $.sql_expression,
- $.lock_expression,
- $.unsafe_expression,
- $.compile_time_if_expression,
- $.map_init_expression,
- ),
-
- strictly_expression_list: ($) =>
- prec(
- PREC.strictly_expression_list,
- seq(
- choice($._expression, $.mutable_expression),
- ",",
- comma_sep1(choice($._expression, $.mutable_expression)),
- ),
- ),
-
- inc_expression: ($) => seq($._expression, "++"),
-
- dec_expression: ($) => seq($._expression, "--"),
-
- or_block_expression: ($) => seq($._expression, $.or_block),
-
- option_propagation_expression: ($) =>
- prec(PREC.match_arm_type, seq($._expression, "?")),
-
- result_propagation_expression: ($) =>
- prec(PREC.match_arm_type, seq($._expression, "!")),
-
- anon_struct_value_expression: ($) =>
- seq(
- "struct",
- "{",
- choice(
- field("element_list", $.element_list),
- // For short struct init syntax
- field("short_element_list", $.short_element_list),
- ),
- "}",
- ),
-
- go_expression: ($) =>
- prec.left(PREC.composite_literal, seq("go", $._expression)),
-
- spawn_expression: ($) =>
- prec.left(PREC.composite_literal, seq("spawn", $._expression)),
-
- parenthesized_expression: ($) =>
- seq("(", field("expression", $._expression), ")"),
-
- call_expression: ($) =>
- prec.right(
- PREC.primary,
- choice(
- seq(
- field("function", token("json.decode")),
- field("arguments", $.special_argument_list),
- ),
- seq(
- field("name", $._expression),
- optional(field("type_parameters", $.type_parameters)),
- field("arguments", $.argument_list),
- ),
- ),
- ),
-
- type_parameters: ($) =>
- prec.dynamic(2, seq(token.immediate("["), comma_sep1($.plain_type), "]")),
-
- argument_list: ($) =>
- seq(
- "(",
- choice(
- repeat(seq($.argument, optional(list_separator))),
- $.short_lambda,
- ),
- ")",
- ),
-
- short_lambda: ($) =>
- seq("|", comma_sep($.reference_expression), "|", $._expression_without_blocks),
-
- argument: ($) =>
- choice(
- $._expression,
- $.mutable_expression,
- $.keyed_element,
- $.spread_expression,
- ),
-
- special_argument_list: ($) =>
- seq(
- "(",
- alias($._plain_type_without_special, $.plain_type),
- optional(seq(",", $._expression)),
- ")",
- ),
-
- type_initializer: ($) =>
- prec(
- PREC.type_initializer,
- seq(
- field("type", $.plain_type),
- field("body", $.type_initializer_body),
- ),
- ),
-
- type_initializer_body: ($) =>
- seq(
- "{",
- optional(
- choice(
- field("element_list", $.element_list),
- // For short struct init syntax
- field("short_element_list", $.short_element_list),
- ),
- ),
- "}",
- ),
-
- element_list: ($) =>
- repeat1(
- seq(
- choice($.spread_expression, $.keyed_element, $.reference_expression),
- optional(list_separator),
- ),
- ),
-
- short_element_list: ($) =>
- repeat1(seq(alias($._expression, $.element), optional(list_separator))),
-
- keyed_element: ($) =>
- seq(
- field("key", alias($.reference_expression, $.field_name)),
- ":",
- field("value", $._expression),
- ),
-
- function_literal: ($) =>
- prec.right(
- seq(
- "fn",
- optional(field("capture_list", $.capture_list)),
- optional(field("generic_parameters", $.generic_parameters)),
- field("signature", $.signature),
- field("body", $.block),
- ),
- ),
-
- capture_list: ($) => seq("[", comma_sep($.capture), optional(","), "]"),
-
- capture: ($) =>
- seq(optional($.mutability_modifiers), $.reference_expression),
-
- reference_expression: ($) => prec.left($.identifier),
- type_reference_expression: ($) => prec.left($.identifier),
-
- unary_expression: ($) =>
- prec(
- PREC.unary,
- seq(
- field("operator", choice(...unary_operators)),
- field("operand", $._expression),
- ),
- ),
-
- receive_expression: ($) =>
- prec.right(
- PREC.unary,
- seq(field("operator", "<-"), field("operand", $._expression)),
- ),
-
- binary_expression: ($) => {
- const table = [
- [PREC.multiplicative, choice(...multiplicative_operators)],
- [PREC.additive, choice(...additive_operators)],
- [PREC.comparative, choice(...comparative_operators)],
- [PREC.and, "&&"],
- [PREC.or, "||"],
- ];
-
- return choice(
- ...table.map(([precedence, operator]) =>
- prec.left(
- Number(precedence),
- seq(
- field("left", $._expression),
- // @ts-ignore
- field("operator", operator),
- field("right", $._expression),
- ),
- ),
- ),
- );
- },
-
- as_type_cast_expression: ($) => seq($._expression, "as", $.plain_type),
-
- compile_time_selector_expression: ($) =>
- comp_time(
- seq("(", choice($.reference_expression, $.selector_expression), ")"),
- ),
-
- or_block: ($) => seq("or", field("block", $.block)),
-
- _max_group: ($) =>
- prec.left(
- PREC.resolve,
- choice($.pseudo_compile_time_identifier, $.literal),
- ),
-
- escape_sequence: () =>
- token(
- prec(
- 1,
- seq(
- "\\",
- choice(
- /u[a-fA-F\d]{4}/,
- /U[a-fA-F\d]{8}/,
- /x[a-fA-F\d]{2}/,
- /\d{3}/,
- /\r?\n/,
- /['"abfrntv$\\]/,
- /\S/,
- ),
- ),
- ),
- ),
-
- literal: ($) =>
- choice(
- $.int_literal,
- $.float_literal,
- $._string_literal,
- $.rune_literal,
- $.none,
- $.true,
- $.false,
- $.nil,
- ),
-
- none: () => "none",
- true: () => "true",
- false: () => "false",
- nil: () => "nil",
-
- spread_expression: ($) => prec.right(PREC.unary, seq("...", $._expression)),
-
- map_init_expression: ($) =>
- prec(
- PREC.composite_literal,
- seq(
- "{",
- repeat(seq($.map_keyed_element, optional(list_separator))),
- "}",
- ),
- ),
-
- map_keyed_element: ($) =>
- seq(field("key", $._expression), ":", field("value", $._expression)),
-
- array_creation: ($) => prec.right(PREC.multiplicative, $._array),
-
- fixed_array_creation: ($) =>
- prec.right(PREC.multiplicative, seq($._array, "!")),
-
- _array: ($) => seq("[", repeat(seq($._expression, optional(","))), "]"),
-
- selector_expression: ($) =>
- prec.dynamic(
- -1,
- prec(
- PREC.primary,
- seq(
- field("operand", $._expression),
- choice(".", "?."),
- field(
- "field",
- choice(
- $.reference_expression,
- $.compile_time_selector_expression,
- ),
- ),
- ),
- ),
- ),
-
- index_expression: ($) =>
- prec.dynamic(
- -1,
- prec.right(
- PREC.primary,
- seq(
- field("operand", $._expression),
- choice("[", token.immediate("["), token("#[")),
- field("index", $._expression),
- "]",
- ),
- ),
- ),
-
- slice_expression: ($) =>
- prec(
- PREC.primary,
- seq(
- field("operand", $._expression),
- choice("[", token.immediate("["), token("#[")),
- $.range,
- "]",
- ),
- ),
-
- if_expression: ($) =>
- seq(
- "if",
- choice(
- field("condition", $._expression),
- field("guard", $.var_declaration),
- ),
- field("block", $.block),
- optional($.else_branch),
- ),
-
- else_branch: ($) =>
- seq(
- "else",
- field("else_branch", choice(field("block", $.block), $.if_expression)),
- ),
-
- compile_time_if_expression: ($) =>
- seq(
- "$if",
- field("condition", seq($._expression, optional("?"))),
- field("block", $.block),
- optional(
- seq(
- "$else",
- field("else_branch", choice($.block, $.compile_time_if_expression)),
- ),
- ),
- ),
-
- is_expression: ($) =>
- prec.dynamic(
- 2,
- seq(
- field("left", seq(optional($.mutability_modifiers), $._expression)),
- "is",
- field("right", $.plain_type),
- ),
- ),
-
- not_is_expression: ($) =>
- prec.dynamic(
- 2,
- seq(
- field("left", seq(optional($.mutability_modifiers), $._expression)),
- "!is",
- field("right", $.plain_type),
- ),
- ),
-
- in_expression: ($) =>
- prec.left(
- PREC.comparative,
- seq(field("left", $._expression), "in", field("right", $._expression)),
- ),
-
- not_in_expression: ($) =>
- prec.left(
- PREC.comparative,
- seq(field("left", $._expression), "!in", field("right", $._expression)),
- ),
-
- enum_fetch: ($) => prec.dynamic(-1, seq(".", $.reference_expression)),
-
- match_expression: ($) =>
- seq(
- "match",
- field("condition", choice($._expression, $.mutable_expression)),
- "{",
- optional($.match_arms),
- "}",
- ),
-
- match_arms: ($) => repeat1(choice($.match_arm, $.match_else_arm_clause)),
-
- match_arm: ($) =>
- seq(field("value", $.match_expression_list), field("block", $.block)),
-
- match_expression_list: ($) =>
- comma_sep1(
- choice(
- $._expression_without_blocks,
- $.match_arm_type,
- alias($._definite_range, $.range),
- ),
- ),
-
- match_arm_type: ($) => prec(PREC.match_arm_type, $.plain_type),
-
- match_else_arm_clause: ($) => seq("else", field("block", $.block)),
-
- select_expression: ($) =>
- seq(
- "select",
- optional(field("selected_variables", $.expression_list)),
- "{",
- repeat($.select_arm),
- optional($.select_else_arn_clause),
- "}",
- ),
-
- select_arm: ($) => seq($.select_arm_statement, $.block),
-
- select_arm_statement: ($) =>
- prec.left(
- choice(
- alias($.select_var_declaration, $.var_declaration),
- $.send_statement,
- seq(
- alias($.expression_without_blocks_list, $.expression_list),
- optional($._select_arm_assignment_statement),
- ),
- ),
- ),
-
- _select_arm_assignment_statement: ($) =>
- seq(
- choice(...assignment_operators),
- alias($.expression_without_blocks_list, $.expression_list),
- ),
-
- select_var_declaration: ($) =>
- prec.left(
- seq(
- field("var_list", $.identifier_list),
- ":=",
- field(
- "expression_list",
- alias($.expression_without_blocks_list, $.expression_list),
- ),
- ),
- ),
-
- select_else_arn_clause: ($) => seq("else", $.block),
-
- lock_expression: ($) =>
- seq(
- choice("lock", "rlock"),
- optional(field("locked_variables", $.expression_list)),
- field("body", $.block),
- ),
-
- unsafe_expression: ($) => seq("unsafe", $.block),
-
- // TODO: this should be put into a separate grammar to avoid any "noise"
- sql_expression: ($) =>
- prec(PREC.resolve, seq("sql", optional($.identifier), $._content_block)),
-
- // ==================== LITERALS ====================
-
- int_literal: () => token(int_literal),
-
- float_literal: () => token(float_literal),
-
- rune_literal: () =>
- token(
- seq(
- "`",
- choice(
- /[^'\\]/,
- "'",
- '"',
- seq(
- "\\",
- choice(
- "0",
- "`",
- seq("x", hex_digit, hex_digit),
- seq(octal_digit, octal_digit, octal_digit),
- seq("u", hex_digit, hex_digit, hex_digit, hex_digit),
- seq(
- "U",
- hex_digit,
- hex_digit,
- hex_digit,
- hex_digit,
- hex_digit,
- hex_digit,
- hex_digit,
- hex_digit,
- ),
- seq(
- choice(
- "a",
- "b",
- "e",
- "f",
- "n",
- "r",
- "t",
- "v",
- "\\",
- "'",
- '"',
- ),
- ),
- ),
- ),
- ),
- "`",
- ),
- ),
-
- _string_literal: ($) =>
- choice(
- $.c_string_literal,
- $.raw_string_literal,
- $.interpreted_string_literal,
- ),
-
- c_string_literal: ($) =>
- prec(
- 1,
- choice(
- seq(
- $.__c_single_quote,
- repeat(
- choice(
- token.immediate(prec.right(1, /[^'\\$]+/)),
- $.escape_sequence,
- $.string_interpolation,
- ),
- ),
- $.__single_quote,
- ),
- seq(
- $.__c_double_quote,
- repeat(
- choice(
- token.immediate(prec.right(1, /[^"\\$]+/)),
- $.escape_sequence,
- $.string_interpolation,
- ),
- ),
- $.__double_quote,
- ),
- ),
- ),
-
- raw_string_literal: ($) =>
- prec(
- 1,
- choice(
- seq(
- $.__r_single_quote,
- repeat(token.immediate(prec.right(1, /[^']+/))),
- $.__single_quote,
- ),
- seq(
- $.__r_double_quote,
- repeat(token.immediate(prec.right(1, /[^"]+/))),
- $.__double_quote,
- ),
- ),
- ),
-
- interpreted_string_literal: ($) =>
- prec(
- 1,
- choice(
- seq(
- $.__single_quote,
- repeat(
- choice(
- token.immediate(prec.right(1, /[^'\\$]+/)),
- $.escape_sequence,
- $.string_interpolation,
- ),
- ),
- $.__single_quote,
- ),
- seq(
- $.__double_quote,
- repeat(
- choice(
- token.immediate(prec.right(1, /[^"\\$]+/)),
- $.escape_sequence,
- $.string_interpolation,
- ),
- ),
- $.__double_quote,
- ),
- ),
- ),
-
- string_interpolation: ($) =>
- seq(
- alias($.__dolcbr, $.interpolation_opening),
- choice(
- repeat(alias($._expression, $.interpolation_expression)),
- seq(
- alias($._expression, $.interpolation_expression),
- $.format_specifier,
- ),
- ),
- alias($.__rcbr, $.interpolation_closing),
- ),
-
- format_specifier: ($) =>
- seq(
- token(":"),
- choice(
- format_flag,
- seq(
- optional(choice(token(/[+\-]/), token("0"))),
- optional($.int_literal),
- optional(seq(".", $.int_literal)),
- optional(format_flag),
- ),
- ),
- ),
-
- pseudo_compile_time_identifier: ($) =>
- token(seq("@", alias(token.immediate(/[A-Z][A-Z0-9_]+/), $.identifier))),
-
- identifier: () =>
- token(
- seq(
- optional("@"),
- optional("$"),
- optional("C."),
- optional("JS."),
- choice(unicode_letter, "_"),
- repeat(choice(letter, unicode_digit)),
- ),
- ),
-
- visibility_modifiers: () => prec.left(choice("pub", "__global")),
-
- mutability_modifiers: () =>
- prec.left(
- PREC.resolve,
- choice(seq("mut", optional("static"), optional("volatile")), "shared"),
- ),
-
- mutable_identifier: ($) =>
- prec(PREC.resolve, seq($.mutability_modifiers, $.identifier)),
-
- mutable_expression: ($) =>
- prec(PREC.resolve, seq($.mutability_modifiers, $._expression)),
-
- identifier_list: ($) =>
- prec(PREC.and, comma_sep1(choice($.mutable_identifier, $.identifier))),
-
- expression_list: ($) =>
- prec(
- PREC.resolve,
- comma_sep1(choice($._expression, $.mutable_expression)),
- ),
-
- expression_without_blocks_list: ($) =>
- prec(PREC.resolve, comma_sep1($._expression_without_blocks)),
-
- // ==================== TYPES ====================
-
- plain_type: ($) =>
- prec.right(
- PREC.primary,
- choice(
- $._plain_type_without_special,
- $.option_type,
- $.result_type,
- $.multi_return_type,
- ),
- ),
-
- _plain_type_without_special: ($) =>
- prec.right(
- PREC.primary,
- choice(
- $.type_reference_expression,
- $.qualified_type,
- $.pointer_type,
- $.wrong_pointer_type,
- $.array_type,
- $.fixed_array_type,
- $.function_type,
- $.generic_type,
- $.map_type,
- $.channel_type,
- $.shared_type,
- $.thread_type,
- $.atomic_type,
- $.anon_struct_type,
- ),
- ),
-
- anon_struct_type: ($) => seq("struct", $._struct_body),
-
- multi_return_type: ($) =>
- seq("(", comma_sep1($.plain_type), optional(","), ")"),
-
- result_type: ($) => prec.right(seq("!", optional($.plain_type))),
-
- option_type: ($) => prec.right(seq("?", optional($.plain_type))),
-
- qualified_type: ($) =>
- seq(
- field("module", $.reference_expression),
- ".",
- field("name", $.type_reference_expression),
- ),
-
- fixed_array_type: ($) =>
- seq(
- "[",
- field(
- "size",
- choice($.int_literal, $.reference_expression, $.selector_expression),
- ),
- "]",
- field("element", $.plain_type),
- ),
-
- array_type: ($) =>
- prec(
- PREC.primary,
- prec.dynamic(2, seq("[", "]", field("element", $.plain_type))),
- ),
-
- variadic_type: ($) => seq("...", $.plain_type),
-
- pointer_type: ($) => prec(PREC.match_arm_type, seq("&", $.plain_type)),
-
- // In languages like Go, pointers use an asterisk, not an ampersand,
- // so this rule is needed to properly parse and then give an error to the user.
- wrong_pointer_type: ($) =>
- prec(PREC.match_arm_type, seq("*", $.plain_type)),
-
- map_type: ($) =>
- seq(
- "map[",
- field("key", $.plain_type),
- "]",
- field("value", $.plain_type),
- ),
-
- channel_type: ($) => prec.right(PREC.primary, seq("chan", $.plain_type)),
-
- shared_type: ($) => seq("shared", $.plain_type),
-
- thread_type: ($) => seq("thread", $.plain_type),
-
- atomic_type: ($) => seq("atomic", $.plain_type),
-
- generic_type: ($) =>
- seq(
- choice($.qualified_type, $.type_reference_expression),
- $.type_parameters,
- ),
-
- function_type: ($) =>
- prec.right(seq("fn", field("signature", $.signature))),
-
- // ==================== TYPES END ====================
-
- // ==================== STATEMENTS ====================
-
- _statement_list: ($) =>
- choice(
- seq(
- $._statement,
- repeat(seq(terminator, $._statement)),
- optional(
- seq(
- terminator,
- optional(alias($.empty_labeled_statement, $.labeled_statement)),
- ),
- ),
- ),
- alias($.empty_labeled_statement, $.labeled_statement),
- ),
-
- _statement: ($) =>
- choice(
- $.simple_statement,
- $.assert_statement,
- $.continue_statement,
- $.break_statement,
- $.return_statement,
- $.asm_statement,
- $.goto_statement,
- $.labeled_statement,
- $.defer_statement,
- $.for_statement,
- $.compile_time_for_statement,
- $.send_statement,
- $.block,
- $.hash_statement,
- $.append_statement,
- ),
-
- simple_statement: ($) =>
- choice(
- $.var_declaration,
- $._expression,
- $.assignment_statement,
- alias($.strictly_expression_list, $.expression_list),
- ),
-
- assert_statement: ($) =>
- prec.left(
- seq("assert", $._expression, optional(seq(",", $._expression))),
- ),
-
- append_statement: ($) =>
- prec(
- PREC.unary,
- seq(field("left", $._expression), "<<", field("right", $._expression)),
- ),
-
- send_statement: ($) =>
- prec.right(
- PREC.primary,
- seq(
- field("channel", $._expression),
- "<-",
- field("value", $._expression),
- ),
- ),
-
- var_declaration: ($) =>
- prec.right(
- seq(
- field("var_list", $.expression_list),
- ":=",
- field("expression_list", $.expression_list),
- ),
- ),
-
- var_definition_list: ($) => comma_sep1($.var_definition),
-
- var_definition: ($) =>
- prec(
- PREC.type_initializer,
- seq(optional(field("modifiers", "mut")), field("name", $.identifier)),
- ),
-
- assignment_statement: ($) =>
- seq(
- field("left", $.expression_list),
- field("operator", choice(...assignment_operators)),
- field("right", $.expression_list),
- ),
-
- block: ($) => seq("{", optional($._statement_list), "}"),
-
- defer_statement: ($) => seq("defer", $.block),
-
- label_reference: ($) => $.identifier,
-
- goto_statement: ($) => seq("goto", $.label_reference),
-
- break_statement: ($) =>
- prec.right(seq("break", optional($.label_reference))),
-
- continue_statement: ($) =>
- prec.right(seq("continue", optional($.label_reference))),
-
- return_statement: ($) =>
- prec.right(
- seq("return", optional(field("expression_list", $.expression_list))),
- ),
-
- label_definition: ($) => seq($.identifier, ":"),
-
- labeled_statement: ($) => seq($.label_definition, $._statement),
-
- empty_labeled_statement: ($) => prec.left($.label_definition),
-
- compile_time_for_statement: ($) =>
- seq("$for", $.range_clause, field("body", $.block)),
-
- for_statement: ($) =>
- seq(
- "for",
- optional(choice($.range_clause, $.for_clause, $._expression)),
- field("body", $.block),
- ),
-
- range_clause: ($) =>
- prec.left(
- PREC.primary,
- seq(
- field("left", $.var_definition_list),
- "in",
- field(
- "right",
- choice(alias($._definite_range, $.range), $._expression),
- ),
- ),
- ),
-
- for_clause: ($) =>
- prec.left(
- seq(
- optional(field("initializer", $.simple_statement)),
- ";",
- optional(field("condition", $._expression)),
- ";",
- optional(field("update", $.simple_statement)),
- ),
- ),
-
- _definite_range: ($) =>
- prec(
- PREC.multiplicative,
- seq(
- field("start", $._expression),
- field("operator", choice("..", "...")),
- field("end", $._expression),
- ),
- ),
-
- range: ($) =>
- prec(
- PREC.multiplicative,
- seq(
- optional(field("start", $._expression)),
- field("operator", ".."),
- optional(field("end", $._expression)),
- ),
- ),
-
- hash_statement: () => seq("#", token.immediate(repeat1(/[^\\\r\n]/))),
-
- asm_statement: ($) => seq("asm", $.identifier, $._content_block),
-
- // Loose checking for asm and sql statements
- _content_block: () => seq("{", token.immediate(prec(1, /[^{}]+/)), "}"),
-
- // ==================== ATTRIBUTES ====================
-
- attributes: ($) => repeat1(seq($.attribute, optional(terminator))),
-
- attribute: ($) =>
- seq(
- choice("[", "@["),
- seq($.attribute_expression, repeat(seq(";", $.attribute_expression))),
- "]",
- ),
-
- attribute_expression: ($) =>
- prec(PREC.attributes, choice($.if_attribute, $._plain_attribute)),
-
- // [if some ?]
- // @[if some ?]
- if_attribute: ($) =>
- prec(PREC.attributes, seq("if", $.reference_expression, optional("?"))),
-
- _plain_attribute: ($) =>
- choice($.literal_attribute, $.value_attribute, $.key_value_attribute),
-
- // ['/query']
- // @['/query']
- literal_attribute: ($) => prec(PREC.attributes, $.literal),
-
- value_attribute: ($) =>
- prec(
- PREC.attributes,
- field(
- "name",
- choice(
- alias("unsafe", $.reference_expression),
- $.reference_expression,
- ),
- ),
- ),
-
- // [key]
- // [key: value]
- // @[key]
- // @[key: value]
- key_value_attribute: ($) =>
- prec(
- PREC.attributes,
- seq(
- $.value_attribute,
- ":",
- field("value", choice($.literal, $.identifier)),
- ),
- ),
-
- __dolcbr: (_) => token("${"),
- __rcbr: (_) => token("}"),
- __double_quote: (_) => token('"'),
- __single_quote: (_) => token("'"),
- __c_double_quote: (_) => token('c"'),
- __c_single_quote: (_) => token("c'"),
- __r_double_quote: (_) => token('r"'),
- __r_single_quote: (_) => token("r'"),
- },
-});
-
-/**
- * @param {RuleOrLiteral} rule
- */
-function comp_time(rule) {
- return seq("$", rule);
-}
-
-/**
- * @param {RuleOrLiteral} rules
- */
-function comma_sep1(rules) {
- return seq(rules, repeat(seq(",", rules)));
-}
-
-/**
- * @param {RuleOrLiteral} rule
- */
-function comma_sep(rule) {
- return optional(comma_sep1(rule));
-}
diff --git a/tree_sitter_v/grammar.js b/tree_sitter_v/grammar.js
deleted file mode 120000
index 51bafdea..00000000
--- a/tree_sitter_v/grammar.js
+++ /dev/null
@@ -1 +0,0 @@
-grammar.cjs
\ No newline at end of file
diff --git a/tree_sitter_v/grammar.js b/tree_sitter_v/grammar.js
new file mode 100644
index 00000000..84dbaf71
--- /dev/null
+++ b/tree_sitter_v/grammar.js
@@ -0,0 +1,1329 @@
+/**
+ * @file V grammar for tree-sitter
+ */
+
+/* eslint-disable arrow-parens */
+/* eslint-disable camelcase */
+/* eslint-disable-next-line spaced-comment */
+///
+// @ts-check
+
+const PREC = {
+ attributes: 10,
+ match_arm_type: 9,
+ type_initializer: 8,
+ primary: 7,
+ unary: 6,
+ multiplicative: 5,
+ additive: 4,
+ comparative: 3,
+ and: 2,
+ or: 1,
+ resolve: 1,
+ composite_literal: -1,
+ strictly_expression_list: -2,
+};
+
+const multiplicative_operators = ['*', '/', '%', '<<', '>>', '>>>', '&', '&^'];
+const additive_operators = ['+', '-', '|', '^'];
+const comparative_operators = ['==', '!=', '<', '<=', '>', '>='];
+const assignment_operators = multiplicative_operators
+ .concat(additive_operators)
+ .map((operator) => operator + '=')
+ .concat('=');
+const unary_operators = ['+', '-', '!', '~', '^', '*', '&'];
+const overridable_operators = ['+', '-', '*', '/', '%', '<', '>', '==', '!=', '<=', '>='].map(
+ (operator) => token(operator),
+);
+
+const terminator = choice('\n', '\r', '\r\n');
+
+const unicode_digit = /[0-9]/;
+const unicode_letter = /[a-zA-Zα-ωΑ-Ωµ]/;
+
+const letter = choice(unicode_letter, '_');
+
+const hex_digit = /[0-9a-fA-F]/;
+const octal_digit = /[0-7]/;
+const decimal_digit = /[0-9]/;
+const binary_digit = /[01]/;
+
+const hex_digits = seq(hex_digit, repeat(seq(optional('_'), hex_digit)));
+const octal_digits = seq(octal_digit, repeat(seq(optional('_'), octal_digit)));
+const decimal_digits = seq(decimal_digit, repeat(seq(optional('_'), decimal_digit)));
+const binary_digits = seq(binary_digit, repeat(seq(optional('_'), binary_digit)));
+
+const hex_literal = seq('0', choice('x', 'X'), optional('_'), hex_digits);
+const octal_literal = seq('0', optional(choice('o', 'O')), optional('_'), octal_digits);
+const decimal_literal = choice('0', seq(/[1-9]/, optional(seq(optional('_'), decimal_digits))));
+const binary_literal = seq('0', choice('b', 'B'), optional('_'), binary_digits);
+
+const int_literal = choice(binary_literal, decimal_literal, octal_literal, hex_literal);
+
+const decimal_exponent = seq(choice('e', 'E'), optional(choice('+', '-')), decimal_digits);
+const decimal_float_literal = choice(
+ seq(decimal_digits, '.', decimal_digits, optional(decimal_exponent)),
+ seq(decimal_digits, decimal_exponent),
+ seq('.', decimal_digits, optional(decimal_exponent)),
+);
+
+const hex_exponent = seq(choice('p', 'P'), optional(choice('+', '-')), decimal_digits);
+const hex_mantissa = choice(
+ seq(optional('_'), hex_digits, '.', optional(hex_digits)),
+ seq(optional('_'), hex_digits),
+ seq('.', hex_digits),
+);
+const hex_float_literal = seq('0', choice('x', 'X'), hex_mantissa, hex_exponent);
+const float_literal = choice(decimal_float_literal, hex_float_literal);
+
+const format_flag = token(/[bgGeEfFcdoxXpsS]/);
+
+const semi = choice(terminator, ';');
+const list_separator = choice(semi, ',');
+
+module.exports = grammar({
+ name: 'v',
+
+ extras: ($) => [$.comment, /\s/],
+
+ word: ($) => $.identifier,
+
+ externals: (_) => [],
+
+ inline: ($) => [$._string_literal, $._top_level_declaration, $._array],
+
+ supertypes: ($) => [
+ $._expression,
+ $._statement,
+ $._top_level_declaration,
+ $._expression_with_blocks,
+ ],
+
+ conflicts: ($) => [
+ [$.fixed_array_type, $._expression_without_blocks],
+ [$.qualified_type, $._expression_without_blocks],
+ [$.fixed_array_type, $.literal],
+ [$.reference_expression, $.type_reference_expression],
+ [$.is_expression],
+ [$.not_is_expression],
+ [$._type_union_list],
+ [$._expression_without_blocks, $.element_list],
+ ],
+
+ rules: {
+ source_file: ($) =>
+ seq(
+ optional($.shebang),
+ optional($.module_clause),
+ optional($.import_list),
+ repeat(
+ choice(
+ seq($._top_level_declaration, optional(terminator)),
+ seq($._statement, optional(terminator)),
+ ),
+ ),
+ ),
+
+ shebang: (_) => token(/\#\!([^\\\r\n]+)+/),
+
+ // http://stackoverflow.com/questions/13014947/regex-to-match-a-c-style-multiline-comment/36328890#36328890
+ comment: (_) =>
+ token(
+ choice(
+ /\/\/[^\n\r]*/,
+ /\/\*(?:[^\/][^\*]+\/\*+[^\/][^\*]+)+(?:[^\*][^\/]+\*+\/[^\*][^\/]+)+\//,
+ /\/\*[^\*]*\*\//,
+ ),
+ ),
+
+ module_clause: ($) => seq(optional($.attributes), 'module', $.identifier),
+
+ import_list: ($) => repeat1($.import_declaration),
+
+ import_declaration: ($) => seq('import', $.import_spec, semi),
+
+ import_spec: ($) =>
+ seq($.import_path, optional($.import_alias), optional($.selective_import_list)),
+
+ // foo.bar.baz
+ import_path: ($) => seq($.import_name, repeat(seq('.', $.import_name))),
+
+ // foo
+ import_name: ($) => $.identifier,
+
+ // foo as bar
+ // ^^^^^^
+ import_alias: ($) => seq('as', $.import_name),
+
+ // { foo, bar }
+ selective_import_list: ($) =>
+ seq(
+ '{',
+ $.reference_expression,
+ repeat(seq(choice(',', terminator), optional($.reference_expression))),
+ '}',
+ ),
+
+ // ==================== TOP LEVEL DECLARATIONS ====================
+
+ _top_level_declaration: ($) =>
+ choice(
+ $.const_declaration,
+ $.global_var_declaration,
+ $.type_declaration,
+ $.function_declaration,
+ $.static_method_declaration,
+ $.struct_declaration,
+ $.enum_declaration,
+ $.interface_declaration,
+ ),
+
+ const_declaration: ($) =>
+ seq(
+ optional(field('attributes', $.attributes)),
+ optional($.visibility_modifiers),
+ 'const',
+ choice($.const_definition, seq('(', repeat(seq($.const_definition, semi)), ')')),
+ ),
+
+ const_definition: ($) => seq(field('name', $.identifier), '=', field('value', $._expression)),
+
+ global_var_declaration: ($) =>
+ seq(
+ optional(field('attributes', $.attributes)),
+ '__global',
+ choice($.global_var_definition, seq('(', repeat(seq($.global_var_definition, semi)), ')')),
+ ),
+
+ global_var_definition: ($) =>
+ seq(field('name', $.identifier), choice($.plain_type, $._global_var_value)),
+
+ _global_var_value: ($) => seq('=', field('value', $._expression)),
+
+ type_declaration: ($) =>
+ seq(
+ optional($.visibility_modifiers),
+ 'type',
+ field('name', $.identifier),
+ optional(field('generic_parameters', $.generic_parameters)),
+ '=',
+ field('types', $._type_union_list),
+ ),
+
+ // int | string | Foo
+ _type_union_list: ($) =>
+ seq($.plain_type, repeat(seq(optional(terminator), '|', $.plain_type))),
+
+ function_declaration: ($) =>
+ prec.right(
+ PREC.resolve,
+ seq(
+ optional(field('attributes', $.attributes)),
+ optional($.visibility_modifiers),
+ 'fn',
+ optional(field('receiver', $.receiver)),
+ field('name', $._function_name),
+ optional(field('generic_parameters', $.generic_parameters)),
+ field('signature', $.signature),
+ optional(field('body', $.block)),
+ ),
+ ),
+
+ static_method_declaration: ($) =>
+ prec.right(
+ PREC.resolve,
+ seq(
+ optional(field('attributes', $.attributes)),
+ optional($.visibility_modifiers),
+ 'fn',
+ field('static_receiver', $.static_receiver),
+ '.',
+ field('name', $._function_name),
+ optional(field('generic_parameters', $.generic_parameters)),
+ field('signature', $.signature),
+ optional(field('body', $.block)),
+ ),
+ ),
+
+ static_receiver: ($) => $.reference_expression,
+
+ _function_name: ($) => choice($.identifier, $.overridable_operator),
+
+ overridable_operator: () => choice(...overridable_operators),
+
+ receiver: ($) =>
+ prec(
+ PREC.primary,
+ seq(
+ '(',
+ seq(
+ optional(field('mutability', $.mutability_modifiers)),
+ field('name', $.identifier),
+ field('type', alias($._plain_type_without_special, $.plain_type)),
+ ),
+ ')',
+ ),
+ ),
+
+ signature: ($) =>
+ prec.right(
+ seq(
+ field('parameters', choice($.parameter_list, $.type_parameter_list)),
+ optional(field('result', $.plain_type)),
+ ),
+ ),
+
+ parameter_list: ($) => prec(PREC.resolve, seq('(', comma_sep($.parameter_declaration), ')')),
+
+ parameter_declaration: ($) =>
+ seq(
+ optional(field('mutability', $.mutability_modifiers)),
+ field('name', $.identifier),
+ optional(field('variadic', '...')),
+ field('type', $.plain_type),
+ ),
+
+ type_parameter_list: ($) => seq('(', comma_sep($.type_parameter_declaration), ')'),
+
+ type_parameter_declaration: ($) =>
+ prec(
+ PREC.primary,
+ seq(
+ optional($.mutability_modifiers),
+ optional(field('variadic', '...')),
+ field('type', $.plain_type),
+ ),
+ ),
+
+ // fn foo[T, T2]() {}
+ // ^^^^^^^
+ generic_parameters: ($) =>
+ prec(
+ PREC.resolve,
+ seq(
+ choice(token.immediate('['), token.immediate('<')),
+ comma_sep1($.generic_parameter),
+ optional(','),
+ choice(']', '>'),
+ ),
+ ),
+
+ generic_parameter: ($) => $.identifier,
+
+ struct_declaration: ($) =>
+ seq(
+ optional(field('attributes', $.attributes)),
+ optional($.visibility_modifiers),
+ choice('struct', 'union'),
+ field('name', $.identifier),
+ optional(field('generic_parameters', $.generic_parameters)),
+ $._struct_body,
+ ),
+
+ _struct_body: ($) =>
+ seq(
+ '{',
+ repeat(
+ choice(
+ seq($.struct_field_scope, optional(terminator)),
+ seq($.struct_field_declaration, optional(terminator)),
+ ),
+ ),
+ '}',
+ ),
+
+ // pub:
+ // mut:
+ // pub mut:
+ // __global:
+ struct_field_scope: () => seq(choice('pub', 'mut', seq('pub', 'mut'), '__global'), ':'),
+
+ struct_field_declaration: ($) => choice($._struct_field_definition, $.embedded_definition),
+
+ _struct_field_definition: ($) =>
+ prec.right(
+ PREC.type_initializer,
+ seq(
+ field('name', $.identifier),
+ field('type', $.plain_type),
+ optional(seq('=', field('default_value', $._expression))),
+ optional(field('attributes', $.attribute)),
+ ),
+ ),
+
+ embedded_definition: ($) =>
+ choice($.type_reference_expression, $.qualified_type, $.generic_type),
+
+ enum_declaration: ($) =>
+ seq(
+ optional(field('attributes', $.attributes)),
+ optional($.visibility_modifiers),
+ 'enum',
+ field('name', $.identifier),
+ optional($.enum_backed_type),
+ $._enum_body,
+ ),
+
+ enum_backed_type: ($) => seq('as', $.plain_type),
+
+ _enum_body: ($) => seq('{', repeat(seq($.enum_field_definition, optional(terminator))), '}'),
+
+ enum_field_definition: ($) =>
+ seq(
+ field('name', $.identifier),
+ optional(seq('=', field('value', $._expression))),
+ optional(field('attributes', $.attribute)),
+ ),
+
+ interface_declaration: ($) =>
+ seq(
+ optional(field('attributes', $.attributes)),
+ optional($.visibility_modifiers),
+ 'interface',
+ field('name', $.identifier),
+ optional(field('generic_parameters', $.generic_parameters)),
+ $._interface_body,
+ ),
+
+ _interface_body: ($) =>
+ seq(
+ '{',
+ repeat(
+ choice(
+ seq($.struct_field_scope, optional(terminator)),
+ seq($.struct_field_declaration, optional(terminator)),
+ seq($.interface_method_definition, optional(terminator)),
+ ),
+ ),
+ '}',
+ ),
+
+ interface_method_definition: ($) =>
+ prec.right(
+ seq(
+ field('name', $.identifier),
+ optional(field('generic_parameters', $.generic_parameters)),
+ field('signature', $.signature),
+ optional(field('attributes', $.attribute)),
+ ),
+ ),
+
+ // ==================== EXPRESSIONS ====================
+
+ _expression: ($) => choice($._expression_without_blocks, $._expression_with_blocks),
+
+ _expression_without_blocks: ($) =>
+ choice(
+ $.parenthesized_expression,
+ $.go_expression,
+ $.spawn_expression,
+ $.call_expression,
+ $.function_literal,
+ $.reference_expression,
+ $._max_group,
+ $.array_creation,
+ $.fixed_array_creation,
+ $.unary_expression,
+ $.receive_expression,
+ $.binary_expression,
+ $.is_expression,
+ $.not_is_expression,
+ $.in_expression,
+ $.not_in_expression,
+ $.index_expression,
+ $.slice_expression,
+ $.as_type_cast_expression,
+ $.selector_expression,
+ $.enum_fetch,
+ $.inc_expression,
+ $.dec_expression,
+ $.or_block_expression,
+ $.option_propagation_expression,
+ $.result_propagation_expression,
+ ),
+
+ _expression_with_blocks: ($) =>
+ choice(
+ $.type_initializer,
+ $.anon_struct_value_expression,
+ $.if_expression,
+ $.match_expression,
+ $.select_expression,
+ $.sql_expression,
+ $.lock_expression,
+ $.unsafe_expression,
+ $.compile_time_if_expression,
+ $.map_init_expression,
+ ),
+
+ strictly_expression_list: ($) =>
+ prec(
+ PREC.strictly_expression_list,
+ seq(
+ choice($._expression, $.mutable_expression),
+ ',',
+ comma_sep1(choice($._expression, $.mutable_expression)),
+ ),
+ ),
+
+ inc_expression: ($) => seq($._expression, '++'),
+
+ dec_expression: ($) => seq($._expression, '--'),
+
+ or_block_expression: ($) => seq($._expression, $.or_block),
+
+ option_propagation_expression: ($) => prec(PREC.match_arm_type, seq($._expression, '?')),
+
+ result_propagation_expression: ($) => prec(PREC.match_arm_type, seq($._expression, '!')),
+
+ anon_struct_value_expression: ($) =>
+ seq(
+ 'struct',
+ '{',
+ choice(
+ field('element_list', $.element_list),
+ // For short struct init syntax
+ field('short_element_list', $.short_element_list),
+ ),
+ '}',
+ ),
+
+ go_expression: ($) => prec.left(PREC.composite_literal, seq('go', $._expression)),
+
+ spawn_expression: ($) => prec.left(PREC.composite_literal, seq('spawn', $._expression)),
+
+ parenthesized_expression: ($) => seq('(', field('expression', $._expression), ')'),
+
+ call_expression: ($) =>
+ prec.right(
+ PREC.primary,
+ choice(
+ seq(field('function', token('json.decode')), field('arguments', $.special_argument_list)),
+ seq(
+ field('name', $._expression),
+ optional(field('type_parameters', $.type_parameters)),
+ field('arguments', $.argument_list),
+ ),
+ ),
+ ),
+
+ type_parameters: ($) =>
+ prec.dynamic(2, seq(token.immediate('['), comma_sep1($.plain_type), ']')),
+
+ argument_list: ($) =>
+ seq('(', choice(repeat(seq($.argument, optional(list_separator))), $.short_lambda), ')'),
+
+ short_lambda: ($) =>
+ seq('|', comma_sep($.reference_expression), '|', $._expression_without_blocks),
+
+ argument: ($) =>
+ choice($._expression, $.mutable_expression, $.keyed_element, $.spread_expression),
+
+ special_argument_list: ($) =>
+ seq(
+ '(',
+ alias($._plain_type_without_special, $.plain_type),
+ optional(seq(',', $._expression)),
+ ')',
+ ),
+
+ type_initializer: ($) =>
+ prec(
+ PREC.type_initializer,
+ seq(field('type', $.plain_type), field('body', $.type_initializer_body)),
+ ),
+
+ type_initializer_body: ($) =>
+ seq(
+ '{',
+ optional(
+ choice(
+ field('element_list', $.element_list),
+ // For short struct init syntax
+ field('short_element_list', $.short_element_list),
+ ),
+ ),
+ '}',
+ ),
+
+ element_list: ($) =>
+ repeat1(
+ seq(
+ choice($.spread_expression, $.keyed_element, $.reference_expression),
+ optional(list_separator),
+ ),
+ ),
+
+ short_element_list: ($) =>
+ repeat1(seq(alias($._expression, $.element), optional(list_separator))),
+
+ keyed_element: ($) =>
+ seq(
+ field('key', alias($.reference_expression, $.field_name)),
+ ':',
+ field('value', $._expression),
+ ),
+
+ function_literal: ($) =>
+ prec.right(
+ seq(
+ 'fn',
+ optional(field('capture_list', $.capture_list)),
+ optional(field('generic_parameters', $.generic_parameters)),
+ field('signature', $.signature),
+ field('body', $.block),
+ ),
+ ),
+
+ capture_list: ($) => seq('[', comma_sep($.capture), optional(','), ']'),
+
+ capture: ($) => seq(optional($.mutability_modifiers), $.reference_expression),
+
+ reference_expression: ($) => prec.left($.identifier),
+ type_reference_expression: ($) => prec.left($.identifier),
+
+ unary_expression: ($) =>
+ prec(
+ PREC.unary,
+ seq(field('operator', choice(...unary_operators)), field('operand', $._expression)),
+ ),
+
+ receive_expression: ($) =>
+ prec.right(PREC.unary, seq(field('operator', '<-'), field('operand', $._expression))),
+
+ binary_expression: ($) => {
+ const table = [
+ [PREC.multiplicative, choice(...multiplicative_operators)],
+ [PREC.additive, choice(...additive_operators)],
+ [PREC.comparative, choice(...comparative_operators)],
+ [PREC.and, '&&'],
+ [PREC.or, '||'],
+ ];
+
+ return choice(
+ ...table.map(([precedence, operator]) =>
+ prec.left(
+ Number(precedence),
+ seq(
+ field('left', $._expression),
+ // @ts-ignore
+ field('operator', operator),
+ field('right', $._expression),
+ ),
+ ),
+ ),
+ );
+ },
+
+ as_type_cast_expression: ($) => seq($._expression, 'as', $.plain_type),
+
+ compile_time_selector_expression: ($) =>
+ comp_time(seq('(', choice($.reference_expression, $.selector_expression), ')')),
+
+ or_block: ($) => seq('or', field('block', $.block)),
+
+ _max_group: ($) => prec.left(PREC.resolve, choice($.pseudo_compile_time_identifier, $.literal)),
+
+ escape_sequence: () =>
+ token(
+ prec(
+ 1,
+ seq(
+ '\\',
+ choice(
+ /u[a-fA-F\d]{4}/,
+ /U[a-fA-F\d]{8}/,
+ /x[a-fA-F\d]{2}/,
+ /\d{3}/,
+ /\r?\n/,
+ /['"abfrntv$\\]/,
+ /\S/,
+ ),
+ ),
+ ),
+ ),
+
+ literal: ($) =>
+ choice(
+ $.int_literal,
+ $.float_literal,
+ $._string_literal,
+ $.rune_literal,
+ $.none,
+ $.true,
+ $.false,
+ $.nil,
+ ),
+
+ none: () => 'none',
+ true: () => 'true',
+ false: () => 'false',
+ nil: () => 'nil',
+
+ spread_expression: ($) => prec.right(PREC.unary, seq('...', $._expression)),
+
+ map_init_expression: ($) =>
+ prec(
+ PREC.composite_literal,
+ seq('{', repeat(seq($.map_keyed_element, optional(list_separator))), '}'),
+ ),
+
+ map_keyed_element: ($) => seq(field('key', $._expression), ':', field('value', $._expression)),
+
+ array_creation: ($) => prec.right(PREC.multiplicative, $._array),
+
+ fixed_array_creation: ($) => prec.right(PREC.multiplicative, seq($._array, '!')),
+
+ _array: ($) => seq('[', repeat(seq($._expression, optional(','))), ']'),
+
+ selector_expression: ($) =>
+ prec.dynamic(
+ -1,
+ prec(
+ PREC.primary,
+ seq(
+ field('operand', $._expression),
+ choice('.', '?.'),
+ field('field', choice($.reference_expression, $.compile_time_selector_expression)),
+ ),
+ ),
+ ),
+
+ index_expression: ($) =>
+ prec.dynamic(
+ -1,
+ prec.right(
+ PREC.primary,
+ seq(
+ field('operand', $._expression),
+ choice('[', token.immediate('['), token('#[')),
+ field('index', $._expression),
+ ']',
+ ),
+ ),
+ ),
+
+ slice_expression: ($) =>
+ prec(
+ PREC.primary,
+ seq(
+ field('operand', $._expression),
+ choice('[', token.immediate('['), token('#[')),
+ $.range,
+ ']',
+ ),
+ ),
+
+ if_expression: ($) =>
+ seq(
+ 'if',
+ choice(field('condition', $._expression), field('guard', $.var_declaration)),
+ field('block', $.block),
+ optional($.else_branch),
+ ),
+
+ else_branch: ($) =>
+ seq('else', field('else_branch', choice(field('block', $.block), $.if_expression))),
+
+ compile_time_if_expression: ($) =>
+ seq(
+ '$if',
+ field('condition', seq($._expression, optional('?'))),
+ field('block', $.block),
+ optional(seq('$else', field('else_branch', choice($.block, $.compile_time_if_expression)))),
+ ),
+
+ is_expression: ($) =>
+ prec.dynamic(
+ 2,
+ seq(
+ field('left', seq(optional($.mutability_modifiers), $._expression)),
+ 'is',
+ field('right', $.plain_type),
+ ),
+ ),
+
+ not_is_expression: ($) =>
+ prec.dynamic(
+ 2,
+ seq(
+ field('left', seq(optional($.mutability_modifiers), $._expression)),
+ '!is',
+ field('right', $.plain_type),
+ ),
+ ),
+
+ in_expression: ($) =>
+ prec.left(
+ PREC.comparative,
+ seq(field('left', $._expression), 'in', field('right', $._expression)),
+ ),
+
+ not_in_expression: ($) =>
+ prec.left(
+ PREC.comparative,
+ seq(field('left', $._expression), '!in', field('right', $._expression)),
+ ),
+
+ enum_fetch: ($) => prec.dynamic(-1, seq('.', $.reference_expression)),
+
+ match_expression: ($) =>
+ seq(
+ 'match',
+ field('condition', choice($._expression, $.mutable_expression)),
+ '{',
+ optional($.match_arms),
+ '}',
+ ),
+
+ match_arms: ($) => repeat1(choice($.match_arm, $.match_else_arm_clause)),
+
+ match_arm: ($) => seq(field('value', $.match_expression_list), field('block', $.block)),
+
+ match_expression_list: ($) =>
+ comma_sep1(
+ choice($._expression_without_blocks, $.match_arm_type, alias($._definite_range, $.range)),
+ ),
+
+ match_arm_type: ($) => prec(PREC.match_arm_type, $.plain_type),
+
+ match_else_arm_clause: ($) => seq('else', field('block', $.block)),
+
+ select_expression: ($) =>
+ seq(
+ 'select',
+ optional(field('selected_variables', $.expression_list)),
+ '{',
+ repeat($.select_arm),
+ optional($.select_else_arn_clause),
+ '}',
+ ),
+
+ select_arm: ($) => seq($.select_arm_statement, $.block),
+
+ select_arm_statement: ($) =>
+ prec.left(
+ choice(
+ alias($.select_var_declaration, $.var_declaration),
+ $.send_statement,
+ seq(
+ alias($.expression_without_blocks_list, $.expression_list),
+ optional($._select_arm_assignment_statement),
+ ),
+ ),
+ ),
+
+ _select_arm_assignment_statement: ($) =>
+ seq(
+ choice(...assignment_operators),
+ alias($.expression_without_blocks_list, $.expression_list),
+ ),
+
+ select_var_declaration: ($) =>
+ prec.left(
+ seq(
+ field('var_list', $.identifier_list),
+ ':=',
+ field('expression_list', alias($.expression_without_blocks_list, $.expression_list)),
+ ),
+ ),
+
+ select_else_arn_clause: ($) => seq('else', $.block),
+
+ lock_expression: ($) =>
+ seq(
+ choice('lock', 'rlock'),
+ optional(field('locked_variables', $.expression_list)),
+ field('body', $.block),
+ ),
+
+ unsafe_expression: ($) => seq('unsafe', $.block),
+
+ // TODO: this should be put into a separate grammar to avoid any "noise"
+ sql_expression: ($) => prec(PREC.resolve, seq('sql', optional($.identifier), $._content_block)),
+
+ // ==================== LITERALS ====================
+
+ int_literal: () => token(int_literal),
+
+ float_literal: () => token(float_literal),
+
+ rune_literal: () =>
+ token(
+ seq(
+ '`',
+ choice(
+ /[^'\\]/,
+ "'",
+ '"',
+ seq(
+ '\\',
+ choice(
+ '0',
+ '`',
+ seq('x', hex_digit, hex_digit),
+ seq(octal_digit, octal_digit, octal_digit),
+ seq('u', hex_digit, hex_digit, hex_digit, hex_digit),
+ seq(
+ 'U',
+ hex_digit,
+ hex_digit,
+ hex_digit,
+ hex_digit,
+ hex_digit,
+ hex_digit,
+ hex_digit,
+ hex_digit,
+ ),
+ seq(choice('a', 'b', 'e', 'f', 'n', 'r', 't', 'v', '\\', "'", '"')),
+ ),
+ ),
+ ),
+ '`',
+ ),
+ ),
+
+ _string_literal: ($) =>
+ choice($.c_string_literal, $.raw_string_literal, $.interpreted_string_literal),
+
+ c_string_literal: ($) =>
+ prec(
+ 1,
+ choice(
+ seq(
+ $.__c_single_quote,
+ repeat(
+ choice(
+ token.immediate(prec.right(1, /[^'\\$]+/)),
+ $.escape_sequence,
+ $.string_interpolation,
+ ),
+ ),
+ $.__single_quote,
+ ),
+ seq(
+ $.__c_double_quote,
+ repeat(
+ choice(
+ token.immediate(prec.right(1, /[^"\\$]+/)),
+ $.escape_sequence,
+ $.string_interpolation,
+ ),
+ ),
+ $.__double_quote,
+ ),
+ ),
+ ),
+
+ raw_string_literal: ($) =>
+ prec(
+ 1,
+ choice(
+ seq(
+ $.__r_single_quote,
+ repeat(token.immediate(prec.right(1, /[^']+/))),
+ $.__single_quote,
+ ),
+ seq(
+ $.__r_double_quote,
+ repeat(token.immediate(prec.right(1, /[^"]+/))),
+ $.__double_quote,
+ ),
+ ),
+ ),
+
+ interpreted_string_literal: ($) =>
+ prec(
+ 1,
+ choice(
+ seq(
+ $.__single_quote,
+ repeat(
+ choice(
+ token.immediate(prec.right(1, /[^'\\$]+/)),
+ $.escape_sequence,
+ $.string_interpolation,
+ ),
+ ),
+ $.__single_quote,
+ ),
+ seq(
+ $.__double_quote,
+ repeat(
+ choice(
+ token.immediate(prec.right(1, /[^"\\$]+/)),
+ $.escape_sequence,
+ $.string_interpolation,
+ ),
+ ),
+ $.__double_quote,
+ ),
+ ),
+ ),
+
+ string_interpolation: ($) =>
+ seq(
+ alias($.__dolcbr, $.interpolation_opening),
+ choice(
+ repeat(alias($._expression, $.interpolation_expression)),
+ seq(alias($._expression, $.interpolation_expression), $.format_specifier),
+ ),
+ alias($.__rcbr, $.interpolation_closing),
+ ),
+
+ format_specifier: ($) =>
+ seq(
+ token(':'),
+ choice(
+ format_flag,
+ seq(
+ optional(choice(token(/[+\-]/), token('0'))),
+ optional($.int_literal),
+ optional(seq('.', $.int_literal)),
+ optional(format_flag),
+ ),
+ ),
+ ),
+
+ pseudo_compile_time_identifier: ($) =>
+ token(seq('@', alias(token.immediate(/[A-Z][A-Z0-9_]+/), $.identifier))),
+
+ identifier: () =>
+ token(
+ seq(
+ optional('@'),
+ optional('$'),
+ optional('C.'),
+ optional('JS.'),
+ choice(unicode_letter, '_'),
+ repeat(choice(letter, unicode_digit)),
+ ),
+ ),
+
+ visibility_modifiers: () => prec.left(choice('pub', '__global')),
+
+ mutability_modifiers: () =>
+ prec.left(
+ PREC.resolve,
+ choice(seq('mut', optional('static'), optional('volatile')), 'shared'),
+ ),
+
+ mutable_identifier: ($) => prec(PREC.resolve, seq($.mutability_modifiers, $.identifier)),
+
+ mutable_expression: ($) => prec(PREC.resolve, seq($.mutability_modifiers, $._expression)),
+
+ identifier_list: ($) => prec(PREC.and, comma_sep1(choice($.mutable_identifier, $.identifier))),
+
+ expression_list: ($) =>
+ prec(PREC.resolve, comma_sep1(choice($._expression, $.mutable_expression))),
+
+ expression_without_blocks_list: ($) =>
+ prec(PREC.resolve, comma_sep1($._expression_without_blocks)),
+
+ // ==================== TYPES ====================
+
+ plain_type: ($) =>
+ prec.right(
+ PREC.primary,
+ choice($._plain_type_without_special, $.option_type, $.result_type, $.multi_return_type),
+ ),
+
+ _plain_type_without_special: ($) =>
+ prec.right(
+ PREC.primary,
+ choice(
+ $.type_reference_expression,
+ $.qualified_type,
+ $.pointer_type,
+ $.wrong_pointer_type,
+ $.array_type,
+ $.fixed_array_type,
+ $.function_type,
+ $.generic_type,
+ $.map_type,
+ $.channel_type,
+ $.shared_type,
+ $.thread_type,
+ $.atomic_type,
+ $.anon_struct_type,
+ ),
+ ),
+
+ anon_struct_type: ($) => seq('struct', $._struct_body),
+
+ multi_return_type: ($) => seq('(', comma_sep1($.plain_type), optional(','), ')'),
+
+ result_type: ($) => prec.right(seq('!', optional($.plain_type))),
+
+ option_type: ($) => prec.right(seq('?', optional($.plain_type))),
+
+ qualified_type: ($) =>
+ seq(field('module', $.reference_expression), '.', field('name', $.type_reference_expression)),
+
+ fixed_array_type: ($) =>
+ seq(
+ '[',
+ field('size', choice($.int_literal, $.reference_expression, $.selector_expression)),
+ ']',
+ field('element', $.plain_type),
+ ),
+
+ array_type: ($) =>
+ prec(PREC.primary, prec.dynamic(2, seq('[', ']', field('element', $.plain_type)))),
+
+ variadic_type: ($) => seq('...', $.plain_type),
+
+ pointer_type: ($) => prec(PREC.match_arm_type, seq('&', $.plain_type)),
+
+ // In languages like Go, pointers use an asterisk, not an ampersand,
+ // so this rule is needed to properly parse and then give an error to the user.
+ wrong_pointer_type: ($) => prec(PREC.match_arm_type, seq('*', $.plain_type)),
+
+ map_type: ($) => seq('map[', field('key', $.plain_type), ']', field('value', $.plain_type)),
+
+ channel_type: ($) => prec.right(PREC.primary, seq('chan', $.plain_type)),
+
+ shared_type: ($) => seq('shared', $.plain_type),
+
+ thread_type: ($) => seq('thread', $.plain_type),
+
+ atomic_type: ($) => seq('atomic', $.plain_type),
+
+ generic_type: ($) =>
+ seq(choice($.qualified_type, $.type_reference_expression), $.type_parameters),
+
+ function_type: ($) => prec.right(seq('fn', field('signature', $.signature))),
+
+ // ==================== TYPES END ====================
+
+ // ==================== STATEMENTS ====================
+
+ _statement_list: ($) =>
+ choice(
+ seq(
+ $._statement,
+ repeat(seq(terminator, $._statement)),
+ optional(
+ seq(terminator, optional(alias($.empty_labeled_statement, $.labeled_statement))),
+ ),
+ ),
+ alias($.empty_labeled_statement, $.labeled_statement),
+ ),
+
+ _statement: ($) =>
+ choice(
+ $.simple_statement,
+ $.assert_statement,
+ $.continue_statement,
+ $.break_statement,
+ $.return_statement,
+ $.asm_statement,
+ $.goto_statement,
+ $.labeled_statement,
+ $.defer_statement,
+ $.for_statement,
+ $.compile_time_for_statement,
+ $.send_statement,
+ $.block,
+ $.hash_statement,
+ $.append_statement,
+ ),
+
+ simple_statement: ($) =>
+ choice(
+ $.var_declaration,
+ $._expression,
+ $.assignment_statement,
+ alias($.strictly_expression_list, $.expression_list),
+ ),
+
+ assert_statement: ($) =>
+ prec.left(seq('assert', $._expression, optional(seq(',', $._expression)))),
+
+ append_statement: ($) =>
+ prec(PREC.unary, seq(field('left', $._expression), '<<', field('right', $._expression))),
+
+ send_statement: ($) =>
+ prec.right(
+ PREC.primary,
+ seq(field('channel', $._expression), '<-', field('value', $._expression)),
+ ),
+
+ var_declaration: ($) =>
+ prec.right(
+ seq(
+ field('var_list', $.expression_list),
+ ':=',
+ field('expression_list', $.expression_list),
+ ),
+ ),
+
+ var_definition_list: ($) => comma_sep1($.var_definition),
+
+ var_definition: ($) =>
+ prec(
+ PREC.type_initializer,
+ seq(optional(field('modifiers', 'mut')), field('name', $.identifier)),
+ ),
+
+ assignment_statement: ($) =>
+ seq(
+ field('left', $.expression_list),
+ field('operator', choice(...assignment_operators)),
+ field('right', $.expression_list),
+ ),
+
+ block: ($) => seq('{', optional($._statement_list), '}'),
+
+ defer_statement: ($) => seq('defer', $.block),
+
+ label_reference: ($) => $.identifier,
+
+ goto_statement: ($) => seq('goto', $.label_reference),
+
+ break_statement: ($) => prec.right(seq('break', optional($.label_reference))),
+
+ continue_statement: ($) => prec.right(seq('continue', optional($.label_reference))),
+
+ return_statement: ($) =>
+ prec.right(seq('return', optional(field('expression_list', $.expression_list)))),
+
+ label_definition: ($) => seq($.identifier, ':'),
+
+ labeled_statement: ($) => seq($.label_definition, $._statement),
+
+ empty_labeled_statement: ($) => prec.left($.label_definition),
+
+ compile_time_for_statement: ($) => seq('$for', $.range_clause, field('body', $.block)),
+
+ for_statement: ($) =>
+ seq(
+ 'for',
+ optional(choice($.range_clause, $.for_clause, $._expression)),
+ field('body', $.block),
+ ),
+
+ range_clause: ($) =>
+ prec.left(
+ PREC.primary,
+ seq(
+ field('left', $.var_definition_list),
+ 'in',
+ field('right', choice(alias($._definite_range, $.range), $._expression)),
+ ),
+ ),
+
+ for_clause: ($) =>
+ prec.left(
+ seq(
+ optional(field('initializer', $.simple_statement)),
+ ';',
+ optional(field('condition', $._expression)),
+ ';',
+ optional(field('update', $.simple_statement)),
+ ),
+ ),
+
+ _definite_range: ($) =>
+ prec(
+ PREC.multiplicative,
+ seq(
+ field('start', $._expression),
+ field('operator', choice('..', '...')),
+ field('end', $._expression),
+ ),
+ ),
+
+ range: ($) =>
+ prec(
+ PREC.multiplicative,
+ seq(
+ optional(field('start', $._expression)),
+ field('operator', '..'),
+ optional(field('end', $._expression)),
+ ),
+ ),
+
+ hash_statement: () => seq('#', token.immediate(repeat1(/[^\\\r\n]/))),
+
+ asm_statement: ($) => seq('asm', $.identifier, $._content_block),
+
+ // Loose checking for asm and sql statements
+ _content_block: () => seq('{', token.immediate(prec(1, /[^{}]+/)), '}'),
+
+ // ==================== ATTRIBUTES ====================
+
+ attributes: ($) => repeat1(seq($.attribute, optional(terminator))),
+
+ attribute: ($) =>
+ seq(
+ choice('[', '@['),
+ seq($.attribute_expression, repeat(seq(';', $.attribute_expression))),
+ ']',
+ ),
+
+ attribute_expression: ($) => prec(PREC.attributes, choice($.if_attribute, $._plain_attribute)),
+
+ // [if some ?]
+ // @[if some ?]
+ if_attribute: ($) => prec(PREC.attributes, seq('if', $.reference_expression, optional('?'))),
+
+ _plain_attribute: ($) => choice($.literal_attribute, $.value_attribute, $.key_value_attribute),
+
+ // ['/query']
+ // @['/query']
+ literal_attribute: ($) => prec(PREC.attributes, $.literal),
+
+ value_attribute: ($) =>
+ prec(
+ PREC.attributes,
+ field('name', choice(alias('unsafe', $.reference_expression), $.reference_expression)),
+ ),
+
+ // [key]
+ // [key: value]
+ // @[key]
+ // @[key: value]
+ key_value_attribute: ($) =>
+ prec(
+ PREC.attributes,
+ seq($.value_attribute, ':', field('value', choice($.literal, $.identifier))),
+ ),
+
+ __dolcbr: (_) => token('${'),
+ __rcbr: (_) => token('}'),
+ __double_quote: (_) => token('"'),
+ __single_quote: (_) => token("'"),
+ __c_double_quote: (_) => token('c"'),
+ __c_single_quote: (_) => token("c'"),
+ __r_double_quote: (_) => token('r"'),
+ __r_single_quote: (_) => token("r'"),
+ },
+});
+
+/**
+ * @param {RuleOrLiteral} rule
+ *
+ * @return {SeqRule}
+ */
+function comp_time(rule) {
+ return seq('$', rule);
+}
+
+/**
+ * @param {RuleOrLiteral} rules
+ *
+ * @return {SeqRule}
+ */
+function comma_sep1(rules) {
+ return seq(rules, repeat(seq(',', rules)));
+}
+
+/**
+ * @param {RuleOrLiteral} rule
+ *
+ * @return {ChoiceRule}
+ */
+function comma_sep(rule) {
+ return optional(comma_sep1(rule));
+}
diff --git a/tree_sitter_v/package.json b/tree_sitter_v/package.json
index 5871ea80..d20e1d0f 100644
--- a/tree_sitter_v/package.json
+++ b/tree_sitter_v/package.json
@@ -15,7 +15,9 @@
"parseg": "tree-sitter parse --debug-graph",
"install": "node-gyp-build",
"prebuildify": "prebuildify --napi --strip",
- "format": "prettier --write \"**/*.cjs\""
+ "lint": "eslint \"**/*.js\"",
+ "format": "prettier --write \"**/*.js\"",
+ "format:check": "prettier --check \"**/*.js\""
},
"dependencies": {
"node-addon-api": "^8.0.0",
@@ -30,9 +32,12 @@
}
},
"devDependencies": {
+ "eslint": "^8.57.0",
+ "eslint-config-google": "^0.14.0",
+ "eslint-config-prettier": "^9.1.0",
+ "prebuildify": "^6.0.0",
"prettier": "^3.2.5",
- "tree-sitter-cli": "^0.22.2",
- "prebuildify": "^6.0.0"
+ "tree-sitter-cli": "^0.22.2"
},
"tree-sitter": [
{