ruby_tree_sitter 0.20.8.3 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +2 -1
  3. data/README.md +32 -18
  4. data/ext/tree_sitter/extconf.rb +1 -1
  5. data/ext/tree_sitter/input.c +1 -0
  6. data/ext/tree_sitter/language.c +131 -46
  7. data/ext/tree_sitter/logger.c +28 -12
  8. data/ext/tree_sitter/node.c +438 -130
  9. data/ext/tree_sitter/parser.c +232 -37
  10. data/ext/tree_sitter/query.c +197 -72
  11. data/ext/tree_sitter/query_cursor.c +140 -28
  12. data/ext/tree_sitter/repo.rb +1 -1
  13. data/ext/tree_sitter/tree.c +118 -34
  14. data/ext/tree_sitter/tree_cursor.c +205 -33
  15. data/ext/tree_sitter/tree_sitter.c +12 -0
  16. data/lib/tree_sitter/node.rb +23 -6
  17. data/lib/tree_sitter/version.rb +4 -2
  18. data/lib/tree_sitter.rb +1 -0
  19. data/lib/tree_stand/ast_modifier.rb +30 -0
  20. data/lib/tree_stand/breadth_first_visitor.rb +54 -0
  21. data/lib/tree_stand/config.rb +13 -0
  22. data/lib/tree_stand/node.rb +224 -0
  23. data/lib/tree_stand/parser.rb +67 -0
  24. data/lib/tree_stand/range.rb +55 -0
  25. data/lib/tree_stand/tree.rb +123 -0
  26. data/lib/tree_stand/utils/printer.rb +73 -0
  27. data/lib/tree_stand/version.rb +7 -0
  28. data/lib/tree_stand/visitor.rb +127 -0
  29. data/lib/tree_stand/visitors/tree_walker.rb +37 -0
  30. data/lib/tree_stand.rb +48 -0
  31. data/tree_sitter.gemspec +14 -11
  32. metadata +37 -108
  33. data/test/README.md +0 -15
  34. data/test/test_helper.rb +0 -9
  35. data/test/tree_sitter/js_test.rb +0 -48
  36. data/test/tree_sitter/language_test.rb +0 -73
  37. data/test/tree_sitter/logger_test.rb +0 -70
  38. data/test/tree_sitter/node_test.rb +0 -411
  39. data/test/tree_sitter/parser_test.rb +0 -140
  40. data/test/tree_sitter/query_test.rb +0 -153
  41. data/test/tree_sitter/tree_cursor_test.rb +0 -83
  42. data/test/tree_sitter/tree_test.rb +0 -51
@@ -40,10 +40,63 @@ static VALUE parser_allocate(VALUE klass) {
40
40
  return res;
41
41
  }
42
42
 
43
+ /**
44
+ * Get the parser's current cancellation flag pointer.
45
+ *
46
+ * @return [Integer]
47
+ */
48
+ static VALUE parser_get_cancellation_flag(VALUE self) {
49
+ return SIZET2NUM(*ts_parser_cancellation_flag(SELF));
50
+ }
51
+
52
+ /**
53
+ * Set the parser's current cancellation flag pointer.
54
+ *
55
+ * If a non-null pointer is assigned, then the parser will periodically read
56
+ * from this pointer during parsing. If it reads a non-zero value, it will
57
+ * halt early, returning +nil+.
58
+ *
59
+ * @see parse
60
+ *
61
+ * @note This is not well-tested in the bindings.
62
+ *
63
+ * @return nil
64
+ */
65
+ static VALUE parser_set_cancellation_flag(VALUE self, VALUE flag) {
66
+ unwrap(self)->cancellation_flag = NUM2SIZET(flag);
67
+ ts_parser_set_cancellation_flag(SELF, &unwrap(self)->cancellation_flag);
68
+ return Qnil;
69
+ }
70
+
71
+ /**
72
+ * Get the parser's current language.
73
+ */
43
74
  static VALUE parser_get_language(VALUE self) {
44
75
  return new_language(ts_parser_language(SELF));
45
76
  }
46
77
 
78
+ /**
79
+ * Set the language that the parser should use for parsing.
80
+ *
81
+ * Returns a boolean indicating whether or not the language was successfully
82
+ * assigned. True means assignment succeeded. False means there was a version
83
+ * mismatch: the language was generated with an incompatible version of the
84
+ * Tree-sitter CLI. Check the language's version using {Language#version}
85
+ * and compare it to this library's {TreeSitter::LANGUAGE_VERSION} and
86
+ * {TreeSitter::MIN_COMPATIBLE_LANGUAGE_VERSION} constants.
87
+ *
88
+ * @return [Boolean]
89
+ */
90
+ static VALUE parser_set_language(VALUE self, VALUE language) {
91
+ return ts_parser_set_language(SELF, value_to_language(language)) ? Qtrue
92
+ : Qfalse;
93
+ }
94
+
95
+ /**
96
+ * Get the ranges of text that the parser will include when parsing.
97
+ *
98
+ * @return [Array<Range>]
99
+ */
47
100
  static VALUE parser_get_included_ranges(VALUE self) {
48
101
  uint32_t length;
49
102
  const TSRange *ranges = ts_parser_included_ranges(SELF, &length);
@@ -54,23 +107,33 @@ static VALUE parser_get_included_ranges(VALUE self) {
54
107
  return res;
55
108
  }
56
109
 
57
- static VALUE parser_get_timeout_micros(VALUE self) {
58
- return ULL2NUM(ts_parser_timeout_micros(SELF));
59
- }
60
-
61
- static VALUE parser_get_logger(VALUE self) {
62
- return new_logger_by_val(ts_parser_logger(SELF));
63
- }
64
-
65
- static VALUE parser_get_cancellation_flag(VALUE self) {
66
- return SIZET2NUM(*ts_parser_cancellation_flag(SELF));
67
- }
68
-
69
- static VALUE parser_set_language(VALUE self, VALUE language) {
70
- return ts_parser_set_language(SELF, value_to_language(language)) ? Qtrue
71
- : Qfalse;
72
- }
73
-
110
+ /**
111
+ * Set the ranges of text that the parser should include when parsing.
112
+ *
113
+ * By default, the parser will always include entire documents. This function
114
+ * allows you to parse only a *portion* of a document but still return a syntax
115
+ * tree whose ranges match up with the document as a whole. You can also pass
116
+ * multiple disjoint ranges.
117
+ *
118
+ * The second and third parameters specify the location and length of an array
119
+ * of ranges. The parser does *not* take ownership of these ranges; it copies
120
+ * the data, so it doesn't matter how these ranges are allocated.
121
+ *
122
+ * If +array+'s +length+ is zero, then the entire document will be parsed.
123
+ * Otherwise, the given ranges must be ordered from earliest to latest in the
124
+ * document, and they must not overlap. That is, the following must hold for
125
+ * all:
126
+ *
127
+ * i < length - 1: ranges[i].end_byte <= ranges[i + 1].start_byte
128
+ *
129
+ * If this requirement is not satisfied, the operation will fail, the ranges
130
+ * will not be assigned, and this function will return +false+. On success,
131
+ * this function returns +true+
132
+ *
133
+ * @param array [Array<Range>]
134
+ *
135
+ * @return [Boolean]
136
+ */
74
137
  static VALUE parser_set_included_ranges(VALUE self, VALUE array) {
75
138
  Check_Type(array, T_ARRAY);
76
139
 
@@ -86,22 +149,76 @@ static VALUE parser_set_included_ranges(VALUE self, VALUE array) {
86
149
  return res ? Qtrue : Qfalse;
87
150
  }
88
151
 
89
- static VALUE parser_set_timeout_micros(VALUE self, VALUE timeout) {
90
- ts_parser_set_timeout_micros(SELF, NUM2ULL(timeout));
91
- return Qnil;
92
- }
93
-
94
- static VALUE parser_set_cancellation_flag(VALUE self, VALUE flag) {
95
- unwrap(self)->cancellation_flag = NUM2SIZET(flag);
96
- ts_parser_set_cancellation_flag(SELF, &unwrap(self)->cancellation_flag);
97
- return Qnil;
152
+ /**
153
+ * Get the parser's current logger.
154
+ *
155
+ * @return [Logger]
156
+ */
157
+ static VALUE parser_get_logger(VALUE self) {
158
+ return new_logger_by_val(ts_parser_logger(SELF));
98
159
  }
99
160
 
161
+ /**
162
+ * Set the logger that a parser should use during parsing.
163
+ *
164
+ * The parser does not take ownership over the logger payload. If a logger was
165
+ * previously assigned, the caller is responsible for releasing any memory
166
+ * owned by the previous logger.
167
+ *
168
+ * @param logger [Logger] or any object that has a +printf+, +puts+, or +write+.
169
+ *
170
+ * @return nil
171
+ */
100
172
  static VALUE parser_set_logger(VALUE self, VALUE logger) {
101
173
  ts_parser_set_logger(SELF, value_to_logger(logger));
102
174
  return Qnil;
103
175
  }
104
176
 
177
+ /**
178
+ * Use the parser to parse some source code and create a syntax tree.
179
+ *
180
+ * If you are parsing this document for the first time, pass +nil+ for the
181
+ * +old_tree+ parameter. Otherwise, if you have already parsed an earlier
182
+ * version of this document and the document has since been edited, pass the
183
+ * previous syntax tree so that the unchanged parts of it can be reused.
184
+ * This will save time and memory. For this to work correctly, you must have
185
+ * already edited the old syntax tree using the {Tree#edit} function in a
186
+ * way that exactly matches the source code changes.
187
+ *
188
+ * The input parameter lets you specify how to read the text. It has the
189
+ * following three fields:
190
+ * 1. +read+: A function to retrieve a chunk of text at a given byte offset
191
+ * and (row, column) position. The function should return a pointer to the
192
+ * text and write its length to the +bytes_read+ pointer. The parser does
193
+ * not take ownership of this buffer; it just borrows it until it has
194
+ * finished reading it. The function should write a zero value to the
195
+ * +bytes_read+ pointer to indicate the end of the document.
196
+ * 2. +payload+: An arbitrary pointer that will be passed to each invocation
197
+ * of the +read+ function.
198
+ * 3. +encoding+: An indication of how the text is encoded. Either
199
+ * {Encoding::UTF8} or {Encoding::UTF16}.
200
+ *
201
+ * This function returns a syntax tree on success, and +nil+ on failure. There
202
+ * are three possible reasons for failure:
203
+ * 1. The parser does not have a language assigned. Check for this using the
204
+ * {Parser#language} function.
205
+ * 2. Parsing was cancelled due to a timeout that was set by an earlier call to
206
+ * the {Parser#timeout_micros=} function. You can resume parsing from
207
+ * where the parser left out by calling {Parser#parse} again with the
208
+ * same arguments. Or you can start parsing from scratch by first calling
209
+ * {Parser#reset}.
210
+ * 3. Parsing was cancelled using a cancellation flag that was set by an
211
+ * earlier call to {Parsert#cancellation_flag=}. You can resume parsing
212
+ * from where the parser left out by calling {Parser#parse} again with
213
+ * the same arguments.
214
+ *
215
+ * @note this is curently incomplete, as the {Input} class is incomplete.
216
+ *
217
+ * @param old_tree [Tree]
218
+ * @param input [Input]
219
+ *
220
+ * @return [Tree, nil] A parse tree if parsing was successful.
221
+ */
105
222
  static VALUE parser_parse(VALUE self, VALUE old_tree, VALUE input) {
106
223
  if (NIL_P(input)) {
107
224
  return Qnil;
@@ -120,6 +237,17 @@ static VALUE parser_parse(VALUE self, VALUE old_tree, VALUE input) {
120
237
  }
121
238
  }
122
239
 
240
+ /**
241
+ * Use the parser to parse some source code stored in one contiguous buffer.
242
+ * The first two parameters are the same as in the {Parser#parse} function
243
+ * above. The second two parameters indicate the location of the buffer and its
244
+ * length in bytes.
245
+ *
246
+ * @param old_tree [Tree]
247
+ * @param string [String]
248
+ *
249
+ * @return [Tree, nil] A parse tree if parsing was successful.
250
+ */
123
251
  static VALUE parser_parse_string(VALUE self, VALUE old_tree, VALUE string) {
124
252
  if (NIL_P(string)) {
125
253
  return Qnil;
@@ -140,6 +268,18 @@ static VALUE parser_parse_string(VALUE self, VALUE old_tree, VALUE string) {
140
268
  }
141
269
  }
142
270
 
271
+ /**
272
+ * Use the parser to parse some source code stored in one contiguous buffer with
273
+ * a given encoding. The first four parameters work the same as in the
274
+ * {Parser#parse_string} method above. The final parameter indicates whether
275
+ * the text is encoded as {Encoding::UTF8} or {Encoding::UTF16}.
276
+ *
277
+ * @param old_tree [Tree]
278
+ * @param string [String]
279
+ * @param encoding [Encoding]
280
+ *
281
+ * @return [Tree, nil] A parse tree if parsing was successful.
282
+ */
143
283
  static VALUE parser_parse_string_encoding(VALUE self, VALUE old_tree,
144
284
  VALUE string, VALUE encoding) {
145
285
  if (NIL_P(string)) {
@@ -163,11 +303,17 @@ static VALUE parser_parse_string_encoding(VALUE self, VALUE old_tree,
163
303
  }
164
304
  }
165
305
 
166
- static VALUE parser_reset(VALUE self) {
167
- ts_parser_reset(SELF);
168
- return Qnil;
169
- }
170
-
306
+ /**
307
+ * Set the file descriptor to which the parser should write debugging graphs
308
+ * during parsing. The graphs are formatted in the DOT language. You may want
309
+ * to pipe these graphs directly to a +dot(1)+ process in order to generate
310
+ * SVG output. You can turn off this logging by passing a negative number.
311
+ *
312
+ * @param file [Integer, String, nil] a file name to print, or turn off by
313
+ * passing +nil+ or +-1+
314
+ *
315
+ * @return nil
316
+ */
171
317
  static VALUE parser_print_dot_graphs(VALUE self, VALUE file) {
172
318
  if (NIL_P(file)) {
173
319
  ts_parser_print_dot_graphs(SELF, -1);
@@ -183,21 +329,70 @@ static VALUE parser_print_dot_graphs(VALUE self, VALUE file) {
183
329
  return Qnil;
184
330
  }
185
331
 
332
+ /**
333
+ * Instruct the parser to start the next parse from the beginning.
334
+ *
335
+ * If the parser previously failed because of a timeout or a cancellation, then
336
+ * by default, it will resume where it left off on the next call to
337
+ * {Parser#parse} or other parsing functions. If you don't want to resume,
338
+ * and instead intend to use this parser to parse some other document, you must
339
+ * call {Parser#reset} first.
340
+ *
341
+ * @return nil
342
+ */
343
+ static VALUE parser_reset(VALUE self) {
344
+ ts_parser_reset(SELF);
345
+ return Qnil;
346
+ }
347
+
348
+ /**
349
+ * Get the duration in microseconds that parsing is allowed to take.
350
+ *
351
+ * @return [Integer]
352
+ */
353
+ static VALUE parser_get_timeout_micros(VALUE self) {
354
+ return ULL2NUM(ts_parser_timeout_micros(SELF));
355
+ }
356
+
357
+ /**
358
+ * Set the maximum duration in microseconds that parsing should be allowed to
359
+ * take before halting.
360
+ *
361
+ * If parsing takes longer than this, it will halt early, returning +nil+.
362
+ *
363
+ * @see parse
364
+ *
365
+ * @param timeout [Integer]
366
+ *
367
+ * @return [nil]
368
+ */
369
+ static VALUE parser_set_timeout_micros(VALUE self, VALUE timeout) {
370
+ ts_parser_set_timeout_micros(SELF, NUM2ULL(timeout));
371
+ return Qnil;
372
+ }
373
+
186
374
  void init_parser(void) {
187
375
  cParser = rb_define_class_under(mTreeSitter, "Parser", rb_cObject);
188
376
 
189
377
  rb_define_alloc_func(cParser, parser_allocate);
190
378
 
191
379
  /* Class methods */
192
- DECLARE_ACCESSOR(cParser, parser, language)
193
- DECLARE_ACCESSOR(cParser, parser, included_ranges)
194
- DECLARE_ACCESSOR(cParser, parser, timeout_micros)
195
- DECLARE_ACCESSOR(cParser, parser, logger)
196
- DECLARE_ACCESSOR(cParser, parser, cancellation_flag)
380
+ rb_define_method(cParser, "cancellation_flag", parser_get_cancellation_flag,
381
+ 0);
382
+ rb_define_method(cParser, "cancellation_flag=", parser_set_cancellation_flag,
383
+ 1);
384
+ rb_define_method(cParser, "included_ranges", parser_get_included_ranges, 0);
385
+ rb_define_method(cParser, "included_ranges=", parser_set_included_ranges, 1);
386
+ rb_define_method(cParser, "language", parser_get_language, 0);
387
+ rb_define_method(cParser, "language=", parser_set_language, 1);
388
+ rb_define_method(cParser, "logger", parser_get_logger, 0);
389
+ rb_define_method(cParser, "logger=", parser_set_logger, 1);
197
390
  rb_define_method(cParser, "parse", parser_parse, 2);
198
391
  rb_define_method(cParser, "parse_string", parser_parse_string, 2);
199
392
  rb_define_method(cParser, "parse_string_encoding",
200
393
  parser_parse_string_encoding, 3);
201
- rb_define_method(cParser, "reset", parser_reset, 0);
202
394
  rb_define_method(cParser, "print_dot_graphs", parser_print_dot_graphs, 1);
395
+ rb_define_method(cParser, "reset", parser_reset, 0);
396
+ rb_define_method(cParser, "timeout_micros", parser_get_timeout_micros, 0);
397
+ rb_define_method(cParser, "timeout_micros=", parser_set_timeout_micros, 1);
203
398
  }
@@ -6,7 +6,125 @@ VALUE cQuery;
6
6
 
7
7
  DATA_PTR_WRAP(Query, query);
8
8
 
9
+ /**
10
+ * Get the number of captures literals in the query.
11
+ *
12
+ * @return [Integer]
13
+ */
14
+ static VALUE query_capture_count(VALUE self) {
15
+ return UINT2NUM(ts_query_capture_count(SELF));
16
+ }
17
+
18
+ /**
19
+ * Get the name and length of one of the query's captures, or one of the
20
+ * query's string literals. Each capture and string is associated with a
21
+ * numeric id based on the order that it appeared in the query's source.
22
+ *
23
+ * @raise [IndexError] if out of range.
24
+ *
25
+ * @param index [Integer]
26
+ *
27
+ * @return [String]
28
+ */
29
+ static VALUE query_capture_name_for_id(VALUE self, VALUE index) {
30
+ const TSQuery *query = SELF;
31
+ uint32_t idx = NUM2UINT(index);
32
+ uint32_t range = ts_query_capture_count(query);
33
+
34
+ if (idx >= range) {
35
+ rb_raise(rb_eIndexError, "Index %d out of range (len = %d)", idx, range);
36
+ } else {
37
+ uint32_t length;
38
+ const char *name = ts_query_capture_name_for_id(query, idx, &length);
39
+ return safe_str2(name, length);
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Get the quantifier of the query's captures. Each capture is associated
45
+ * with a numeric id based on the order that it appeared in the query's source.
46
+ *
47
+ * @raise [IndexError] if out of range.
48
+ *
49
+ * @param query_idx [Integer]
50
+ * @param capture_idx [Integer]
51
+ *
52
+ * @return [Integer]
53
+ */
54
+ static VALUE query_capture_quantifier_for_id(VALUE self, VALUE query_idx,
55
+ VALUE capture_idx) {
56
+ const TSQuery *query = SELF;
57
+ uint32_t pattern = NUM2UINT(query_idx);
58
+ uint32_t index = NUM2UINT(capture_idx);
59
+ uint32_t range = ts_query_capture_count(query);
60
+
61
+ if (index >= range) {
62
+ rb_raise(rb_eIndexError, "Capture ID %d out of range (len = %d)", index,
63
+ range);
64
+ } else {
65
+ return UINT2NUM(ts_query_capture_quantifier_for_id(query, pattern, index));
66
+ }
67
+ }
68
+
69
+ /**
70
+ * Disable a certain capture within a query.
71
+ *
72
+ * This prevents the capture from being returned in matches, and also avoids
73
+ * any resource usage associated with recording the capture. Currently, there
74
+ * is no way to undo this.
75
+ *
76
+ * @param capture [String]
77
+ *
78
+ * @return [nil]
79
+ */
80
+ static VALUE query_disable_capture(VALUE self, VALUE capture) {
81
+ const char *cap = StringValuePtr(capture);
82
+ uint32_t length = (uint32_t)RSTRING_LEN(capture);
83
+ ts_query_disable_capture(SELF, cap, length);
84
+ return Qnil;
85
+ }
86
+
87
+ /**
88
+ * Disable a certain pattern within a query.
89
+ *
90
+ * This prevents the pattern from matching and removes most of the overhead
91
+ * associated with the pattern. Currently, there is no way to undo this.
92
+ *
93
+ * @raise [IndexError] if out of range.
94
+ *
95
+ * @param pattern [Integer]
96
+ *
97
+ * @return [nil]
98
+ */
99
+ static VALUE query_disable_pattern(VALUE self, VALUE pattern) {
100
+ TSQuery *query = SELF;
101
+ uint32_t index = NUM2UINT(pattern);
102
+ uint32_t range = ts_query_pattern_count(query);
103
+
104
+ if (index >= range) {
105
+ rb_raise(rb_eIndexError, "Index %d out of range (len = %d)", index, range);
106
+ } else {
107
+ ts_query_disable_pattern(query, index);
108
+ return Qnil;
109
+ }
110
+ }
111
+
112
+ /**
113
+ * Create a new query from a string containing one or more S-expression
114
+ * patterns. The query is associated with a particular language, and can
115
+ * only be run on syntax nodes parsed with that language.
116
+ *
117
+ * If all of the given patterns are valid, this returns a {Query}.
118
+ *
119
+ * @raise [RuntimeError]
120
+ *
121
+ * @param language [Language]
122
+ * @param source [String]
123
+ *
124
+ * @return [Query]
125
+ */
9
126
  static VALUE query_initialize(VALUE self, VALUE language, VALUE source) {
127
+ // FIXME: should we raise an exception here?
10
128
  TSLanguage *lang = value_to_language(language);
11
129
  const char *src = StringValuePtr(source);
12
130
  uint32_t len = (uint32_t)RSTRING_LEN(source);
@@ -25,30 +143,48 @@ static VALUE query_initialize(VALUE self, VALUE language, VALUE source) {
25
143
  return self;
26
144
  }
27
145
 
146
+ /**
147
+ * Get the number of patterns in the query.
148
+ *
149
+ * @return [Integer]
150
+ */
28
151
  static VALUE query_pattern_count(VALUE self) {
29
152
  return UINT2NUM(ts_query_pattern_count(SELF));
30
153
  }
31
154
 
32
- static VALUE query_capture_count(VALUE self) {
33
- return UINT2NUM(ts_query_capture_count(SELF));
34
- }
35
-
36
- static VALUE query_string_count(VALUE self) {
37
- return UINT2NUM(ts_query_string_count(SELF));
38
- }
39
-
40
- static VALUE query_start_byte_for_pattern(VALUE self, VALUE pattern_index) {
41
- const TSQuery *query = SELF;
42
- uint32_t index = NUM2UINT(pattern_index);
43
- uint32_t range = ts_query_pattern_count(query);
44
-
45
- if (index >= range) {
46
- rb_raise(rb_eIndexError, "Index %d out of range (len = %d)", index, range);
47
- } else {
48
- return UINT2NUM(ts_query_start_byte_for_pattern(SELF, index));
49
- }
155
+ /**
156
+ * Check if a given pattern is guaranteed to match once a given step is reached.
157
+ * The step is specified by its byte offset in the query's source code.
158
+ *
159
+ * @param byte_offset [Integer]
160
+ *
161
+ * @return [Integer]
162
+ */
163
+ static VALUE query_pattern_guaranteed_at_step(VALUE self, VALUE byte_offset) {
164
+ return UINT2NUM(
165
+ ts_query_is_pattern_guaranteed_at_step(SELF, NUM2UINT(byte_offset)));
50
166
  }
51
167
 
168
+ /**
169
+ * Get all of the predicates for the given pattern in the query.
170
+ *
171
+ * The predicates are represented as a single array of steps. There are three
172
+ * types of steps in this array, which correspond to the three legal values for
173
+ * the +type+ field:
174
+ * - {QueryPredicateStep::CAPTURE}: Steps with this type represent names
175
+ * of captures. Their +value_id+ can be used with the
176
+ * {Query#capture_name_for_id} function to obtain the name of the capture.
177
+ * - {QueryPredicateStep::STRING}: Steps with this type represent literal
178
+ * strings. Their +value_id+ can be used with the
179
+ * {Query#string_value_for_id} function to obtain their string value.
180
+ * - {QueryPredicateStep::DONE}: Steps with this type are *sentinels*
181
+ * that represent the end of an individual predicate. If a pattern has two
182
+ * predicates, then there will be two steps with this +type+ in the array.
183
+ *
184
+ * @param pattern_index [Integer]
185
+ *
186
+ * @return [Array<QueryPredicateStep>]
187
+ */
52
188
  static VALUE query_predicates_for_pattern(VALUE self, VALUE pattern_index) {
53
189
  const TSQuery *query = SELF;
54
190
  uint32_t index = NUM2UINT(pattern_index);
@@ -64,40 +200,46 @@ static VALUE query_predicates_for_pattern(VALUE self, VALUE pattern_index) {
64
200
  return res;
65
201
  }
66
202
 
67
- static VALUE query_pattern_guaranteed_at_step(VALUE self, VALUE byte_offset) {
68
- return UINT2NUM(
69
- ts_query_is_pattern_guaranteed_at_step(SELF, NUM2UINT(byte_offset)));
70
- }
71
-
72
- static VALUE query_capture_name_for_id(VALUE self, VALUE id) {
203
+ /**
204
+ * Get the byte offset where the given pattern starts in the query's source.
205
+ *
206
+ * This can be useful when combining queries by concatenating their source
207
+ * code strings.
208
+ *
209
+ * @raise [IndexError] if out of range.
210
+ *
211
+ * @param pattern_index [Integer]
212
+ *
213
+ * @return [Integer]
214
+ */
215
+ static VALUE query_start_byte_for_pattern(VALUE self, VALUE pattern_index) {
73
216
  const TSQuery *query = SELF;
74
- uint32_t index = NUM2UINT(id);
75
- uint32_t range = ts_query_capture_count(query);
217
+ uint32_t index = NUM2UINT(pattern_index);
218
+ uint32_t range = ts_query_pattern_count(query);
76
219
 
77
220
  if (index >= range) {
78
221
  rb_raise(rb_eIndexError, "Index %d out of range (len = %d)", index, range);
79
222
  } else {
80
- uint32_t length;
81
- const char *name = ts_query_capture_name_for_id(query, index, &length);
82
- return safe_str2(name, length);
223
+ return UINT2NUM(ts_query_start_byte_for_pattern(SELF, index));
83
224
  }
84
225
  }
85
226
 
86
- static VALUE query_capture_quantifier_for_id(VALUE self, VALUE id,
87
- VALUE capture_id) {
88
- const TSQuery *query = SELF;
89
- uint32_t pattern = NUM2UINT(id);
90
- uint32_t index = NUM2UINT(capture_id);
91
- uint32_t range = ts_query_capture_count(query);
92
-
93
- if (index >= range) {
94
- rb_raise(rb_eIndexError, "Capture ID %d out of range (len = %d)", index,
95
- range);
96
- } else {
97
- return UINT2NUM(ts_query_capture_quantifier_for_id(query, pattern, index));
98
- }
227
+ /**
228
+ * Get the number of string literals in the query.
229
+ *
230
+ * @return [Integer]
231
+ */
232
+ static VALUE query_string_count(VALUE self) {
233
+ return UINT2NUM(ts_query_string_count(SELF));
99
234
  }
100
235
 
236
+ /**
237
+ * @raise [IndexError] if out of range.
238
+ *
239
+ * @param id [Integer]
240
+ *
241
+ * @return [String]
242
+ */
101
243
  static VALUE query_string_value_for_id(VALUE self, VALUE id) {
102
244
  const TSQuery *query = SELF;
103
245
  uint32_t index = NUM2UINT(id);
@@ -112,46 +254,29 @@ static VALUE query_string_value_for_id(VALUE self, VALUE id) {
112
254
  }
113
255
  }
114
256
 
115
- static VALUE query_disable_capture(VALUE self, VALUE capture) {
116
- const char *cap = StringValuePtr(capture);
117
- uint32_t length = (uint32_t)RSTRING_LEN(capture);
118
- ts_query_disable_capture(SELF, cap, length);
119
- return Qnil;
120
- }
121
-
122
- static VALUE query_disable_pattern(VALUE self, VALUE pattern) {
123
- TSQuery *query = SELF;
124
- uint32_t index = NUM2UINT(pattern);
125
- uint32_t range = ts_query_pattern_count(query);
126
-
127
- if (index >= range) {
128
- rb_raise(rb_eIndexError, "Index %d out of range (len = %d)", index, range);
129
- } else {
130
- ts_query_disable_pattern(query, index);
131
- return Qnil;
132
- }
133
- }
134
-
257
+ // FIXME: missing:
258
+ // 1. ts_query_is_pattern_rooted
259
+ // 1. ts_query_is_pattern_non_local
135
260
  void init_query(void) {
136
261
  cQuery = rb_define_class_under(mTreeSitter, "Query", rb_cObject);
137
262
 
138
263
  rb_define_alloc_func(cQuery, query_allocate);
139
264
 
140
265
  /* Class methods */
141
- rb_define_method(cQuery, "initialize", query_initialize, 2);
142
- rb_define_method(cQuery, "pattern_count", query_pattern_count, 0);
143
266
  rb_define_method(cQuery, "capture_count", query_capture_count, 0);
144
- rb_define_method(cQuery, "string_count", query_string_count, 0);
145
- rb_define_method(cQuery, "start_byte_for_pattern",
146
- query_start_byte_for_pattern, 1);
147
- rb_define_method(cQuery, "predicates_for_pattern",
148
- query_predicates_for_pattern, 1);
149
- rb_define_method(cQuery, "pattern_guaranteed_at_step?",
150
- query_pattern_guaranteed_at_step, 1);
151
267
  rb_define_method(cQuery, "capture_name_for_id", query_capture_name_for_id, 1);
152
268
  rb_define_method(cQuery, "capture_quantifier_for_id",
153
269
  query_capture_quantifier_for_id, 2);
154
- rb_define_method(cQuery, "string_value_for_id", query_string_value_for_id, 1);
155
270
  rb_define_method(cQuery, "disable_capture", query_disable_capture, 1);
156
271
  rb_define_method(cQuery, "disable_pattern", query_disable_pattern, 1);
272
+ rb_define_method(cQuery, "initialize", query_initialize, 2);
273
+ rb_define_method(cQuery, "pattern_count", query_pattern_count, 0);
274
+ rb_define_method(cQuery, "pattern_guaranteed_at_step?",
275
+ query_pattern_guaranteed_at_step, 1);
276
+ rb_define_method(cQuery, "predicates_for_pattern",
277
+ query_predicates_for_pattern, 1);
278
+ rb_define_method(cQuery, "start_byte_for_pattern",
279
+ query_start_byte_for_pattern, 1);
280
+ rb_define_method(cQuery, "string_count", query_string_count, 0);
281
+ rb_define_method(cQuery, "string_value_for_id", query_string_value_for_id, 1);
157
282
  }