ruby_tree_sitter 0.20.6.4-x86_64-darwin-20

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +152 -0
  4. data/ext/tree_sitter/encoding.c +29 -0
  5. data/ext/tree_sitter/extconf.rb +172 -0
  6. data/ext/tree_sitter/input.c +126 -0
  7. data/ext/tree_sitter/input_edit.c +42 -0
  8. data/ext/tree_sitter/language.c +134 -0
  9. data/ext/tree_sitter/logger.c +212 -0
  10. data/ext/tree_sitter/macros.h +163 -0
  11. data/ext/tree_sitter/node.c +310 -0
  12. data/ext/tree_sitter/parser.c +203 -0
  13. data/ext/tree_sitter/point.c +26 -0
  14. data/ext/tree_sitter/quantifier.c +43 -0
  15. data/ext/tree_sitter/query.c +157 -0
  16. data/ext/tree_sitter/query_capture.c +28 -0
  17. data/ext/tree_sitter/query_cursor.c +103 -0
  18. data/ext/tree_sitter/query_error.c +41 -0
  19. data/ext/tree_sitter/query_match.c +44 -0
  20. data/ext/tree_sitter/query_predicate_step.c +83 -0
  21. data/ext/tree_sitter/range.c +35 -0
  22. data/ext/tree_sitter/symbol_type.c +46 -0
  23. data/ext/tree_sitter/tree.c +144 -0
  24. data/ext/tree_sitter/tree_cursor.c +97 -0
  25. data/ext/tree_sitter/tree_sitter.c +32 -0
  26. data/ext/tree_sitter/tree_sitter.h +107 -0
  27. data/lib/tree_sitter/node.rb +164 -0
  28. data/lib/tree_sitter/tree_sitter.bundle +0 -0
  29. data/lib/tree_sitter/version.rb +5 -0
  30. data/lib/tree_sitter.rb +13 -0
  31. data/test/README.md +15 -0
  32. data/test/test_helper.rb +9 -0
  33. data/test/tree_sitter/language_test.rb +68 -0
  34. data/test/tree_sitter/logger_test.rb +69 -0
  35. data/test/tree_sitter/node_test.rb +355 -0
  36. data/test/tree_sitter/parser_test.rb +140 -0
  37. data/test/tree_sitter/query_test.rb +153 -0
  38. data/test/tree_sitter/tree_cursor_test.rb +83 -0
  39. data/test/tree_sitter/tree_test.rb +51 -0
  40. data/tree_sitter.gemspec +32 -0
  41. metadata +192 -0
@@ -0,0 +1,83 @@
1
+ #include "tree_sitter.h"
2
+
3
+ extern VALUE mTreeSitter;
4
+
5
+ VALUE cQueryPredicateStep;
6
+
7
+ const char *done = "Done";
8
+ const char *capture = "capture";
9
+ const char *string = "String";
10
+
11
+ DATA_WRAP(QueryPredicateStep, query_predicate_step)
12
+
13
+ VALUE new_query_predicate_step_type(TSQueryPredicateStepType type) {
14
+ switch (type) {
15
+ case TSQueryPredicateStepTypeDone:
16
+ return ID2SYM(rb_intern(done));
17
+ case TSQueryPredicateStepTypeCapture:
18
+ return ID2SYM(rb_intern(capture));
19
+ case TSQueryPredicateStepTypeString:
20
+ return ID2SYM(rb_intern(string));
21
+ default:
22
+ return Qnil;
23
+ }
24
+ }
25
+
26
+ static const char *query_predicate_type_string(TSQueryPredicateStepType type) {
27
+ switch (type) {
28
+ case TSQueryPredicateStepTypeDone:
29
+ return done;
30
+ case TSQueryPredicateStepTypeCapture:
31
+ return capture;
32
+ case TSQueryPredicateStepTypeString:
33
+ return string;
34
+ default:
35
+ return "???";
36
+ }
37
+ }
38
+
39
+ TSQueryPredicateStepType value_to_query_predicate_step_type(VALUE step_type) {
40
+ VALUE type = SYM2ID(step_type);
41
+ VALUE c = rb_const_get_at(cQueryPredicateStep, rb_intern(capture));
42
+ VALUE s = rb_const_get_at(cQueryPredicateStep, rb_intern(string));
43
+
44
+ // NOTE: should we emit a warning instead of defaulting to done?
45
+ if (type == c) {
46
+ return TSQueryPredicateStepTypeCapture;
47
+ } else if (type == s) {
48
+ return TSQueryPredicateStepTypeString;
49
+ } else {
50
+ return TSQueryPredicateStepTypeDone;
51
+ }
52
+ }
53
+
54
+ static VALUE query_predicate_step_inspect(VALUE self) {
55
+ query_predicate_step_t *step = unwrap(self);
56
+ return rb_sprintf("{value_id=%i, type=%s}", step->data.value_id,
57
+ query_predicate_type_string(step->data.type));
58
+ }
59
+
60
+ DATA_DEFINE_ACCESSOR(query_predicate_step, type, new_query_predicate_step_type,
61
+ value_to_query_predicate_step_type)
62
+ DATA_DEFINE_ACCESSOR(query_predicate_step, value_id, UINT2NUM, NUM2UINT)
63
+
64
+ void init_query_predicate_step(void) {
65
+ cQueryPredicateStep =
66
+ rb_define_class_under(mTreeSitter, "QueryPredicateStep", rb_cObject);
67
+
68
+ rb_define_alloc_func(cQueryPredicateStep, query_predicate_step_allocate);
69
+
70
+ /* Constants */
71
+ rb_define_const(cQueryPredicateStep, "DONE", ID2SYM(rb_intern(done)));
72
+ rb_define_const(cQueryPredicateStep, "CAPTURE", ID2SYM(rb_intern(capture)));
73
+ rb_define_const(cQueryPredicateStep, "STRING", ID2SYM(rb_intern(string)));
74
+
75
+ /* Class methods */
76
+ DECLARE_ACCESSOR(cQueryPredicateStep, query_predicate_step, type)
77
+ DECLARE_ACCESSOR(cQueryPredicateStep, query_predicate_step, value_id)
78
+
79
+ rb_define_method(cQueryPredicateStep, "inspect", query_predicate_step_inspect,
80
+ 0);
81
+ rb_define_method(cQueryPredicateStep, "to_s", query_predicate_step_inspect,
82
+ 0);
83
+ }
@@ -0,0 +1,35 @@
1
+ #include "tree_sitter.h"
2
+
3
+ extern VALUE mTreeSitter;
4
+
5
+ VALUE cRange;
6
+
7
+ DATA_WRAP(Range, range)
8
+ DATA_DEFINE_ACCESSOR(range, start_point, new_point_by_val, value_to_point)
9
+ DATA_DEFINE_ACCESSOR(range, end_point, new_point_by_val, value_to_point)
10
+ DATA_DEFINE_ACCESSOR(range, start_byte, UINT2NUM, NUM2UINT)
11
+ DATA_DEFINE_ACCESSOR(range, end_byte, UINT2NUM, NUM2UINT)
12
+
13
+ static VALUE range_inspect(VALUE self) {
14
+ range_t *range = unwrap(self);
15
+ return rb_sprintf("{start_point= %+" PRIsVALUE ", end_point=%+" PRIsVALUE
16
+ ", start_byte=%i, end_byte=%i}",
17
+ new_point_by_val(range->data.start_point),
18
+ new_point_by_val(range->data.end_point),
19
+ range->data.start_byte, range->data.end_byte);
20
+ }
21
+
22
+ void init_range(void) {
23
+ cRange = rb_define_class_under(mTreeSitter, "Range", rb_cObject);
24
+
25
+ rb_define_alloc_func(cRange, range_allocate);
26
+
27
+ /* Class methods */
28
+ DECLARE_ACCESSOR(cRange, range, start_point)
29
+ DECLARE_ACCESSOR(cRange, range, end_point)
30
+ DECLARE_ACCESSOR(cRange, range, start_byte)
31
+ DECLARE_ACCESSOR(cRange, range, end_byte)
32
+
33
+ rb_define_method(cRange, "inspect", range_inspect, 0);
34
+ rb_define_method(cRange, "to_s", range_inspect, 0);
35
+ }
@@ -0,0 +1,46 @@
1
+ #include "tree_sitter.h"
2
+
3
+ extern VALUE mTreeSitter;
4
+
5
+ VALUE mSymbolType;
6
+
7
+ const char *regular = "regular";
8
+ const char *anonymous = "anonymous";
9
+ const char *auxiliary = "auxiliary";
10
+
11
+ TSSymbolType value_to_symbol_type(VALUE symbol_type) {
12
+ VALUE sym = SYM2ID(symbol_type);
13
+ VALUE anon = rb_const_get_at(mSymbolType, rb_intern(anonymous));
14
+ VALUE aux = rb_const_get_at(mSymbolType, rb_intern(auxiliary));
15
+
16
+ // NOTE: should we emit a warning instead of defaulting to regular?
17
+ if (sym == anon) {
18
+ return TSSymbolTypeAnonymous;
19
+ } else if (sym == aux) {
20
+ return TSSymbolTypeAuxiliary;
21
+ } else {
22
+ return TSSymbolTypeRegular;
23
+ }
24
+ }
25
+
26
+ VALUE new_symbol_type(TSSymbolType symbol_type) {
27
+ switch (symbol_type) {
28
+ case TSSymbolTypeRegular:
29
+ return ID2SYM(rb_intern(regular));
30
+ case TSSymbolTypeAnonymous:
31
+ return ID2SYM(rb_intern(anonymous));
32
+ case TSSymbolTypeAuxiliary:
33
+ return ID2SYM(rb_intern(auxiliary));
34
+ default:
35
+ return ID2SYM(rb_intern("this_should_never_get_reached"));
36
+ }
37
+ }
38
+
39
+ void init_symbol_type(void) {
40
+ mSymbolType = rb_define_module_under(mTreeSitter, "SymbolType");
41
+
42
+ /* Constants */
43
+ rb_define_const(mSymbolType, "REGULAR", ID2SYM(rb_intern(regular)));
44
+ rb_define_const(mSymbolType, "ANONYMOUS", ID2SYM(rb_intern(anonymous)));
45
+ rb_define_const(mSymbolType, "AUXILIARY", ID2SYM(rb_intern(auxiliary)));
46
+ }
@@ -0,0 +1,144 @@
1
+ #include "tree_sitter.h"
2
+
3
+ extern VALUE mTreeSitter;
4
+
5
+ VALUE cTree;
6
+
7
+ int tree_rc_free(const TSTree *tree) {
8
+ VALUE ptr = ULONG2NUM((uintptr_t)tree);
9
+ VALUE rc = rb_cv_get(cTree, "@@rc");
10
+ VALUE val = rb_hash_lookup(rc, ptr);
11
+
12
+ if (!NIL_P(val)) {
13
+ unsigned int count = NUM2UINT(val);
14
+ --count;
15
+ if (count < 1) {
16
+ rb_hash_delete(rc, ptr);
17
+ ts_tree_delete((TSTree *)tree);
18
+ return 1;
19
+ } else {
20
+ rb_hash_aset(rc, ptr, ULONG2NUM(count));
21
+ return 0;
22
+ }
23
+ } else {
24
+ return 1;
25
+ }
26
+ }
27
+
28
+ void tree_rc_new(const TSTree *tree) {
29
+ VALUE ptr = ULONG2NUM((uintptr_t)tree);
30
+ VALUE rc = rb_cv_get(cTree, "@@rc");
31
+ VALUE val = rb_hash_lookup(rc, ptr);
32
+
33
+ if (NIL_P(val)) {
34
+ rb_hash_aset(rc, ptr, UINT2NUM(1));
35
+ } else {
36
+ rb_hash_aset(rc, ptr, UINT2NUM(NUM2UINT(val) + 1));
37
+ }
38
+ }
39
+
40
+ DATA_TYPE(TSTree *, tree)
41
+ static void tree_free(void *ptr) {
42
+ tree_t *type = (tree_t *)ptr;
43
+ if (tree_rc_free(type->data)) {
44
+ xfree(ptr);
45
+ }
46
+ }
47
+
48
+ DATA_MEMSIZE(tree)
49
+ DATA_DECLARE_DATA_TYPE(tree)
50
+ DATA_ALLOCATE(tree)
51
+ DATA_UNWRAP(tree)
52
+
53
+ VALUE new_tree(TSTree *ptr) {
54
+ if (ptr == NULL) {
55
+ return Qnil;
56
+ }
57
+ VALUE res = tree_allocate(cTree);
58
+ tree_t *type = unwrap(res);
59
+ type->data = ptr;
60
+ tree_rc_new(ptr);
61
+ return res;
62
+ }
63
+
64
+ DATA_FROM_VALUE(TSTree *, tree)
65
+
66
+ static VALUE tree_copy(VALUE self) { return new_tree(ts_tree_copy(SELF)); }
67
+
68
+ static VALUE tree_root_node(VALUE self) {
69
+ return new_node_by_val(ts_tree_root_node(SELF));
70
+ }
71
+
72
+ static VALUE tree_language(VALUE self) {
73
+ return new_language(ts_tree_language(SELF));
74
+ }
75
+
76
+ static VALUE tree_edit(VALUE self, VALUE edit) {
77
+ TSInputEdit in = value_to_input_edit(edit);
78
+ ts_tree_edit(SELF, &in);
79
+ return Qnil;
80
+ }
81
+
82
+ static VALUE tree_changed_ranges(VALUE _self, VALUE old_tree, VALUE new_tree) {
83
+ TSTree *old = unwrap(old_tree)->data;
84
+ TSTree *new = unwrap(new_tree)->data;
85
+ uint32_t length;
86
+ TSRange *ranges = ts_tree_get_changed_ranges(old, new, &length);
87
+ VALUE res = rb_ary_new_capa(length);
88
+
89
+ for (uint32_t i = 0; i < length; i++) {
90
+ rb_ary_push(res, new_range(&ranges[i]));
91
+ }
92
+
93
+ if (ranges) {
94
+ free(ranges);
95
+ }
96
+
97
+ return res;
98
+ }
99
+
100
+ static VALUE tree_print_dot_graph(VALUE self, VALUE file) {
101
+ Check_Type(file, T_STRING);
102
+ char *path = StringValueCStr(file);
103
+ FILE *fd = fopen(path, "w+");
104
+ ts_tree_print_dot_graph(SELF, fd);
105
+ fclose(fd);
106
+ return Qnil;
107
+ }
108
+
109
+ static VALUE tree_finalizer(VALUE _self) {
110
+ VALUE rc = rb_cv_get(cTree, "@@rc");
111
+ VALUE keys = rb_funcall(rc, rb_intern("keys"), 0);
112
+ long len = RARRAY_LEN(keys);
113
+
114
+ for (long i = 0; i < len; ++i) {
115
+ VALUE curr = RARRAY_AREF(keys, i);
116
+ unsigned int val = NUM2UINT(rb_hash_lookup(rc, curr));
117
+ if (val > 0) {
118
+ ts_tree_delete((TSTree *)NUM2ULONG(curr));
119
+ }
120
+
121
+ rb_hash_delete(rc, curr);
122
+ }
123
+
124
+ return Qnil;
125
+ }
126
+
127
+ void init_tree(void) {
128
+ cTree = rb_define_class_under(mTreeSitter, "Tree", rb_cObject);
129
+
130
+ rb_undef_alloc_func(cTree);
131
+
132
+ /* Class methods */
133
+ rb_define_method(cTree, "copy", tree_copy, 0);
134
+ rb_define_method(cTree, "root_node", tree_root_node, 0);
135
+ rb_define_method(cTree, "language", tree_language, 0);
136
+ rb_define_method(cTree, "edit", tree_edit, 1);
137
+ rb_define_module_function(cTree, "changed_ranges", tree_changed_ranges, 2);
138
+ rb_define_method(cTree, "print_dot_graph", tree_print_dot_graph, 1);
139
+ rb_define_module_function(cTree, "finalizer", tree_finalizer, 0);
140
+
141
+ // Reference-count created trees
142
+ VALUE rc = rb_hash_new();
143
+ rb_cv_set(cTree, "@@rc", rc);
144
+ }
@@ -0,0 +1,97 @@
1
+ #include "tree_sitter.h"
2
+
3
+ extern VALUE mTreeSitter;
4
+
5
+ VALUE cTreeCursor;
6
+
7
+ DATA_TYPE(TSTreeCursor, tree_cursor)
8
+ static void tree_cursor_free(void *ptr) {
9
+ tree_cursor_t *type = (tree_cursor_t *)ptr;
10
+ ts_tree_cursor_delete(&type->data);
11
+ xfree(ptr);
12
+ }
13
+ DATA_MEMSIZE(tree_cursor)
14
+ DATA_DECLARE_DATA_TYPE(tree_cursor)
15
+ DATA_ALLOCATE(tree_cursor)
16
+ DATA_UNWRAP(tree_cursor)
17
+ DATA_NEW(cTreeCursor, TSTreeCursor, tree_cursor)
18
+ DATA_FROM_VALUE(TSTreeCursor, tree_cursor)
19
+
20
+ static VALUE tree_cursor_initialize(VALUE self, VALUE node) {
21
+ TSNode n = value_to_node(node);
22
+ tree_cursor_t *ptr = unwrap(self);
23
+ ptr->data = ts_tree_cursor_new(n);
24
+ return self;
25
+ }
26
+
27
+ static VALUE tree_cursor_reset(VALUE self, VALUE node) {
28
+ ts_tree_cursor_reset(&SELF, value_to_node(node));
29
+ return Qnil;
30
+ }
31
+
32
+ static VALUE tree_cursor_current_node(VALUE self) {
33
+ TSNode node = ts_tree_cursor_current_node(&SELF);
34
+ return new_node(&node);
35
+ }
36
+
37
+ static VALUE tree_cursor_current_field_name(VALUE self) {
38
+ return safe_str(ts_tree_cursor_current_field_name(&SELF));
39
+ }
40
+
41
+ static VALUE tree_cursor_current_field_id(VALUE self) {
42
+ return UINT2NUM(ts_tree_cursor_current_field_id(&SELF));
43
+ }
44
+
45
+ static VALUE tree_cursor_goto_parent(VALUE self) {
46
+ return ts_tree_cursor_goto_parent(&SELF) ? Qtrue : Qfalse;
47
+ }
48
+
49
+ static VALUE tree_cursor_goto_next_sibling(VALUE self) {
50
+ return ts_tree_cursor_goto_next_sibling(&SELF) ? Qtrue : Qfalse;
51
+ }
52
+
53
+ static VALUE tree_cursor_goto_first_child(VALUE self) {
54
+ return ts_tree_cursor_goto_first_child(&SELF) ? Qtrue : Qfalse;
55
+ }
56
+
57
+ static VALUE tree_cursor_goto_first_child_for_byte(VALUE self, VALUE byte) {
58
+ return LL2NUM(
59
+ ts_tree_cursor_goto_first_child_for_byte(&SELF, NUM2UINT(byte)));
60
+ }
61
+
62
+ static VALUE tree_cursor_goto_first_child_for_point(VALUE self, VALUE point) {
63
+ return LL2NUM(
64
+ ts_tree_cursor_goto_first_child_for_point(&SELF, value_to_point(point)));
65
+ }
66
+
67
+ static VALUE tree_cursor_copy(VALUE self) {
68
+ VALUE res = tree_cursor_allocate(cTreeCursor);
69
+ tree_cursor_t *ptr = unwrap(res);
70
+ ptr->data = ts_tree_cursor_copy(&SELF);
71
+ return res;
72
+ }
73
+
74
+ void init_tree_cursor(void) {
75
+ cTreeCursor = rb_define_class_under(mTreeSitter, "TreeCursor", rb_cObject);
76
+
77
+ rb_define_alloc_func(cTreeCursor, tree_cursor_allocate);
78
+
79
+ /* Class methods */
80
+ rb_define_method(cTreeCursor, "initialize", tree_cursor_initialize, 1);
81
+ rb_define_method(cTreeCursor, "reset", tree_cursor_reset, 1);
82
+ rb_define_method(cTreeCursor, "current_node", tree_cursor_current_node, 0);
83
+ rb_define_method(cTreeCursor, "current_field_name",
84
+ tree_cursor_current_field_name, 0);
85
+ rb_define_method(cTreeCursor, "current_field_id",
86
+ tree_cursor_current_field_id, 0);
87
+ rb_define_method(cTreeCursor, "goto_parent", tree_cursor_goto_parent, 0);
88
+ rb_define_method(cTreeCursor, "goto_next_sibling",
89
+ tree_cursor_goto_next_sibling, 0);
90
+ rb_define_method(cTreeCursor, "goto_first_child",
91
+ tree_cursor_goto_first_child, 0);
92
+ rb_define_method(cTreeCursor, "goto_first_child_for_byte",
93
+ tree_cursor_goto_first_child_for_byte, 1);
94
+ rb_define_method(cTreeCursor, "goto_first_child_for_point",
95
+ tree_cursor_goto_first_child_for_point, 1);
96
+ rb_define_method(cTreeCursor, "copy", tree_cursor_copy, 0);
97
+ }
@@ -0,0 +1,32 @@
1
+ #include "tree_sitter.h"
2
+
3
+ VALUE mTreeSitter;
4
+
5
+ void Init_tree_sitter() {
6
+ mTreeSitter = rb_define_module("TreeSitter");
7
+
8
+ rb_define_const(mTreeSitter, "LANGUAGE_VERSION",
9
+ INT2NUM(TREE_SITTER_LANGUAGE_VERSION));
10
+ rb_define_const(mTreeSitter, "MIN_COMPATIBLE_LANGUAGE_VERSION",
11
+ TREE_SITTER_MIN_COMPATIBLE_LANGUAGE_VERSION);
12
+
13
+ init_encoding();
14
+ init_input();
15
+ init_input_edit();
16
+ init_language();
17
+ init_logger();
18
+ init_node();
19
+ init_parser();
20
+ init_point();
21
+ init_quantifier();
22
+ init_query();
23
+ init_query_capture();
24
+ init_query_cursor();
25
+ init_query_error();
26
+ init_query_match();
27
+ init_query_predicate_step();
28
+ init_range();
29
+ init_symbol_type();
30
+ init_tree();
31
+ init_tree_cursor();
32
+ }
@@ -0,0 +1,107 @@
1
+ #ifndef _RB_TREE_SITTER_H
2
+ #define _RB_TREE_SITTER_H
3
+
4
+ #include "macros.h"
5
+ #include <dlfcn.h>
6
+ #include <fcntl.h>
7
+ #include <ruby.h>
8
+ #include <stdio.h>
9
+ #include <string.h>
10
+ #include <tree_sitter/api.h>
11
+
12
+ static inline VALUE safe_str(const char *str) {
13
+ if (str == NULL) {
14
+ return Qnil;
15
+ } else {
16
+ return rb_utf8_str_new_cstr(str);
17
+ }
18
+ }
19
+
20
+ static inline VALUE safe_str2(const char *str, uint32_t len) {
21
+ if (str == NULL) {
22
+ return Qnil;
23
+ } else if (len == 0) {
24
+ return rb_utf8_str_new_cstr("");
25
+ } else {
26
+ return rb_utf8_str_new(str, len);
27
+ }
28
+ }
29
+
30
+ static inline VALUE safe_symbol(const char *str) {
31
+ if (str == NULL) {
32
+ return Qnil;
33
+ } else {
34
+ return ID2SYM(rb_intern(str));
35
+ }
36
+ }
37
+
38
+ // VALUE to TS* converters
39
+
40
+ TSInput value_to_input(VALUE);
41
+ TSInputEdit value_to_input_edit(VALUE);
42
+ TSInputEncoding value_to_encoding(VALUE);
43
+ TSLanguage *value_to_language(VALUE);
44
+ TSLogger value_to_logger(VALUE);
45
+ TSNode value_to_node(VALUE);
46
+ TSPoint value_to_point(VALUE);
47
+ TSQuantifier value_to_quantifier(VALUE);
48
+ TSQuery *value_to_query(VALUE);
49
+ TSQueryCursor *value_to_query_cursor(VALUE);
50
+ TSQueryError value_to_query_error(VALUE);
51
+ TSQueryMatch value_to_query_match(VALUE);
52
+ TSQueryPredicateStep value_to_query_predicate_step(VALUE);
53
+ TSQueryPredicateStepType value_to_query_predicate_step_type(VALUE);
54
+ TSRange value_to_range(VALUE);
55
+ TSSymbolType value_to_symbol_type(VALUE);
56
+ TSTree *value_to_tree(VALUE);
57
+ TSTreeCursor value_to_tree_cursor(VALUE);
58
+
59
+ // TS* to VALUE converters
60
+ VALUE new_input(const TSInput *);
61
+ VALUE new_language(const TSLanguage *);
62
+ VALUE new_logger(const TSLogger *);
63
+ VALUE new_logger_by_val(TSLogger);
64
+ VALUE new_node(const TSNode *);
65
+ VALUE new_node_by_val(TSNode);
66
+ VALUE new_point(const TSPoint *);
67
+ VALUE new_point_by_val(TSPoint);
68
+ VALUE new_query_capture(const TSQueryCapture *);
69
+ VALUE new_query_match(const TSQueryMatch *);
70
+ VALUE new_query_predicate_step(const TSQueryPredicateStep *);
71
+ VALUE new_range(const TSRange *);
72
+ VALUE new_symbol_type(TSSymbolType);
73
+ VALUE new_tree(TSTree *);
74
+
75
+ // All init_* functions are called from Init_tree_sitter
76
+ void init_encoding(void);
77
+ void init_input(void);
78
+ void init_input_edit(void);
79
+ void init_language(void);
80
+ void init_logger(void);
81
+ void init_node(void);
82
+ void init_parser(void);
83
+ void init_point(void);
84
+ void init_quantifier(void);
85
+ void init_query(void);
86
+ void init_query_capture(void);
87
+ void init_query_cursor(void);
88
+ void init_query_error(void);
89
+ void init_query_match(void);
90
+ void init_query_predicate_step(void);
91
+ void init_range(void);
92
+ void init_symbol_type(void);
93
+ void init_tree(void);
94
+ void init_tree_cursor(void);
95
+
96
+ // Other helpers
97
+ const char *quantifier_str(TSQuantifier);
98
+ const char *query_error_str(TSQueryError);
99
+
100
+ // TSTree reference counting
101
+ int tree_rc_free(const TSTree *);
102
+ void tree_rc_new(const TSTree *);
103
+
104
+ // This is a special entry-point for the extension
105
+ void Init_tree_sitter(void);
106
+
107
+ #endif
@@ -0,0 +1,164 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TreeSitter
4
+ class Node
5
+ def fields
6
+ return @fields if @fields
7
+
8
+ @fields = Set.new
9
+ child_count.times do |i|
10
+ name = field_name_for_child(i)
11
+ @fields << name.to_sym if name
12
+ end
13
+
14
+ @fields
15
+ end
16
+
17
+ def field?(field)
18
+ fields.include?(field)
19
+ end
20
+
21
+ # Access node's named children.
22
+ #
23
+ # It's similar to {#fetch}, but differes in input type, return values, and
24
+ # the internal implementation.
25
+ #
26
+ # Both of these methods exist for separate use cases, but also because
27
+ # sometime tree-sitter does some monkey business and having both separate
28
+ # implementations can help.
29
+ #
30
+ # Comparison with {#fetch}:
31
+ #
32
+ # [] | fetch
33
+ # ------------------------------+----------------------
34
+ # input types Integer, String, Symbol | Array<String, Symbol>
35
+ # Array<Integer, String, Symbol>|
36
+ # ------------------------------+----------------------
37
+ # returns 1-to-1 correspondance with | unique nodes
38
+ # input |
39
+ # ------------------------------+----------------------
40
+ # uses named_child | field_name_for_child
41
+ # child_by_field_name | via each_node
42
+ # ------------------------------+----------------------
43
+ #
44
+ # @param keys [Integer | String | Symbol | Array<Integer, String, Symbol>, #read]
45
+ #
46
+ # @return [Node | Array<Node>]
47
+ def [](*keys)
48
+ case keys.length
49
+ when 0 then raise "#{self.class.name}##{__method__} requires a key."
50
+ when 1
51
+ case k = keys.first
52
+ when Numeric then named_child(k)
53
+ when String, Symbol
54
+ if fields.include?(k.to_sym)
55
+ child_by_field_name(k.to_s)
56
+ else
57
+ raise "Cannot find field #{k}"
58
+ end
59
+ else raise <<~ERR
60
+ #{self.class.name}##{__method__} accepts Integer and returns named child at given index,
61
+ or a (String | Symbol) and returns the child by given field name.
62
+ ERR
63
+ end
64
+ else
65
+ keys.map { |key| self[key] }
66
+ end
67
+ end
68
+
69
+ # Allows access to child_by_field_name without using [].
70
+ def method_missing(method_name, *_args, &_block)
71
+ if fields.include?(method_name)
72
+ child_by_field_name(method_name.to_s)
73
+ else
74
+ super
75
+ end
76
+ end
77
+
78
+ def respond_to_missing?(*args)
79
+ init_fields
80
+ args.length == 1 && fields.include?(args[0])
81
+ end
82
+
83
+ # Iterate over a node's children.
84
+ #
85
+ # @yieldparam child [Node] the child
86
+ def each
87
+ return enum_for __method__ if !block_given?
88
+
89
+ (0...(child_count)).each do |i|
90
+ yield child(i)
91
+ end
92
+ end
93
+
94
+ # Iterate over a node's children assigned to a field.
95
+ #
96
+ # @yieldparam name [NilClass | String] field name.
97
+ # @yieldparam child [Node] the child.
98
+ def each_field
99
+ return enum_for __method__ if !block_given?
100
+
101
+ each.with_index do |c, i|
102
+ f = field_name_for_child(i)
103
+ next if f.nil? || f.empty?
104
+
105
+ yield f, c
106
+ end
107
+ end
108
+
109
+ # Iterate over a node's named children
110
+ #
111
+ # @yieldparam child [Node] the child
112
+ def each_named
113
+ return enum_for __method__ if !block_given?
114
+
115
+ (0...(named_child_count)).each do |i|
116
+ yield named_child(i)
117
+ end
118
+ end
119
+
120
+ def to_a
121
+ each.to_a
122
+ end
123
+
124
+ # Access node's named children.
125
+ #
126
+ # It's similar to {#fetch}, but differes in input type, return values, and
127
+ # the internal implementation.
128
+ #
129
+ # Both of these methods exist for separate use cases, but also because
130
+ # sometime tree-sitter does some monkey business and having both separate
131
+ # implementations can help.
132
+ #
133
+ # Comparison with {#fetch}:
134
+ #
135
+ # [] | fetch
136
+ # ------------------------------+----------------------
137
+ # input types Integer, String, Symbol | String, Symbol
138
+ # Array<Integer, String, Symbol>| Array<String, Symbol>
139
+ # ------------------------------+----------------------
140
+ # returns 1-to-1 correspondance with | unique nodes
141
+ # input |
142
+ # ------------------------------+----------------------
143
+ # uses named_child | field_name_for_child
144
+ # child_by_field_name | via each_node
145
+ # ------------------------------+----------------------
146
+ def fetch(*keys)
147
+ dict = {}
148
+ keys.each.with_index do |k, i|
149
+ dict[k.to_s] = i
150
+ end
151
+
152
+ res = {}
153
+ each_field do |f, c|
154
+ if dict.key?(f)
155
+ res[dict[f]] = c
156
+ dict.delete(f)
157
+ end
158
+ break if dict.empty?
159
+ end
160
+
161
+ res.sort.map { |_, v| v }
162
+ end
163
+ end
164
+ end