tree-sitter-clojure-orchard 0.2.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/grammar.js ADDED
@@ -0,0 +1,528 @@
1
+ // one aim is to try to parse what is correct (in the sense of
2
+ // officially supported), but also be looser in parsing additional
3
+ // things. this is more or less in line with advice from tree-sitter
4
+ // folks.
5
+
6
+ function regex(...patts) {
7
+ return RegExp(patts.join(""));
8
+ }
9
+
10
+ // java.lang.Character.isWhitespace AND comma
11
+ //
12
+ // Space Separator (Zs) but NOT including (U+00A0, U+2007, U+202F)
13
+ // U+0020, U+1680, U+2000, U+2001, U+2002, U+2003, U+2004, U+2005,
14
+ // U+2006, U+2008, U+2009, U+200A, U+205F, U+3000
15
+ // Line Separator (Zl)
16
+ // U+2028
17
+ // Paragraph Separator (Zp)
18
+ // U+2029
19
+ // Horizontal Tabulation
20
+ // \t
21
+ // Line Feed
22
+ // \n
23
+ // Vertical Tabulation
24
+ // U+000B
25
+ // Form Feed
26
+ // \f
27
+ // Carriage Return
28
+ // \r
29
+ // File Separator
30
+ // U+001C
31
+ // Group Separator
32
+ // U+001D
33
+ // Record Separator
34
+ // U+001E
35
+ // Unit Separator
36
+ // U+001F
37
+ const WHITESPACE_CHAR =
38
+ regex("[",
39
+ "\\f\\n\\r\\t, ",
40
+ "\\u000B\\u001C\\u001D\\u001E\\u001F",
41
+ "\\u2028\\u2029\\u1680",
42
+ "\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2008",
43
+ "\\u2009\\u200a\\u205f\\u3000",
44
+ "]");
45
+
46
+ const WHITESPACE =
47
+ token(repeat1(WHITESPACE_CHAR));
48
+
49
+ const COMMENT =
50
+ token(regex('(;|#!).*\n?'));
51
+
52
+ const DIGIT =
53
+ regex('[0-9]');
54
+
55
+ const ALPHANUMERIC =
56
+ regex('[0-9a-zA-Z]');
57
+
58
+ const HEX_DIGIT =
59
+ regex('[0-9a-fA-F]');
60
+
61
+ const OCTAL_DIGIT =
62
+ regex('[0-7]');
63
+
64
+ const HEX_NUMBER =
65
+ seq("0",
66
+ regex('[xX]'),
67
+ repeat1(HEX_DIGIT),
68
+ optional("N"));
69
+
70
+ const OCTAL_NUMBER =
71
+ seq("0",
72
+ repeat1(OCTAL_DIGIT),
73
+ optional("N"));
74
+
75
+ // XXX: not constraining number before r/R
76
+ // XXX: not constraining portion after r/R
77
+ const RADIX_NUMBER =
78
+ seq(repeat1(DIGIT),
79
+ regex('[rR]'),
80
+ repeat1(ALPHANUMERIC));
81
+
82
+ const RATIO =
83
+ seq(repeat1(DIGIT),
84
+ "/",
85
+ repeat1(DIGIT));
86
+
87
+ const DOUBLE =
88
+ seq(repeat1(DIGIT),
89
+ optional(seq(".",
90
+ repeat(DIGIT))),
91
+ optional(seq(regex('[eE]'),
92
+ optional(regex('[+-]')),
93
+ repeat1(DIGIT))),
94
+ optional("M"));
95
+
96
+ const INTEGER =
97
+ seq(repeat1(DIGIT),
98
+ optional(regex('[MN]')));
99
+
100
+ const NUMBER =
101
+ token(prec(10, seq(optional(regex('[+-]')),
102
+ choice(HEX_NUMBER,
103
+ OCTAL_NUMBER,
104
+ RADIX_NUMBER,
105
+ RATIO,
106
+ DOUBLE,
107
+ INTEGER))));
108
+
109
+ const NIL =
110
+ token('nil');
111
+
112
+ const BOOLEAN =
113
+ token(choice('false',
114
+ 'true'));
115
+
116
+ const KEYWORD_HEAD =
117
+ regex("[^",
118
+ "\\f\\n\\r\\t ",
119
+ "()",
120
+ "\\[\\]",
121
+ "{}",
122
+ '"',
123
+ "@~^;`",
124
+ "\\\\",
125
+ ",:/",
126
+ "\\u000B\\u001C\\u001D\\u001E\\u001F",
127
+ "\\u2028\\u2029\\u1680",
128
+ "\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2008",
129
+ "\\u2009\\u200a\\u205f\\u3000",
130
+ "]");
131
+
132
+ const KEYWORD_BODY =
133
+ choice(regex("[:']"), KEYWORD_HEAD);
134
+
135
+ const KEYWORD_NAMESPACED_BODY =
136
+ token(repeat1(choice(regex("[:'/]"), KEYWORD_HEAD)));
137
+
138
+ const KEYWORD_NO_SIGIL =
139
+ token(seq(KEYWORD_HEAD,
140
+ repeat(KEYWORD_BODY)));
141
+
142
+ const KEYWORD_MARK =
143
+ token(":");
144
+
145
+ const AUTO_RESOLVE_MARK =
146
+ token("::");
147
+
148
+ const STRING =
149
+ token(seq('"',
150
+ repeat(regex('[^"\\\\]')),
151
+ repeat(seq("\\",
152
+ regex("."),
153
+ repeat(regex('[^"\\\\]')))),
154
+ '"'));
155
+
156
+ // XXX: better to match \o378 as a single item
157
+ const OCTAL_CHAR =
158
+ seq("o",
159
+ choice(seq(DIGIT, DIGIT, DIGIT),
160
+ seq(DIGIT, DIGIT),
161
+ seq(DIGIT)));
162
+
163
+ const NAMED_CHAR =
164
+ choice("backspace",
165
+ "formfeed",
166
+ "newline",
167
+ "return",
168
+ "space",
169
+ "tab");
170
+
171
+ // XXX: outside of: (c >= '\uD800' && c <= '\uDFFF') - LispReader.java
172
+ // but not doing this
173
+ const UNICODE =
174
+ seq("u",
175
+ HEX_DIGIT,
176
+ HEX_DIGIT,
177
+ HEX_DIGIT,
178
+ HEX_DIGIT);
179
+
180
+ // XXX: not quite sure what this is supposed to be...
181
+ // return Character.valueOf(token.charAt(0)); -- LispReader.java
182
+ // java char is 16 bits...what can tree-sitter manage?
183
+ //
184
+ // XXX: null is supposed to be usable but putting \x00 below
185
+ // does not seem to work
186
+ const ANY_CHAR =
187
+ regex('.|\n');
188
+
189
+ const CHARACTER =
190
+ token(seq("\\",
191
+ choice(OCTAL_CHAR,
192
+ NAMED_CHAR,
193
+ UNICODE,
194
+ ANY_CHAR)));
195
+
196
+ const SYMBOL_HEAD =
197
+ regex("[^",
198
+ "\\f\\n\\r\\t ",
199
+ "/",
200
+ "()\\[\\]{}",
201
+ '"',
202
+ "@~^;`",
203
+ "\\\\",
204
+ ",:#'0-9",
205
+ "\\u000B\\u001C\\u001D\\u001E\\u001F",
206
+ "\\u2028\\u2029\\u1680",
207
+ "\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2008",
208
+ "\\u2009\\u200a\\u205f\\u3000",
209
+ "]");
210
+
211
+ const NS_DELIMITER =
212
+ token("/");
213
+
214
+ const SYMBOL_BODY =
215
+ choice(SYMBOL_HEAD,
216
+ regex("[:#'0-9]"));
217
+
218
+ const SYMBOL_NAMESPACED_NAME =
219
+ token(repeat1(choice(SYMBOL_HEAD,
220
+ regex("[/:#'0-9]"))));
221
+
222
+ // XXX: no attempt is made to enforce certain complex things, e.g.
223
+ //
224
+ // Symbols beginning or ending with ':' are reserved by Clojure.
225
+ // A symbol can contain one or more non-repeating ':'s
226
+ const SYMBOL =
227
+ token(seq(SYMBOL_HEAD,
228
+ repeat(SYMBOL_BODY)));
229
+
230
+ module.exports = grammar({
231
+ name: 'clojure_orchard',
232
+
233
+ extras: $ =>
234
+ [],
235
+
236
+ conflicts: $ =>
237
+ [],
238
+
239
+ inline: $ =>
240
+ [$._kwd_leading_slash,
241
+ $._kwd_just_slash,
242
+ $._kwd_qualified,
243
+ $._kwd_unqualified,
244
+ $._kwd_marker,
245
+ $._sym_qualified,
246
+ $._sym_unqualified],
247
+
248
+ rules: {
249
+ // THIS MUST BE FIRST -- even though this doesn't look like it matters
250
+ source: $ =>
251
+ repeat(choice($._form,
252
+ $._gap)),
253
+
254
+ _gap: $ =>
255
+ choice($._ws,
256
+ $.comment,
257
+ $.dis_expr),
258
+
259
+ _ws: $ =>
260
+ WHITESPACE,
261
+
262
+ comment: $ =>
263
+ COMMENT,
264
+
265
+ dis_expr: $ =>
266
+ seq(field('marker', "#_"),
267
+ repeat($._gap),
268
+ field('value', $._form)),
269
+
270
+ _form: $ =>
271
+ choice($.num_lit, // atom-ish
272
+ $.kwd_lit,
273
+ $.str_lit,
274
+ $.char_lit,
275
+ $.nil_lit,
276
+ $.bool_lit,
277
+ $.sym_lit,
278
+ // basic collection-ish
279
+ $.list_lit,
280
+ $.map_lit,
281
+ $.vec_lit,
282
+ // dispatch reader macros
283
+ $.set_lit,
284
+ $.anon_fn_lit,
285
+ $.regex_lit,
286
+ $.read_cond_lit,
287
+ $.splicing_read_cond_lit,
288
+ $.ns_map_lit,
289
+ $.var_quoting_lit,
290
+ $.sym_val_lit,
291
+ $.evaling_lit,
292
+ $.tagged_or_ctor_lit,
293
+ // some other reader macros
294
+ $.derefing_lit,
295
+ $.quoting_lit,
296
+ $.syn_quoting_lit,
297
+ $.unquote_splicing_lit,
298
+ $.unquoting_lit),
299
+
300
+ num_lit: $ =>
301
+ NUMBER,
302
+
303
+ kwd_lit: $ =>
304
+ choice($._kwd_leading_slash,
305
+ $._kwd_just_slash,
306
+ $._kwd_qualified,
307
+ $._kwd_unqualified),
308
+
309
+ // (namespace :/usr/bin/env) ; => ""
310
+ // (name :/usr/bin/env) ; => "usr/bin/env"
311
+ _kwd_leading_slash: $ =>
312
+ seq(field('marker', $._kwd_marker),
313
+ field('delimiter', NS_DELIMITER),
314
+ field('name', alias(KEYWORD_NAMESPACED_BODY, $.kwd_name))),
315
+
316
+ // (namespace :/) ;=> nil
317
+ // (name :/) ;=> "/"
318
+ _kwd_just_slash: $ =>
319
+ seq(field('marker', $._kwd_marker),
320
+ field('name', alias(NS_DELIMITER, $.kwd_name))),
321
+
322
+ _kwd_qualified: $ =>
323
+ prec(2, seq(field('marker', $._kwd_marker),
324
+ field('namespace', alias(KEYWORD_NO_SIGIL, $.kwd_ns)),
325
+ field('delimiter', NS_DELIMITER),
326
+ field('name', alias(KEYWORD_NAMESPACED_BODY, $.kwd_name)))),
327
+
328
+ _kwd_unqualified: $ =>
329
+ prec(1, seq(field('marker', $._kwd_marker),
330
+ field('name', alias(KEYWORD_NO_SIGIL, $.kwd_name)))),
331
+
332
+ _kwd_marker: $ =>
333
+ choice(KEYWORD_MARK, AUTO_RESOLVE_MARK),
334
+
335
+ str_lit: $ =>
336
+ STRING,
337
+
338
+ char_lit: $ =>
339
+ CHARACTER,
340
+
341
+ nil_lit: $ =>
342
+ NIL,
343
+
344
+ bool_lit: $ =>
345
+ BOOLEAN,
346
+
347
+ sym_lit: $ =>
348
+ seq(repeat($._metadata_lit),
349
+ choice($._sym_qualified, $._sym_unqualified)),
350
+
351
+ _sym_qualified: $ =>
352
+ prec(1, seq(field("namespace", alias(SYMBOL, $.sym_ns)),
353
+ field("delimiter", NS_DELIMITER),
354
+ field("name", alias(SYMBOL_NAMESPACED_NAME, $.sym_name)))),
355
+
356
+ _sym_unqualified: $ =>
357
+ field('name', alias(choice(NS_DELIMITER, // division symbol
358
+ SYMBOL),
359
+ $.sym_name)),
360
+
361
+ _metadata_lit: $ =>
362
+ seq(choice(field("meta", $.meta_lit),
363
+ field("old_meta", $.old_meta_lit)),
364
+ optional(repeat($._gap))),
365
+
366
+ meta_lit: $ =>
367
+ seq(field('marker', "^"),
368
+ repeat($._gap),
369
+ field('value', $._form)),
370
+
371
+ old_meta_lit: $ =>
372
+ seq(field('marker', "#^"),
373
+ repeat($._gap),
374
+ field('value', $._form)),
375
+
376
+ list_lit: $ =>
377
+ seq(repeat($._metadata_lit),
378
+ $._bare_list_lit),
379
+
380
+ _bare_list_lit: $ =>
381
+ seq(field('open', "("),
382
+ repeat(choice(field('value', $._form),
383
+ $._gap)),
384
+ field('close', ")")),
385
+
386
+ map_lit: $ =>
387
+ seq(repeat($._metadata_lit),
388
+ $._bare_map_lit),
389
+
390
+ _bare_map_lit: $ =>
391
+ seq(field('open', "{"),
392
+ repeat(choice(field('value', $._form),
393
+ $._gap)),
394
+ field('close', "}")),
395
+
396
+ vec_lit: $ =>
397
+ seq(repeat($._metadata_lit),
398
+ $._bare_vec_lit),
399
+
400
+ _bare_vec_lit: $ =>
401
+ seq(field('open', "["),
402
+ repeat(choice(field('value', $._form),
403
+ $._gap)),
404
+ field('close', "]")),
405
+
406
+ set_lit: $ =>
407
+ seq(repeat($._metadata_lit),
408
+ $._bare_set_lit),
409
+
410
+ _bare_set_lit: $ =>
411
+ seq(field('marker', "#"),
412
+ field('open', "{"),
413
+ repeat(choice(field('value', $._form),
414
+ $._gap)),
415
+ field('close', "}")),
416
+
417
+ anon_fn_lit: $ =>
418
+ seq(repeat($._metadata_lit),
419
+ field('marker', "#"),
420
+ $._bare_list_lit),
421
+
422
+ regex_lit: $ =>
423
+ seq(field('marker', "#"),
424
+ STRING),
425
+
426
+ read_cond_lit: $ =>
427
+ seq(repeat($._metadata_lit),
428
+ field('marker', "#?"),
429
+ // whitespace possible, but neither comment nor discard
430
+ repeat($._ws),
431
+ $._bare_list_lit),
432
+
433
+ splicing_read_cond_lit: $ =>
434
+ // XXX: metadata here doesn't seem to make sense, but the repl
435
+ // will accept: [^:x #?@(:clj [[:a]] :cljr [[:b]])]
436
+ seq(repeat($._metadata_lit),
437
+ field('marker', "#?@"),
438
+ // whitespace possible, but neither comment nor discard
439
+ repeat($._ws),
440
+ $._bare_list_lit),
441
+
442
+ auto_res_mark: $ =>
443
+ AUTO_RESOLVE_MARK,
444
+
445
+ ns_map_lit: $ =>
446
+ seq(repeat($._metadata_lit),
447
+ field('marker', "#"),
448
+ field('prefix', choice($.auto_res_mark,
449
+ $.kwd_lit)),
450
+ repeat($._gap),
451
+ $._bare_map_lit),
452
+
453
+ var_quoting_lit: $ =>
454
+ seq(repeat($._metadata_lit),
455
+ field('marker', "#'"),
456
+ repeat($._gap),
457
+ // XXX: symbol, reader conditional, and tagged literal can work
458
+ // any other things?
459
+ field('value', $._form)),
460
+
461
+ sym_val_lit: $ =>
462
+ seq(field('marker', "##"),
463
+ repeat($._gap),
464
+ field('value', $._form)),
465
+
466
+ evaling_lit: $ =>
467
+ seq(repeat($._metadata_lit), // ^:x #=(vector 1)
468
+ field('marker', "#="),
469
+ repeat($._gap),
470
+ field('value', choice($.list_lit,
471
+ $.read_cond_lit,
472
+ // #= ^:a java.lang.String
473
+ $.sym_lit))),
474
+
475
+ // #uuid "00000000-0000-0000-0000-000000000000"
476
+ // #user.Fun[1 2]
477
+ // #user.Fun{:a 1 :b 2}
478
+ tagged_or_ctor_lit: $ =>
479
+ seq(repeat($._metadata_lit),
480
+ field('marker', "#"),
481
+ // # uuid "00000000-0000-0000-0000-000000000000"
482
+ // # #_ 1 uuid "00000000-0000-0000-0000-000000000000"
483
+ // etc.
484
+ repeat($._gap),
485
+ // # ^:a uuid "00000000-0000-0000-0000-000000000000"
486
+ field('tag', $.sym_lit),
487
+ repeat($._gap),
488
+ field('value', $._form)),
489
+
490
+ derefing_lit: $ =>
491
+ seq(repeat($._metadata_lit),
492
+ field('marker', "@"),
493
+ repeat($._gap),
494
+ field('value', $._form)),
495
+
496
+ quoting_lit: $ =>
497
+ seq(repeat($._metadata_lit),
498
+ field('marker', "'"),
499
+ repeat($._gap),
500
+ field('value', $._form)),
501
+
502
+ syn_quoting_lit: $ =>
503
+ seq(repeat($._metadata_lit),
504
+ field('marker', "`"),
505
+ repeat($._gap),
506
+ field('value', $._form)),
507
+
508
+ unquote_splicing_lit: $ =>
509
+ // XXX: metadata here doesn't seem to make sense, but the repl
510
+ // will accept: `(^:x ~@[:a :b :c])
511
+ seq(repeat($._metadata_lit),
512
+ field('marker', "~@"),
513
+ repeat($._gap),
514
+ field('value', $._form)),
515
+
516
+ unquoting_lit: $ =>
517
+ seq(repeat($._metadata_lit),
518
+ field('marker', "~"),
519
+ repeat($._gap),
520
+ field('value', $._form)),
521
+ }
522
+ });
523
+
524
+ // Local Variables:
525
+ // mode: js-mode
526
+ // js-indent-align-list-continuation: t
527
+ // js-indent-level: 2
528
+ // End:
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "tree-sitter-clojure-orchard",
3
+ "version": "0.2.1",
4
+ "description": "Parser for Clojure files",
5
+ "repository": "https://codeberg.org/grammar-orchard/tree-sitter-clojure-orchard",
6
+ "license": "MIT",
7
+ "author": {
8
+ "name": "a"
9
+ },
10
+ "main": "bindings/node",
11
+ "types": "bindings/node",
12
+ "keywords": [
13
+ "incremental",
14
+ "parsing",
15
+ "tree-sitter",
16
+ "clojure_orchard"
17
+ ],
18
+ "files": [
19
+ "grammar.js",
20
+ "tree-sitter.json",
21
+ "binding.gyp",
22
+ "prebuilds/**",
23
+ "bindings/node/*",
24
+ "queries/*",
25
+ "src/**",
26
+ "*.wasm"
27
+ ],
28
+ "dependencies": {
29
+ "node-addon-api": "^8.5.0",
30
+ "node-gyp-build": "^4.8.4"
31
+ },
32
+ "devDependencies": {
33
+ "prebuildify": "^6.0.1",
34
+ "tree-sitter": "^0.22.4",
35
+ "tree-sitter-cli": "^0.25.9"
36
+ },
37
+ "peerDependencies": {
38
+ "tree-sitter": "^0.22.4"
39
+ },
40
+ "peerDependenciesMeta": {
41
+ "tree-sitter": {
42
+ "optional": true
43
+ }
44
+ },
45
+ "scripts": {
46
+ "install": "node-gyp-build",
47
+ "prestart": "tree-sitter build --wasm",
48
+ "start": "tree-sitter playground",
49
+ "test": "node --test bindings/node/*_test.js"
50
+ }
51
+ }
@@ -0,0 +1,29 @@
1
+ ;; Literals
2
+
3
+ (num_lit) @number
4
+
5
+ [
6
+ (char_lit)
7
+ (str_lit)
8
+ ] @string
9
+
10
+ [
11
+ (bool_lit)
12
+ (nil_lit)
13
+ ] @constant.builtin
14
+
15
+ (kwd_lit) @constant
16
+
17
+ ;; Comments
18
+
19
+ (comment) @comment
20
+
21
+ ;; Treat quasiquotation as operators for the purpose of highlighting.
22
+
23
+ [
24
+ "'"
25
+ "`"
26
+ "~"
27
+ "@"
28
+ "~@"
29
+ ] @operator