@willbooster/tree-sitter-haskell 8.2.0 → 8.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -79,6 +79,8 @@ parser.setLanguage(await Language.load(haskell));
79
79
 
80
80
  The package also ships `grammar.js` with the files in `grammar/` it loads, the queries in `queries/`, and the node types in `src/node-types.json`.
81
81
 
82
+ For [hsc2hs](https://github.com/haskell/hsc2hs) source in `.hsc` files, load `tree-sitter-hsc.wasm` instead. This dialect parses C directives and the doubled hashes that hsc2hs turns into literal hashes. Its node schema is `hsc/src/node-types.json`. Combine the ordinary queries with the matching suffixes in `hsc/queries/` for directive highlighting and C-body injections.
83
+
82
84
  For code navigation, use `queries/tags.scm` (or `TAGS_QUERY` in Rust). It indexes module headers, top-level named functions and bindings, named types and classes, class and instance methods, and syntactic variable/operator calls. A signature and each equation have separate definition locations. Call references identify the called name without resolving its binding.
83
85
 
84
86
  Declaration names and variable/operator callees remain indexed through nested parentheses. Class and instance equations retain their method roles; grouping a value without applying it does not create a call reference. Destructuring bindings contribute their explicit names at every nesting depth, including as-pattern binders and record puns. Local pattern bindings, names bound by patterns inside declaration quotes and constructors (including pattern synonyms) are not indexed.
@@ -96,7 +98,7 @@ fuzzed with:
96
98
  ```toml
97
99
  [dependencies]
98
100
  tree-sitter = { package = "willbooster-tree-sitter", version = "7.0.5" }
99
- tree-sitter-haskell = { package = "willbooster-tree-sitter-haskell", version = "7" }
101
+ tree-sitter-haskell = { package = "willbooster-tree-sitter-haskell", version = "8" }
100
102
  ```
101
103
 
102
104
  ```rust
@@ -104,6 +106,8 @@ let mut parser = tree_sitter::Parser::new();
104
106
  parser.set_language(&tree_sitter_haskell::LANGUAGE.into())?;
105
107
  ```
106
108
 
109
+ For `.hsc` files in Rust, select `HSC_LANGUAGE` and `HSC_NODE_TYPES`. Use `HSC_HIGHLIGHTS_QUERY` and `HSC_INJECTIONS_QUERY` for the combined queries; `TAGS_QUERY` and `LOCALS_QUERY` are shared with ordinary Haskell.
110
+
107
111
  ## Development
108
112
 
109
113
  ```sh
@@ -125,7 +129,7 @@ well (e.g. `script/tree-sitter parse file.hs`).
125
129
  `bun run generate` records a fresh generation profile from the applicable `test/corpus` cases and Git-tracked
126
130
  files in `examples/`, then generates compact parser tables. The parser also embeds metadata from `tree-sitter.json`. After changing a grammar file,
127
131
  `tree-sitter.json`, a corpus case, or a tracked example,
128
- regenerate and commit `src/`. Stage added or removed examples with `git add -A examples` before generation so the profile uses the intended file list.
132
+ regenerate and commit `src/` and `hsc/src/`. Stage added or removed examples with `git add -A examples` before generation so the profile uses the intended file list.
129
133
  Profiles in `.tmp/generation-profiles/` are temporary and must not be committed. `bun run build-wasm`, `bun run build/ci`,
130
134
  and the release build regenerate the parsers before compiling them.
131
135
 
package/grammar/data.js CHANGED
@@ -70,7 +70,7 @@ module.exports = {
70
70
  */
71
71
  gadt_constructor: $ => seq(
72
72
  choice(
73
- field('name', $._con),
73
+ field('name', $._decl_con),
74
74
  field('names', alias($._con_binding_list, $.binding_list)),
75
75
  ),
76
76
  $._colon2,
@@ -97,7 +97,7 @@ module.exports = {
97
97
  _field_type: $ => choice($.strict_field, $.lazy_field, $.type),
98
98
 
99
99
  _datacon_prefix: $ => seq(
100
- field('name', $._con),
100
+ field('name', $._decl_con),
101
101
  repeat(prec('patterns', field('field', $._field_type))),
102
102
  ),
103
103
 
@@ -109,7 +109,7 @@ module.exports = {
109
109
  )),
110
110
 
111
111
  _datacon_record: $ => seq(
112
- field('name', $._constructor),
112
+ field('name', $._decl_constructor),
113
113
  field('fields', alias($._record_fields, $.fields)),
114
114
  ),
115
115
 
@@ -169,7 +169,7 @@ module.exports = {
169
169
  _newtype_con_field: $ => $.type,
170
170
 
171
171
  newtype_constructor: $ => seq(
172
- field('name', $._con),
172
+ field('name', $._decl_con),
173
173
  field('field', choice(
174
174
  alias($._newtype_con_field, $.field),
175
175
  alias($._record_fields, $.record),
package/grammar/id.js CHANGED
@@ -37,11 +37,13 @@ module.exports = {
37
37
  // ------------------------------------------------------------------------
38
38
 
39
39
  _constructor: $ => alias($.name, $.constructor),
40
+ _decl_constructor: $ => $._constructor,
40
41
  _qualified_constructor: $ => qualified($, $._constructor),
41
42
  _qconid: $ => alias($._qualified_constructor, $.qualified),
42
43
  _conids: $ => choice($._qconid, $._constructor),
43
44
 
44
45
  _con: $ => choice($._constructor, $._pconsym),
46
+ _decl_con: $ => $._con,
45
47
  _qcon: $ => choice($._qconid, $._pqconsym),
46
48
  _cons: $ => choice(prec('con', $._con), $._qcon),
47
49
 
package/grammar/lexeme.js CHANGED
@@ -6,15 +6,15 @@ const varid_start_char = /[_\p{Ll}\p{Lo}]/
6
6
 
7
7
  const conid_start_char = /[\p{Lu}\p{Lt}]/
8
8
 
9
- module.exports = {
9
+ module.exports = (hash = '#') => ({
10
10
 
11
- variable: _ => token(seq(varid_start_char, id_char, /#*/)),
11
+ variable: _ => token(seq(varid_start_char, id_char, hash === '#' ? /#*/ : /(##)*/)),
12
12
 
13
13
  implicit_variable: _ => token(seq('?', varid_start_char, id_char)),
14
14
 
15
- name: _ => token(seq(conid_start_char, id_char, /#*/)),
15
+ name: _ => token(seq(conid_start_char, id_char, hash === '#' ? /#*/ : /(##)*/)),
16
16
 
17
- label: _ => token(seq('#', choice(/[\pL\p{Mn}\pN_']+/, quoted_string(
17
+ label: _ => token(seq(hash, choice(/[\pL\p{Mn}\pN_']+/, quoted_string(
18
18
  /[^\p{C}\p{Zl}\p{Zp}\\"]/,
19
19
  /\\(?:[abfnrtv\\"'&]|\^[@-_]|[0-9]+|o[0-7]+|x[0-9a-fA-F]+|NUL|SOH|STX|ETX|EOT|ENQ|ACK|BEL|BS|HT|LF|VT|FF|CR|SO|SI|DLE|DC[1-4]|NAK|SYN|ETB|CAN|EM|SUB|ESC|FS|GS|RS|US|SP|DEL)/,
20
20
  )))),
@@ -52,12 +52,12 @@ module.exports = {
52
52
  _bracket_open: $ => seq('[', $._cmd_texp_start),
53
53
  _bracket_close: $ => seq(']', $._cmd_texp_end),
54
54
 
55
- _unboxed_open: $ => seq(optional($._unboxed_label_start), alias(seq($._paren_open, token.immediate('#')), '(#')),
56
- _unboxed_close: $ => seq('#)', $._cmd_texp_end),
55
+ _unboxed_open: $ => seq(optional($._unboxed_label_start), alias(seq($._paren_open, token.immediate(hash)), '(#')),
56
+ _unboxed_close: $ => seq(`${hash})`, $._cmd_texp_end),
57
57
  _unboxed_bar: _ => choice('|', token.immediate('|')),
58
58
 
59
59
  _where: $ => seq(optional($._phantom_where), 'where'),
60
60
 
61
61
  _bar: $ => seq(optional($._phantom_bar), '|'),
62
62
 
63
- }
63
+ })
@@ -9,9 +9,11 @@ const {
9
9
  const decimal = /[0-9][0-9_]*/
10
10
  const exponent = /[eE][+-]?[0-9_]+/
11
11
  const hex_exponent = /[pP][+-]?[0-9a-fA-F_]+/
12
- const magic_hash = rule => token(seq(rule, optional(token.immediate(/##?/))))
13
12
 
14
- module.exports = {
13
+
14
+ module.exports = (hashSuffix = /##?/) => {
15
+ const magic_hash = rule => token(seq(rule, optional(token.immediate(hashSuffix))))
16
+ return {
15
17
 
16
18
  float: _ => magic_hash(
17
19
  seq(
@@ -100,3 +102,4 @@ module.exports = {
100
102
  ),
101
103
 
102
104
  }
105
+ }
package/grammar.js CHANGED
@@ -9,8 +9,8 @@ const
9
9
  general = require('./grammar/general.js'),
10
10
  id = require('./grammar/id.js'),
11
11
  inline = require('./grammar/inline.js'),
12
- lexeme = require('./grammar/lexeme.js'),
13
- literal = require('./grammar/literal.js'),
12
+ lexeme = require('./grammar/lexeme.js')(),
13
+ literal = require('./grammar/literal.js')(),
14
14
  module_ = require('./grammar/module.js'),
15
15
  operator = require('./grammar/operator.js'),
16
16
  pat = require('./grammar/pat.js'),
package/hsc/grammar.js ADDED
@@ -0,0 +1,69 @@
1
+ const haskell = require('../grammar.js')
2
+ const literal = require('../grammar/literal.js')
3
+ const lexeme = require('../grammar/lexeme.js')
4
+
5
+ const braced = ($, close) => seq(
6
+ $._cond_hsc_hash,
7
+ '#',
8
+ optional($._hsc_name_space),
9
+ token.immediate('{'),
10
+ $._cmd_hsc_brace_open,
11
+ optional($._hsc_braced_space),
12
+ field('name', $.hsc_directive_name),
13
+ field('body', alias($.hsc_args_nested, $.hsc_args)),
14
+ close,
15
+ $._cmd_brace_close,
16
+ )
17
+
18
+ module.exports = grammar(haskell, {
19
+ name: 'hsc',
20
+
21
+ externals: ($, previous) => [
22
+ ...previous.slice(0, -1),
23
+ $._cmd_hsc_brace_open,
24
+ $._cond_hsc_hash,
25
+ $.hsc_args_nested,
26
+ $.hsc_args_newline,
27
+ previous[previous.length - 1],
28
+ ],
29
+
30
+ conflicts: ($, previous) => [
31
+ ...previous,
32
+ [$._foreign_safety, $.entity],
33
+ ],
34
+
35
+ rules: {
36
+ ...literal(/(?:##){1,2}/),
37
+ ...lexeme('##'),
38
+
39
+ _operator_hash_head: _ => seq(
40
+ choice('##', token.immediate('##')),
41
+ optional(choice(token.immediate('##'), token.immediate('|'))),
42
+ ),
43
+
44
+ _foreign_calling_convention: ($, previous) => choice(previous, $.hsc),
45
+ _foreign_safety: ($, previous) => choice(previous, $.hsc),
46
+ _ie_entity: ($, previous) => choice(previous, $.hsc),
47
+ entity: ($, previous) => choice(previous, $.hsc),
48
+ literal: ($, previous) => choice(previous, $._hsc_literal),
49
+ _var: ($, previous) => choice(previous, $.hsc),
50
+ _tycon: ($, previous) => choice(previous, $.hsc),
51
+ _decl_con: ($, previous) => choice(previous, $.hsc),
52
+ _decl_constructor: ($, previous) => choice(previous, $.hsc),
53
+
54
+ hsc: $ => choice(
55
+ braced($, '}'),
56
+ seq(
57
+ $._cond_hsc_hash,
58
+ '#',
59
+ optional($._hsc_name_space),
60
+ field('name', $.hsc_directive_name),
61
+ field('body', alias($.hsc_args_newline, $.hsc_args)),
62
+ ),
63
+ ),
64
+ _hsc_literal: $ => braced($, choice('}##', '}####')),
65
+ _hsc_name_space: _ => token.immediate(/(?:[\t\v\f\r\p{Zs}\x85\u2028\u2029]|\\\r?\n)+/),
66
+ _hsc_braced_space: _ => token.immediate(/(?:\p{White_Space}|\\\r?\n)+/),
67
+ hsc_directive_name: _ => token.immediate(prec(-1, /[\pL_](?:[\pL\pN_]|\\\r?\n)*/)),
68
+ },
69
+ })
@@ -0,0 +1 @@
1
+ (hsc_directive_name) @function.macro
@@ -0,0 +1,2 @@
1
+ ((hsc_args) @injection.content
2
+ (#set! injection.language "c"))