@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 +30 -0
- package/bindings/node/binding.cc +20 -0
- package/bindings/node/index.d.ts +28 -0
- package/bindings/node/index.js +7 -0
- package/grammar.js +193 -0
- package/package.json +56 -0
- package/src/grammar.json +633 -0
- package/src/node-types.json +594 -0
- package/src/parser.c +2759 -0
- package/src/tree_sitter/alloc.h +54 -0
- package/src/tree_sitter/array.h +290 -0
- package/src/tree_sitter/parser.h +265 -0
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;
|
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
|
+
}
|