diff --git a/README.md b/README.md
index e387a4d..fc02cb1 100644
--- a/README.md
+++ b/README.md
@@ -2,13 +2,62 @@
This repository contains a parser definition of the [ReScript](https://rescript-lang.org/) language for the [Tree-sitter](https://tree-sitter.github.io/tree-sitter/) parser generator tool.
-Athough Tree-sitter has many applications, the main intent of this parser is powering the [`nvim-treesitter-rescript`](https://github.com/nkrkv/nvim-tree-sitter-rescript/) NeoVim plugin which may be used to improve development experience in the NeoVim + ReScript combo.
-
Queries for text objects are also included which help you to navigate, select, and modify ReScript code syntactically. For NeoVim, the [`nvim-treesitter-textobjects`](https://github.com/nvim-treesitter/nvim-treesitter-textobjects) plugin is required to use Tree-sitter text objects.
## Installation
-- If you want ReScript Tree-sitter in NeoVim, refer to [`nvim-treesitter-rescript`](https://github.com/nkrkv/nvim-tree-sitter-rescript/) installation notes;
+### Neovim
+
+If you want ReScript Tree-sitter in NeoVim, you will first need to register a new parser for it like so:
+
+```lua
+local parser_config = require("nvim-treesitter.parsers").get_parser_configs()
+parser_config.rescript = {
+ install_info = {
+ url = "https://github.com/rescript-lang/tree-sitter-rescript",
+ branch = "main",
+ files = { "src/scanner.c" },
+ generate_requires_npm = false,
+ requires_generate_from_grammar = true,
+ use_makefile = true, -- macOS specific instruction
+ },
+}
+```
+
+This will make `TSInstall rescript` globally available. For more persistent approach you should add this parser to your Lua configuration.
+
+Default configuration detects `.res` and `.resi` files. You can confirm that it's correctly installed by invoking `:InspectTree` when you are in the ReScript file.
+
+- Notice that by default you will not see the highlighting! To enable highlighting, you will need to install this package either as a dependency or directly.
+
+If you are using `lazy.nvim` example configuration will look like so:
+
+```lua
+ {
+ "nvim-treesitter/nvim-treesitter",
+ dependencies = {
+ "rescript-lang/tree-sitter-rescript"
+ },
+ opts = function(_, opts) -- this is needed so you won't override your default nvim-treesitter configuration
+ vim.list_extend(opts.ensure_installed, {
+ "rescript",
+ })
+
+ local parser_config = require("nvim-treesitter.parsers").get_parser_configs()
+ parser_config.rescript = {
+ install_info = {
+ url = "https://github.com/rescript-lang/tree-sitter-rescript",
+ branch = "main",
+ files = { "src/scanner.c" },
+ generate_requires_npm = false,
+ requires_generate_from_grammar = true,
+ use_makefile = true, -- macOS specific instruction
+ },
+ }
+ end,
+ }
+```
+
- If you want it for other purposes, you probably know what to do.
## Contributing
diff --git a/grammar.js b/grammar.js
index 10b537d..e75fdc3 100644
--- a/grammar.js
+++ b/grammar.js
@@ -1,3 +1,5 @@
+///
+
module.exports = grammar({
name: 'rescript',
@@ -105,7 +107,9 @@ module.exports = grammar({
[$._reserved_identifier, $.function],
[$.exception_pattern, $.or_pattern],
[$.type_binding, $._inline_type],
- [$._module_structure, $.parenthesized_module_expression]
+ [$._module_structure, $.parenthesized_module_expression],
+ [$.record_type_field, $.object_type_field],
+ [$._record_type_member, $._object_type_member],
],
rules: {
@@ -174,6 +178,7 @@ module.exports = grammar({
)),
optional(seq(
'=',
+ optional('await'),
field('definition', $._module_definition),
)),
)),
@@ -314,6 +319,7 @@ module.exports = grammar({
$.module_pack,
$.unit,
$.polymorphic_type,
+ alias($._as_aliasing_non_function_inline_type, $.as_aliasing_type)
),
polymorphic_type: $ => seq(
@@ -377,37 +383,48 @@ module.exports = grammar({
record_type: $ => seq(
'{',
- commaSept($.record_type_field),
+ commaSept($._record_type_member),
'}',
),
- record_type_field: $ => seq(
- optional('mutable'),
- alias($.value_identifier, $.property_identifier),
- optional('?'),
- $.type_annotation,
+ record_type_field: $ =>
+ seq(
+ optional('mutable'),
+ alias($.value_identifier, $.property_identifier),
+ optional('?'),
+ $.type_annotation,
+ ),
+
+ type_spread: $ =>
+ seq('...', choice($.type_identifier, $.generic_type, $.type_identifier_path)),
+
+ _record_type_member: $ => choice(
+ $.record_type_field,
+ $.type_spread
),
object_type: $ => prec.left(seq(
'{',
choice(
- commaSep1t($._object_type_field),
- seq('.', commaSept($._object_type_field)),
- seq('..', commaSept($._object_type_field)),
+ commaSep1t($._object_type_member),
+ seq('.', commaSept($._object_type_member)),
+ seq('..', commaSept($._object_type_member)),
),
'}',
)),
- _object_type_field: $ => alias($.object_type_field, $.field),
+ _object_type_member: $ =>
+ choice(
+ alias($.object_type_field, $.field),
+ $.type_spread
+ ),
object_type_field: $ => choice(
- seq('...', choice($.type_identifier, $.type_identifier_path)),
seq(
alias($.string, $.property_identifier),
':',
$._type,
),
-
),
generic_type: $ => prec.left(seq(
@@ -521,6 +538,7 @@ module.exports = grammar({
$.module_pack,
$.extension_expression,
$.lazy_expression,
+ $._jsx_element
),
parenthesized_expression: $ => seq(
@@ -698,6 +716,9 @@ module.exports = grammar({
as_aliasing_type: $ => seq($._type, 'as', $.type_identifier),
+ _as_aliasing_non_function_inline_type: $ =>
+ prec(2, seq($._non_function_inline_type, 'as', $.type_identifier)),
+
assert_expression: $ => prec.left(seq('assert', $.expression)),
call_expression: $ => prec('call', seq(
@@ -726,6 +747,7 @@ module.exports = grammar({
'(',
optional($.uncurry),
optional(commaSep1t($._call_argument)),
+ optional($.partial_application_spread),
')'
),
@@ -737,6 +759,8 @@ module.exports = grammar({
$.labeled_argument,
),
+ partial_application_spread: $ => "...",
+
labeled_argument: $ => seq(
'~',
field('label', $.value_identifier),
@@ -876,6 +900,7 @@ module.exports = grammar({
record_pattern: $ => seq(
'{',
commaSep1t(seq(
+ optional("?"),
choice(
$.value_identifier,
$.value_identifier_path,
@@ -1331,7 +1356,7 @@ module.exports = grammar({
const bigint_literal = seq(choice(hex_literal, binary_literal, octal_literal, decimal_digits), 'n')
const decimal_integer_literal = choice(
- repeat('0'),
+ repeat1('0'),
seq(repeat('0'), /[1-9]/, optional(seq(optional('_'), decimal_digits)))
)
diff --git a/package.json b/package.json
index 6a9bbbf..8980c64 100644
--- a/package.json
+++ b/package.json
@@ -17,7 +17,19 @@
"res",
"resi"
],
- "injection-regex": "rescript"
+ "injection-regex": "rescript",
+ "highlights": [
+ "queries/rescript/highlights.scm"
+ ],
+ "locals": [
+ "queries/rescript/locals.scm"
+ ],
+ "injections": [
+ "queries/rescript/injections.scm"
+ ],
+ "textobjects": [
+ "queries/rescript/textobjects.scm"
+ ]
}
]
}
diff --git a/queries/injections.scm b/queries/injections.scm
deleted file mode 100644
index ad135cb..0000000
--- a/queries/injections.scm
+++ /dev/null
@@ -1,21 +0,0 @@
-(comment) @comment
-
-; %re
-(extension_expression
- (extension_identifier) @_name
- (#eq? @_name "re")
- (expression_statement (_) @regex))
-
-; %raw
-(extension_expression
- (extension_identifier) @_name
- (#eq? @_name "raw")
- (expression_statement
- (_ (_) @javascript)))
-
-; %graphql
-(extension_expression
- (extension_identifier) @_name
- (#eq? @_name "graphql")
- (expression_statement
- (_ (_) @graphql)))
diff --git a/queries/highlights.scm b/queries/rescript/highlights.scm
similarity index 100%
rename from queries/highlights.scm
rename to queries/rescript/highlights.scm
diff --git a/queries/rescript/injections.scm b/queries/rescript/injections.scm
new file mode 100644
index 0000000..67f530d
--- /dev/null
+++ b/queries/rescript/injections.scm
@@ -0,0 +1,29 @@
+((comment) @injection.content (#set! injection.language "comment"))
+
+; %re
+(extension_expression
+ (extension_identifier) @_name
+ (#eq? @_name "re")
+ (expression_statement (_) @injection.content (#set! injection.language "regex")))
+
+; %raw
+(extension_expression
+ (extension_identifier) @_name
+ (#eq? @_name "raw")
+ (expression_statement
+ (_ (_) @injection.content (#set! injection.language "javascript"))))
+
+; %graphql
+(extension_expression
+ (extension_identifier) @_name
+ (#eq? @_name "graphql")
+ (expression_statement
+ (_ (_) @injection.content (#set! injection.language "graphql"))))
+
+; %relay
+(extension_expression
+ (extension_identifier) @_name
+ (#eq? @_name "relay")
+ (expression_statement
+ (_ (_) @injection.content (#set! injection.language "graphql") )))
+
diff --git a/queries/locals.scm b/queries/rescript/locals.scm
similarity index 100%
rename from queries/locals.scm
rename to queries/rescript/locals.scm
diff --git a/queries/textobjects.scm b/queries/rescript/textobjects.scm
similarity index 100%
rename from queries/textobjects.scm
rename to queries/rescript/textobjects.scm
diff --git a/src/scanner.c b/src/scanner.c
index 4c20192..3e80a79 100644
--- a/src/scanner.c
+++ b/src/scanner.c
@@ -113,7 +113,7 @@ static bool scan_comment(TSLexer *lexer) {
// Single-line comment
do {
advance(lexer);
- } while (lexer->lookahead != '\n');
+ } while (lexer->lookahead != '\n' && !lexer->eof(lexer));
return true;
case '*':
diff --git a/test/corpus/expressions.txt b/test/corpus/expressions.txt
index 2764643..fc20174 100644
--- a/test/corpus/expressions.txt
+++ b/test/corpus/expressions.txt
@@ -111,6 +111,7 @@ blocky(
~third={3},
)
f(raise)
+f(1, ...)
--------------------------------------------------------------------------------
@@ -191,7 +192,13 @@ f(raise)
(call_expression
function: (value_identifier)
arguments: (arguments
- (value_identifier)))))
+ (value_identifier))))
+ (expression_statement
+ (call_expression
+ function: (value_identifier)
+ arguments: (arguments
+ (number)
+ (partial_application_spread)))))
================================================================================
Pipe
@@ -755,6 +762,7 @@ switch person {
}) => 20
| Student({status: Sick}) => 30
| Student({name}) => 40
+| Student({?age}) => 50
}
--------------------------------------------------------------------------------
@@ -818,7 +826,16 @@ switch person {
(value_identifier))))
(sequence_expression
(expression_statement
- (number)))))))
+ (number))))
+ (switch_match
+ (variant_pattern
+ (variant_identifier)
+ (formal_parameters
+ (record_pattern
+ (value_identifier))))
+ (sequence_expression
+ (expression_statement
+ (number)))))))
================================================================================
Switch of lists
@@ -1149,6 +1166,8 @@ Math operators
- 1 + 2 / 3
-. 1.0 +. 2.0 /. 3.0
2.0 ** 3.0
+-0l
+-ln
--------------------------------------------------------------------------------
@@ -1170,7 +1189,12 @@ Math operators
(expression_statement
(binary_expression
(number)
- (number))))
+ (number)))
+ (expression_statement
+ (number))
+ (expression_statement
+ (unary_expression
+ (value_identifier))))
================================================================================
Boolean operators
diff --git a/test/corpus/jsx.txt b/test/corpus/jsx.txt
index 477c076..f736275 100644
--- a/test/corpus/jsx.txt
+++ b/test/corpus/jsx.txt
@@ -310,3 +310,20 @@ Spread props
(value_identifier))))
(jsx_closing_element
(jsx_identifier)))))
+
+================================================================================
+Elements in pipes
+================================================================================
+
+->Some
+
+--------------------------------------------------------------------------------
+
+(source_file
+ (expression_statement
+ (pipe_expression
+ (jsx_self_closing_element
+ (jsx_identifier))
+ (variant
+ (variant_identifier)))))
+
diff --git a/test/corpus/let_bindings.txt b/test/corpus/let_bindings.txt
index 54ae990..901b5d6 100644
--- a/test/corpus/let_bindings.txt
+++ b/test/corpus/let_bindings.txt
@@ -101,6 +101,8 @@ Record destructuring
let {bar, baz} = foo
let {bar, baz: qux} = foo
let {Bar.Bar.bar: bar} = foo
+let {?Bar.bar} = foo
+let {?bar} = foo
--------------------------------------------------------------------------------
@@ -127,6 +129,18 @@ let {Bar.Bar.bar: bar} = foo
(module_identifier))
(value_identifier))
(value_identifier))
+ (value_identifier)))
+ (let_declaration
+ (let_binding
+ (record_pattern
+ (value_identifier_path
+ (module_identifier)
+ (value_identifier)))
+ (value_identifier)))
+ (let_declaration
+ (let_binding
+ (record_pattern
+ (value_identifier))
(value_identifier))))
================================================================================
diff --git a/test/corpus/modules.txt b/test/corpus/modules.txt
index e42782c..3054a4b 100644
--- a/test/corpus/modules.txt
+++ b/test/corpus/modules.txt
@@ -746,3 +746,18 @@ module M = (Na: N, Nb: N): (
(type_identifier)
(type_identifier)))))
body: (block)))))
+
+================================================================================
+Dynamic imports
+================================================================================
+
+module LazyUtils: UtilsType = await Utils
+
+--------------------------------------------------------------------------------
+
+(source_file
+ (module_declaration
+ (module_binding
+ (module_identifier)
+ (module_identifier)
+ (module_identifier))))
diff --git a/test/corpus/type_declarations.txt b/test/corpus/type_declarations.txt
index 10f91d0..652e048 100644
--- a/test/corpus/type_declarations.txt
+++ b/test/corpus/type_declarations.txt
@@ -99,13 +99,23 @@ type t = {
mutable x: int,
- opt?: string
+ opt?: string,
+
+ env: {..} as 'env
}
type t = Mod.t = {a: int}
type t = {}
+type t = {
+ ...a,
+ ...b,
+ ...Mod.t,
+ ...Mod.t,
+ other: int,
+}
+
--------------------------------------------------------------------------------
(source_file
@@ -132,7 +142,13 @@ type t = {}
(record_type_field
(property_identifier)
(type_annotation
- (type_identifier))))))
+ (type_identifier)))
+ (record_type_field
+ (property_identifier)
+ (type_annotation
+ (as_aliasing_type
+ (object_type)
+ (type_identifier)))))))
(type_declaration
(type_binding
(type_identifier)
@@ -147,7 +163,33 @@ type t = {}
(type_declaration
(type_binding
(type_identifier)
- (record_type))))
+ (record_type)))
+ (type_declaration
+ (type_binding
+ (type_identifier)
+ (record_type
+ (type_spread
+ (type_identifier))
+ (type_spread
+ (generic_type
+ (type_identifier)
+ (type_arguments
+ (type_identifier))))
+ (type_spread
+ (generic_type
+ (type_identifier_path
+ (module_identifier)
+ (type_identifier))
+ (type_arguments
+ (type_identifier))))
+ (type_spread
+ (type_identifier_path
+ (module_identifier)
+ (type_identifier)))
+ (record_type_field
+ (property_identifier)
+ (type_annotation
+ (type_identifier)))))))
================================================================================
Extensible Variant
@@ -436,7 +478,7 @@ type t<'a> = {.."name": string} as 'a
(property_identifier
(string_fragment))
(type_identifier))
- (field
+ (type_spread
(type_identifier)))))
(type_declaration
(type_binding