@algosail/tree-sitter 0.1.1 → 0.1.3

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/grammar.js CHANGED
@@ -1,92 +1,179 @@
1
1
  /// <reference types="tree-sitter-cli/dsl" />
2
2
  // @ts-check
3
3
 
4
+ const UPPERNAME = /[A-Z][a-zA-Z0-9_]*/
5
+ const LOWERNAME = /[a-z][a-zA-Z0-9_]*/
6
+
4
7
  module.exports = grammar({
5
8
  name: 'sail',
6
9
 
7
10
  extras: ($) => [/\s+/],
8
11
 
9
12
  conflicts: ($) => [
10
- // '(' can start a comment OR a signature — tree-sitter resolves by
11
- // looking for '--' inside.
12
13
  [$.comment, $.signature],
13
14
  [$.comment, $.sig_quotation],
14
- // After word_def's signature, '(' is ambiguous: body comment vs next
15
- // top-level item. Declare as GLR self-conflict so both are explored.
16
- [$.word_def],
17
- // tag_group contains tag_def children; both can follow an uppercase name
18
- [$.tag_def, $.tag_group],
19
- // module_alias and type_name are both /[A-Z][a-zA-Z0-9_]*/
20
- // [$.type_name, $.module_alias],
21
- // type_variable and identifier are both lowercase words
22
- [$.type_variable, $.identifier],
15
+
16
+ [$.module_def, $.module_ref],
17
+ [$.group_def, $.group_ref],
18
+ [$.tag_def, $.tag_ref],
19
+ [$.map_def, $.map_ref],
20
+ [$.field_def, $.field_ref],
21
+
22
+ [$.group],
23
+ [$.tag],
24
+ [$.map],
25
+ [$.field],
26
+ [$.word],
27
+
28
+ [$.group_def],
29
+ [$.tag, $.group],
30
+ [$.word, $._expr],
23
31
  ],
24
32
 
25
33
  rules: {
26
34
  source_file: ($) => repeat($._top_level),
35
+ _top_level: ($) => choice($.comment, $.import, $.group, $.map, $.word),
36
+
37
+ // ~Module
38
+ module_def: ($) => /~[A-Z][a-zA-Z0-9_]*/,
39
+ // ~Module
40
+ module_ref: ($) => /~[A-Z][a-zA-Z0-9_]*/,
41
+ // &Group
42
+ group_def: ($) => /&[A-Z][a-zA-Z0-9_]*/,
43
+ // &Group
44
+ group_ref: ($) => /&[A-Z][a-zA-Z0-9_]*/,
45
+ // #Tag
46
+ tag_def: ($) => /#[A-Z][a-zA-Z0-9_]*/,
47
+ // #Tag
48
+ tag_ref: ($) => /#[A-Z][a-zA-Z0-9_]*/,
49
+ // _Tag
50
+ tag_pattern: ($) => /\_[A-Z][a-zA-Z0-9_]*/,
51
+ // _
52
+ default_pattern: ($) => token('_'),
53
+ // $Map
54
+ map_def: ($) => /\$[A-Z][a-zA-Z0-9_]*/,
55
+ // $Map
56
+ map_ref: ($) => /\$[A-Z][a-zA-Z0-9_]*/,
57
+ // .field
58
+ field_def: ($) => /\.[a-z][a-zA-Z0-9_]*/,
59
+ // $Map.field
60
+ field_ref: ($) => /\$[A-Z][a-zA-Z0-9_]*\.[a-z][a-zA-Z0-9_]*/,
61
+ // @word
62
+ word_def: ($) => /@[a-z][a-zA-Z0-9_]*/,
63
+ // /word
64
+ word_ref: ($) => /\/[a-z][a-zA-Z0-9_]*/,
65
+
66
+ // ~Module&Group
67
+ module_group_ref: ($) => /~[A-Z][a-zA-Z0-9_]*&[A-Z][a-zA-Z0-9_]*/,
68
+ // ~Module#Tag
69
+ module_tag_ref: ($) => /~[A-Z][a-zA-Z0-9_]*#[A-Z][a-zA-Z0-9_]*/,
70
+ // ~Module$Map
71
+ module_map_ref: ($) => /~[A-Z][a-zA-Z0-9_]*\$[A-Z][a-zA-Z0-9_]*/,
72
+ // ~Module$Map.field
73
+ module_field_ref: ($) => /~[A-Z][a-zA-Z0-9_]*\$[A-Z][a-zA-Z0-9_]*\.[a-z][a-zA-Z0-9_]*/,
74
+ // ~Module/word
75
+ module_word_ref: ($) => /~[A-Z][a-zA-Z0-9_]*\/[a-z][a-zA-Z0-9_]*/,
27
76
 
28
- _top_level: ($) =>
29
- choice($.comment, $.module_def, $.import_decl, $.tag_group, $.map_def, $.word_def),
30
-
31
- // Comment / doc block: ( any text )
32
- // Intentionally simple no nested-paren support inside comment text.
33
- comment: ($) => seq('(', optional($.comment_content), ')'),
34
- comment_content: ($) => /[^()]+/,
35
-
36
- // Module definition: !ModuleName
37
- module_def: ($) => field('name', $.module_name),
38
- module_name: ($) => /![A-Z][a-zA-Z0-9_]*/,
39
-
40
- // Import: |path/or/npm:pkg Alias
41
- import_decl: ($) => seq(field('path', $.import_path), field('alias', $.module_alias)),
42
-
43
- import_path: ($) => /\|[^\s]+/,
44
-
45
- module_alias: ($) => /~[A-Z][a-zA-Z0-9_]*/,
46
-
47
- // Tag group: &Name typeParam* (>TagCase typeParam*)*
48
- tag_group: ($) =>
49
- seq(field('name', $.tag_group_name), repeat($.type_variable), repeat($.tag_def)),
50
-
51
- tag_group_name: ($) => /&[A-Z][a-zA-Z0-9_]*/,
77
+ // Uppercase type: Int, Str, Maybe, List, etc.
78
+ type: ($) => /[A-Z][a-zA-Z0-9_]*/,
79
+ // Lowercase type variable: a, b, elem, etc.
80
+ type_var: ($) => /[a-z][a-zA-Z0-9_]*/,
81
+ // Lowercase type variable: a, b, elem, etc.
82
+ spread: ($) => /\.\.[a-z][a-zA-Z0-9_]*/,
52
83
 
53
- tag_def: ($) => seq(field('name', $.tag_name), repeat($.type_variable)),
84
+ // +Effect
85
+ effect_add: ($) => /\+[A-Z][a-zA-Z0-9_]*/,
86
+ // -Effect
87
+ effect_remove: ($) => /\-[A-Z][a-zA-Z0-9_]*/,
54
88
 
55
- tag_name: ($) => />[A-Z][a-zA-Z0-9_]*/,
89
+ // :name
90
+ slot_push: ($) => /:[a-z][a-zA-Z0-9_]*/,
56
91
 
57
- // Map definition: %Name (:field Type)*
58
- map_def: ($) => seq(field('name', $.map_name), repeat($.map_field)),
92
+ // ;name
93
+ slot_pop: ($) => /;[a-z][a-zA-Z0-9_]*/,
59
94
 
60
- map_name: ($) => /%[A-Z][a-zA-Z0-9_]*/,
95
+ // 'raw string literal'
96
+ raw_string: ($) => /\'[^\']*\'/,
61
97
 
62
- map_field: ($) => seq(field('key', $.map_field_name), field('type', $.type_name)),
98
+ // Catch-all: any non-whitespace sequence that doesn't match a more specific
99
+ // rule. prec(-1) gives it the lowest priority so every other token wins
100
+ // when there is a tie. Structural characters ( ) [ ] are excluded because
101
+ // they are needed by the parser to delimit blocks and comments.
102
+ raw_value: ($) => token(prec(-1, /[^\s\[\]()']+/)),
63
103
 
64
- map_field_name: ($) => /:[a-z][a-zA-Z0-9_]*/,
104
+ // Comment / doc block: ( any text )
105
+ // comment_content is recursive: it can contain plain text and/or nested
106
+ // parenthesised groups, so ( use f(x) here ) parses correctly.
107
+ comment: ($) => seq('(', optional($.comment_content), ')'),
108
+ comment_content: ($) => repeat1(choice(/[^()]+/, $.comment)),
109
+
110
+ // Import: +path/or/+pkg Alias
111
+ import: ($) => seq(field('path', $.path), field('module', $.module_def)),
112
+ path: ($) => /\+[^\s]+/,
113
+ // seq('+', field('url', alias(/[^\s]+/, $.url))),
114
+
115
+ // Tag group: &Name typeParam* (#TagCase typeParam*)*
116
+ group: ($) =>
117
+ seq(
118
+ field('def', $.group_def),
119
+ repeat($.type_var),
120
+ optional(field('doc', $.comment)),
121
+ repeat($.tag),
122
+ ),
123
+ tag: ($) =>
124
+ seq(
125
+ field('def', $.tag_def),
126
+ optional(field('type_param', $.type_var)),
127
+ optional(field('doc', $.comment)),
128
+ ),
129
+ group_type: ($) =>
130
+ seq(
131
+ field('group', choice($.group_ref, $.module_group_ref)),
132
+ optional(field('params', $._generic)),
133
+ ),
134
+ _generic: ($) => seq('{', repeat($._generic_content), '}'),
135
+ _generic_content: ($) => choice($.type, $.group_type, $.map_ref, $.module_map_ref),
136
+
137
+ // Map definition: %Name (.field Type)*
138
+ map: ($) => seq(field('def', $.map_def), optional(field('doc', $.comment)), repeat($.field)),
139
+ field: ($) =>
140
+ seq(
141
+ field('key', $.field_def),
142
+ field('type', $._field_types),
143
+ optional(field('doc', $.comment)),
144
+ ),
145
+ _field_types: ($) => choice($.type, $.group_type, $.map_ref, $.module_map_ref),
65
146
 
66
147
  // Word definition: @name ( sig ) expr*
67
148
  // Signature is required per the spec ("Word definition must have a signature").
68
149
  // prec.right makes the body's repeat greedy: prefer consuming '(' as a body
69
150
  // comment rather than ending the word_def early.
70
- word_def: ($) =>
71
- prec.right(seq(field('name', $.word_name), field('sig', $.signature), repeat($._expr))),
72
-
73
- word_name: ($) => /@[a-z][a-zA-Z0-9_]*/,
151
+ word: ($) =>
152
+ prec.right(
153
+ seq(
154
+ field('name_def', $.word_def),
155
+ field('sig', $.signature),
156
+ optional(field('doc', $.comment)),
157
+ repeat($._expr),
158
+ ),
159
+ ),
74
160
 
75
161
  // Signature: ( inputs -- outputs +effects )
76
162
  // The required '--' token is what makes it unambiguous vs a comment.
77
163
  signature: ($) => seq('(', repeat($._sig_item), $.sig_arrow, repeat($._sig_item), ')'),
78
-
79
164
  sig_arrow: ($) => token('--'),
80
-
81
165
  _sig_item: ($) =>
82
166
  choice(
83
167
  $.effect_add,
84
168
  $.effect_remove,
85
169
  $.spread,
86
- $.type_name,
87
- $.type_variable,
170
+ $.type,
171
+ $.type_var,
88
172
  $.sig_list,
89
173
  $.sig_quotation,
174
+ $.group_type,
175
+ $.map_ref,
176
+ $.module_map_ref,
90
177
  ),
91
178
 
92
179
  // [ Type Type ... ] — list / tuple type in a signature
@@ -95,37 +182,24 @@ module.exports = grammar({
95
182
  // ( a b -- c d ) — higher-order function type nested inside a signature
96
183
  sig_quotation: ($) => seq('(', repeat($._sig_item), $.sig_arrow, repeat($._sig_item), ')'),
97
184
 
98
- // +IO, +FAIL, etc.
99
- effect_add: ($) => /\+[A-Z][a-zA-Z0-9_]*/,
100
-
101
- // -IO, -FAIL, etc. (uppercase after dash avoids matching negative numbers)
102
- effect_remove: ($) => /-[A-Z][a-zA-Z0-9_]*/,
103
-
104
- // ..a, ..row — spread / row-variable in a signature
105
- spread: ($) => /\.\.[a-zA-Z][a-zA-Z0-9_]*/,
106
-
107
- // Uppercase type: Int, Str, Maybe, List, etc.
108
- type_name: ($) => /[A-Z][a-zA-Z0-9_]*/,
109
-
110
- // Lowercase type variable: a, b, elem, etc.
111
- type_variable: ($) => /[a-z][a-zA-Z0-9_]*/,
112
-
113
185
  // Expressions inside word bodies
114
186
  _expr: ($) =>
115
187
  choice(
116
188
  $.comment, // doc / inline comment block
117
189
  $.quotation,
118
190
  $.builtin_word,
119
- $.word_call,
120
- $.module_call,
121
- $.map_access,
122
- $.tag_constructor,
191
+ $.word_ref,
192
+ $.module_word_ref,
193
+ $.tag_ref,
194
+ $.module_tag_ref,
123
195
  $.tag_pattern,
196
+ $.default_pattern,
197
+ $.field_ref,
198
+ $.module_field_ref,
124
199
  $.slot_push,
125
200
  $.slot_pop,
126
201
  $.raw_string,
127
- $.number,
128
- $.identifier,
202
+ $.raw_value,
129
203
  ),
130
204
 
131
205
  // [ expr* ] — quotation (anonymous code block or list literal)
@@ -159,35 +233,5 @@ module.exports = grammar({
159
233
  'ERROR',
160
234
  ),
161
235
  ),
162
-
163
- // /wordName — call a locally defined word
164
- word_call: ($) => /\/[a-z][a-zA-Z0-9_]*/,
165
-
166
- // ~Module/word or ~Module — module-qualified word call
167
- module_call: ($) => /~[A-Z][a-zA-Z0-9_]*(\/[a-zA-Z][a-zA-Z0-9_]*)?/,
168
-
169
- // *Map/field — map field accessor / lens
170
- map_access: ($) => /\*[A-Z][a-zA-Z0-9_]*\/[a-z][a-zA-Z0-9_]*/,
171
-
172
- // #TagName — construct a tagged union value
173
- tag_constructor: ($) => /#[A-Z][a-zA-Z0-9_]*/,
174
-
175
- // _TagName — match/destructure a tag in MATCH
176
- tag_pattern: ($) => /_[A-Z][a-zA-Z0-9_]*/,
177
-
178
- // .name — pop the top of the stack into a named local slot
179
- slot_push: ($) => /\.[a-z][a-zA-Z0-9_]*/,
180
-
181
- // ,name — push a named local slot back onto the stack
182
- slot_pop: ($) => /,[a-z][a-zA-Z0-9_]*/,
183
-
184
- // 'raw string literal'
185
- raw_string: ($) => /\'[^\']*\'/,
186
-
187
- // Numeric literal: integer or decimal
188
- number: ($) => /[0-9]+(\.[0-9]+)?/,
189
-
190
- // Generic bare identifier (raw data tokens, unrecognised lowercase words)
191
- identifier: ($) => /[a-zA-Z_][a-zA-Z0-9_]*/,
192
236
  },
193
237
  })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@algosail/tree-sitter",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Tree-sitter grammar for the Sail language",
5
5
  "main": "bindings/node",
6
6
  "types": "bindings/node",
@@ -8,7 +8,8 @@
8
8
  "build:wasm": "tree-sitter build --wasm",
9
9
  "build:native": "node-gyp rebuild",
10
10
  "generate": "tree-sitter generate",
11
- "install": "echo 'Skipping native build. Run npm run build:native manually if needed.'"
11
+ "install": "echo 'Skipping native build. Run npm run build:native manually if needed.'",
12
+ "playground": "tree-sitter playground"
12
13
  },
13
14
  "devDependencies": {
14
15
  "node-addon-api": "^8.6.0",