tree_stand 0.1.6 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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)