diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..b2e707a --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,20 @@ +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': 120, 'ignoreComments': true, 'ignoreUrls': true, 'ignoreStrings': true}, + ], + }, +}; diff --git a/.gitattributes b/.gitattributes index f60d7b9..c647c2b 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/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..327630a --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,30 @@ +name: CI +on: + workflow_dispatch: + pull_request: + push: + +jobs: + test: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: true + matrix: + os: [macos-latest, ubuntu-latest] + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: 18 + - run: npm install + - run: npm test + + test_windows: + runs-on: windows-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: 18 + - run: npm install + - run: npm run test-windows diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..d94f7f3 --- /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/.npmignore b/.npmignore index bed0e3d..194ff84 100644 --- a/.npmignore +++ b/.npmignore @@ -3,4 +3,3 @@ /build /script /target - diff --git a/Cargo.toml b/Cargo.toml index 9e2e88c..4f82ce0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ keywords = ["incremental", "parsing", "c"] categories = ["parsing", "text-editors"] repository = "https://github.com/tree-sitter/tree-sitter-c" edition = "2018" +autoexamples = false build = "bindings/rust/build.rs" include = ["bindings/rust/*", "grammar.js", "queries/*", "src/*"] @@ -17,7 +18,7 @@ include = ["bindings/rust/*", "grammar.js", "queries/*", "src/*"] path = "bindings/rust/lib.rs" [dependencies] -tree-sitter = "0.20" +tree-sitter = "0.20.10" [build-dependencies] cc = "1.0" diff --git a/Package.swift b/Package.swift index c6c5376..97f073d 100644 --- a/Package.swift +++ b/Package.swift @@ -33,4 +33,4 @@ let package = Package( publicHeadersPath: "bindings/swift", cSettings: [.headerSearchPath("src")]) ] -) \ No newline at end of file +) diff --git a/README.md b/README.md index d89830b..877378b 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ -tree-sitter-c -================== +# tree-sitter-c [![Build Status](https://travis-ci.org/tree-sitter/tree-sitter-c.svg?branch=master)](https://travis-ci.org/tree-sitter/tree-sitter-c) [![Build status](https://ci.appveyor.com/api/projects/status/7u0sy6ajmxro4wfh/branch/master?svg=true)](https://ci.appveyor.com/project/maxbrunsfeld/tree-sitter-c/branch/master) -C grammar for [tree-sitter](https://github.com/tree-sitter/tree-sitter). Adapted from [this C99 grammar](http://slps.github.io/zoo/c/iso-9899-tc3.html). +C grammar for [tree-sitter](https://github.com/tree-sitter/tree-sitter). +Adapted from [this C99 grammar](http://slps.github.io/zoo/c/iso-9899-tc3.html). diff --git a/bindings/node/binding.cc b/bindings/node/binding.cc index aea5598..f90c59d 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_c(); +extern "C" TSLanguage *tree_sitter_c(); 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_c()); - - Nan::Set(instance, Nan::New("name").ToLocalChecked(), Nan::New("c").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_c()); + + Nan::Set(instance, Nan::New("name").ToLocalChecked(), + Nan::New("c").ToLocalChecked()); + Nan::Set(module, Nan::New("exports").ToLocalChecked(), instance); } NODE_MODULE(tree_sitter_c_binding, Init) -} // namespace +} // namespace diff --git a/bindings/node/index.js b/bindings/node/index.js index 51a5d6c..62cc2fe 100644 --- a/bindings/node/index.js +++ b/bindings/node/index.js @@ -1,19 +1,19 @@ try { - module.exports = require("../../build/Release/tree_sitter_c_binding"); + module.exports = require('../../build/Release/tree_sitter_c_binding'); } catch (error1) { if (error1.code !== 'MODULE_NOT_FOUND') { throw error1; } try { - module.exports = require("../../build/Debug/tree_sitter_c_binding"); + module.exports = require('../../build/Debug/tree_sitter_c_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/build.rs b/bindings/rust/build.rs index 3efc628..d8ec29c 100644 --- a/bindings/rust/build.rs +++ b/bindings/rust/build.rs @@ -5,7 +5,7 @@ fn main() { let src_dir = 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/grammar.js b/grammar.js index 77d68ac..8aa9176 100644 --- a/grammar.js +++ b/grammar.js @@ -1,3 +1,15 @@ +/** + * @file C 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 = { PAREN_DECLARATOR: -10, ASSIGNMENT: -1, @@ -18,7 +30,7 @@ const PREC = { UNARY: 13, CALL: 14, FIELD: 15, - SUBSCRIPT: 16 + SUBSCRIPT: 16, }; module.exports = grammar({ @@ -68,7 +80,7 @@ module.exports = grammar({ $.preproc_include, $.preproc_def, $.preproc_function_def, - $.preproc_call + $.preproc_call, ), // Preprocesser @@ -81,14 +93,14 @@ module.exports = grammar({ $.identifier, alias($.preproc_call_expression, $.call_expression), )), - '\n' + '\n', ), preproc_def: $ => seq( preprocessor('define'), field('name', $.identifier), field('value', optional($.preproc_arg)), - '\n' + '\n', ), preproc_function_def: $ => seq( @@ -96,24 +108,24 @@ module.exports = grammar({ field('name', $.identifier), field('parameters', $.preproc_params), field('value', optional($.preproc_arg)), - '\n' + '\n', ), preproc_params: $ => seq( - token.immediate('('), commaSep(choice($.identifier, '...')), ')' + token.immediate('('), commaSep(choice($.identifier, '...')), ')', ), preproc_call: $ => seq( field('directive', $.preproc_directive), field('argument', optional($.preproc_arg)), - '\n' + '\n', ), ...preprocIf('', $ => $._top_level_item), ...preprocIf('_in_field_declaration_list', $ => $._field_declaration_list_item), - preproc_directive: $ => /#[ \t]*[a-zA-Z]\w*/, - preproc_arg: $ => token(prec(-1, repeat1(/.|\\\r?\n/))), + preproc_directive: _ => /#[ \t]*[a-zA-Z]\w*/, + preproc_arg: _ => token(prec(-1, repeat1(/.|\\\r?\n/))), _preproc_expression: $ => choice( $.identifier, @@ -123,13 +135,13 @@ module.exports = grammar({ $.preproc_defined, alias($.preproc_unary_expression, $.unary_expression), alias($.preproc_binary_expression, $.binary_expression), - alias($.preproc_parenthesized_expression, $.parenthesized_expression) + alias($.preproc_parenthesized_expression, $.parenthesized_expression), ), preproc_parenthesized_expression: $ => seq( '(', $._preproc_expression, - ')' + ')', ), preproc_defined: $ => choice( @@ -139,18 +151,18 @@ module.exports = grammar({ preproc_unary_expression: $ => prec.left(PREC.UNARY, seq( field('operator', choice('!', '~', '-', '+')), - field('argument', $._preproc_expression) + field('argument', $._preproc_expression), )), preproc_call_expression: $ => prec(PREC.CALL, seq( field('function', $.identifier), - field('arguments', alias($.preproc_argument_list, $.argument_list)) + field('arguments', alias($.preproc_argument_list, $.argument_list)), )), preproc_argument_list: $ => seq( '(', commaSep($._preproc_expression), - ')' + ')', ), preproc_binary_expression: $ => { @@ -178,9 +190,10 @@ module.exports = grammar({ return choice(...table.map(([operator, precedence]) => { return prec.left(precedence, seq( field('left', $._preproc_expression), + // @ts-ignore field('operator', operator), - field('right', $._preproc_expression) - )) + field('right', $._preproc_expression), + )); })); }, @@ -190,16 +203,16 @@ module.exports = grammar({ optional($.ms_call_modifier), $._declaration_specifiers, field('declarator', $._declarator), - field('body', $.compound_statement) + field('body', $.compound_statement), ), declaration: $ => seq( $._declaration_specifiers, commaSep1(field('declarator', choice( $._declarator, - $.init_declarator + $.init_declarator, ))), - ';' + ';', ), type_definition: $ => seq( @@ -207,7 +220,7 @@ module.exports = grammar({ repeat($.type_qualifier), field('type', $._type_specifier), commaSep1(field('declarator', $._type_declarator)), - ';' + ';', ), _declaration_modifiers: $ => choice( @@ -215,7 +228,7 @@ module.exports = grammar({ $.type_qualifier, $.attribute_specifier, $.attribute_declaration, - $.ms_declspec_modifier + $.ms_declspec_modifier, ), _declaration_specifiers: $ => seq( @@ -230,27 +243,27 @@ module.exports = grammar({ field('body', choice( $.function_definition, $.declaration, - $.declaration_list - )) + $.declaration_list, + )), ), attribute_specifier: $ => seq( '__attribute__', '(', $.argument_list, - ')' + ')', ), attribute: $ => seq( optional(seq(field('prefix', $.identifier), '::')), field('name', $.identifier), - optional($.argument_list) + optional($.argument_list), ), attribute_declaration: $ => seq( '[[', commaSep1($.attribute), - ']]' + ']]', ), ms_declspec_modifier: $ => seq( @@ -265,22 +278,22 @@ module.exports = grammar({ $.argument_list, ), - ms_call_modifier: $ => choice( + ms_call_modifier: _ => choice( '__cdecl', '__clrcall', '__stdcall', '__fastcall', '__thiscall', - '__vectorcall' + '__vectorcall', ), - ms_restrict_modifier: $ => '__restrict', + ms_restrict_modifier: _ => '__restrict', - ms_unsigned_ptr_modifier: $ => '__uptr', + ms_unsigned_ptr_modifier: _ => '__uptr', - ms_signed_ptr_modifier: $ => '__sptr', + ms_signed_ptr_modifier: _ => '__sptr', - ms_unaligned_ptr_modifier: $ => choice('_unaligned', '__unaligned'), + ms_unaligned_ptr_modifier: _ => choice('_unaligned', '__unaligned'), ms_pointer_modifier: $ => choice( $.ms_unaligned_ptr_modifier, @@ -292,7 +305,7 @@ module.exports = grammar({ declaration_list: $ => seq( '{', repeat($._top_level_item), - '}' + '}', ), _declarator: $ => choice( @@ -301,7 +314,7 @@ module.exports = grammar({ $.function_declarator, $.array_declarator, $.parenthesized_declarator, - $.identifier + $.identifier, ), _field_declarator: $ => choice( @@ -310,7 +323,7 @@ module.exports = grammar({ alias($.function_field_declarator, $.function_declarator), alias($.array_field_declarator, $.array_declarator), alias($.parenthesized_field_declarator, $.parenthesized_declarator), - $._field_identifier + $._field_identifier, ), _type_declarator: $ => choice( @@ -319,7 +332,7 @@ module.exports = grammar({ alias($.function_type_declarator, $.function_declarator), alias($.array_type_declarator, $.array_declarator), alias($.parenthesized_type_declarator, $.parenthesized_declarator), - $._type_identifier + $._type_identifier, ), _abstract_declarator: $ => choice( @@ -332,22 +345,22 @@ module.exports = grammar({ parenthesized_declarator: $ => prec.dynamic(PREC.PAREN_DECLARATOR, seq( '(', $._declarator, - ')' + ')', )), parenthesized_field_declarator: $ => prec.dynamic(PREC.PAREN_DECLARATOR, seq( '(', $._field_declarator, - ')' + ')', )), parenthesized_type_declarator: $ => prec.dynamic(PREC.PAREN_DECLARATOR, seq( '(', $._type_declarator, - ')' + ')', )), abstract_parenthesized_declarator: $ => prec(1, seq( '(', $._abstract_declarator, - ')' + ')', )), @@ -369,25 +382,25 @@ module.exports = grammar({ '*', repeat($.ms_pointer_modifier), repeat($.type_qualifier), - field('declarator', $._declarator) + field('declarator', $._declarator), ))), pointer_field_declarator: $ => prec.dynamic(1, prec.right(seq( optional($.ms_based_modifier), '*', repeat($.ms_pointer_modifier), repeat($.type_qualifier), - field('declarator', $._field_declarator) + field('declarator', $._field_declarator), ))), pointer_type_declarator: $ => prec.dynamic(1, prec.right(seq( optional($.ms_based_modifier), '*', repeat($.ms_pointer_modifier), repeat($.type_qualifier), - field('declarator', $._type_declarator) + field('declarator', $._type_declarator), ))), abstract_pointer_declarator: $ => prec.dynamic(1, prec.right(seq('*', repeat($.type_qualifier), - field('declarator', optional($._abstract_declarator)) + field('declarator', optional($._abstract_declarator)), ))), function_declarator: $ => prec(1, @@ -398,15 +411,15 @@ module.exports = grammar({ )), function_field_declarator: $ => prec(1, seq( field('declarator', $._field_declarator), - field('parameters', $.parameter_list) + field('parameters', $.parameter_list), )), function_type_declarator: $ => prec(1, seq( field('declarator', $._type_declarator), - field('parameters', $.parameter_list) + field('parameters', $.parameter_list), )), abstract_function_declarator: $ => prec(1, seq( field('declarator', optional($._abstract_declarator)), - field('parameters', $.parameter_list) + field('parameters', $.parameter_list), )), array_declarator: $ => prec(1, seq( @@ -414,55 +427,55 @@ module.exports = grammar({ '[', repeat($.type_qualifier), field('size', optional(choice($._expression, '*'))), - ']' + ']', )), array_field_declarator: $ => prec(1, seq( field('declarator', $._field_declarator), '[', repeat($.type_qualifier), field('size', optional(choice($._expression, '*'))), - ']' + ']', )), array_type_declarator: $ => prec(1, seq( field('declarator', $._type_declarator), '[', repeat($.type_qualifier), field('size', optional(choice($._expression, '*'))), - ']' + ']', )), abstract_array_declarator: $ => prec(1, seq( field('declarator', optional($._abstract_declarator)), '[', repeat($.type_qualifier), field('size', optional(choice($._expression, '*'))), - ']' + ']', )), init_declarator: $ => seq( field('declarator', $._declarator), '=', - field('value', choice($.initializer_list, $._expression)) + field('value', choice($.initializer_list, $._expression)), ), compound_statement: $ => seq( '{', repeat($._top_level_item), - '}' + '}', ), - storage_class_specifier: $ => choice( + storage_class_specifier: _ => choice( 'extern', 'static', 'auto', 'register', - 'inline' + 'inline', ), - type_qualifier: $ => choice( + type_qualifier: _ => choice( 'const', 'volatile', 'restrict', - '_Atomic' + '_Atomic', ), _type_specifier: $ => choice( @@ -472,7 +485,7 @@ module.exports = grammar({ $.macro_type_specifier, $.sized_type_specifier, $.primitive_type, - $._type_identifier + $._type_identifier, ), sized_type_specifier: $ => seq( @@ -480,15 +493,15 @@ module.exports = grammar({ 'signed', 'unsigned', 'long', - 'short' + 'short', )), field('type', optional(choice( prec.dynamic(-1, $._type_identifier), - $.primitive_type - ))) + $.primitive_type, + ))), ), - primitive_type: $ => token(choice( + primitive_type: _ => token(choice( 'bool', 'char', 'int', @@ -502,7 +515,7 @@ module.exports = grammar({ 'charptr_t', ...[8, 16, 32, 64].map(n => `int${n}_t`), ...[8, 16, 32, 64].map(n => `uint${n}_t`), - ...[8, 16, 32, 64].map(n => `char${n}_t`) + ...[8, 16, 32, 64].map(n => `char${n}_t`), )), enum_specifier: $ => seq( @@ -510,17 +523,17 @@ module.exports = grammar({ choice( seq( field('name', $._type_identifier), - field('body', optional($.enumerator_list)) + field('body', optional($.enumerator_list)), ), - field('body', $.enumerator_list) - ) + field('body', $.enumerator_list), + ), ), enumerator_list: $ => seq( '{', commaSep($.enumerator), optional(','), - '}' + '}', ), struct_specifier: $ => seq( @@ -529,10 +542,10 @@ module.exports = grammar({ choice( seq( field('name', $._type_identifier), - field('body', optional($.field_declaration_list)) + field('body', optional($.field_declaration_list)), ), - field('body', $.field_declaration_list) - ) + field('body', $.field_declaration_list), + ), ), union_specifier: $ => seq( @@ -541,16 +554,16 @@ module.exports = grammar({ choice( seq( field('name', $._type_identifier), - field('body', optional($.field_declaration_list)) + field('body', optional($.field_declaration_list)), ), - field('body', $.field_declaration_list) - ) + field('body', $.field_declaration_list), + ), ), field_declaration_list: $ => seq( '{', repeat($._field_declaration_list_item), - '}' + '}', ), _field_declaration_list_item: $ => choice( @@ -566,44 +579,44 @@ module.exports = grammar({ $._declaration_specifiers, commaSep(field('declarator', $._field_declarator)), optional($.bitfield_clause), - ';' + ';', ), bitfield_clause: $ => seq(':', $._expression), enumerator: $ => seq( field('name', $.identifier), - optional(seq('=', field('value', $._expression))) + optional(seq('=', field('value', $._expression))), ), - variadic_parameter: $ => seq( + variadic_parameter: _ => seq( '...', ), parameter_list: $ => seq( '(', commaSep(choice($.parameter_declaration, $.variadic_parameter)), - ')' + ')', ), parameter_declaration: $ => seq( $._declaration_specifiers, optional(field('declarator', choice( $._declarator, - $._abstract_declarator - ))) + $._abstract_declarator, + ))), ), // Statements attributed_statement: $ => seq( repeat1($.attribute_declaration), - $._statement + $._statement, ), _statement: $ => choice( $.case_statement, - $._non_case_statement + $._non_case_statement, ), _non_case_statement: $ => choice( @@ -619,21 +632,21 @@ module.exports = grammar({ $.return_statement, $.break_statement, $.continue_statement, - $.goto_statement + $.goto_statement, ), labeled_statement: $ => seq( field('label', $._statement_identifier), ':', - $._statement + $._statement, ), expression_statement: $ => seq( optional(choice( $._expression, - $.comma_expression + $.comma_expression, )), - ';' + ';', ), if_statement: $ => prec.right(seq( @@ -642,33 +655,33 @@ module.exports = grammar({ field('consequence', $._statement), optional(seq( 'else', - field('alternative', $._statement) - )) + field('alternative', $._statement), + )), )), switch_statement: $ => seq( 'switch', field('condition', $.parenthesized_expression), - field('body', $.compound_statement) + field('body', $.compound_statement), ), case_statement: $ => prec.right(seq( choice( seq('case', field('value', $._expression)), - 'default' + 'default', ), ':', repeat(choice( $._non_case_statement, $.declaration, - $.type_definition - )) + $.type_definition, + )), )), while_statement: $ => seq( 'while', field('condition', $.parenthesized_expression), - field('body', $._statement) + field('body', $._statement), ), do_statement: $ => seq( @@ -676,7 +689,7 @@ module.exports = grammar({ field('body', $._statement), 'while', field('condition', $.parenthesized_expression), - ';' + ';', ), for_statement: $ => seq( @@ -684,32 +697,32 @@ module.exports = grammar({ '(', choice( field('initializer', $.declaration), - seq(field('initializer', optional(choice($._expression, $.comma_expression))), ';') + seq(field('initializer', optional(choice($._expression, $.comma_expression))), ';'), ), field('condition', optional(choice($._expression, $.comma_expression))), ';', field('update', optional(choice($._expression, $.comma_expression))), ')', - field('body', $._statement) + field('body', $._statement), ), return_statement: $ => seq( 'return', optional(choice($._expression, $.comma_expression)), - ';' + ';', ), - break_statement: $ => seq( - 'break', ';' + break_statement: _ => seq( + 'break', ';', ), - continue_statement: $ => seq( - 'continue', ';' + continue_statement: _ => seq( + 'continue', ';', ), goto_statement: $ => seq( 'goto', field('label', $._statement_identifier), - ';' + ';', ), // Expressions @@ -735,13 +748,13 @@ module.exports = grammar({ $.null, $.concatenated_string, $.char_literal, - $.parenthesized_expression + $.parenthesized_expression, ), comma_expression: $ => seq( field('left', $._expression), ',', - field('right', choice($._expression, $.comma_expression)) + field('right', choice($._expression, $.comma_expression)), ), conditional_expression: $ => prec.right(PREC.CONDITIONAL, seq( @@ -749,7 +762,7 @@ module.exports = grammar({ '?', optional(field('consequence', $._expression)), ':', - field('alternative', $._expression) + field('alternative', $._expression), )), _assignment_left_expression: $ => choice( @@ -758,7 +771,7 @@ module.exports = grammar({ $.field_expression, $.pointer_expression, $.subscript_expression, - $.parenthesized_expression + $.parenthesized_expression, ), assignment_expression: $ => prec.right(PREC.ASSIGNMENT, seq( @@ -774,19 +787,19 @@ module.exports = grammar({ '>>=', '&=', '^=', - '|=' + '|=', )), - field('right', $._expression) + field('right', $._expression), )), pointer_expression: $ => prec.left(PREC.CAST, seq( field('operator', choice('*', '&')), - field('argument', $._expression) + field('argument', $._expression), )), unary_expression: $ => prec.left(PREC.UNARY, seq( field('operator', choice('!', '~', '-', '+')), - field('argument', $._expression) + field('argument', $._expression), )), binary_expression: $ => { @@ -814,9 +827,10 @@ module.exports = grammar({ return choice(...table.map(([operator, precedence]) => { return prec.left(precedence, seq( field('left', $._expression), + // @ts-ignore field('operator', operator), - field('right', $._expression) - )) + field('right', $._expression), + )); })); }, @@ -833,34 +847,34 @@ module.exports = grammar({ '(', field('type', $.type_descriptor), ')', - field('value', $._expression) + field('value', $._expression), )), type_descriptor: $ => seq( repeat($.type_qualifier), field('type', $._type_specifier), repeat($.type_qualifier), - field('declarator', optional($._abstract_declarator)) + field('declarator', optional($._abstract_declarator)), ), sizeof_expression: $ => prec(PREC.SIZEOF, seq( 'sizeof', choice( field('value', $._expression), - seq('(', field('type', $.type_descriptor), ')') - ) + seq('(', field('type', $.type_descriptor), ')'), + ), )), subscript_expression: $ => prec(PREC.SUBSCRIPT, seq( field('argument', $._expression), '[', field('index', $._expression), - ']' + ']', )), call_expression: $ => prec(PREC.CALL, seq( field('function', $._expression), - field('arguments', $.argument_list) + field('arguments', $.argument_list), )), argument_list: $ => seq('(', commaSep($._expression), ')'), @@ -868,22 +882,22 @@ module.exports = grammar({ field_expression: $ => seq( prec(PREC.FIELD, seq( field('argument', $._expression), - field('operator', choice('.', '->')) + field('operator', choice('.', '->')), )), - field('field', $._field_identifier) + field('field', $._field_identifier), ), compound_literal_expression: $ => seq( '(', field('type', $.type_descriptor), ')', - field('value', $.initializer_list) + field('value', $.initializer_list), ), parenthesized_expression: $ => seq( '(', choice($._expression, $.comma_expression), - ')' + ')', ), initializer_list: $ => seq( @@ -891,24 +905,24 @@ module.exports = grammar({ commaSep(choice( $.initializer_pair, $._expression, - $.initializer_list + $.initializer_list, )), optional(','), - '}' + '}', ), initializer_pair: $ => seq( field('designator', repeat1(choice($.subscript_designator, $.field_designator))), '=', - field('value', choice($._expression, $.initializer_list)) + field('value', choice($._expression, $.initializer_list)), ), subscript_designator: $ => seq('[', $._expression, ']'), field_designator: $ => seq('.', $._field_identifier), - number_literal: $ => { - const separator = "'"; + number_literal: _ => { + const separator = '\''; const hex = /[0-9a-fA-F]/; const decimal = /[0-9]/; const hexDigits = seq(repeat1(hex), repeat(seq(separator, repeat1(hex)))); @@ -921,68 +935,68 @@ module.exports = grammar({ choice( decimalDigits, seq('0b', decimalDigits), - seq('0x', hexDigits) + seq('0x', hexDigits), ), - optional(seq('.', optional(hexDigits))) + optional(seq('.', optional(hexDigits))), ), - seq('.', decimalDigits) + seq('.', decimalDigits), ), optional(seq( /[eEpP]/, optional(seq( optional(/[-\+]/), - hexDigits - )) + hexDigits, + )), )), - repeat(choice('u', 'l', 'U', 'L', 'f', 'F')) - )) + repeat(choice('u', 'l', 'U', 'L', 'f', 'F')), + )); }, char_literal: $ => seq( choice('L\'', 'u\'', 'U\'', 'u8\'', '\''), choice( $.escape_sequence, - token.immediate(/[^\n']/) + token.immediate(/[^\n']/), ), - '\'' + '\'', ), concatenated_string: $ => seq( $.string_literal, - repeat1($.string_literal) + repeat1($.string_literal), ), string_literal: $ => seq( choice('L"', 'u"', 'U"', 'u8"', '"'), repeat(choice( token.immediate(prec(1, /[^\\"\n]+/)), - $.escape_sequence + $.escape_sequence, )), '"', ), - escape_sequence: $ => token(prec(1, seq( + escape_sequence: _ => token(prec(1, 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}/, + ), ))), - system_lib_string: $ => token(seq( + system_lib_string: _ => token(seq( '<', repeat(choice(/[^>\n]/, '\\>')), - '>' + '>', )), - true: $ => token(choice('TRUE', 'true')), - false: $ => token(choice('FALSE', 'false')), - null: $ => 'NULL', + true: _ => token(choice('TRUE', 'true')), + false: _ => token(choice('FALSE', 'false')), + null: _ => 'NULL', - identifier: $ => /(\p{XID_Start}|_)\p{XID_Continue}*/, + identifier: _ => /(\p{XID_Start}|_)\p{XID_Continue}*/, _type_identifier: $ => alias($.identifier, $.type_identifier), _field_identifier: $ => alias($.identifier, $.field_identifier), @@ -990,24 +1004,24 @@ module.exports = grammar({ _empty_declaration: $ => seq( $._type_specifier, - ';' + ';', ), macro_type_specifier: $ => prec.dynamic(-1, seq( field('name', $.identifier), '(', field('type', $.type_descriptor), - ')' + ')', )), // http://stackoverflow.com/questions/13014947/regex-to-match-a-c-style-multiline-comment/36328890#36328890 - comment: $ => token(choice( + comment: _ => token(choice( seq('//', /(\\+(.|\r?\n)|[^\\\n])*/), seq( '/*', /[^*]*\*+([^/*][^*]*\*+)*/, - '/' - ) + '/', + ), )), }, @@ -1019,13 +1033,28 @@ module.exports = grammar({ $._field_declarator, $._type_declarator, $._abstract_declarator, - ] + ], }); -module.exports.PREC = PREC - -function preprocIf (suffix, content) { - function elseBlock ($) { +module.exports.PREC = PREC; + +/** + * + * @param {string} suffix + * + * @param {RuleBuilder} content + * + * @return {RuleBuilders} + */ +function preprocIf(suffix, content) { + /** + * + * @param {GrammarSymbols} $ + * + * @return {ChoiceRule} + * + */ + function elseBlock($) { return choice( suffix ? alias($['preproc_else' + suffix], $.preproc_else) : $.preproc_else, suffix ? alias($['preproc_elif' + suffix], $.preproc_elif) : $.preproc_elif, @@ -1039,7 +1068,7 @@ function preprocIf (suffix, content) { '\n', repeat(content($)), field('alternative', optional(elseBlock($))), - preprocessor('endif') + preprocessor('endif'), ), ['preproc_ifdef' + suffix]: $ => seq( @@ -1047,12 +1076,12 @@ function preprocIf (suffix, content) { field('name', $.identifier), repeat(content($)), field('alternative', optional(elseBlock($))), - preprocessor('endif') + preprocessor('endif'), ), ['preproc_else' + suffix]: $ => seq( preprocessor('else'), - repeat(content($)) + repeat(content($)), ), ['preproc_elif' + suffix]: $ => seq( @@ -1061,22 +1090,41 @@ function preprocIf (suffix, content) { '\n', repeat(content($)), field('alternative', optional(elseBlock($))), - ) - } -} - -function preprocessor (command) { - return alias(new RegExp('#[ \t]*' + command), '#' + command) + ), + }; } -function commaSep (rule) { - return optional(commaSep1(rule)) +/** + * Creates a preprocessor regex rule + * + * @param {RegExp|Rule|String} command + * + * @return {AliasRule} + */ +function preprocessor(command) { + return alias(new RegExp('#[ \t]*' + command), '#' + command); } -function commaSep1 (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)); } -function commaSepTrailing (recurSymbol, rule) { - return choice(rule, seq(recurSymbol, ',', rule)) +/** + * 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))); } diff --git a/package.json b/package.json index 707facf..df20c9b 100644 --- a/package.json +++ b/package.json @@ -17,10 +17,13 @@ "nan": "^2.14.0" }, "devDependencies": { + "eslint": "^8.41.0", + "eslint-config-google": "^0.14.0", "tree-sitter-cli": "^0.20.0" }, "scripts": { "build": "tree-sitter generate && node-gyp build", + "lint": "eslint grammar.js", "test": "tree-sitter test && tree-sitter parse examples/* --quiet --time", "test-windows": "tree-sitter test" }, @@ -30,6 +33,10 @@ "file-types": [ "c", "h" + ], + "injection-regex": "^(c|h)$", + "highlights": [ + "queries/highlights.scm" ] } ]