ruby_tree_sitter 1.1.0-arm64-darwin-22
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.
- checksums.yaml +7 -0
- data/LICENSE +22 -0
- data/README.md +199 -0
- data/ext/tree_sitter/encoding.c +29 -0
- data/ext/tree_sitter/extconf.rb +149 -0
- data/ext/tree_sitter/input.c +127 -0
- data/ext/tree_sitter/input_edit.c +42 -0
- data/ext/tree_sitter/language.c +219 -0
- data/ext/tree_sitter/logger.c +228 -0
- data/ext/tree_sitter/macros.h +163 -0
- data/ext/tree_sitter/node.c +618 -0
- data/ext/tree_sitter/parser.c +398 -0
- data/ext/tree_sitter/point.c +26 -0
- data/ext/tree_sitter/quantifier.c +43 -0
- data/ext/tree_sitter/query.c +282 -0
- data/ext/tree_sitter/query_capture.c +28 -0
- data/ext/tree_sitter/query_cursor.c +215 -0
- data/ext/tree_sitter/query_error.c +41 -0
- data/ext/tree_sitter/query_match.c +44 -0
- data/ext/tree_sitter/query_predicate_step.c +83 -0
- data/ext/tree_sitter/range.c +35 -0
- data/ext/tree_sitter/repo.rb +121 -0
- data/ext/tree_sitter/symbol_type.c +46 -0
- data/ext/tree_sitter/tree.c +234 -0
- data/ext/tree_sitter/tree_cursor.c +269 -0
- data/ext/tree_sitter/tree_sitter.c +44 -0
- data/ext/tree_sitter/tree_sitter.h +107 -0
- data/lib/tree_sitter/node.rb +197 -0
- data/lib/tree_sitter/tree_sitter.bundle +0 -0
- data/lib/tree_sitter/version.rb +8 -0
- data/lib/tree_sitter.rb +14 -0
- data/lib/tree_stand/ast_modifier.rb +30 -0
- data/lib/tree_stand/breadth_first_visitor.rb +54 -0
- data/lib/tree_stand/config.rb +13 -0
- data/lib/tree_stand/node.rb +224 -0
- data/lib/tree_stand/parser.rb +67 -0
- data/lib/tree_stand/range.rb +55 -0
- data/lib/tree_stand/tree.rb +123 -0
- data/lib/tree_stand/utils/printer.rb +73 -0
- data/lib/tree_stand/version.rb +7 -0
- data/lib/tree_stand/visitor.rb +127 -0
- data/lib/tree_stand/visitors/tree_walker.rb +37 -0
- data/lib/tree_stand.rb +48 -0
- data/tree_sitter.gemspec +35 -0
- metadata +124 -0
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# typed: true
|
3
|
+
|
4
|
+
module TreeStand
|
5
|
+
# Wrapper around the TreeSitter parser. It looks up the parser by filename in
|
6
|
+
# the configured parsers directory.
|
7
|
+
# @example
|
8
|
+
# TreeStand.configure do
|
9
|
+
# config.parser_path = "path/to/parser/folder/"
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
# # Looks for a parser in `path/to/parser/folder/sql.{so,dylib}`
|
13
|
+
# sql_parser = TreeStand::Parser.new("sql")
|
14
|
+
#
|
15
|
+
# # Looks for a parser in `path/to/parser/folder/ruby.{so,dylib}`
|
16
|
+
# ruby_parser = TreeStand::Parser.new("ruby")
|
17
|
+
class Parser
|
18
|
+
extend T::Sig
|
19
|
+
|
20
|
+
sig { returns(TreeSitter::Language) }
|
21
|
+
attr_reader :ts_language
|
22
|
+
|
23
|
+
sig { returns(TreeSitter::Parser) }
|
24
|
+
attr_reader :ts_parser
|
25
|
+
|
26
|
+
# @param language [String]
|
27
|
+
sig { params(language: String).void }
|
28
|
+
def initialize(language)
|
29
|
+
@language_string = language
|
30
|
+
@ts_language = TreeSitter::Language.load(
|
31
|
+
language,
|
32
|
+
"#{TreeStand.config.parser_path}/#{language}.so",
|
33
|
+
)
|
34
|
+
@ts_parser = TreeSitter::Parser.new.tap do |parser|
|
35
|
+
parser.language = @ts_language
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Parse the provided document with the TreeSitter parser.
|
40
|
+
# @param tree [TreeStand::Tree, nil] providing the old tree will allow the
|
41
|
+
# parser to take advantage of incremental parsing and improve performance
|
42
|
+
# by re-useing nodes from the old tree.
|
43
|
+
sig { params(document: String, tree: T.nilable(TreeStand::Tree)).returns(TreeStand::Tree) }
|
44
|
+
def parse_string(document, tree: nil)
|
45
|
+
# @todo There's a bug with passing a non-nil tree
|
46
|
+
ts_tree = @ts_parser.parse_string(nil, document)
|
47
|
+
TreeStand::Tree.new(self, ts_tree, document)
|
48
|
+
end
|
49
|
+
|
50
|
+
# (see #parse_string)
|
51
|
+
# @note Like {#parse_string}, except that if the tree contains any parse
|
52
|
+
# errors, raises an {TreeStand::InvalidDocument} error.
|
53
|
+
#
|
54
|
+
# @see #parse_string
|
55
|
+
# @raise [TreeStand::InvalidDocument]
|
56
|
+
sig { params(document: String, tree: T.nilable(TreeStand::Tree)).returns(TreeStand::Tree) }
|
57
|
+
def parse_string!(document, tree: nil)
|
58
|
+
tree = parse_string(document, tree: tree)
|
59
|
+
return tree unless tree.any?(&:error?)
|
60
|
+
|
61
|
+
raise(InvalidDocument, <<~ERROR)
|
62
|
+
Encountered errors in the document. Check the tree for more details.
|
63
|
+
#{tree}
|
64
|
+
ERROR
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# typed: true
|
3
|
+
|
4
|
+
module TreeStand
|
5
|
+
# Wrapper around a TreeSitter range. This is mainly used to compare ranges.
|
6
|
+
class Range
|
7
|
+
extend T::Sig
|
8
|
+
|
9
|
+
# Point is a Struct containing the row and column from a TreeSitter point.
|
10
|
+
# TreeStand uses this to compare points.
|
11
|
+
# @!attribute [rw] row
|
12
|
+
# @return [Integer]
|
13
|
+
# @!attribute [rw] column
|
14
|
+
# @return [Integer]
|
15
|
+
Point = Struct.new(:row, :column)
|
16
|
+
|
17
|
+
sig { returns(Integer) }
|
18
|
+
attr_reader :start_byte
|
19
|
+
|
20
|
+
sig { returns(Integer) }
|
21
|
+
attr_reader :end_byte
|
22
|
+
|
23
|
+
sig { returns(TreeStand::Range::Point) }
|
24
|
+
attr_reader :start_point
|
25
|
+
|
26
|
+
sig { returns(TreeStand::Range::Point) }
|
27
|
+
attr_reader :end_point
|
28
|
+
|
29
|
+
# @api private
|
30
|
+
sig do
|
31
|
+
params(
|
32
|
+
start_byte: Integer,
|
33
|
+
end_byte: Integer,
|
34
|
+
start_point: T.any(TreeStand::Range::Point, TreeSitter::Point),
|
35
|
+
end_point: T.any(TreeStand::Range::Point, TreeSitter::Point),
|
36
|
+
).void
|
37
|
+
end
|
38
|
+
def initialize(start_byte:, end_byte:, start_point:, end_point:)
|
39
|
+
@start_byte = start_byte
|
40
|
+
@end_byte = end_byte
|
41
|
+
@start_point = Point.new(start_point.row, start_point.column)
|
42
|
+
@end_point = Point.new(end_point.row, end_point.column)
|
43
|
+
end
|
44
|
+
|
45
|
+
sig { params(other: Object).returns(T::Boolean) }
|
46
|
+
def ==(other)
|
47
|
+
return false unless other.is_a?(TreeStand::Range)
|
48
|
+
|
49
|
+
@start_byte == other.start_byte &&
|
50
|
+
@end_byte == other.end_byte &&
|
51
|
+
@start_point == other.start_point &&
|
52
|
+
@end_point == other.end_point
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# typed: true
|
3
|
+
|
4
|
+
module TreeStand
|
5
|
+
# Wrapper around a TreeSitter tree.
|
6
|
+
#
|
7
|
+
# This class exposes a convient API for working with the tree. There are
|
8
|
+
# dangers in using this class. The tree is mutable and the document can be
|
9
|
+
# changed. This class does not protect against that.
|
10
|
+
#
|
11
|
+
# Some of the moetods on this class edit and re-parse the document updating
|
12
|
+
# the tree. Because the document is re-parsed, the tree will be different. Which
|
13
|
+
# means all outstanding nodes & ranges will be invalid.
|
14
|
+
#
|
15
|
+
# Methods that edit the document are suffixed with `!`, e.g. `#edit!`.
|
16
|
+
#
|
17
|
+
# It's often the case that you will want perfrom multiple edits. One such
|
18
|
+
# pattern is to call #query & #edit on all matches in a loop. It's important
|
19
|
+
# to keep the destructive nature of #edit in mind and re-issue the query
|
20
|
+
# after each edit.
|
21
|
+
#
|
22
|
+
# Another thing to keep in mind is that edits done later in the document will
|
23
|
+
# likely not affect the ranges that occur earlier in the document. This can
|
24
|
+
# be a convient property that could allow you to apply edits in a reverse order.
|
25
|
+
# This is not always possible and depends on the edits you make, beware that
|
26
|
+
# the tree will be different after each edit and this approach may cause bugs.
|
27
|
+
class Tree
|
28
|
+
extend T::Sig
|
29
|
+
extend Forwardable
|
30
|
+
include Enumerable
|
31
|
+
|
32
|
+
sig { returns(String) }
|
33
|
+
attr_reader :document
|
34
|
+
|
35
|
+
sig { returns(TreeSitter::Tree) }
|
36
|
+
attr_reader :ts_tree
|
37
|
+
|
38
|
+
sig { returns(TreeStand::Parser) }
|
39
|
+
attr_reader :parser
|
40
|
+
|
41
|
+
# @!method query(query_string)
|
42
|
+
# (see TreeStand::Node#query)
|
43
|
+
# @note This is a convenience method that calls {TreeStand::Node#query} on
|
44
|
+
# {#root_node}.
|
45
|
+
#
|
46
|
+
# @!method find_node(query_string)
|
47
|
+
# (see TreeStand::Node#find_node)
|
48
|
+
# @note This is a convenience method that calls {TreeStand::Node#find_node} on
|
49
|
+
# {#root_node}.
|
50
|
+
#
|
51
|
+
# @!method find_node!(query_string)
|
52
|
+
# (see TreeStand::Node#find_node!)
|
53
|
+
# @note This is a convenience method that calls {TreeStand::Node#find_node!} on
|
54
|
+
# {#root_node}.
|
55
|
+
#
|
56
|
+
# @!method walk(&block)
|
57
|
+
# (see TreeStand::Node#walk)
|
58
|
+
#
|
59
|
+
# @note This is a convenience method that calls {TreeStand::Node#walk} on
|
60
|
+
# {#root_node}.
|
61
|
+
#
|
62
|
+
# @example Tree includes Enumerable
|
63
|
+
# tree.any? { |node| node.type == :error }
|
64
|
+
#
|
65
|
+
# @!method text
|
66
|
+
# (see TreeStand::Node#text)
|
67
|
+
# @note This is a convenience method that calls {TreeStand::Node#text} on
|
68
|
+
# {#root_node}.
|
69
|
+
def_delegators(
|
70
|
+
:root_node,
|
71
|
+
:query,
|
72
|
+
:find_node,
|
73
|
+
:find_node!,
|
74
|
+
:walk,
|
75
|
+
:text,
|
76
|
+
)
|
77
|
+
|
78
|
+
alias_method :each, :walk
|
79
|
+
|
80
|
+
# @api private
|
81
|
+
sig { params(parser: TreeStand::Parser, tree: TreeSitter::Tree, document: String).void }
|
82
|
+
def initialize(parser, tree, document)
|
83
|
+
@parser = parser
|
84
|
+
@ts_tree = tree
|
85
|
+
@document = document
|
86
|
+
end
|
87
|
+
|
88
|
+
sig { returns(TreeStand::Node) }
|
89
|
+
def root_node
|
90
|
+
TreeStand::Node.new(self, @ts_tree.root_node)
|
91
|
+
end
|
92
|
+
|
93
|
+
# This method replaces the section of the document specified by range and
|
94
|
+
# replaces it with the provided text. Then it will reparse the document and
|
95
|
+
# update the tree!
|
96
|
+
sig { params(range: TreeStand::Range, replacement: String).void }
|
97
|
+
def edit!(range, replacement)
|
98
|
+
new_document = +''
|
99
|
+
new_document << @document[0...range.start_byte]
|
100
|
+
new_document << replacement
|
101
|
+
new_document << @document[range.end_byte..]
|
102
|
+
replace_with_new_doc(new_document)
|
103
|
+
end
|
104
|
+
|
105
|
+
# This method deletes the section of the document specified by range. Then
|
106
|
+
# it will reparse the document and update the tree!
|
107
|
+
sig { params(range: TreeStand::Range).void }
|
108
|
+
def delete!(range)
|
109
|
+
new_document = +''
|
110
|
+
new_document << @document[0...range.start_byte]
|
111
|
+
new_document << @document[range.end_byte..]
|
112
|
+
replace_with_new_doc(new_document)
|
113
|
+
end
|
114
|
+
|
115
|
+
private
|
116
|
+
|
117
|
+
def replace_with_new_doc(new_document)
|
118
|
+
@document = new_document
|
119
|
+
new_tree = @parser.parse_string(@document, tree: self)
|
120
|
+
@ts_tree = new_tree.ts_tree
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# typed: true
|
3
|
+
|
4
|
+
module TreeStand
|
5
|
+
# A collection of useful methods for working with syntax trees.
|
6
|
+
module Utils
|
7
|
+
# Used to {TreeStand::Node#pretty_print pretty-print} the node.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# pp node
|
11
|
+
# # (expression
|
12
|
+
# # (sum
|
13
|
+
# # left: (number) | 1
|
14
|
+
# # ("+") | +
|
15
|
+
# # right: (variable))) | x
|
16
|
+
class Printer
|
17
|
+
extend T::Sig
|
18
|
+
|
19
|
+
# @param ralign the right alignment for the text column.
|
20
|
+
sig { params(ralign: Integer).void }
|
21
|
+
def initialize(ralign:)
|
22
|
+
@ralign = ralign
|
23
|
+
end
|
24
|
+
|
25
|
+
# (see TreeStand::Utils::Printer)
|
26
|
+
sig { params(node: TreeStand::Node, io: T.any(IO, StringIO, String)).returns(T.any(IO, StringIO, String)) }
|
27
|
+
def print(node, io: StringIO.new)
|
28
|
+
lines = pretty_output_lines(node)
|
29
|
+
|
30
|
+
lines.each do |line|
|
31
|
+
if line.text.empty?
|
32
|
+
io << line.sexpr << "\n"
|
33
|
+
next
|
34
|
+
end
|
35
|
+
|
36
|
+
io << "#{line.sexpr}#{' ' * [(@ralign - line.sexpr.size), 0].max}| #{line.text}\n"
|
37
|
+
end
|
38
|
+
|
39
|
+
io
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
Line = Struct.new(:sexpr, :text)
|
45
|
+
private_constant :Line
|
46
|
+
|
47
|
+
def pretty_output_lines(node, prefix: '', depth: 0)
|
48
|
+
indent = ' ' * depth
|
49
|
+
ts_node = node.ts_node
|
50
|
+
if indent.size + prefix.size + ts_node.to_s.size < @ralign || ts_node.child_count.zero?
|
51
|
+
return [Line.new("#{indent}#{prefix}#{ts_node}", node.text)]
|
52
|
+
end
|
53
|
+
|
54
|
+
lines = T.let([Line.new("#{indent}#{prefix}(#{ts_node.type}", '')], T::Array[Line])
|
55
|
+
|
56
|
+
node.each.with_index do |child, index|
|
57
|
+
lines += if field_name = ts_node.field_name_for_child(index)
|
58
|
+
pretty_output_lines(
|
59
|
+
child,
|
60
|
+
prefix: "#{field_name}: ",
|
61
|
+
depth: depth + 1,
|
62
|
+
)
|
63
|
+
else
|
64
|
+
pretty_output_lines(child, depth: depth + 1)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
T.must(lines.last).sexpr << ')'
|
69
|
+
lines
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# typed: true
|
3
|
+
|
4
|
+
module TreeStand
|
5
|
+
# Depth-first traversal through the tree, calling hooks at each stop.
|
6
|
+
#
|
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.
|
13
|
+
#
|
14
|
+
# You can also define default hooks by implementing an {on} or {around}
|
15
|
+
# method to call when visiting each node.
|
16
|
+
#
|
17
|
+
# @example Create a visitor counting certain nodes
|
18
|
+
# class CountingVisitor < TreeStand::Visitor
|
19
|
+
# attr_reader :count
|
20
|
+
#
|
21
|
+
# def initialize(root, type:)
|
22
|
+
# super(root)
|
23
|
+
# @type = type
|
24
|
+
# @count = 0
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# def on_predicate(node)
|
28
|
+
# # if this node matches our search, increment the counter
|
29
|
+
# @count += 1 if node.type == @type
|
30
|
+
# end
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# # Initialize a visitor
|
34
|
+
# visitor = CountingVisitor.new(document, :predicate).visit
|
35
|
+
# # Check the result
|
36
|
+
# visitor.count
|
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
|
63
|
+
class Visitor
|
64
|
+
extend T::Sig
|
65
|
+
|
66
|
+
sig { params(node: TreeStand::Node).void }
|
67
|
+
def initialize(node)
|
68
|
+
@node = node
|
69
|
+
end
|
70
|
+
|
71
|
+
# Run the visitor on the document and return self. Allows chaining create and visit.
|
72
|
+
# @example
|
73
|
+
# visitor = CountingVisitor.new(node, :predicate).visit
|
74
|
+
sig { returns(T.self_type) }
|
75
|
+
def visit
|
76
|
+
visit_node(@node)
|
77
|
+
self
|
78
|
+
end
|
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
|
+
|
107
|
+
private
|
108
|
+
|
109
|
+
def visit_node(node)
|
110
|
+
if respond_to?("on_#{node.type}")
|
111
|
+
public_send("on_#{node.type}", node)
|
112
|
+
else
|
113
|
+
on(node)
|
114
|
+
end
|
115
|
+
|
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
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# typed: true
|
3
|
+
|
4
|
+
module TreeStand
|
5
|
+
# A collection of useful visitors for traversing trees.
|
6
|
+
module Visitors
|
7
|
+
# Walks the tree depth-first and yields each node to the provided block.
|
8
|
+
#
|
9
|
+
# @example Create a list of all the nodes in the tree.
|
10
|
+
# list = []
|
11
|
+
# TreeStand::Visitors::TreeWalker.new(root) do |node|
|
12
|
+
# list << node
|
13
|
+
# end.visit
|
14
|
+
#
|
15
|
+
# @see TreeStand::Node#walk
|
16
|
+
# @see TreeStand::Tree#walk
|
17
|
+
class TreeWalker < Visitor
|
18
|
+
extend T::Sig
|
19
|
+
|
20
|
+
# @param block [Proc] A block that will be called for
|
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
|
28
|
+
def initialize(node, &block)
|
29
|
+
super(node)
|
30
|
+
@block = block
|
31
|
+
end
|
32
|
+
|
33
|
+
sig { override.params(node: TreeStand::Node).void }
|
34
|
+
def on(node) = @block.call(node)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/tree_stand.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# typed: true
|
3
|
+
|
4
|
+
require 'forwardable'
|
5
|
+
require 'sorbet-runtime'
|
6
|
+
require 'stringio'
|
7
|
+
require 'tree_sitter'
|
8
|
+
require 'zeitwerk'
|
9
|
+
|
10
|
+
loader = Zeitwerk::Loader.for_gem
|
11
|
+
loader.ignore("#{__dir__}/tree_sitter")
|
12
|
+
loader.ignore("#{__dir__}/tree_sitter.rb")
|
13
|
+
loader.setup
|
14
|
+
|
15
|
+
# TreeStand is a high-level Ruby wrapper for {https://tree-sitter.github.io/tree-sitter tree-sitter} bindings. It makes
|
16
|
+
# it easier to configure the parsers, and work with the underlying syntax tree.
|
17
|
+
module TreeStand
|
18
|
+
# Common Ancestor for all TreeStand errors.
|
19
|
+
class Error < StandardError; end
|
20
|
+
# Raised when the parsed document contains errors.
|
21
|
+
class InvalidDocument < Error; end
|
22
|
+
# Raised when performing a search on a tree where a return value is expected,
|
23
|
+
# but no match is found.
|
24
|
+
class NodeNotFound < Error; end
|
25
|
+
|
26
|
+
class << self
|
27
|
+
extend T::Sig
|
28
|
+
|
29
|
+
# Easy configuration of the gem.
|
30
|
+
#
|
31
|
+
# @example
|
32
|
+
# TreeStand.configure do
|
33
|
+
# config.parser_path = "path/to/parser/folder/"
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
# sql_parser = TreeStand::Parser.new("sql")
|
37
|
+
# ruby_parser = TreeStand::Parser.new("ruby")
|
38
|
+
sig { params(block: T.proc.void).void }
|
39
|
+
def configure(&block)
|
40
|
+
instance_eval(&block)
|
41
|
+
end
|
42
|
+
|
43
|
+
sig { returns(TreeStand::Config) }
|
44
|
+
def config
|
45
|
+
@config ||= Config.new
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/tree_sitter.gemspec
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
4
|
+
$LOAD_PATH.unshift(lib) if !$LOAD_PATH.include?(lib)
|
5
|
+
|
6
|
+
require 'tree_sitter/version'
|
7
|
+
|
8
|
+
Gem::Specification.new do |spec|
|
9
|
+
spec.required_ruby_version = '>= 3.0'
|
10
|
+
|
11
|
+
spec.authors = ['Firas al-Khalil', 'Derek Stride']
|
12
|
+
spec.email = ['firasalkhalil@gmail.com', 'derek@stride.host']
|
13
|
+
spec.homepage = 'https://www.github.com/Faveod/ruby-tree-sitter'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
spec.name = 'ruby_tree_sitter'
|
16
|
+
spec.summary = 'Ruby bindings for Tree-Sitter'
|
17
|
+
spec.version = TreeSitter::VERSION
|
18
|
+
|
19
|
+
spec.metadata = {
|
20
|
+
'allowed_push_host' => 'https://rubygems.org',
|
21
|
+
'homepage_uri' => spec.homepage,
|
22
|
+
'source_code_uri' => spec.homepage,
|
23
|
+
'changelog_uri' => spec.homepage,
|
24
|
+
'documentation_uri' => 'https://faveod.github.io/ruby-tree-sitter/',
|
25
|
+
}
|
26
|
+
|
27
|
+
spec.extensions = %(ext/tree_sitter/extconf.rb)
|
28
|
+
spec.files = %w[LICENSE README.md tree_sitter.gemspec]
|
29
|
+
spec.files += Dir.glob('ext/**/*.{c,h,rb}')
|
30
|
+
spec.files += Dir.glob('lib/**/*.rb')
|
31
|
+
spec.require_paths = ['lib']
|
32
|
+
|
33
|
+
spec.add_dependency 'sorbet-runtime'
|
34
|
+
spec.add_dependency 'zeitwerk'
|
35
|
+
end
|
metadata
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ruby_tree_sitter
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.1.0
|
5
|
+
platform: arm64-darwin-22
|
6
|
+
authors:
|
7
|
+
- Firas al-Khalil
|
8
|
+
- Derek Stride
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2024-05-10 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: sorbet-runtime
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ">="
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '0'
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '0'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: zeitwerk
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '0'
|
35
|
+
type: :runtime
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
42
|
+
description:
|
43
|
+
email:
|
44
|
+
- firasalkhalil@gmail.com
|
45
|
+
- derek@stride.host
|
46
|
+
executables: []
|
47
|
+
extensions: []
|
48
|
+
extra_rdoc_files: []
|
49
|
+
files:
|
50
|
+
- LICENSE
|
51
|
+
- README.md
|
52
|
+
- ext/tree_sitter/encoding.c
|
53
|
+
- ext/tree_sitter/extconf.rb
|
54
|
+
- ext/tree_sitter/input.c
|
55
|
+
- ext/tree_sitter/input_edit.c
|
56
|
+
- ext/tree_sitter/language.c
|
57
|
+
- ext/tree_sitter/logger.c
|
58
|
+
- ext/tree_sitter/macros.h
|
59
|
+
- ext/tree_sitter/node.c
|
60
|
+
- ext/tree_sitter/parser.c
|
61
|
+
- ext/tree_sitter/point.c
|
62
|
+
- ext/tree_sitter/quantifier.c
|
63
|
+
- ext/tree_sitter/query.c
|
64
|
+
- ext/tree_sitter/query_capture.c
|
65
|
+
- ext/tree_sitter/query_cursor.c
|
66
|
+
- ext/tree_sitter/query_error.c
|
67
|
+
- ext/tree_sitter/query_match.c
|
68
|
+
- ext/tree_sitter/query_predicate_step.c
|
69
|
+
- ext/tree_sitter/range.c
|
70
|
+
- ext/tree_sitter/repo.rb
|
71
|
+
- ext/tree_sitter/symbol_type.c
|
72
|
+
- ext/tree_sitter/tree.c
|
73
|
+
- ext/tree_sitter/tree_cursor.c
|
74
|
+
- ext/tree_sitter/tree_sitter.c
|
75
|
+
- ext/tree_sitter/tree_sitter.h
|
76
|
+
- lib/tree_sitter.rb
|
77
|
+
- lib/tree_sitter/node.rb
|
78
|
+
- lib/tree_sitter/tree_sitter.bundle
|
79
|
+
- lib/tree_sitter/version.rb
|
80
|
+
- lib/tree_stand.rb
|
81
|
+
- lib/tree_stand/ast_modifier.rb
|
82
|
+
- lib/tree_stand/breadth_first_visitor.rb
|
83
|
+
- lib/tree_stand/config.rb
|
84
|
+
- lib/tree_stand/node.rb
|
85
|
+
- lib/tree_stand/parser.rb
|
86
|
+
- lib/tree_stand/range.rb
|
87
|
+
- lib/tree_stand/tree.rb
|
88
|
+
- lib/tree_stand/utils/printer.rb
|
89
|
+
- lib/tree_stand/version.rb
|
90
|
+
- lib/tree_stand/visitor.rb
|
91
|
+
- lib/tree_stand/visitors/tree_walker.rb
|
92
|
+
- tree_sitter.gemspec
|
93
|
+
homepage: https://www.github.com/Faveod/ruby-tree-sitter
|
94
|
+
licenses:
|
95
|
+
- MIT
|
96
|
+
metadata:
|
97
|
+
allowed_push_host: https://rubygems.org
|
98
|
+
homepage_uri: https://www.github.com/Faveod/ruby-tree-sitter
|
99
|
+
source_code_uri: https://www.github.com/Faveod/ruby-tree-sitter
|
100
|
+
changelog_uri: https://www.github.com/Faveod/ruby-tree-sitter
|
101
|
+
documentation_uri: https://faveod.github.io/ruby-tree-sitter/
|
102
|
+
post_install_message:
|
103
|
+
rdoc_options: []
|
104
|
+
require_paths:
|
105
|
+
- lib
|
106
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '3.2'
|
111
|
+
- - "<"
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: 3.3.dev
|
114
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - ">="
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
requirements: []
|
120
|
+
rubygems_version: 3.4.19
|
121
|
+
signing_key:
|
122
|
+
specification_version: 4
|
123
|
+
summary: Ruby bindings for Tree-Sitter
|
124
|
+
test_files: []
|