diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 000000000..de1cc0506 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,21 @@ +module.exports = { + 'env': { + 'commonjs': true, + 'es2021': true, + }, + 'extends': 'google', + 'overrides': [ + ], + 'parserOptions': { + 'ecmaVersion': 'latest', + 'sourceType': 'module', + }, + 'rules': { + 'indent': ['error', 2, {'SwitchCase': 1}], + 'max-len': [ + 'error', + {'code': 160, 'ignoreComments': true, 'ignoreUrls': true, 'ignoreStrings': true}, + ], + 'one-var': ['error', 'consecutive'], + }, +}; diff --git a/.gitattributes b/.gitattributes index f60d7b977..c647c2bf4 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,6 @@ /src/** linguist-vendored /examples/* linguist-vendored + +src/grammar.json -diff +src/node-types.json -diff +src/parser.c -diff diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 000000000..d94f7f39d --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,19 @@ +name: Lint + +on: + push: + branches: + - master + pull_request: + branches: + - "**" + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Install modules + run: npm install + - name: Run ESLint + run: npm run lint diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..c2020e92f --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,103 @@ +name: Release + +on: + workflow_run: + workflows: ["CI"] + branches: + - master + types: + - completed + +jobs: + release: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Get previous commit SHA + id: get_previous_commit + run: | + LATEST_TAG=$(git describe --tags --abbrev=0) + if [[ -z "$LATEST_TAG" ]]; then + echo "No tag found. Failing..." + exit 1 + fi + echo "latest_tag=${LATEST_TAG#v}" >> "$GITHUB_ENV" # Remove 'v' prefix from the tag + + - name: Check if version changed and is greater than the previous + id: version_check + run: | + # Compare the current version with the version from the previous commit + PREVIOUS_NPM_VERSION=${{ env.latest_tag }} + CURRENT_NPM_VERSION=$(jq -r '.version' package.json) + CURRENT_CARGO_VERSION=$(awk -F '"' '/^version/ {print $2}' Cargo.toml) + if [[ "$CURRENT_NPM_VERSION" != "$CURRENT_CARGO_VERSION" ]]; then # Cargo.toml and package.json versions must match + echo "Mismatch: NPM version ($CURRENT_NPM_VERSION) and Cargo.toml version ($CURRENT_CARGO_VERSION)" + echo "version_changed=false" >> "$GITHUB_ENV" + else + if [[ "$PREVIOUS_NPM_VERSION" == "$CURRENT_NPM_VERSION" ]]; then + echo "version_changed=" >> "$GITHUB_ENV" + else + IFS='.' read -ra PREVIOUS_VERSION_PARTS <<< "$PREVIOUS_NPM_VERSION" + IFS='.' read -ra CURRENT_VERSION_PARTS <<< "$CURRENT_NPM_VERSION" + VERSION_CHANGED=false + for i in "${!PREVIOUS_VERSION_PARTS[@]}"; do + if [[ ${CURRENT_VERSION_PARTS[i]} -gt ${PREVIOUS_VERSION_PARTS[i]} ]]; then + VERSION_CHANGED=true + break + elif [[ ${CURRENT_VERSION_PARTS[i]} -lt ${PREVIOUS_VERSION_PARTS[i]} ]]; then + break + fi + done + + echo "version_changed=$VERSION_CHANGED" >> "$GITHUB_ENV" + echo "current_version=${CURRENT_NPM_VERSION}" >> "$GITHUB_ENV" + fi + fi + + - name: Display result + run: | + echo "Version bump detected: ${{ env.version_changed }}" + + - name: Fail if version is lower + if: env.version_changed == 'false' + run: exit 1 + + - name: Setup Node + if: env.version_changed == 'true' + uses: actions/setup-node@v3 + with: + node-version: 18 + registry-url: "https://registry.npmjs.org" + - name: Publish to NPM + if: env.version_changed == 'true' + env: + NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} + run: npm publish + + - name: Setup Rust + if: env.version_changed == 'true' + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + - name: Publish to Crates.io + if: env.version_changed == 'true' + uses: katyo/publish-crates@v2 + with: + registry-token: ${{ secrets.CARGO_REGISTRY_TOKEN }} + + - name: Tag versions + if: env.version_changed == 'true' + run: | + git checkout master + git config user.name github-actions[bot] + git config user.email github-actions[bot]@users.noreply.github.com + git tag -d "v${{ env.current_version }}" || true + git push origin --delete "v${{ env.current_version }}" || true + git tag -a "v${{ env.current_version }}" -m "Version ${{ env.current_version }}" + git push origin "v${{ env.current_version }}" diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index e69de29bb..000000000 diff --git a/Cargo.toml b/Cargo.toml index 4de26496d..3af34c1ab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,8 +3,8 @@ name = "tree-sitter-go" description = "Go grammar for the tree-sitter parsing library" version = "0.19.1" authors = [ - "Max Brunsfeld ", - "Douglas Creager ", + "Max Brunsfeld ", + "Douglas Creager ", ] license = "MIT" readme = "bindings/rust/README.md" @@ -14,12 +14,7 @@ repository = "https://github.com/tree-sitter/tree-sitter-go" edition = "2018" build = "bindings/rust/build.rs" -include = [ - "bindings/rust/*", - "grammar.js", - "queries/*", - "src/*", -] +include = ["bindings/rust/*", "grammar.js", "queries/*", "src/*"] [lib] path = "bindings/rust/lib.rs" diff --git a/README.md b/README.md index b8002673a..74dde3f06 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ -tree-sitter-go -=========================== +# tree-sitter-go [![Build/test](https://github.com/tree-sitter/tree-sitter-go/actions/workflows/ci.yml/badge.svg)](https://github.com/tree-sitter/tree-sitter-go/actions/workflows/ci.yml) diff --git a/bindings/node/binding.cc b/bindings/node/binding.cc index 914b6779f..784fd1c1e 100644 --- a/bindings/node/binding.cc +++ b/bindings/node/binding.cc @@ -1,28 +1,30 @@ +#include "nan.h" #include "tree_sitter/parser.h" #include -#include "nan.h" using namespace v8; -extern "C" TSLanguage * tree_sitter_go(); +extern "C" TSLanguage *tree_sitter_go(); namespace { NAN_METHOD(New) {} void Init(Local exports, Local module) { - Local tpl = Nan::New(New); - tpl->SetClassName(Nan::New("Language").ToLocalChecked()); - tpl->InstanceTemplate()->SetInternalFieldCount(1); - - Local constructor = Nan::GetFunction(tpl).ToLocalChecked(); - Local instance = constructor->NewInstance(Nan::GetCurrentContext()).ToLocalChecked(); - Nan::SetInternalFieldPointer(instance, 0, tree_sitter_go()); - - Nan::Set(instance, Nan::New("name").ToLocalChecked(), Nan::New("go").ToLocalChecked()); - Nan::Set(module, Nan::New("exports").ToLocalChecked(), instance); + Local tpl = Nan::New(New); + tpl->SetClassName(Nan::New("Language").ToLocalChecked()); + tpl->InstanceTemplate()->SetInternalFieldCount(1); + + Local constructor = Nan::GetFunction(tpl).ToLocalChecked(); + Local instance = + constructor->NewInstance(Nan::GetCurrentContext()).ToLocalChecked(); + Nan::SetInternalFieldPointer(instance, 0, tree_sitter_go()); + + Nan::Set(instance, Nan::New("name").ToLocalChecked(), + Nan::New("go").ToLocalChecked()); + Nan::Set(module, Nan::New("exports").ToLocalChecked(), instance); } NODE_MODULE(tree_sitter_go_binding, Init) -} // namespace +} // namespace diff --git a/bindings/node/index.js b/bindings/node/index.js index f8080700c..2ce1c1e05 100644 --- a/bindings/node/index.js +++ b/bindings/node/index.js @@ -1,19 +1,19 @@ try { - module.exports = require("../../build/Release/tree_sitter_go_binding"); + module.exports = require('../../build/Release/tree_sitter_go_binding'); } catch (error1) { if (error1.code !== 'MODULE_NOT_FOUND') { throw error1; } try { - module.exports = require("../../build/Debug/tree_sitter_go_binding"); + module.exports = require('../../build/Debug/tree_sitter_go_binding'); } catch (error2) { if (error2.code !== 'MODULE_NOT_FOUND') { throw error2; } - throw error1 + throw error1; } } try { - module.exports.nodeTypeInfo = require("../../src/node-types.json"); + module.exports.nodeTypeInfo = require('../../src/node-types.json'); } catch (_) {} diff --git a/bindings/rust/README.md b/bindings/rust/README.md index 776c2b805..0eeaf6c16 100644 --- a/bindings/rust/README.md +++ b/bindings/rust/README.md @@ -1,24 +1,24 @@ # tree-sitter-go -This crate provides a Go grammar for the [tree-sitter][] parsing library. To +This crate provides a Go grammar for the [tree-sitter][] parsing library. To use this crate, add it to the `[dependencies]` section of your `Cargo.toml` -file. (Note that you will probably also need to depend on the +file. (Note that you will probably also need to depend on the [`tree-sitter`][tree-sitter crate] crate to use the parsed result in any useful way.) -``` toml +```toml [dependencies] tree-sitter = "0.20" tree-sitter-go = "0.19" ``` -Typically, you will use the [language][language func] function to add this +Typically, you will use the [language][language] function to add this grammar to a tree-sitter [Parser][], and then use the parser to parse some code: -``` rust +```rust let code = r#" func double(x int) int { - return x * 2 + return x * 2 } "#; let mut parser = Parser::new(); @@ -29,8 +29,7 @@ let parsed = parser.parse(code, None); If you have any questions, please reach out to us in the [tree-sitter discussions] page. -[Language]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Language.html -[language func]: https://docs.rs/tree-sitter-go/*/tree_sitter_go/fn.language.html +[language]: https://docs.rs/tree-sitter-go/*/tree_sitter_go/fn.language.html [Parser]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Parser.html [tree-sitter]: https://tree-sitter.github.io/ [tree-sitter crate]: https://crates.io/crates/tree-sitter diff --git a/bindings/rust/build.rs b/bindings/rust/build.rs index 45b4151cb..6a41cd05c 100644 --- a/bindings/rust/build.rs +++ b/bindings/rust/build.rs @@ -1,7 +1,7 @@ fn main() { let src_dir = std::path::Path::new("src"); let mut c_config = cc::Build::new(); - c_config.include(&src_dir); + c_config.include(src_dir); c_config .flag_if_supported("-Wno-unused-parameter") .flag_if_supported("-Wno-unused-but-set-variable") diff --git a/bindings/rust/lib.rs b/bindings/rust/lib.rs index 57d9c2d05..d2212211c 100644 --- a/bindings/rust/lib.rs +++ b/bindings/rust/lib.rs @@ -14,15 +14,14 @@ //! //! let code = r#" //! func double(x int) int { -//! return x * 2 +//! return x * 2 //! } //! "#; //! let mut parser = Parser::new(); //! parser.set_language(tree_sitter_go::language()).expect("Error loading Go grammar"); -//! let parsed = parser.parse(code, None); -//! # let parsed = parsed.unwrap(); -//! # let root = parsed.root_node(); -//! # assert!(!root.has_error()); +//! let parsed = parser.parse(code, None).unwrap(); +//! let root = parsed.root_node(); +//! assert!(!root.has_error()); //! ``` //! //! [Language]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Language.html @@ -44,18 +43,18 @@ pub fn language() -> Language { } /// The source of the Go tree-sitter grammar description. -pub const GRAMMAR: &'static str = include_str!("../../grammar.js"); +pub const GRAMMAR: &str = include_str!("../../grammar.js"); /// The syntax highlighting query for this language. -pub const HIGHLIGHT_QUERY: &'static str = include_str!("../../queries/highlights.scm"); +pub const HIGHLIGHT_QUERY: &str = include_str!("../../queries/highlights.scm"); /// The content of the [`node-types.json`][] file for this grammar. /// /// [`node-types.json`]: https://tree-sitter.github.io/tree-sitter/using-parsers#static-node-types -pub const NODE_TYPES: &'static str = include_str!("../../src/node-types.json"); +pub const NODE_TYPES: &str = include_str!("../../src/node-types.json"); /// The symbol tagging query for this language. -pub const TAGGING_QUERY: &'static str = include_str!("../../queries/tags.scm"); +pub const TAGGING_QUERY: &str = include_str!("../../queries/tags.scm"); #[cfg(test)] mod tests { diff --git a/grammar.js b/grammar.js index a8b952ee1..1817066ef 100644 --- a/grammar.js +++ b/grammar.js @@ -1,3 +1,15 @@ +/** + * @file Go grammar for tree-sitter + * @author Max Brunsfeld + * @license MIT + */ + +/* eslint-disable arrow-parens */ +/* eslint-disable camelcase */ +/* eslint-disable-next-line spaced-comment */ +/// +// @ts-check + const PREC = { primary: 7, @@ -17,7 +29,7 @@ const newline = '\n', - terminator = choice(newline, ';'), + terminator = choice(newline, ';', '\0'), hexDigit = /[0-9a-fA-F]/, octalDigit = /[0-7]/, @@ -53,14 +65,14 @@ const floatLiteral = choice(decimalFloatLiteral, hexFloatLiteral), - imaginaryLiteral = seq(choice(decimalDigits, intLiteral, floatLiteral), 'i') + imaginaryLiteral = seq(choice(decimalDigits, intLiteral, floatLiteral), 'i'); module.exports = grammar({ name: 'go', extras: $ => [ $.comment, - /\s/ + /\s/, ], inline: $ => [ @@ -96,10 +108,10 @@ module.exports = grammar({ rules: { source_file: $ => seq( repeat(choice( - // Unlike a Go compiler, we accept statements at top-level to enable - // parsing of partial code snippets in documentation (see #63). - seq($._statement, terminator), - seq($._top_level_declaration, terminator), + // Unlike a Go compiler, we accept statements at top-level to enable + // parsing of partial code snippets in documentation (see #63). + seq($._statement, terminator), + seq($._top_level_declaration, terminator), )), optional($._top_level_declaration), ), @@ -108,32 +120,32 @@ module.exports = grammar({ $.package_clause, $.function_declaration, $.method_declaration, - $.import_declaration + $.import_declaration, ), package_clause: $ => seq( 'package', - $._package_identifier + $._package_identifier, ), import_declaration: $ => seq( 'import', choice( $.import_spec, - $.import_spec_list - ) + $.import_spec_list, + ), ), import_spec: $ => seq( optional(field('name', choice( $.dot, $.blank_identifier, - $._package_identifier + $._package_identifier, ))), - field('path', $._string_literal) + field('path', $._string_literal), ), - dot: $ => '.', - blank_identifier: $ => '_', + dot: _ => '.', + blank_identifier: _ => '_', import_spec_list: $ => seq( '(', @@ -148,7 +160,7 @@ module.exports = grammar({ _declaration: $ => choice( $.const_declaration, $.type_declaration, - $.var_declaration + $.var_declaration, ), const_declaration: $ => seq( @@ -158,9 +170,9 @@ module.exports = grammar({ seq( '(', repeat(seq($.const_spec, terminator)), - ')' - ) - ) + ')', + ), + ), ), const_spec: $ => prec.left(seq( @@ -168,8 +180,8 @@ module.exports = grammar({ optional(seq( optional(field('type', $._type)), '=', - field('value', $.expression_list) - )) + field('value', $.expression_list), + )), )), var_declaration: $ => seq( @@ -179,9 +191,9 @@ module.exports = grammar({ seq( '(', repeat(seq($.var_spec, terminator)), - ')' - ) - ) + ')', + ), + ), ), var_spec: $ => seq( @@ -189,10 +201,10 @@ module.exports = grammar({ choice( seq( field('type', $._type), - optional(seq('=', field('value', $.expression_list))) + optional(seq('=', field('value', $.expression_list))), ), - seq('=', field('value', $.expression_list)) - ) + seq('=', field('value', $.expression_list)), + ), ), function_declaration: $ => prec.right(1, seq( @@ -201,7 +213,7 @@ module.exports = grammar({ field('type_parameters', optional($.type_parameter_list)), field('parameters', $.parameter_list), field('result', optional(choice($.parameter_list, $._simple_type))), - field('body', optional($.block)) + field('body', optional($.block)), )), method_declaration: $ => prec.right(1, seq( @@ -210,23 +222,23 @@ module.exports = grammar({ field('name', $._field_identifier), field('parameters', $.parameter_list), field('result', optional(choice($.parameter_list, $._simple_type))), - field('body', optional($.block)) + field('body', optional($.block)), )), type_parameter_list: $ => seq( '[', commaSep1($.parameter_declaration), optional(','), - ']' + ']', ), parameter_list: $ => seq( '(', optional(seq( commaSep(choice($.parameter_declaration, $.variadic_parameter_declaration)), - optional(',') + optional(','), )), - ')' + ')', ), parameter_declaration: $ => prec.left(seq( @@ -237,13 +249,13 @@ module.exports = grammar({ variadic_parameter_declaration: $ => seq( field('name', optional($.identifier)), '...', - field('type', $._type) + field('type', $._type), ), type_alias: $ => seq( field('name', $._type_identifier), '=', - field('type', $._type) + field('type', $._type), ), type_declaration: $ => seq( @@ -254,15 +266,15 @@ module.exports = grammar({ seq( '(', repeat(seq(choice($.type_spec, $.type_alias), terminator)), - ')' - ) - ) + ')', + ), + ), ), type_spec: $ => seq( field('name', $._type_identifier), field('type_parameters', optional($.type_parameter_list)), - field('type', $._type) + field('type', $._type), ), field_name_list: $ => commaSep1($._field_identifier), @@ -271,7 +283,7 @@ module.exports = grammar({ _type: $ => choice( $._simple_type, - $.parenthesized_type + $.parenthesized_type, ), parenthesized_type: $ => seq('(', $._type, ')'), @@ -299,9 +311,9 @@ module.exports = grammar({ type_arguments: $ => prec.dynamic(2, seq( '[', - commaSep1($._type), - optional(','), - ']' + commaSep1($._type), + optional(','), + ']', )), pointer_type: $ => prec(PREC.unary, seq('*', $._type)), @@ -310,25 +322,25 @@ module.exports = grammar({ '[', field('length', $._expression), ']', - field('element', $._type) + field('element', $._type), )), implicit_length_array_type: $ => seq( '[', '...', ']', - field('element', $._type) + field('element', $._type), ), slice_type: $ => prec.right(seq( '[', ']', - field('element', $._type) + field('element', $._type), )), struct_type: $ => seq( 'struct', - $.field_declaration_list + $.field_declaration_list, ), union_type: $ => prec.left(seq( @@ -347,16 +359,16 @@ module.exports = grammar({ optional(seq( $.field_declaration, repeat(seq(terminator, $.field_declaration)), - optional(terminator) + optional(terminator), )), - '}' + '}', ), field_declaration: $ => seq( choice( seq( commaSep1(field('name', $._field_identifier)), - field('type', $._type) + field('type', $._type), ), seq( optional('*'), @@ -364,10 +376,10 @@ module.exports = grammar({ $._type_identifier, $.qualified_type, $.generic_type, - )) - ) + )), + ), ), - field('tag', optional($._string_literal)) + field('tag', optional($._string_literal)), ), interface_type: $ => seq( @@ -376,9 +388,9 @@ module.exports = grammar({ optional(seq( $._interface_body, repeat(seq(terminator, $._interface_body)), - optional(terminator) + optional(terminator), )), - '}' + '}', ), _interface_body: $ => choice( @@ -389,18 +401,18 @@ module.exports = grammar({ struct_elem: $ => seq( $.struct_term, - repeat(seq('|', $.struct_term)) + repeat(seq('|', $.struct_term)), ), struct_term: $ => prec(1, seq( optional(choice('~', '*')), - $.struct_type + $.struct_type, )), method_spec: $ => seq( field('name', $._field_identifier), field('parameters', $.parameter_list), - field('result', optional(choice($.parameter_list, $._simple_type))) + field('result', optional(choice($.parameter_list, $._simple_type))), ), map_type: $ => prec.right(seq( @@ -408,25 +420,25 @@ module.exports = grammar({ '[', field('key', $._type), ']', - field('value', $._type) + field('value', $._type), )), channel_type: $ => prec.left(choice( seq('chan', field('value', $._type)), seq('chan', '<-', field('value', $._type)), - prec(PREC.unary, seq('<-', 'chan', field('value', $._type))) + prec(PREC.unary, seq('<-', 'chan', field('value', $._type))), )), function_type: $ => prec.right(seq( 'func', field('parameters', $.parameter_list), - field('result', optional(choice($.parameter_list, $._simple_type))) + field('result', optional(choice($.parameter_list, $._simple_type))), )), block: $ => seq( '{', optional($._statement_list), - '}' + '}', ), _statement_list: $ => choice( @@ -435,10 +447,10 @@ module.exports = grammar({ repeat(seq(terminator, $._statement)), optional(seq( terminator, - optional(alias($.empty_labeled_statement, $.labeled_statement)) - )) + optional(alias($.empty_labeled_statement, $.labeled_statement)), + )), ), - alias($.empty_labeled_statement, $.labeled_statement) + alias($.empty_labeled_statement, $.labeled_statement), ), _statement: $ => choice( @@ -458,18 +470,18 @@ module.exports = grammar({ $.continue_statement, $.goto_statement, $.block, - $.empty_statement + $.empty_statement, ), - empty_statement: $ => ';', + empty_statement: _ => ';', _simple_statement: $ => choice( - $.expression_statement, + $.expression_statement, $.send_statement, $.inc_statement, $.dec_statement, $.assignment_statement, - $.short_var_declaration + $.short_var_declaration, ), expression_statement: $ => $._expression, @@ -477,31 +489,31 @@ module.exports = grammar({ send_statement: $ => seq( field('channel', $._expression), '<-', - field('value', $._expression) + field('value', $._expression), ), receive_statement: $ => seq( optional(seq( field('left', $.expression_list), - choice('=', ':=') + choice('=', ':='), )), - field('right', $._expression) + field('right', $._expression), ), inc_statement: $ => seq( $._expression, - '++' + '++', ), dec_statement: $ => seq( $._expression, - '--' + '--', ), assignment_statement: $ => seq( field('left', $.expression_list), field('operator', choice(...assignment_operators)), - field('right', $.expression_list) + field('right', $.expression_list), ), short_var_declaration: $ => seq( @@ -509,24 +521,24 @@ module.exports = grammar({ // conflicts between identifiers as expressions vs identifiers here. field('left', $.expression_list), ':=', - field('right', $.expression_list) + field('right', $.expression_list), ), labeled_statement: $ => seq( field('label', alias($.identifier, $.label_name)), ':', - $._statement + $._statement, ), empty_labeled_statement: $ => seq( field('label', alias($.identifier, $.label_name)), - ':' + ':', ), // This is a hack to prevent `fallthrough_statement` from being parsed as // a single token. For consistency with `break_statement` etc it should // be parsed as a parent node that *contains* a `fallthrough` token. - fallthrough_statement: $ => prec.left('fallthrough'), + fallthrough_statement: _ => prec.left('fallthrough'), break_statement: $ => seq('break', optional(alias($.identifier, $.label_name))), @@ -544,20 +556,20 @@ module.exports = grammar({ 'if', optional(seq( field('initializer', $._simple_statement), - ';' + ';', )), field('condition', $._expression), field('consequence', $.block), optional(seq( 'else', - field('alternative', choice($.block, $.if_statement)) - )) + field('alternative', choice($.block, $.if_statement)), + )), ), for_statement: $ => seq( 'for', optional(choice($._expression, $.for_clause, $.range_clause)), - field('body', $.block) + field('body', $.block), ), for_clause: $ => seq( @@ -565,41 +577,41 @@ module.exports = grammar({ ';', field('condition', optional($._expression)), ';', - field('update', optional($._simple_statement)) + field('update', optional($._simple_statement)), ), range_clause: $ => seq( optional(seq( field('left', $.expression_list), - choice('=', ':=') + choice('=', ':='), )), 'range', - field('right', $._expression) + field('right', $._expression), ), expression_switch_statement: $ => seq( 'switch', optional(seq( field('initializer', $._simple_statement), - ';' + ';', )), field('value', optional($._expression)), '{', repeat(choice($.expression_case, $.default_case)), - '}' + '}', ), expression_case: $ => seq( 'case', field('value', $.expression_list), ':', - optional($._statement_list) + optional($._statement_list), ), default_case: $ => seq( 'default', ':', - optional($._statement_list) + optional($._statement_list), ), type_switch_statement: $ => seq( @@ -607,41 +619,41 @@ module.exports = grammar({ $._type_switch_header, '{', repeat(choice($.type_case, $.default_case)), - '}' + '}', ), _type_switch_header: $ => seq( optional(seq( field('initializer', $._simple_statement), - ';' + ';', )), optional(seq(field('alias', $.expression_list), ':=')), field('value', $._expression), '.', '(', 'type', - ')' + ')', ), type_case: $ => seq( 'case', field('type', commaSep1($._type)), ':', - optional($._statement_list) + optional($._statement_list), ), select_statement: $ => seq( 'select', '{', repeat(choice($.communication_case, $.default_case)), - '}' + '}', ), communication_case: $ => seq( 'case', field('communication', choice($.send_statement, $.receive_statement)), ':', - optional($._statement_list) + optional($._statement_list), ), _expression: $ => choice( @@ -666,30 +678,30 @@ module.exports = grammar({ $.true, $.false, $.iota, - $.parenthesized_expression + $.parenthesized_expression, ), parenthesized_expression: $ => seq( '(', $._expression, - ')' + ')', ), call_expression: $ => prec(PREC.primary, choice( seq( field('function', alias(choice('new', 'make'), $.identifier)), - field('arguments', alias($.special_argument_list, $.argument_list)) + field('arguments', alias($.special_argument_list, $.argument_list)), ), seq( field('function', $._expression), field('type_arguments', optional($.type_arguments)), - field('arguments', $.argument_list) - ) + field('arguments', $.argument_list), + ), )), variadic_argument: $ => prec.right(seq( $._expression, - '...' + '...', )), special_argument_list: $ => seq( @@ -697,7 +709,7 @@ module.exports = grammar({ $._type, repeat(seq(',', $._expression)), optional(','), - ')' + ')', ), argument_list: $ => seq( @@ -705,22 +717,22 @@ module.exports = grammar({ optional(seq( choice($._expression, $.variadic_argument), repeat(seq(',', choice($._expression, $.variadic_argument))), - optional(',') + optional(','), )), - ')' + ')', ), selector_expression: $ => prec(PREC.primary, seq( field('operand', $._expression), '.', - field('field', $._field_identifier) + field('field', $._field_identifier), )), index_expression: $ => prec(PREC.primary, seq( field('operand', $._expression), '[', field('index', $._expression), - ']' + ']', )), slice_expression: $ => prec(PREC.primary, seq( @@ -730,17 +742,17 @@ module.exports = grammar({ seq( field('start', optional($._expression)), ':', - field('end', optional($._expression)) + field('end', optional($._expression)), ), seq( field('start', optional($._expression)), ':', field('end', $._expression), ':', - field('capacity', $._expression) - ) + field('capacity', $._expression), + ), ), - ']' + ']', )), type_assertion_expression: $ => prec(PREC.primary, seq( @@ -748,7 +760,7 @@ module.exports = grammar({ '.', '(', field('type', $._type), - ')' + ')', )), type_conversion_expression: $ => prec.dynamic(-1, seq( @@ -756,7 +768,7 @@ module.exports = grammar({ '(', field('operand', $._expression), optional(','), - ')' + ')', )), composite_literal: $ => prec(PREC.composite_literal, seq( @@ -768,18 +780,18 @@ module.exports = grammar({ $.struct_type, $._type_identifier, $.generic_type, - $.qualified_type + $.qualified_type, )), - field('body', $.literal_value) + field('body', $.literal_value), )), literal_value: $ => seq( '{', optional( - seq( - commaSep(choice($.literal_element, $.keyed_element)), + seq( + commaSep(choice($.literal_element, $.keyed_element)), optional(','))), - '}' + '}', ), literal_element: $ => choice($._expression, $.literal_value), @@ -795,12 +807,12 @@ module.exports = grammar({ 'func', field('parameters', $.parameter_list), field('result', optional(choice($.parameter_list, $._simple_type))), - field('body', $.block) + field('body', $.block), ), unary_expression: $ => prec(PREC.unary, seq( field('operator', choice('+', '-', '!', '^', '*', '&', '<-')), - field('operand', $._expression) + field('operand', $._expression), )), binary_expression: $ => { @@ -813,18 +825,20 @@ module.exports = grammar({ ]; return choice(...table.map(([precedence, operator]) => + // @ts-ignore prec.left(precedence, seq( field('left', $._expression), + // @ts-ignore field('operator', operator), - field('right', $._expression) - )) + field('right', $._expression), + )), )); }, qualified_type: $ => seq( field('package', $._package_identifier), '.', - field('name', $._type_identifier) + field('name', $._type_identifier), ), identifier: _ => /[_\p{XID_Start}][_\p{XID_Continue}]*/, @@ -835,44 +849,44 @@ module.exports = grammar({ _string_literal: $ => choice( $.raw_string_literal, - $.interpreted_string_literal + $.interpreted_string_literal, ), - raw_string_literal: $ => token(seq( + raw_string_literal: _ => token(seq( '`', repeat(/[^`]/), - '`' + '`', )), interpreted_string_literal: $ => seq( '"', repeat(choice( $._interpreted_string_literal_basic_content, - $.escape_sequence + $.escape_sequence, )), - token.immediate('"') + token.immediate('"'), ), - _interpreted_string_literal_basic_content: $ => token.immediate(prec(1, /[^"\n\\]+/)), + _interpreted_string_literal_basic_content: _ => token.immediate(prec(1, /[^"\n\\]+/)), - escape_sequence: $ => token.immediate(seq( + escape_sequence: _ => token.immediate(seq( '\\', choice( /[^xuU]/, /\d{2,3}/, /x[0-9a-fA-F]{2,}/, /u[0-9a-fA-F]{4}/, - /U[0-9a-fA-F]{8}/ - ) + /U[0-9a-fA-F]{8}/, + ), )), - int_literal: $ => token(intLiteral), + int_literal: _ => token(intLiteral), - float_literal: $ => token(floatLiteral), + float_literal: _ => token(floatLiteral), - imaginary_literal: $ => token(imaginaryLiteral), + imaginary_literal: _ => token(imaginaryLiteral), - rune_literal: $ => token(seq( - "'", + rune_literal: _ => token(seq( + '\'', choice( /[^'\\]/, seq( @@ -882,34 +896,50 @@ module.exports = grammar({ seq(octalDigit, octalDigit, octalDigit), seq('u', hexDigit, hexDigit, hexDigit, hexDigit), seq('U', hexDigit, hexDigit, hexDigit, hexDigit, hexDigit, hexDigit, hexDigit, hexDigit), - seq(choice('a', 'b', 'f', 'n', 'r', 't', 'v', '\\', "'", '"')) - ) - ) + seq(choice('a', 'b', 'f', 'n', 'r', 't', 'v', '\\', '\'', '"')), + ), + ), ), - "'" + '\'', )), - nil: $ => 'nil', - true: $ => 'true', - false: $ => 'false', - iota: $ => 'iota', + nil: _ => 'nil', + true: _ => 'true', + false: _ => 'false', + iota: _ => 'iota', // http://stackoverflow.com/questions/13014947/regex-to-match-a-c-style-multiline-comment/36328890#36328890 - comment: $ => token(choice( + comment: _ => token(choice( seq('//', /.*/), seq( '/*', /[^*]*\*+([^/*][^*]*\*+)*/, - '/' - ) - )) - } -}) - + '/', + ), + )), + }, +}); + +/** + * Creates a rule to match one or more of the rules separated by a comma + * + * @param {Rule} rule + * + * @return {SeqRule} + * + */ function commaSep1(rule) { - return seq(rule, repeat(seq(',', rule))) + return seq(rule, repeat(seq(',', rule))); } +/** + * Creates a rule to optionally match one or more of the rules separated by a comma + * + * @param {Rule} rule + * + * @return {ChoiceRule} + * + */ function commaSep(rule) { - return optional(commaSep1(rule)) + return optional(commaSep1(rule)); } diff --git a/package.json b/package.json index ffa60c50d..28083b191 100644 --- a/package.json +++ b/package.json @@ -17,10 +17,13 @@ "nan": "^2.14.0" }, "devDependencies": { + "eslint": "^8.45.0", + "eslint-config-google": "^0.14.0", "tree-sitter-cli": "^0.20.6" }, "scripts": { "build": "tree-sitter generate && node-gyp build", + "lint": "eslint grammar.js", "test": "tree-sitter test && script/parse-examples", "test-windows": "tree-sitter test" }, diff --git a/src/grammar.json b/src/grammar.json index 3554824ca..55e81d067 100644 --- a/src/grammar.json +++ b/src/grammar.json @@ -27,6 +27,10 @@ { "type": "STRING", "value": ";" + }, + { + "type": "STRING", + "value": "\u0000" } ] } @@ -49,6 +53,10 @@ { "type": "STRING", "value": ";" + }, + { + "type": "STRING", + "value": "\u0000" } ] } @@ -209,6 +217,10 @@ { "type": "STRING", "value": ";" + }, + { + "type": "STRING", + "value": "\u0000" } ] }, @@ -232,6 +244,10 @@ { "type": "STRING", "value": ";" + }, + { + "type": "STRING", + "value": "\u0000" } ] }, @@ -310,6 +326,10 @@ { "type": "STRING", "value": ";" + }, + { + "type": "STRING", + "value": "\u0000" } ] } @@ -445,6 +465,10 @@ { "type": "STRING", "value": ";" + }, + { + "type": "STRING", + "value": "\u0000" } ] } @@ -1027,6 +1051,10 @@ { "type": "STRING", "value": ";" + }, + { + "type": "STRING", + "value": "\u0000" } ] } @@ -1496,6 +1524,10 @@ { "type": "STRING", "value": ";" + }, + { + "type": "STRING", + "value": "\u0000" } ] }, @@ -1519,6 +1551,10 @@ { "type": "STRING", "value": ";" + }, + { + "type": "STRING", + "value": "\u0000" } ] }, @@ -1686,6 +1722,10 @@ { "type": "STRING", "value": ";" + }, + { + "type": "STRING", + "value": "\u0000" } ] }, @@ -1709,6 +1749,10 @@ { "type": "STRING", "value": ";" + }, + { + "type": "STRING", + "value": "\u0000" } ] }, @@ -2062,6 +2106,10 @@ { "type": "STRING", "value": ";" + }, + { + "type": "STRING", + "value": "\u0000" } ] }, @@ -2088,6 +2136,10 @@ { "type": "STRING", "value": ";" + }, + { + "type": "STRING", + "value": "\u0000" } ] }, diff --git a/src/node-types.json b/src/node-types.json index ac700bba1..60621cb7d 100644 --- a/src/node-types.json +++ b/src/node-types.json @@ -2515,6 +2515,10 @@ } } }, + { + "type": "\u0000", + "named": false + }, { "type": "\n", "named": false diff --git a/src/parser.c b/src/parser.c index ba00b3fc0..cdcad118b 100644 Binary files a/src/parser.c and b/src/parser.c differ diff --git a/corpus/declarations.txt b/test/corpus/declarations.txt similarity index 100% rename from corpus/declarations.txt rename to test/corpus/declarations.txt diff --git a/corpus/expressions.txt b/test/corpus/expressions.txt similarity index 100% rename from corpus/expressions.txt rename to test/corpus/expressions.txt diff --git a/corpus/literals.txt b/test/corpus/literals.txt similarity index 100% rename from corpus/literals.txt rename to test/corpus/literals.txt diff --git a/corpus/source_files.txt b/test/corpus/source_files.txt similarity index 100% rename from corpus/source_files.txt rename to test/corpus/source_files.txt diff --git a/corpus/statements.txt b/test/corpus/statements.txt similarity index 100% rename from corpus/statements.txt rename to test/corpus/statements.txt diff --git a/corpus/types.txt b/test/corpus/types.txt similarity index 100% rename from corpus/types.txt rename to test/corpus/types.txt