tree_stand 0.1.5 → 0.2.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.
@@ -1,17 +1,25 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
1
4
  module TreeStand
2
5
  # Depth-first traversal through the tree, calling hooks at each stop.
3
6
  #
4
- # Hooks are language depended so are defined by creating methods on the
5
- # visitor with the form `on_#{node.type}`.
7
+ # Hooks are language dependent and are defined by creating methods on the
8
+ # visitor with the form `on_*` or `around_*`, where `*` is {Node#type}.
9
+ #
10
+ # - Hooks prefixed with `on_*` are called *before* visiting a node.
11
+ # - Hooks prefixed with `around_*` must `yield` to continue visiting child
12
+ # nodes.
6
13
  #
7
- # You can also define an `_on_default` method to run on all nodes.
14
+ # You can also define default hooks by implementing an {on} or {around}
15
+ # method to call when visiting each node.
8
16
  #
9
17
  # @example Create a visitor counting certain nodes
10
18
  # class CountingVisitor < TreeStand::Visitor
11
19
  # attr_reader :count
12
20
  #
13
- # def initialize(document, type:)
14
- # super(document)
21
+ # def initialize(root, type:)
22
+ # super(root)
15
23
  # @type = type
16
24
  # @count = 0
17
25
  # end
@@ -27,8 +35,35 @@ module TreeStand
27
35
  # # Check the result
28
36
  # visitor.count
29
37
  # # => 3
38
+ #
39
+ # @example A visitor using around hooks to contruct a tree
40
+ # class TreeBuilder < TreeStand::Visitor
41
+ # TreeNode = Struct.new(:name, :children)
42
+ #
43
+ # attr_reader :stack
44
+ #
45
+ # def initialize(root)
46
+ # super(root)
47
+ # @stack = []
48
+ # end
49
+ #
50
+ # def around(node)
51
+ # @stack << TreeNode.new(node.type, [])
52
+ #
53
+ # # visit all children of this node
54
+ # yield
55
+ #
56
+ # # The last node on the stack is the root of the tree.
57
+ # return if @stack.size == 1
58
+ #
59
+ # # Pop the last node off the stack and add it to the parent
60
+ # @stack[-2].children << @stack.pop
61
+ # end
62
+ # end
30
63
  class Visitor
31
- # @param node [TreeStand::Node]
64
+ extend T::Sig
65
+
66
+ sig { params(node: TreeStand::Node).void }
32
67
  def initialize(node)
33
68
  @node = node
34
69
  end
@@ -36,23 +71,56 @@ module TreeStand
36
71
  # Run the visitor on the document and return self. Allows chaining create and visit.
37
72
  # @example
38
73
  # visitor = CountingVisitor.new(node, :predicate).visit
39
- # @return [self]
74
+ sig { returns(T.self_type) }
40
75
  def visit
41
76
  visit_node(@node)
42
77
  self
43
78
  end
44
79
 
80
+ # @abstract The default implementation does nothing.
81
+ #
82
+ # @example Create callback to count all nodes in a tree.
83
+ # def on(node)
84
+ # @count += 1
85
+ # end
86
+ sig { overridable.params(node: TreeStand::Node).void }
87
+ def on(node) = nil
88
+
89
+ # @abstract The default implementation yields to visit all children.
90
+ #
91
+ # @example Use around hooks to run logic before & after visiting a node. Pairs will with a stack.
92
+ # def around(node)
93
+ # @stack << TreeNode.new(node.type, [])
94
+ #
95
+ # # visit all children of this node
96
+ # yield
97
+ #
98
+ # # The last node on the stack is the root of the tree.
99
+ # return if @stack.size == 1
100
+ #
101
+ # # Pop the last node off the stack and add it to the parent
102
+ # @stack[-2].children << @stack.pop
103
+ # end
104
+ sig { overridable.params(node: TreeStand::Node, block: T.proc.void).void }
105
+ def around(node, &block) = yield
106
+
45
107
  private
46
108
 
47
109
  def visit_node(node)
48
110
  if respond_to?("on_#{node.type}")
49
111
  public_send("on_#{node.type}", node)
50
- elsif respond_to?(:_on_default, true)
51
- _on_default(node)
112
+ else
113
+ on(node)
52
114
  end
53
115
 
54
- node.each do |child|
55
- visit_node(child)
116
+ if respond_to?("around_#{node.type}")
117
+ public_send("around_#{node.type}", node) do
118
+ node.each { |child| visit_node(child) }
119
+ end
120
+ else
121
+ around(node) do
122
+ node.each { |child| visit_node(child) }
123
+ end
56
124
  end
57
125
  end
58
126
  end
@@ -1,3 +1,6 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
1
4
  module TreeStand
2
5
  # A collection of useful visitors for traversing trees.
3
6
  module Visitors
@@ -12,19 +15,23 @@ module TreeStand
12
15
  # @see TreeStand::Node#walk
13
16
  # @see TreeStand::Tree#walk
14
17
  class TreeWalker < Visitor
15
- # @param node [TreeStand::Node]
18
+ extend T::Sig
19
+
16
20
  # @param block [Proc] A block that will be called for
17
21
  # each node in the tree.
22
+ sig do
23
+ params(
24
+ node: TreeStand::Node,
25
+ block: T.proc.params(node: TreeStand::Node).void,
26
+ ).void
27
+ end
18
28
  def initialize(node, &block)
19
29
  super(node)
20
30
  @block = block
21
31
  end
22
32
 
23
- private
24
-
25
- def _on_default(node)
26
- @block.call(node)
27
- end
33
+ sig { override.params(node: TreeStand::Node).void }
34
+ def on(node) = @block.call(node)
28
35
  end
29
36
  end
30
37
  end
data/lib/tree_stand.rb CHANGED
@@ -1,3 +1,9 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
4
+ require "forwardable"
5
+ require "sorbet-runtime"
6
+ require "stringio"
1
7
  require "tree_sitter"
2
8
  require "zeitwerk"
3
9
 
@@ -16,6 +22,8 @@ module TreeStand
16
22
  class NodeNotFound < Error; end
17
23
 
18
24
  class << self
25
+ extend T::Sig
26
+
19
27
  # Easy configuration of the gem.
20
28
  #
21
29
  # @example
@@ -25,12 +33,12 @@ module TreeStand
25
33
  #
26
34
  # sql_parser = TreeStand::Parser.new("sql")
27
35
  # ruby_parser = TreeStand::Parser.new("ruby")
28
- # @return [void]
36
+ sig { params(block: T.proc.void).void }
29
37
  def configure(&block)
30
38
  instance_eval(&block)
31
39
  end
32
40
 
33
- # @return [TreeStand::Config]
41
+ sig { returns(TreeStand::Config) }
34
42
  def config
35
43
  @config ||= Config.new
36
44
  end
data/sorbet/config ADDED
@@ -0,0 +1,5 @@
1
+ --dir
2
+ .
3
+ --ignore=tmp/
4
+ --ignore=test/
5
+ --ignore=vendor/
@@ -0,0 +1,391 @@
1
+ # typed: true
2
+
3
+ # DO NOT EDIT MANUALLY
4
+ # This is an autogenerated file for types exported from the `ruby_tree_sitter` gem.
5
+ # Please instead update this file by running `bin/tapioca gem ruby_tree_sitter`.
6
+
7
+ # source://ruby_tree_sitter//lib/tree_sitter.rb#3
8
+ module TreeSitter
9
+ private
10
+
11
+ def quantifier_name(_arg0); end
12
+
13
+ class << self
14
+ def quantifier_name(_arg0); end
15
+ end
16
+ end
17
+
18
+ module TreeSitter::Encoding; end
19
+ TreeSitter::Encoding::UTF16 = T.let(T.unsafe(nil), Symbol)
20
+ TreeSitter::Encoding::UTF8 = T.let(T.unsafe(nil), Symbol)
21
+
22
+ class TreeSitter::Input
23
+ def initialize(*_arg0); end
24
+
25
+ def inspect; end
26
+ def payload; end
27
+ def payload=(_arg0); end
28
+ def to_s; end
29
+ end
30
+
31
+ class TreeSitter::InputEdit
32
+ def inspect; end
33
+ def new_end_byte; end
34
+ def new_end_byte=(_arg0); end
35
+ def new_end_point; end
36
+ def new_end_point=(_arg0); end
37
+ def old_end_byte; end
38
+ def old_end_byte=(_arg0); end
39
+ def old_end_point; end
40
+ def old_end_point=(_arg0); end
41
+ def start_byte; end
42
+ def start_byte=(_arg0); end
43
+ def start_point; end
44
+ def start_point=(_arg0); end
45
+ def to_s; end
46
+ end
47
+
48
+ TreeSitter::LANGUAGE_VERSION = T.let(T.unsafe(nil), Integer)
49
+
50
+ class TreeSitter::Language
51
+ def ==(_arg0); end
52
+ def field_count; end
53
+ def field_id_for_name(_arg0); end
54
+ def field_name_for_id(_arg0); end
55
+ def symbol_count; end
56
+ def symbol_for_name(_arg0, _arg1); end
57
+ def symbol_name(_arg0); end
58
+ def symbol_type(_arg0); end
59
+ def version; end
60
+
61
+ private
62
+
63
+ def load(_arg0, _arg1); end
64
+
65
+ class << self
66
+ def load(_arg0, _arg1); end
67
+ end
68
+ end
69
+
70
+ class TreeSitter::Logger
71
+ def initialize(*_arg0); end
72
+
73
+ def format; end
74
+ def format=(_arg0); end
75
+ def inspect; end
76
+ def payload; end
77
+ def payload=(_arg0); end
78
+ def printf(*_arg0); end
79
+ def puts(*_arg0); end
80
+ def to_s; end
81
+ def write(*_arg0); end
82
+ end
83
+
84
+ TreeSitter::MIN_COMPATIBLE_LANGUAGE_VERSION = T.let(T.unsafe(nil), Integer)
85
+
86
+ # source://ruby_tree_sitter//lib/tree_sitter/node.rb#4
87
+ class TreeSitter::Node
88
+ def ==(_arg0); end
89
+
90
+ # Access node's named children.
91
+ #
92
+ # It's similar to {#fetch}, but differes in input type, return values, and
93
+ # the internal implementation.
94
+ #
95
+ # Both of these methods exist for separate use cases, but also because
96
+ # sometime tree-sitter does some monkey business and having both separate
97
+ # implementations can help.
98
+ #
99
+ # Comparison with {#fetch}:
100
+ #
101
+ # [] | fetch
102
+ # ------------------------------+----------------------
103
+ # input types Integer, String, Symbol | Array<String, Symbol>
104
+ # Array<Integer, String, Symbol>|
105
+ # ------------------------------+----------------------
106
+ # returns 1-to-1 correspondance with | unique nodes
107
+ # input |
108
+ # ------------------------------+----------------------
109
+ # uses named_child | field_name_for_child
110
+ # child_by_field_name | via each_node
111
+ # ------------------------------+----------------------
112
+ #
113
+ # @param keys [Integer | String | Symbol | Array<Integer, String, Symbol>, #read]
114
+ # @return [Node | Array<Node>]
115
+ #
116
+ # source://ruby_tree_sitter//lib/tree_sitter/node.rb#47
117
+ def [](*keys); end
118
+
119
+ def changed?; end
120
+ def child(_arg0); end
121
+ def child_by_field_id(_arg0); end
122
+ def child_by_field_name(_arg0); end
123
+ def child_count; end
124
+ def descendant_for_byte_range(_arg0, _arg1); end
125
+ def descendant_for_point_range(_arg0, _arg1); end
126
+
127
+ # Iterate over a node's children.
128
+ #
129
+ # @yieldparam child [Node] the child
130
+ #
131
+ # source://ruby_tree_sitter//lib/tree_sitter/node.rb#86
132
+ def each; end
133
+
134
+ # Iterate over a node's children assigned to a field.
135
+ #
136
+ # @yieldparam name [NilClass | String] field name.
137
+ # @yieldparam child [Node] the child.
138
+ #
139
+ # source://ruby_tree_sitter//lib/tree_sitter/node.rb#98
140
+ def each_field; end
141
+
142
+ # Iterate over a node's named children
143
+ #
144
+ # @yieldparam child [Node] the child
145
+ #
146
+ # source://ruby_tree_sitter//lib/tree_sitter/node.rb#112
147
+ def each_named; end
148
+
149
+ def edit(_arg0); end
150
+ def end_byte; end
151
+ def end_point; end
152
+ def eq?(_arg0); end
153
+ def error?; end
154
+ def extra?; end
155
+
156
+ # Access node's named children.
157
+ #
158
+ # It's similar to {#fetch}, but differes in input type, return values, and
159
+ # the internal implementation.
160
+ #
161
+ # Both of these methods exist for separate use cases, but also because
162
+ # sometime tree-sitter does some monkey business and having both separate
163
+ # implementations can help.
164
+ #
165
+ # Comparison with {#fetch}:
166
+ #
167
+ # [] | fetch
168
+ # ------------------------------+----------------------
169
+ # input types Integer, String, Symbol | String, Symbol
170
+ # Array<Integer, String, Symbol>| Array<String, Symbol>
171
+ # ------------------------------+----------------------
172
+ # returns 1-to-1 correspondance with | unique nodes
173
+ # input |
174
+ # ------------------------------+----------------------
175
+ # uses named_child | field_name_for_child
176
+ # child_by_field_name | via each_node
177
+ # ------------------------------+----------------------
178
+ #
179
+ # source://ruby_tree_sitter//lib/tree_sitter/node.rb#146
180
+ def fetch(*keys); end
181
+
182
+ # @return [Boolean]
183
+ #
184
+ # source://ruby_tree_sitter//lib/tree_sitter/node.rb#17
185
+ def field?(field); end
186
+
187
+ def field_name_for_child(_arg0); end
188
+
189
+ # source://ruby_tree_sitter//lib/tree_sitter/node.rb#5
190
+ def fields; end
191
+
192
+ def first_child_for_byte(_arg0); end
193
+ def first_named_child_for_byte(_arg0); end
194
+ def inspect; end
195
+
196
+ # Allows access to child_by_field_name without using [].
197
+ #
198
+ # source://ruby_tree_sitter//lib/tree_sitter/node.rb#70
199
+ def method_missing(method_name, *_args, &_block); end
200
+
201
+ def missing?; end
202
+ def named?; end
203
+ def named_child(_arg0); end
204
+ def named_child_count; end
205
+ def named_descendant_for_byte_range(_arg0, _arg1); end
206
+ def named_descendant_for_point_range(_arg0, _arg1); end
207
+ def next_named_sibling; end
208
+ def next_sibling; end
209
+ def null?; end
210
+ def parent; end
211
+ def prev_named_sibling; end
212
+ def prev_sibling; end
213
+ def start_byte; end
214
+ def start_point; end
215
+ def symbol; end
216
+
217
+ # source://ruby_tree_sitter//lib/tree_sitter/node.rb#120
218
+ def to_a; end
219
+
220
+ def to_s; end
221
+ def to_str; end
222
+ def type; end
223
+
224
+ private
225
+
226
+ # @return [Boolean]
227
+ #
228
+ # source://ruby_tree_sitter//lib/tree_sitter/node.rb#78
229
+ def respond_to_missing?(*args); end
230
+ end
231
+
232
+ class TreeSitter::Parser
233
+ def cancellation_flag; end
234
+ def cancellation_flag=(_arg0); end
235
+ def included_ranges; end
236
+ def included_ranges=(_arg0); end
237
+ def language; end
238
+ def language=(_arg0); end
239
+ def logger; end
240
+ def logger=(_arg0); end
241
+ def parse(_arg0, _arg1); end
242
+ def parse_string(_arg0, _arg1); end
243
+ def parse_string_encoding(_arg0, _arg1, _arg2); end
244
+ def print_dot_graphs(_arg0); end
245
+ def reset; end
246
+ def timeout_micros; end
247
+ def timeout_micros=(_arg0); end
248
+ end
249
+
250
+ class TreeSitter::Point
251
+ def column; end
252
+ def column=(_arg0); end
253
+ def inspect; end
254
+ def row; end
255
+ def row=(_arg0); end
256
+ def to_s; end
257
+ end
258
+
259
+ module TreeSitter::Quantifier; end
260
+ TreeSitter::Quantifier::ONE = T.let(T.unsafe(nil), Integer)
261
+ TreeSitter::Quantifier::ONE_OR_MORE = T.let(T.unsafe(nil), Integer)
262
+ TreeSitter::Quantifier::ZERO = T.let(T.unsafe(nil), Integer)
263
+ TreeSitter::Quantifier::ZERO_OR_MORE = T.let(T.unsafe(nil), Integer)
264
+ TreeSitter::Quantifier::ZERO_OR_ONE = T.let(T.unsafe(nil), Integer)
265
+
266
+ class TreeSitter::Query
267
+ def initialize(_arg0, _arg1); end
268
+
269
+ def capture_count; end
270
+ def capture_name_for_id(_arg0); end
271
+ def capture_quantifier_for_id(_arg0, _arg1); end
272
+ def disable_capture(_arg0); end
273
+ def disable_pattern(_arg0); end
274
+ def pattern_count; end
275
+ def pattern_guaranteed_at_step?(_arg0); end
276
+ def predicates_for_pattern(_arg0); end
277
+ def start_byte_for_pattern(_arg0); end
278
+ def string_count; end
279
+ def string_value_for_id(_arg0); end
280
+ end
281
+
282
+ class TreeSitter::QueryCapture
283
+ def index; end
284
+ def inspect; end
285
+ def node; end
286
+ def to_s; end
287
+ end
288
+
289
+ class TreeSitter::QueryCursor
290
+ def exceed_match_limit?; end
291
+ def match_limit; end
292
+ def match_limit=(_arg0); end
293
+ def next_capture; end
294
+ def next_match; end
295
+ def remove_match(_arg0); end
296
+ def set_byte_range(_arg0, _arg1); end
297
+ def set_point_range(_arg0, _arg1); end
298
+
299
+ private
300
+
301
+ def exec(_arg0, _arg1); end
302
+
303
+ class << self
304
+ def exec(_arg0, _arg1); end
305
+ end
306
+ end
307
+
308
+ module TreeSitter::QueryError; end
309
+ TreeSitter::QueryError::Capture = T.let(T.unsafe(nil), Integer)
310
+ TreeSitter::QueryError::Field = T.let(T.unsafe(nil), Integer)
311
+ TreeSitter::QueryError::Language = T.let(T.unsafe(nil), Integer)
312
+ TreeSitter::QueryError::NONE = T.let(T.unsafe(nil), Integer)
313
+ TreeSitter::QueryError::NodeType = T.let(T.unsafe(nil), Integer)
314
+ TreeSitter::QueryError::Structure = T.let(T.unsafe(nil), Integer)
315
+ TreeSitter::QueryError::Syntax = T.let(T.unsafe(nil), Integer)
316
+
317
+ class TreeSitter::QueryMatch
318
+ def capture_count; end
319
+ def captures; end
320
+ def id; end
321
+ def inspect; end
322
+ def pattern_index; end
323
+ def to_s; end
324
+ end
325
+
326
+ class TreeSitter::QueryPredicateStep
327
+ def inspect; end
328
+ def to_s; end
329
+ def type; end
330
+ def type=(_arg0); end
331
+ def value_id; end
332
+ def value_id=(_arg0); end
333
+ end
334
+
335
+ TreeSitter::QueryPredicateStep::CAPTURE = T.let(T.unsafe(nil), Symbol)
336
+ TreeSitter::QueryPredicateStep::DONE = T.let(T.unsafe(nil), Symbol)
337
+ TreeSitter::QueryPredicateStep::STRING = T.let(T.unsafe(nil), Symbol)
338
+
339
+ class TreeSitter::Range
340
+ def end_byte; end
341
+ def end_byte=(_arg0); end
342
+ def end_point; end
343
+ def end_point=(_arg0); end
344
+ def inspect; end
345
+ def start_byte; end
346
+ def start_byte=(_arg0); end
347
+ def start_point; end
348
+ def start_point=(_arg0); end
349
+ def to_s; end
350
+ end
351
+
352
+ module TreeSitter::SymbolType; end
353
+ TreeSitter::SymbolType::ANONYMOUS = T.let(T.unsafe(nil), Symbol)
354
+ TreeSitter::SymbolType::AUXILIARY = T.let(T.unsafe(nil), Symbol)
355
+ TreeSitter::SymbolType::REGULAR = T.let(T.unsafe(nil), Symbol)
356
+
357
+ class TreeSitter::Tree
358
+ def copy; end
359
+ def edit(_arg0); end
360
+ def language; end
361
+ def print_dot_graph(_arg0); end
362
+ def root_node; end
363
+
364
+ private
365
+
366
+ def changed_ranges(_arg0, _arg1); end
367
+ def finalizer; end
368
+
369
+ class << self
370
+ def changed_ranges(_arg0, _arg1); end
371
+ def finalizer; end
372
+ end
373
+ end
374
+
375
+ class TreeSitter::TreeCursor
376
+ def initialize(_arg0); end
377
+
378
+ def copy; end
379
+ def current_field_id; end
380
+ def current_field_name; end
381
+ def current_node; end
382
+ def goto_first_child; end
383
+ def goto_first_child_for_byte(_arg0); end
384
+ def goto_first_child_for_point(_arg0); end
385
+ def goto_next_sibling; end
386
+ def goto_parent; end
387
+ def reset(_arg0); end
388
+ end
389
+
390
+ # source://ruby_tree_sitter//lib/tree_sitter/version.rb#4
391
+ TreeSitter::VERSION = T.let(T.unsafe(nil), String)