@ast-grep/lang-elixir 0.0.2

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/src/scanner.c ADDED
@@ -0,0 +1,638 @@
1
+ #include "tree_sitter/parser.h"
2
+
3
+ // See references in grammar.externals
4
+ enum TokenType {
5
+ QUOTED_CONTENT_I_SINGLE,
6
+ QUOTED_CONTENT_I_DOUBLE,
7
+ QUOTED_CONTENT_I_HEREDOC_SINGLE,
8
+ QUOTED_CONTENT_I_HEREDOC_DOUBLE,
9
+ QUOTED_CONTENT_I_PARENTHESIS,
10
+ QUOTED_CONTENT_I_CURLY,
11
+ QUOTED_CONTENT_I_SQUARE,
12
+ QUOTED_CONTENT_I_ANGLE,
13
+ QUOTED_CONTENT_I_BAR,
14
+ QUOTED_CONTENT_I_SLASH,
15
+ QUOTED_CONTENT_SINGLE,
16
+ QUOTED_CONTENT_DOUBLE,
17
+ QUOTED_CONTENT_HEREDOC_SINGLE,
18
+ QUOTED_CONTENT_HEREDOC_DOUBLE,
19
+ QUOTED_CONTENT_PARENTHESIS,
20
+ QUOTED_CONTENT_CURLY,
21
+ QUOTED_CONTENT_SQUARE,
22
+ QUOTED_CONTENT_ANGLE,
23
+ QUOTED_CONTENT_BAR,
24
+ QUOTED_CONTENT_SLASH,
25
+
26
+ NEWLINE_BEFORE_DO,
27
+ NEWLINE_BEFORE_BINARY_OPERATOR,
28
+ NEWLINE_BEFORE_COMMENT,
29
+
30
+ BEFORE_UNARY_OPERATOR,
31
+
32
+ NOT_IN,
33
+
34
+ QUOTED_ATOM_START
35
+ };
36
+
37
+ static inline void advance(TSLexer *lexer) { lexer->advance(lexer, false); }
38
+
39
+ static inline void skip(TSLexer *lexer) { lexer->advance(lexer, true); }
40
+
41
+ // Note: some checks require several lexer steps of lookahead
42
+ // and alter its state, for these we use names check_*
43
+
44
+ static inline bool is_whitespace(int32_t c) {
45
+ return c == ' ' || c == '\t' || c == '\n' || c == '\r';
46
+ }
47
+
48
+ static inline bool is_inline_whitespace(int32_t c) {
49
+ return c == ' ' || c == '\t';
50
+ }
51
+
52
+ static inline bool is_newline(int32_t c) {
53
+ // Note: this implies \r\n is treated as two line breaks,
54
+ // but in our case it's fine, since multiple line breaks
55
+ // make no difference
56
+ return c == '\n' || c == '\r';
57
+ }
58
+
59
+ static inline bool is_digit(int32_t c) { return '0' <= c && c <= '9'; }
60
+
61
+ static inline bool check_keyword_end(TSLexer *lexer) {
62
+ if (lexer->lookahead == ':') {
63
+ advance(lexer);
64
+ return is_whitespace(lexer->lookahead);
65
+ }
66
+ return false;
67
+ }
68
+
69
+ static bool check_operator_end(TSLexer *lexer) {
70
+ // Keyword
71
+ if (lexer->lookahead == ':') {
72
+ return !check_keyword_end(lexer);
73
+ }
74
+ while (is_inline_whitespace(lexer->lookahead)) {
75
+ advance(lexer);
76
+ }
77
+ // Operator identifier with arity
78
+ if (lexer->lookahead == '/') {
79
+ advance(lexer);
80
+ while (is_whitespace(lexer->lookahead)) {
81
+ advance(lexer);
82
+ }
83
+ if (is_digit(lexer->lookahead)) {
84
+ return false;
85
+ }
86
+ }
87
+
88
+ return true;
89
+ }
90
+
91
+ const char token_terminators[] = {
92
+ // Operator starts
93
+ '@', '.', '+', '-', '^', '-', '*', '/', '<', '>', '|', '~', '=', '&', '\\',
94
+ '%',
95
+ // Delimiters
96
+ '{', '}', '[', ']', '(', ')', '"', '\'',
97
+ // Separators
98
+ ',', ';',
99
+ // Comment
100
+ '#'};
101
+
102
+ const uint8_t token_terminators_length =
103
+ sizeof(token_terminators) / sizeof(char);
104
+
105
+ // Note: this is a heuristic as we only use this to distinguish word
106
+ // operators and we don't want to include complex Unicode ranges
107
+ static inline bool is_token_end(int32_t c) {
108
+ for (uint8_t i = 0; i < token_terminators_length; i++) {
109
+ if (c == token_terminators[i]) {
110
+ return true;
111
+ }
112
+ }
113
+
114
+ return is_whitespace(c);
115
+ }
116
+
117
+ typedef struct {
118
+ const enum TokenType token_type;
119
+ const bool supports_interpol;
120
+ const int32_t end_delimiter;
121
+ const uint8_t delimiter_length;
122
+ } QuotedContentInfo;
123
+
124
+ const QuotedContentInfo quoted_content_infos[] = {
125
+ {QUOTED_CONTENT_I_SINGLE, true, '\'', 1},
126
+ {QUOTED_CONTENT_I_DOUBLE, true, '"', 1},
127
+ {QUOTED_CONTENT_I_HEREDOC_SINGLE, true, '\'', 3},
128
+ {QUOTED_CONTENT_I_HEREDOC_DOUBLE, true, '"', 3},
129
+ {QUOTED_CONTENT_I_PARENTHESIS, true, ')', 1},
130
+ {QUOTED_CONTENT_I_CURLY, true, '}', 1},
131
+ {QUOTED_CONTENT_I_SQUARE, true, ']', 1},
132
+ {QUOTED_CONTENT_I_ANGLE, true, '>', 1},
133
+ {QUOTED_CONTENT_I_BAR, true, '|', 1},
134
+ {QUOTED_CONTENT_I_SLASH, true, '/', 1},
135
+ {QUOTED_CONTENT_SINGLE, false, '\'', 1},
136
+ {QUOTED_CONTENT_DOUBLE, false, '"', 1},
137
+ {QUOTED_CONTENT_HEREDOC_SINGLE, false, '\'', 3},
138
+ {QUOTED_CONTENT_HEREDOC_DOUBLE, false, '"', 3},
139
+ {QUOTED_CONTENT_PARENTHESIS, false, ')', 1},
140
+ {QUOTED_CONTENT_CURLY, false, '}', 1},
141
+ {QUOTED_CONTENT_SQUARE, false, ']', 1},
142
+ {QUOTED_CONTENT_ANGLE, false, '>', 1},
143
+ {QUOTED_CONTENT_BAR, false, '|', 1},
144
+ {QUOTED_CONTENT_SLASH, false, '/', 1},
145
+ };
146
+
147
+ const uint8_t quoted_content_infos_length =
148
+ sizeof(quoted_content_infos) / sizeof(QuotedContentInfo);
149
+
150
+ static inline int8_t find_quoted_token_info(const bool *valid_symbols) {
151
+ // Quoted tokens are mutually exclusive and only one should be valid
152
+ // at a time. If multiple are valid it means we parse an arbitrary
153
+ // code outside quotes, in which case we don't want to tokenize it as
154
+ // quoted content.
155
+ if (valid_symbols[QUOTED_CONTENT_I_SINGLE] &&
156
+ valid_symbols[QUOTED_CONTENT_I_DOUBLE]) {
157
+ return -1;
158
+ }
159
+
160
+ for (uint8_t i = 0; i < quoted_content_infos_length; i++) {
161
+ if (valid_symbols[quoted_content_infos[i].token_type]) {
162
+ return i;
163
+ }
164
+ }
165
+
166
+ return -1;
167
+ }
168
+
169
+ static bool scan_quoted_content(TSLexer *lexer, const QuotedContentInfo *info) {
170
+ lexer->result_symbol = info->token_type;
171
+
172
+ bool is_heredoc = (info->delimiter_length == 3);
173
+
174
+ for (bool has_content = false; true; has_content = true) {
175
+ bool newline = false;
176
+
177
+ if (is_newline(lexer->lookahead)) {
178
+ advance(lexer);
179
+
180
+ has_content = true;
181
+ newline = true;
182
+
183
+ while (is_whitespace(lexer->lookahead)) {
184
+ advance(lexer);
185
+ }
186
+ }
187
+
188
+ lexer->mark_end(lexer);
189
+
190
+ if (lexer->lookahead == info->end_delimiter) {
191
+ uint8_t length = 1;
192
+
193
+ while (length < info->delimiter_length) {
194
+ advance(lexer);
195
+ if (lexer->lookahead == info->end_delimiter) {
196
+ length++;
197
+ } else {
198
+ break;
199
+ }
200
+ }
201
+
202
+ if (length == info->delimiter_length && (!is_heredoc || newline)) {
203
+ return has_content;
204
+ }
205
+ } else {
206
+ if (lexer->lookahead == '#') {
207
+ advance(lexer);
208
+ if (info->supports_interpol && lexer->lookahead == '{') {
209
+ return has_content;
210
+ }
211
+ } else if (lexer->lookahead == '\\') {
212
+ advance(lexer);
213
+ if (is_heredoc && lexer->lookahead == '\n') {
214
+ // We need to know about the newline to correctly recognise
215
+ // heredoc end delimiter, so we intentionally ignore
216
+ // escaping
217
+ } else if (info->supports_interpol ||
218
+ lexer->lookahead == info->end_delimiter) {
219
+ return has_content;
220
+ }
221
+ } else if (lexer->lookahead == '\0') {
222
+ // If we reached the end of the file, this means there is no
223
+ // end delimiter, so the syntax is invalid. In that case we
224
+ // want to treat all the scanned content as quoted content.
225
+ return has_content;
226
+ } else {
227
+ advance(lexer);
228
+ }
229
+ }
230
+ }
231
+
232
+ return false;
233
+ }
234
+
235
+ static bool scan_newline(TSLexer *lexer, const bool *valid_symbols) {
236
+ advance(lexer);
237
+
238
+ while (is_whitespace(lexer->lookahead)) {
239
+ advance(lexer);
240
+ }
241
+
242
+ // Note we include all the whitespace after newline, so that the
243
+ // parser doesn't have to go through it again
244
+ lexer->mark_end(lexer);
245
+
246
+ if (lexer->lookahead == '#') {
247
+ lexer->result_symbol = NEWLINE_BEFORE_COMMENT;
248
+ return true;
249
+ }
250
+
251
+ if (lexer->lookahead == 'd' && valid_symbols[NEWLINE_BEFORE_DO]) {
252
+ lexer->result_symbol = NEWLINE_BEFORE_DO;
253
+ advance(lexer);
254
+ if (lexer->lookahead == 'o') {
255
+ advance(lexer);
256
+ return is_token_end(lexer->lookahead);
257
+ }
258
+ return false;
259
+ }
260
+
261
+ if (valid_symbols[NEWLINE_BEFORE_BINARY_OPERATOR]) {
262
+ lexer->result_symbol = NEWLINE_BEFORE_BINARY_OPERATOR;
263
+
264
+ // &&, &&&
265
+ if (lexer->lookahead == '&') {
266
+ advance(lexer);
267
+ if (lexer->lookahead == '&') {
268
+ advance(lexer);
269
+ if (lexer->lookahead == '&') {
270
+ advance(lexer);
271
+ return check_operator_end(lexer);
272
+ } else {
273
+ return check_operator_end(lexer);
274
+ }
275
+ }
276
+ // =, ==, ===, =~, =>
277
+ } else if (lexer->lookahead == '=') {
278
+ advance(lexer);
279
+ if (lexer->lookahead == '=') {
280
+ advance(lexer);
281
+ if (lexer->lookahead == '=') {
282
+ advance(lexer);
283
+ return check_operator_end(lexer);
284
+ } else {
285
+ return check_operator_end(lexer);
286
+ }
287
+ } else if (lexer->lookahead == '~') {
288
+ advance(lexer);
289
+ return check_operator_end(lexer);
290
+ } else if (lexer->lookahead == '>') {
291
+ advance(lexer);
292
+ return check_operator_end(lexer);
293
+ } else {
294
+ return check_operator_end(lexer);
295
+ }
296
+ // ::
297
+ } else if (lexer->lookahead == ':') {
298
+ advance(lexer);
299
+ if (lexer->lookahead == ':') {
300
+ advance(lexer);
301
+ // Ignore ::: atom
302
+ if (lexer->lookahead == ':')
303
+ return false;
304
+ return check_operator_end(lexer);
305
+ }
306
+ // ++, +++
307
+ } else if (lexer->lookahead == '+') {
308
+ advance(lexer);
309
+ if (lexer->lookahead == '+') {
310
+ advance(lexer);
311
+ if (lexer->lookahead == '+') {
312
+ advance(lexer);
313
+ return check_operator_end(lexer);
314
+ } else {
315
+ return check_operator_end(lexer);
316
+ }
317
+ }
318
+ // --, ---, ->
319
+ } else if (lexer->lookahead == '-') {
320
+ advance(lexer);
321
+ if (lexer->lookahead == '-') {
322
+ advance(lexer);
323
+ if (lexer->lookahead == '-') {
324
+ advance(lexer);
325
+ return check_operator_end(lexer);
326
+ } else {
327
+ return check_operator_end(lexer);
328
+ }
329
+ } else if (lexer->lookahead == '>') {
330
+ advance(lexer);
331
+ return check_operator_end(lexer);
332
+ }
333
+ // <, <=, <-, <>, <~, <~>, <|>, <<<, <<~
334
+ } else if (lexer->lookahead == '<') {
335
+ advance(lexer);
336
+ if (lexer->lookahead == '=' || lexer->lookahead == '-' ||
337
+ lexer->lookahead == '>') {
338
+ advance(lexer);
339
+ return check_operator_end(lexer);
340
+ } else if (lexer->lookahead == '~') {
341
+ advance(lexer);
342
+ if (lexer->lookahead == '>') {
343
+ advance(lexer);
344
+ return check_operator_end(lexer);
345
+ } else {
346
+ return check_operator_end(lexer);
347
+ }
348
+ } else if (lexer->lookahead == '|') {
349
+ advance(lexer);
350
+ if (lexer->lookahead == '>') {
351
+ advance(lexer);
352
+ return check_operator_end(lexer);
353
+ }
354
+ } else if (lexer->lookahead == '<') {
355
+ advance(lexer);
356
+ if (lexer->lookahead == '<' || lexer->lookahead == '~') {
357
+ advance(lexer);
358
+ return check_operator_end(lexer);
359
+ }
360
+ } else {
361
+ return check_operator_end(lexer);
362
+ }
363
+ // >, >=, >>>
364
+ } else if (lexer->lookahead == '>') {
365
+ advance(lexer);
366
+ if (lexer->lookahead == '=') {
367
+ advance(lexer);
368
+ return check_operator_end(lexer);
369
+ } else if (lexer->lookahead == '>') {
370
+ advance(lexer);
371
+ if (lexer->lookahead == '>') {
372
+ advance(lexer);
373
+ return check_operator_end(lexer);
374
+ }
375
+ } else {
376
+ return check_operator_end(lexer);
377
+ }
378
+ // ^^^
379
+ } else if (lexer->lookahead == '^') {
380
+ advance(lexer);
381
+ if (lexer->lookahead == '^') {
382
+ advance(lexer);
383
+ if (lexer->lookahead == '^') {
384
+ advance(lexer);
385
+ return check_operator_end(lexer);
386
+ }
387
+ }
388
+ // !=, !==
389
+ } else if (lexer->lookahead == '!') {
390
+ advance(lexer);
391
+ if (lexer->lookahead == '=') {
392
+ advance(lexer);
393
+ if (lexer->lookahead == '=') {
394
+ advance(lexer);
395
+ return check_operator_end(lexer);
396
+ } else {
397
+ return check_operator_end(lexer);
398
+ }
399
+ }
400
+ // ~>, ~>>
401
+ } else if (lexer->lookahead == '~') {
402
+ advance(lexer);
403
+ if (lexer->lookahead == '>') {
404
+ advance(lexer);
405
+ if (lexer->lookahead == '>') {
406
+ advance(lexer);
407
+ return check_operator_end(lexer);
408
+ } else {
409
+ return check_operator_end(lexer);
410
+ }
411
+ }
412
+ // |, ||, |||, |>
413
+ } else if (lexer->lookahead == '|') {
414
+ advance(lexer);
415
+ if (lexer->lookahead == '|') {
416
+ advance(lexer);
417
+ if (lexer->lookahead == '|') {
418
+ advance(lexer);
419
+ return check_operator_end(lexer);
420
+ } else {
421
+ return check_operator_end(lexer);
422
+ }
423
+ } else if (lexer->lookahead == '>') {
424
+ advance(lexer);
425
+ return check_operator_end(lexer);
426
+ } else {
427
+ return check_operator_end(lexer);
428
+ }
429
+ // *, **
430
+ } else if (lexer->lookahead == '*') {
431
+ advance(lexer);
432
+ if (lexer->lookahead == '*') {
433
+ advance(lexer);
434
+ return check_operator_end(lexer);
435
+ } else {
436
+ return check_operator_end(lexer);
437
+ }
438
+ // / //
439
+ } else if (lexer->lookahead == '/') {
440
+ advance(lexer);
441
+ if (lexer->lookahead == '/') {
442
+ advance(lexer);
443
+ return check_operator_end(lexer);
444
+ } else {
445
+ return check_operator_end(lexer);
446
+ }
447
+ // ., ..
448
+ } else if (lexer->lookahead == '.') {
449
+ advance(lexer);
450
+ if (lexer->lookahead == '.') {
451
+ advance(lexer);
452
+ // Ignore ... identifier
453
+ if (lexer->lookahead == '.')
454
+ return false;
455
+ return check_operator_end(lexer);
456
+ } else {
457
+ return check_operator_end(lexer);
458
+ }
459
+ // double slash
460
+ } else if (lexer->lookahead == '\\') {
461
+ advance(lexer);
462
+ if (lexer->lookahead == '\\') {
463
+ advance(lexer);
464
+ return check_operator_end(lexer);
465
+ }
466
+ // when
467
+ } else if (lexer->lookahead == 'w') {
468
+ advance(lexer);
469
+ if (lexer->lookahead == 'h') {
470
+ advance(lexer);
471
+ if (lexer->lookahead == 'e') {
472
+ advance(lexer);
473
+ if (lexer->lookahead == 'n') {
474
+ advance(lexer);
475
+ return is_token_end(lexer->lookahead) && check_operator_end(lexer);
476
+ }
477
+ }
478
+ }
479
+ // and
480
+ } else if (lexer->lookahead == 'a') {
481
+ advance(lexer);
482
+ if (lexer->lookahead == 'n') {
483
+ advance(lexer);
484
+ if (lexer->lookahead == 'd') {
485
+ advance(lexer);
486
+ return is_token_end(lexer->lookahead) && check_operator_end(lexer);
487
+ }
488
+ }
489
+ // or
490
+ } else if (lexer->lookahead == 'o') {
491
+ advance(lexer);
492
+ if (lexer->lookahead == 'r') {
493
+ advance(lexer);
494
+ return is_token_end(lexer->lookahead) && check_operator_end(lexer);
495
+ }
496
+ // in
497
+ } else if (lexer->lookahead == 'i') {
498
+ advance(lexer);
499
+ if (lexer->lookahead == 'n') {
500
+ advance(lexer);
501
+ return is_token_end(lexer->lookahead) && check_operator_end(lexer);
502
+ }
503
+ // not in
504
+ } else if (lexer->lookahead == 'n') {
505
+ advance(lexer);
506
+ if (lexer->lookahead == 'o') {
507
+ advance(lexer);
508
+ if (lexer->lookahead == 't') {
509
+ advance(lexer);
510
+ while (is_inline_whitespace(lexer->lookahead)) {
511
+ advance(lexer);
512
+ }
513
+ if (lexer->lookahead == 'i') {
514
+ advance(lexer);
515
+ if (lexer->lookahead == 'n') {
516
+ advance(lexer);
517
+ return is_token_end(lexer->lookahead) &&
518
+ check_operator_end(lexer);
519
+ }
520
+ }
521
+ }
522
+ }
523
+ }
524
+ }
525
+
526
+ return false;
527
+ }
528
+
529
+ static bool scan(TSLexer *lexer, const bool *valid_symbols) {
530
+ int8_t quoted_content_info_idx = find_quoted_token_info(valid_symbols);
531
+
532
+ // Quoted content, which matches any character except for close
533
+ // delimiters, escapes and interpolations
534
+ if (quoted_content_info_idx != -1) {
535
+ const QuotedContentInfo info =
536
+ quoted_content_infos[quoted_content_info_idx];
537
+ return scan_quoted_content(lexer, &info);
538
+ }
539
+
540
+ bool skipped_whitespace = false;
541
+
542
+ while (is_inline_whitespace(lexer->lookahead)) {
543
+ skipped_whitespace = true;
544
+ skip(lexer);
545
+ }
546
+
547
+ // Newline, which is either tokenized as a special newline or ignored
548
+ if (is_newline(lexer->lookahead) &&
549
+ (valid_symbols[NEWLINE_BEFORE_DO] ||
550
+ valid_symbols[NEWLINE_BEFORE_BINARY_OPERATOR] ||
551
+ valid_symbols[NEWLINE_BEFORE_COMMENT])) {
552
+ return scan_newline(lexer, valid_symbols);
553
+ }
554
+
555
+ // before unary +
556
+ if (lexer->lookahead == '+') {
557
+ if (skipped_whitespace && valid_symbols[BEFORE_UNARY_OPERATOR]) {
558
+ lexer->mark_end(lexer);
559
+ advance(lexer);
560
+ if (lexer->lookahead == '+' || lexer->lookahead == ':' ||
561
+ lexer->lookahead == '/') {
562
+ return false;
563
+ }
564
+ if (is_whitespace(lexer->lookahead)) {
565
+ return false;
566
+ }
567
+ lexer->result_symbol = BEFORE_UNARY_OPERATOR;
568
+ return true;
569
+ }
570
+ // before unary -
571
+ } else if (lexer->lookahead == '-') {
572
+ if (skipped_whitespace && valid_symbols[BEFORE_UNARY_OPERATOR]) {
573
+ lexer->mark_end(lexer);
574
+ lexer->result_symbol = BEFORE_UNARY_OPERATOR;
575
+ advance(lexer);
576
+ if (lexer->lookahead == '-' || lexer->lookahead == '>' ||
577
+ lexer->lookahead == ':' || lexer->lookahead == '/') {
578
+ return false;
579
+ }
580
+ if (is_whitespace(lexer->lookahead)) {
581
+ return false;
582
+ }
583
+ return true;
584
+ }
585
+ // not in
586
+ } else if (lexer->lookahead == 'n') {
587
+ if (valid_symbols[NOT_IN]) {
588
+ lexer->result_symbol = NOT_IN;
589
+ advance(lexer);
590
+ if (lexer->lookahead == 'o') {
591
+ advance(lexer);
592
+ if (lexer->lookahead == 't') {
593
+ advance(lexer);
594
+ while (is_inline_whitespace(lexer->lookahead)) {
595
+ advance(lexer);
596
+ }
597
+ if (lexer->lookahead == 'i') {
598
+ advance(lexer);
599
+ if (lexer->lookahead == 'n') {
600
+ advance(lexer);
601
+ return is_token_end(lexer->lookahead);
602
+ }
603
+ }
604
+ }
605
+ }
606
+ }
607
+ // quoted atom start
608
+ } else if (lexer->lookahead == ':') {
609
+ if (valid_symbols[QUOTED_ATOM_START]) {
610
+ advance(lexer);
611
+ lexer->mark_end(lexer);
612
+ lexer->result_symbol = QUOTED_ATOM_START;
613
+ if (lexer->lookahead == '"' || lexer->lookahead == '\'') {
614
+ return true;
615
+ }
616
+ }
617
+ }
618
+
619
+ return false;
620
+ }
621
+
622
+ void *tree_sitter_elixir_external_scanner_create() { return NULL; }
623
+
624
+ bool tree_sitter_elixir_external_scanner_scan(void *payload, TSLexer *lexer,
625
+ const bool *valid_symbols) {
626
+ return scan(lexer, valid_symbols);
627
+ }
628
+
629
+ unsigned tree_sitter_elixir_external_scanner_serialize(void *payload,
630
+ char *buffer) {
631
+ return 0;
632
+ }
633
+
634
+ void tree_sitter_elixir_external_scanner_deserialize(void *payload,
635
+ const char *buffer,
636
+ unsigned length) {}
637
+
638
+ void tree_sitter_elixir_external_scanner_destroy(void *payload) {}
@@ -0,0 +1,54 @@
1
+ #ifndef TREE_SITTER_ALLOC_H_
2
+ #define TREE_SITTER_ALLOC_H_
3
+
4
+ #ifdef __cplusplus
5
+ extern "C" {
6
+ #endif
7
+
8
+ #include <stdbool.h>
9
+ #include <stdio.h>
10
+ #include <stdlib.h>
11
+
12
+ // Allow clients to override allocation functions
13
+ #ifdef TREE_SITTER_REUSE_ALLOCATOR
14
+
15
+ extern void *(*ts_current_malloc)(size_t size);
16
+ extern void *(*ts_current_calloc)(size_t count, size_t size);
17
+ extern void *(*ts_current_realloc)(void *ptr, size_t size);
18
+ extern void (*ts_current_free)(void *ptr);
19
+
20
+ #ifndef ts_malloc
21
+ #define ts_malloc ts_current_malloc
22
+ #endif
23
+ #ifndef ts_calloc
24
+ #define ts_calloc ts_current_calloc
25
+ #endif
26
+ #ifndef ts_realloc
27
+ #define ts_realloc ts_current_realloc
28
+ #endif
29
+ #ifndef ts_free
30
+ #define ts_free ts_current_free
31
+ #endif
32
+
33
+ #else
34
+
35
+ #ifndef ts_malloc
36
+ #define ts_malloc malloc
37
+ #endif
38
+ #ifndef ts_calloc
39
+ #define ts_calloc calloc
40
+ #endif
41
+ #ifndef ts_realloc
42
+ #define ts_realloc realloc
43
+ #endif
44
+ #ifndef ts_free
45
+ #define ts_free free
46
+ #endif
47
+
48
+ #endif
49
+
50
+ #ifdef __cplusplus
51
+ }
52
+ #endif
53
+
54
+ #endif // TREE_SITTER_ALLOC_H_