tree-sitter-bsl 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/grammar.js ADDED
@@ -0,0 +1,600 @@
1
+ /**
2
+ * @file Tree sitter parser for bsl
3
+ * @author Dmitrii Liubanevich <dlyubanevich@gmail.com>
4
+ * @license MIT
5
+ */
6
+
7
+ /// <reference types="tree-sitter-cli/dsl" />
8
+ // @ts-check
9
+
10
+ // https://its.1c.ru/db/v838doc#bookmark:dev:TI000000139
11
+ const TOKEN_TREE_NON_SPECIAL_PUNCTUATION = [
12
+ "+",
13
+ "-",
14
+ "*",
15
+ "/",
16
+ "%",
17
+ "<>",
18
+ "=",
19
+ ">",
20
+ "<",
21
+ ">=",
22
+ "<=",
23
+ ".",
24
+ ",",
25
+ ";",
26
+ ":",
27
+ "?",
28
+ "~",
29
+ "|",
30
+ "&",
31
+ "#",
32
+ ];
33
+
34
+ const Keywords = {
35
+ IF_KEYWORD: ($) => keyword("если", "if"),
36
+
37
+ THEN_KEYWORD: ($) => keyword("тогда", "then"),
38
+
39
+ ELSE_IF_KEYWORD: ($) => keyword("иначеесли", "elsif"),
40
+
41
+ ELSE_KEYWORD: ($) => keyword("иначе", "else"),
42
+
43
+ END_IF_KEYWORD: ($) => keyword("конецесли", "endif"),
44
+
45
+ FOR_KEYWORD: ($) => keyword("для", "for"),
46
+
47
+ EACH_KEYWORD: ($) => keyword("каждого", "each"),
48
+
49
+ IN_KEYWORD: ($) => keyword("из", "in"),
50
+
51
+ TO_KEYWORD: ($) => keyword("по", "to"),
52
+
53
+ WHILE_KEYWORD: ($) => keyword("пока", "while"),
54
+
55
+ DO_KEYWORD: ($) => keyword("цикл", "do"),
56
+
57
+ END_DO_KEYWORD: ($) => keyword("конеццикла", "enddo"),
58
+
59
+ PROCEDURE_KEYWORD: ($) => keyword("процедура", "procedure"),
60
+
61
+ FUNCTION_KEYWORD: ($) => keyword("функция", "function"),
62
+
63
+ END_PROCEDURE_KEYWORD: ($) => keyword("конецпроцедуры", "endprocedure"),
64
+
65
+ END_FUNCTION_KEYWORD: ($) => keyword("конецфункции", "endfunction"),
66
+
67
+ VAR_KEYWORD: ($) => keyword("перем", "var"),
68
+
69
+ GOTO_KEYWORD: ($) => keyword("перейти", "goto"),
70
+
71
+ RETURN_KEYWORD: ($) => keyword("возврат", "return"),
72
+
73
+ CONTINUE_KEYWORD: ($) => keyword("продолжить", "continue"),
74
+
75
+ BREAK_KEYWORD: ($) => keyword("прервать", "break"),
76
+
77
+ AND_KEYWORD: ($) => keyword("и", "and"),
78
+
79
+ OR_KEYWORD: ($) => keyword("или", "or"),
80
+
81
+ NOT_KEYWORD: ($) => keyword("не", "not"),
82
+
83
+ TRY_KEYWORD: ($) => keyword("попытка", "try"),
84
+
85
+ EXCEPT_KEYWORD: ($) => keyword("исключение", "except"),
86
+
87
+ RAISE_KEYWORD: ($) => keyword("вызватьисключение", "raise"),
88
+
89
+ END_TRY_KEYWORD: ($) => keyword("конецпопытки", "endtry"),
90
+
91
+ NEW_KEYWORD: ($) => keyword("новый", "new"),
92
+
93
+ EXECUTE_KEYWORD: ($) => keyword("выполнить", "execute"),
94
+
95
+ ADD_HANDLER_KEYWORD: ($) => keyword("добавитьобработчик", "addhandler"),
96
+
97
+ REMOVE_HANDLER_KEYWORD: ($) => keyword("удалитьобработчик", "removehandler"),
98
+
99
+ VAL_KEYWORD: ($) => keyword("знач", "val"),
100
+
101
+ TRUE_KEYWORD: ($) => keyword("истина", "true"),
102
+
103
+ FALSE_KEYWORD: ($) => keyword("ложь", "false"),
104
+
105
+ NULL_KEYWORD: ($) => /(null)/i,
106
+
107
+ UNDEFINED_KEYWORD: ($) => keyword("неопределено", "undefine"),
108
+
109
+ EXPORT_KEYWORD: ($) => keyword("экспорт", "export"),
110
+
111
+ PREPROC_IF_KEYWORD: ($) => keyword("#если", "#if"),
112
+ PREPROC_ELSE_IF_KEYWORD: ($) => keyword("#иначеесли", "#elsif"),
113
+ PREPROC_ELSE_KEYWORD: ($) => keyword("#иначе", "#else"),
114
+ PREPROC_END_IF_KEYWORD: ($) => keyword("#конецесли", "#endif"),
115
+ PREPROC_REGION_START_KEYWORD: ($) => keyword("#область", "#region"),
116
+ PREPROC_REGION_END_KEYWORD: ($) => keyword("#конецобласти", "#endregion"),
117
+
118
+ ASYNC_KEYWORD: ($) => keyword("асинх", "async"),
119
+ AWAIT_KEYWORD: ($) => keyword("ждать", "await"),
120
+ };
121
+
122
+ const Operations = {
123
+ operation: ($) => {
124
+ const boolOperation = [$.AND_KEYWORD, $.OR_KEYWORD];
125
+ const compareOperation = ["<>", "=", ">", "<", ">=", "<="];
126
+ const arithmeticOperation = ["+", "-", "*", "/", "%"];
127
+ return choice(
128
+ ...boolOperation,
129
+ ...arithmeticOperation,
130
+ ...compareOperation
131
+ );
132
+ },
133
+ };
134
+
135
+ const Preprocessor = {
136
+ preprocessor: ($) => {
137
+ const region = [
138
+ seq($.PREPROC_REGION_START_KEYWORD, $.identifier),
139
+ $.PREPROC_REGION_END_KEYWORD,
140
+ ];
141
+
142
+ const preproc_if = [
143
+ seq($.PREPROC_IF_KEYWORD, $.expression, $.THEN_KEYWORD),
144
+ seq($.PREPROC_ELSE_IF_KEYWORD, $.expression, $.THEN_KEYWORD),
145
+ $.PREPROC_ELSE_KEYWORD,
146
+ $.PREPROC_END_IF_KEYWORD,
147
+ ];
148
+
149
+ const preproc_change = [
150
+ "Вставка",
151
+ "Insert",
152
+ "КонецВставки",
153
+ "EndInsert",
154
+ "Удаление",
155
+ "Delete",
156
+ "КонецУдаления",
157
+ "EndDelete",
158
+ ].map((annotation) =>
159
+ alias(token(caseInsensitive("#" + annotation)), $.preproc)
160
+ );
161
+
162
+ const annotations = [
163
+ "Перед",
164
+ "Before",
165
+ "После",
166
+ "After",
167
+ "Вместо",
168
+ "Around",
169
+ "ИзменениеИКонтроль",
170
+ "ChangeAndValidate",
171
+ ].map((annotation) =>
172
+ seq(
173
+ alias(token(caseInsensitive("&" + annotation)), $.annotation),
174
+ "(",
175
+ $.string,
176
+ ")"
177
+ )
178
+ );
179
+ const compilation_directives = [
180
+ "НаКлиенте",
181
+ "AtClient",
182
+ "НаСервере",
183
+ "AtServer",
184
+ "НаСервереБезКонтекста",
185
+ "AtServerNoContext",
186
+ "НаКлиентеНаСервереБезКонтекста",
187
+ "AtClientAtServerNoContext",
188
+ "НаКлиентеНаСервере",
189
+ "AtClientAtServer",
190
+ ].map((annotation) =>
191
+ alias(token(caseInsensitive("&" + annotation)), $.annotation)
192
+ );
193
+ return choice(
194
+ ...region,
195
+ ...preproc_if,
196
+ ...preproc_change,
197
+ ...annotations,
198
+ ...compilation_directives
199
+ );
200
+ },
201
+ };
202
+
203
+ module.exports = grammar({
204
+ name: "bsl",
205
+
206
+ extras: ($) => [/\s/, $.line_comment],
207
+
208
+ supertypes: ($) => [$.statement],
209
+
210
+ inline: ($) => [],
211
+
212
+ conflicts: ($) => [],
213
+
214
+ word: ($) => $.identifier,
215
+
216
+ rules: {
217
+ source_file: ($) => repeat($._definition),
218
+
219
+ _definition: ($) =>
220
+ choice(
221
+ $.procedure_definition,
222
+ $.function_definition,
223
+ $.var_definition,
224
+ $.statement
225
+ ),
226
+
227
+ procedure_definition: ($) =>
228
+ seq(
229
+ optional($.ASYNC_KEYWORD),
230
+ $.PROCEDURE_KEYWORD,
231
+ field("name", $.identifier),
232
+ field("parameters", $.parameters),
233
+ optional(field("export", $.EXPORT_KEYWORD)),
234
+ repeat($.statement),
235
+ $.END_PROCEDURE_KEYWORD
236
+ ),
237
+
238
+ function_definition: ($) =>
239
+ seq(
240
+ optional($.ASYNC_KEYWORD),
241
+ $.FUNCTION_KEYWORD,
242
+ field("name", $.identifier),
243
+ field("parameters", $.parameters),
244
+ optional(field("export", $.EXPORT_KEYWORD)),
245
+ repeat($.statement),
246
+ $.END_FUNCTION_KEYWORD
247
+ ),
248
+
249
+ var_definition: ($) =>
250
+ prec(
251
+ 1,
252
+ seq(
253
+ $.VAR_KEYWORD,
254
+ sepBy1(",", field("var_name", $.identifier)),
255
+ optional(field("export", $.EXPORT_KEYWORD)),
256
+ optional(";")
257
+ )
258
+ ),
259
+ parameters: ($) =>
260
+ seq("(", sepBy(",", field("parameter", $.parameter)), ")"),
261
+
262
+ parameter: ($) =>
263
+ seq(
264
+ field("val", optional($.VAL_KEYWORD)),
265
+ field("name", $.identifier),
266
+ field("def", optional($._def_value))
267
+ ),
268
+
269
+ _def_value: ($) => seq("=", $._const_value),
270
+
271
+ // Statements
272
+ statement: ($) =>
273
+ choice(
274
+ $.call_statement,
275
+ $.assignment_statement,
276
+ $.return_statement,
277
+ $.try_statement,
278
+ $.rise_error_statement,
279
+ $.var_statement,
280
+ $.if_statement,
281
+ $.while_statement,
282
+ $.for_statement,
283
+ $.for_each_statement,
284
+ $.continue_statement,
285
+ $.break_statement,
286
+ $.execute_statement,
287
+ $.goto_statement,
288
+ $.label_statement,
289
+ $.add_handler_statement,
290
+ $.remove_handler_statement,
291
+ $.preprocessor,
292
+ $.await_statement
293
+ ),
294
+
295
+ call_statement: ($) => seq($.call_expression, optional(";")),
296
+
297
+ assignment_statement: ($) =>
298
+ seq(
299
+ field("left", $._assignment_member),
300
+ "=",
301
+ field("right", $.expression),
302
+ optional(";")
303
+ ),
304
+
305
+ return_statement: ($) =>
306
+ prec.right(seq($.RETURN_KEYWORD, optional($.expression), optional(";"))),
307
+
308
+ try_statement: ($) =>
309
+ seq(
310
+ $.TRY_KEYWORD,
311
+ repeat($.statement),
312
+ $.EXCEPT_KEYWORD,
313
+ repeat($.statement),
314
+ $.END_TRY_KEYWORD,
315
+ optional(";")
316
+ ),
317
+
318
+ rise_error_statement: ($) =>
319
+ seq($.RAISE_KEYWORD, choice($.arguments, $.expression), optional(";")),
320
+
321
+ var_statement: ($) =>
322
+ seq(
323
+ $.VAR_KEYWORD,
324
+ sepBy1(",", field("var_name", $.identifier)),
325
+ optional(";")
326
+ ),
327
+
328
+ if_statement: ($) =>
329
+ seq(
330
+ $.IF_KEYWORD,
331
+ $.expression,
332
+ $.THEN_KEYWORD,
333
+ repeat($.statement),
334
+ repeat(
335
+ seq(
336
+ $.ELSE_IF_KEYWORD,
337
+ $.expression,
338
+ $.THEN_KEYWORD,
339
+ repeat($.statement)
340
+ )
341
+ ),
342
+ optional($.else),
343
+ $.END_IF_KEYWORD,
344
+ optional(";")
345
+ ),
346
+
347
+ else_if: ($) =>
348
+ seq($.ELSE_IF_KEYWORD, $.expression, $.THEN_KEYWORD, repeat($.statement)),
349
+
350
+ else: ($) => seq($.ELSE_KEYWORD, repeat($.statement)),
351
+
352
+ while_statement: ($) =>
353
+ seq(
354
+ $.WHILE_KEYWORD,
355
+ $.expression,
356
+ $.DO_KEYWORD,
357
+ repeat($.statement),
358
+ $.END_DO_KEYWORD
359
+ ),
360
+
361
+ for_statement: ($) =>
362
+ seq(
363
+ $.FOR_KEYWORD,
364
+ $.assignment_statement,
365
+ $.TO_KEYWORD,
366
+ $.expression,
367
+ $.DO_KEYWORD,
368
+ repeat($.statement),
369
+ $.END_DO_KEYWORD,
370
+ optional(";")
371
+ ),
372
+
373
+ for_each_statement: ($) =>
374
+ seq(
375
+ $.FOR_KEYWORD,
376
+ $.EACH_KEYWORD,
377
+ $.identifier,
378
+ $.IN_KEYWORD,
379
+ $.expression,
380
+ $.TO_KEYWORD,
381
+ $.expression,
382
+ $.DO_KEYWORD,
383
+ repeat($.statement),
384
+ $.END_DO_KEYWORD,
385
+ optional(";")
386
+ ),
387
+ continue_statement: ($) => seq($.CONTINUE_KEYWORD, optional(";")),
388
+
389
+ break_statement: ($) => seq($.BREAK_KEYWORD, optional(";")),
390
+
391
+ execute_statement: ($) =>
392
+ seq($.EXECUTE_KEYWORD, "(", $.expression, ")", optional(";")),
393
+
394
+ goto_statement: ($) =>
395
+ seq($.GOTO_KEYWORD, "~", $.identifier, optional(";")),
396
+
397
+ label_statement: ($) => seq("~", $.identifier, ":", optional(";")),
398
+
399
+ add_handler_statement: ($) =>
400
+ seq(
401
+ $.ADD_HANDLER_KEYWORD,
402
+ $.expression,
403
+ ",",
404
+ $.expression,
405
+ optional(";")
406
+ ),
407
+
408
+ remove_handler_statement: ($) =>
409
+ seq(
410
+ $.REMOVE_HANDLER_KEYWORD,
411
+ $.expression,
412
+ ",",
413
+ $.expression,
414
+ optional(";")
415
+ ),
416
+ await_statement: ($) => seq($.await_expression, optional(";")),
417
+
418
+ // Expressions
419
+ expression: ($) =>
420
+ choice(
421
+ alias($._const_value, $.const_expression),
422
+ $.identifier,
423
+ $.unary_expression,
424
+ $.binary_expression,
425
+ $.ternary_expression,
426
+ $.new_expression,
427
+ $.call_expression,
428
+ $.property_access,
429
+ $.await_expression
430
+ ),
431
+ unary_expression: ($) =>
432
+ prec.left(
433
+ seq(
434
+ field("operator", alias(choice("-", "+", $.NOT_KEYWORD), $.operation)),
435
+ field("argument", $.expression)
436
+ )
437
+ ),
438
+
439
+ binary_expression: ($) =>
440
+ prec.left(
441
+ seq(
442
+ field("left", $.expression),
443
+ field("operator", $.operation),
444
+ field("right", $.expression)
445
+ )
446
+ ),
447
+
448
+ ternary_expression: ($) =>
449
+ prec.right(
450
+ seq(
451
+ "?(",
452
+ field("condition", $.expression),
453
+ ",",
454
+ field("consequence", $.expression),
455
+ ",",
456
+ field("alternative", $.expression),
457
+ ")"
458
+ )
459
+ ),
460
+
461
+ new_expression: ($) =>
462
+ choice(
463
+ prec.right(
464
+ 0,
465
+ seq(
466
+ $.NEW_KEYWORD,
467
+ field("type", $.identifier),
468
+ field("arguments", optional($.arguments))
469
+ )
470
+ ),
471
+ seq($.NEW_KEYWORD, field("arguments", $.arguments))
472
+ ),
473
+
474
+ call_expression: ($) =>
475
+ prec(
476
+ 2,
477
+ choice(
478
+ $.method_call,
479
+ seq(alias($.identifier, $.property), repeat($._access), ".", $.method_call),
480
+ seq($.method_call, repeat($._access), ".", $.method_call)
481
+ )
482
+ ),
483
+
484
+ await_expression: ($) => prec(1, seq($.AWAIT_KEYWORD, $.expression)),
485
+
486
+ _assignment_member: ($) =>
487
+ choice(
488
+ $.identifier,
489
+ $.property_access
490
+ ),
491
+
492
+ property_access: ($) => seq(choice($.identifier, $.method_call), repeat1($._access)),
493
+
494
+ _access: ($) => choice($._access_call, $._access_index, $._access_property),
495
+ _access_call: ($) => seq(".", $.method_call),
496
+ _access_index: ($) => seq("[", alias($.expression, $.index), "]"),
497
+ _access_property: ($) => seq(".", alias($.identifier, $.property)),
498
+
499
+ method_call: ($) =>
500
+ seq(field("name", $.identifier), field("arguments", $.arguments)),
501
+
502
+ arguments: ($) => seq("(", sepBy(",", $.expression), ")"),
503
+
504
+ // Primitive
505
+ ...Keywords,
506
+ ...Operations,
507
+ ...Preprocessor,
508
+
509
+ _const_value: ($) =>
510
+ choice(
511
+ $.number,
512
+ $.date,
513
+ $.string,
514
+ alias($.multiline_string, $.string),
515
+ $.boolean,
516
+ $.UNDEFINED_KEYWORD,
517
+ $.NULL_KEYWORD
518
+ //TODO Date
519
+ ),
520
+
521
+ boolean: ($) => choice($.TRUE_KEYWORD, $.FALSE_KEYWORD),
522
+ null: ($) => $.NULL_KEYWORD,
523
+
524
+ number: ($) => /\d+(\.\d+)?/,
525
+ date: ($) => /'\d{8,14}'/,
526
+ string: ($) =>
527
+ seq(
528
+ '"',
529
+ alias(token.immediate(prec(1, /([^\r\n"]|"")*/)), $.string_content),
530
+ '"'
531
+ ),
532
+ multiline_string: ($) =>
533
+ seq(
534
+ '"',
535
+ alias(token.immediate(prec(1, /([^\r\n"]|"")*/)), $.string_content),
536
+ repeat1(
537
+ seq(
538
+ "|",
539
+ alias(token.immediate(prec(1, /([^\r\n"]|"")*/)), $.string_content)
540
+ )
541
+ ),
542
+ '"'
543
+ ),
544
+ identifier: ($) => /[\wа-я_][\wа-я_0-9]*/i,
545
+
546
+ line_comment: ($) => seq("//", /.*/),
547
+ _non_special_token: ($) =>
548
+ choice(
549
+ prec.right(repeat1(choice(...TOKEN_TREE_NON_SPECIAL_PUNCTUATION)))
550
+ ),
551
+ },
552
+ });
553
+
554
+ /**
555
+ * Creates a rule to match one or more of the rules separated by a comma
556
+ *
557
+ * @param {RuleOrLiteral} rule
558
+ */
559
+ function commaSep1(rule) {
560
+ return sepBy1(",", rule);
561
+ }
562
+
563
+ /**
564
+ * Creates a rule to optionally match one or more of the rules separated by a comma
565
+ *
566
+ * @param {RuleOrLiteral} rule
567
+ */
568
+ function commaSep(rule) {
569
+ return sepBy(",", rule);
570
+ }
571
+
572
+ /**
573
+ * Creates a rule to optionally match one or more of the rules separated by a separator
574
+ *
575
+ * @param {RuleOrLiteral} sep
576
+ *
577
+ * @param {RuleOrLiteral} rule
578
+ */
579
+ function sepBy(sep, rule) {
580
+ return optional(sepBy1(sep, rule));
581
+ }
582
+
583
+ /**
584
+ * Creates a rule to match one or more of the rules separated by a separator
585
+ *
586
+ * @param {RuleOrLiteral} sep
587
+ *
588
+ * @param {RuleOrLiteral} rule
589
+ */
590
+ function sepBy1(sep, rule) {
591
+ return seq(rule, repeat(seq(sep, rule)));
592
+ }
593
+
594
+ function keyword(...words) {
595
+ return token(choice(...words.map(caseInsensitive)));
596
+ }
597
+
598
+ function caseInsensitive(word) {
599
+ return new RegExp(word, "i");
600
+ }
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "tree-sitter-bsl",
3
+ "version": "0.1.0",
4
+ "description": "1C (BSL) language",
5
+ "repository": "https://github.com/tree-sitter/tree-sitter-bsl",
6
+ "license": "MIT",
7
+ "author": {
8
+ "name": "alkoleft"
9
+ },
10
+ "main": "bindings/node",
11
+ "types": "bindings/node",
12
+ "keywords": [
13
+ "incremental",
14
+ "parsing",
15
+ "tree-sitter",
16
+ "bsl"
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.2.1",
30
+ "node-gyp-build": "^4.8.2"
31
+ },
32
+ "devDependencies": {
33
+ "prebuildify": "^6.0.1",
34
+ "tree-sitter-cli": "^0.25.1"
35
+ },
36
+ "peerDependencies": {
37
+ "tree-sitter": "^0.21.1"
38
+ },
39
+ "peerDependenciesMeta": {
40
+ "tree-sitter": {
41
+ "optional": true
42
+ }
43
+ },
44
+ "scripts": {
45
+ "install": "node-gyp-build",
46
+ "prestart": "tree-sitter build --wasm",
47
+ "start": "tree-sitter playground",
48
+ "test": "node --test bindings/node/*_test.js"
49
+ }
50
+ }