@algosail/tree-sitter 0.1.0

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/binding.gyp ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "targets": [
3
+ {
4
+ "target_name": "tree_sitter_sail_binding",
5
+ "dependencies": [
6
+ "<!(node -p \"require('node-addon-api').targets\"):node_addon_api_except",
7
+ ],
8
+ "include_dirs": [
9
+ "src",
10
+ ],
11
+ "sources": [
12
+ "bindings/node/binding.cc",
13
+ "src/parser.c",
14
+ # NOTE: if your language has an external scanner, add it here.
15
+ ],
16
+ "conditions": [
17
+ ["OS!='win'", {
18
+ "cflags_c": [
19
+ "-std=c11",
20
+ ],
21
+ }, { # OS == "win"
22
+ "cflags_c": [
23
+ "/std:c11",
24
+ "/utf-8",
25
+ ],
26
+ }],
27
+ ],
28
+ }
29
+ ]
30
+ }
@@ -0,0 +1,20 @@
1
+ #include <napi.h>
2
+
3
+ typedef struct TSLanguage TSLanguage;
4
+
5
+ extern "C" TSLanguage *tree_sitter_sail();
6
+
7
+ // "tree-sitter", "language" hashed with BLAKE2
8
+ const napi_type_tag LANGUAGE_TYPE_TAG = {
9
+ 0x8AF2E5212AD58ABF, 0xD5006CAD83ABBA16
10
+ };
11
+
12
+ Napi::Object Init(Napi::Env env, Napi::Object exports) {
13
+ exports["name"] = Napi::String::New(env, "sail");
14
+ auto language = Napi::External<TSLanguage>::New(env, tree_sitter_sail());
15
+ language.TypeTag(&LANGUAGE_TYPE_TAG);
16
+ exports["language"] = language;
17
+ return exports;
18
+ }
19
+
20
+ NODE_API_MODULE(tree_sitter_sail_binding, Init)
@@ -0,0 +1,28 @@
1
+ type BaseNode = {
2
+ type: string;
3
+ named: boolean;
4
+ };
5
+
6
+ type ChildNode = {
7
+ multiple: boolean;
8
+ required: boolean;
9
+ types: BaseNode[];
10
+ };
11
+
12
+ type NodeInfo =
13
+ | (BaseNode & {
14
+ subtypes: BaseNode[];
15
+ })
16
+ | (BaseNode & {
17
+ fields: { [name: string]: ChildNode };
18
+ children: ChildNode[];
19
+ });
20
+
21
+ type Language = {
22
+ name: string;
23
+ language: unknown;
24
+ nodeTypeInfo: NodeInfo[];
25
+ };
26
+
27
+ declare const language: Language;
28
+ export = language;
@@ -0,0 +1,7 @@
1
+ const root = require("path").join(__dirname, "..", "..");
2
+
3
+ module.exports = require("node-gyp-build")(root);
4
+
5
+ try {
6
+ module.exports.nodeTypeInfo = require("../../src/node-types.json");
7
+ } catch (_) {}
package/grammar.js ADDED
@@ -0,0 +1,193 @@
1
+ /// <reference types="tree-sitter-cli/dsl" />
2
+ // @ts-check
3
+
4
+ module.exports = grammar({
5
+ name: 'sail',
6
+
7
+ extras: ($) => [/\s+/],
8
+
9
+ conflicts: ($) => [
10
+ // '(' can start a comment OR a signature — tree-sitter resolves by
11
+ // looking for '--' inside.
12
+ [$.comment, $.signature],
13
+ [$.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],
23
+ ],
24
+
25
+ rules: {
26
+ source_file: ($) => repeat($._top_level),
27
+
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_]*/,
52
+
53
+ tag_def: ($) => seq(field('name', $.tag_name), repeat($.type_variable)),
54
+
55
+ tag_name: ($) => />[A-Z][a-zA-Z0-9_]*/,
56
+
57
+ // Map definition: %Name (:field Type)*
58
+ map_def: ($) => seq(field('name', $.map_name), repeat($.map_field)),
59
+
60
+ map_name: ($) => /%[A-Z][a-zA-Z0-9_]*/,
61
+
62
+ map_field: ($) => seq(field('key', $.map_field_name), field('type', $.type_name)),
63
+
64
+ map_field_name: ($) => /:[a-z][a-zA-Z0-9_]*/,
65
+
66
+ // Word definition: @name ( sig ) expr*
67
+ // Signature is required per the spec ("Word definition must have a signature").
68
+ // prec.right makes the body's repeat greedy: prefer consuming '(' as a body
69
+ // 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_]*/,
74
+
75
+ // Signature: ( inputs -- outputs +effects )
76
+ // The required '--' token is what makes it unambiguous vs a comment.
77
+ signature: ($) => seq('(', repeat($._sig_item), $.sig_arrow, repeat($._sig_item), ')'),
78
+
79
+ sig_arrow: ($) => token('--'),
80
+
81
+ _sig_item: ($) =>
82
+ choice(
83
+ $.effect_add,
84
+ $.effect_remove,
85
+ $.spread,
86
+ $.type_name,
87
+ $.type_variable,
88
+ $.sig_list,
89
+ $.sig_quotation,
90
+ ),
91
+
92
+ // [ Type Type ... ] — list / tuple type in a signature
93
+ sig_list: ($) => seq('[', repeat($._sig_item), ']'),
94
+
95
+ // ( a b -- c d ) — higher-order function type nested inside a signature
96
+ sig_quotation: ($) => seq('(', repeat($._sig_item), $.sig_arrow, repeat($._sig_item), ')'),
97
+
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
+ // Expressions inside word bodies
114
+ _expr: ($) =>
115
+ choice(
116
+ $.comment, // doc / inline comment block
117
+ $.quotation,
118
+ $.builtin_word,
119
+ $.word_call,
120
+ $.module_call,
121
+ $.map_access,
122
+ $.tag_constructor,
123
+ $.tag_pattern,
124
+ $.slot_push,
125
+ $.slot_pop,
126
+ $.raw_string,
127
+ $.number,
128
+ $.identifier,
129
+ ),
130
+
131
+ // [ expr* ] — quotation (anonymous code block or list literal)
132
+ quotation: ($) => seq('[', repeat($._expr), ']'),
133
+
134
+ // All-caps stack-manipulation and control-flow builtins.
135
+ // Listed as a single token() so they take priority over $.identifier.
136
+ builtin_word: ($) =>
137
+ token(
138
+ choice(
139
+ 'DUP',
140
+ 'SWAP',
141
+ 'DROP',
142
+ 'OVER',
143
+ 'ROT',
144
+ 'ROTR',
145
+ 'NIP',
146
+ 'TUCK',
147
+ 'DUP2',
148
+ 'DROP2',
149
+ 'SWAP2',
150
+ 'CALL',
151
+ 'MATCH',
152
+ 'COMPOSE',
153
+ 'IF',
154
+ 'MAP',
155
+ 'GETL',
156
+ 'SETL',
157
+ 'UPDL',
158
+ 'APP',
159
+ 'ERROR',
160
+ ),
161
+ ),
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
+ },
193
+ })
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@algosail/tree-sitter",
3
+ "version": "0.1.0",
4
+ "description": "Tree-sitter grammar for the Sail language",
5
+ "main": "bindings/node",
6
+ "types": "bindings/node",
7
+ "scripts": {
8
+ "build": "node-gyp rebuild",
9
+ "generate": "tree-sitter generate",
10
+ "install": "node-gyp-build",
11
+ "prebuildify": "prebuildify --napi --strip"
12
+ },
13
+ "dependencies": {
14
+ "node-addon-api": "^7.1.0",
15
+ "node-gyp-build": "^4.8.0"
16
+ },
17
+ "peerDependencies": {
18
+ "tree-sitter": "^0.21.0"
19
+ },
20
+ "peerDependenciesMeta": {
21
+ "tree_sitter": {
22
+ "optional": true
23
+ }
24
+ },
25
+ "devDependencies": {
26
+ "tree-sitter-cli": "^0.22.0",
27
+ "prebuildify": "^6.0.0"
28
+ },
29
+ "tree-sitter": [
30
+ {
31
+ "scope": "source.sail",
32
+ "file-types": [
33
+ "sail"
34
+ ],
35
+ "highlights": "queries/highlights.scm"
36
+ }
37
+ ],
38
+ "author": "algosail",
39
+ "repository": {
40
+ "type": "git",
41
+ "url": "git+https://github.com/algosail/tree-sitter.git"
42
+ },
43
+ "bugs": {
44
+ "url": "https://github.com/algosail/tree-sitter/issues"
45
+ },
46
+ "homepage": "https://github.com/algosail/tree-sitter#readme",
47
+ "license": "MIT",
48
+ "files": [
49
+ "grammar.js",
50
+ "binding.gyp",
51
+ "prebuilds/**",
52
+ "bindings/node/*",
53
+ "queries/*",
54
+ "src/**"
55
+ ]
56
+ }