ruby_tree_sitter 1.6.0-x86_64-linux-gnu
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 +213 -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 +623 -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 +289 -0
- data/ext/tree_sitter/query_capture.c +28 -0
- data/ext/tree_sitter/query_cursor.c +231 -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 +128 -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/3.0/tree_sitter.so +0 -0
- data/lib/tree_sitter/3.1/tree_sitter.so +0 -0
- data/lib/tree_sitter/3.2/tree_sitter.so +0 -0
- data/lib/tree_sitter/3.3/tree_sitter.so +0 -0
- data/lib/tree_sitter/helpers.rb +23 -0
- data/lib/tree_sitter/mixins/language.rb +167 -0
- data/lib/tree_sitter/node.rb +167 -0
- data/lib/tree_sitter/query.rb +191 -0
- data/lib/tree_sitter/query_captures.rb +30 -0
- data/lib/tree_sitter/query_cursor.rb +27 -0
- data/lib/tree_sitter/query_match.rb +100 -0
- data/lib/tree_sitter/query_matches.rb +39 -0
- data/lib/tree_sitter/query_predicate.rb +14 -0
- data/lib/tree_sitter/text_predicate_capture.rb +37 -0
- data/lib/tree_sitter/version.rb +8 -0
- data/lib/tree_sitter.rb +34 -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 +19 -0
- data/lib/tree_stand/node.rb +351 -0
- data/lib/tree_stand/parser.rb +87 -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 +34 -0
- metadata +135 -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,128 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../lib/tree_sitter/version'
|
4
|
+
|
5
|
+
module TreeSitter
|
6
|
+
# Fetches tree-sitter sources.
|
7
|
+
class Repo
|
8
|
+
attr_reader :exe, :src, :url, :version
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@version = TREESITTER_VERSION
|
12
|
+
|
13
|
+
# `tree-sitter-@version` is the name produced by tagged releases of sources
|
14
|
+
# by git, so we use it everywhere, including when cloning from git.
|
15
|
+
@src = Pathname.pwd / "tree-sitter-#{@version}"
|
16
|
+
|
17
|
+
@url = {
|
18
|
+
git: 'https://github.com/tree-sitter/tree-sitter',
|
19
|
+
tar: "https://github.com/tree-sitter/tree-sitter/archive/refs/tags/v#{@version}.tar.gz",
|
20
|
+
zip: "https://github.com/tree-sitter/tree-sitter/archive/refs/tags/v#{@version}.zip",
|
21
|
+
}
|
22
|
+
|
23
|
+
@exe = {}
|
24
|
+
%i[curl git tar wget zip].each do |cmd|
|
25
|
+
@exe[cmd] = find_executable(cmd.to_s)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def compile
|
30
|
+
# We need to clean because the same folder is used over and over
|
31
|
+
# by rake-compiler-dock
|
32
|
+
ar = RbConfig::MAKEFILE_CONFIG['AR']
|
33
|
+
ar = " AR=#{ar}" if ar
|
34
|
+
sh "cd #{src} && make clean &&#{ar} make libtree-sitter.a"
|
35
|
+
end
|
36
|
+
|
37
|
+
def exe?(name)
|
38
|
+
@exe[name]
|
39
|
+
end
|
40
|
+
|
41
|
+
def extract?
|
42
|
+
!exe.filter { |k, v| %i[tar zip].include?(k) && v }.empty?
|
43
|
+
end
|
44
|
+
|
45
|
+
def download
|
46
|
+
# TODO: should we force re-download? Maybe with a flag?
|
47
|
+
return true if Dir.exist? src
|
48
|
+
|
49
|
+
res = false
|
50
|
+
%w[git curl wget].each do |cmd|
|
51
|
+
res =
|
52
|
+
if find_executable(cmd)
|
53
|
+
send("sources_from_#{cmd}")
|
54
|
+
else
|
55
|
+
false
|
56
|
+
end
|
57
|
+
break if res
|
58
|
+
end
|
59
|
+
|
60
|
+
res
|
61
|
+
end
|
62
|
+
|
63
|
+
def include_and_lib_dirs
|
64
|
+
[[(src / 'lib' / 'include').to_s], [src.to_s]]
|
65
|
+
end
|
66
|
+
|
67
|
+
def patch
|
68
|
+
root = Pathname.new(File.expand_path(__dir__)).realpath.parent.parent
|
69
|
+
patch = root / 'patches' / 'cross-compile.patch'
|
70
|
+
|
71
|
+
sh "patch --forward #{src / 'Makefile'} #{patch}"
|
72
|
+
end
|
73
|
+
|
74
|
+
def sh(cmd)
|
75
|
+
return if system(cmd)
|
76
|
+
|
77
|
+
abort <<~MSG
|
78
|
+
|
79
|
+
Failed to run: #{cmd}
|
80
|
+
|
81
|
+
exiting …
|
82
|
+
|
83
|
+
MSG
|
84
|
+
end
|
85
|
+
|
86
|
+
def sources_from_curl
|
87
|
+
return false if !exe?(:curl) || !extract?
|
88
|
+
|
89
|
+
if exe?(:tar)
|
90
|
+
sh "curl -L #{url[:tar]} -o tree-sitter-v#{version}.tar.gz"
|
91
|
+
sh "tar -xf tree-sitter-v#{version}.tar.gz"
|
92
|
+
elsif exe?(:zip)
|
93
|
+
sh "curl -L #{url[:zip]} -o tree-sitter-v#{version}.zip"
|
94
|
+
sh "unzip -q tree-sitter-v#{version}.zip"
|
95
|
+
end
|
96
|
+
|
97
|
+
true
|
98
|
+
end
|
99
|
+
|
100
|
+
def sources_from_git
|
101
|
+
return false if !exe?(:git)
|
102
|
+
|
103
|
+
sh <<~SHELL.chomp
|
104
|
+
mkdir #{src} \\
|
105
|
+
&& cd #{src} \\
|
106
|
+
&& git init \\
|
107
|
+
&& git remote add origin "#{url[:git]}" \\
|
108
|
+
&& git fetch origin --depth 1 tags/v#{version} \\
|
109
|
+
&& git reset --hard FETCH_HEAD
|
110
|
+
SHELL
|
111
|
+
true
|
112
|
+
end
|
113
|
+
|
114
|
+
def sources_from_wget
|
115
|
+
return false if !exe?(:wget) || !extract?
|
116
|
+
|
117
|
+
if exe?(:tar)
|
118
|
+
sh "wget #{url[:tar]} -O tree-sitter-v#{version}.tar.gz"
|
119
|
+
sh "tar -xf tree-sitter-v#{version}.tar.gz"
|
120
|
+
elsif exe?(:zip)
|
121
|
+
sh "wget #{url[:zip]} -O tree-sitter-v#{version}.zip"
|
122
|
+
sh "unzip -q tree-sitter-v#{version}.zip"
|
123
|
+
end
|
124
|
+
|
125
|
+
true
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -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,234 @@
|
|
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
|
+
/**
|
67
|
+
* Compare an old edited syntax tree to a new syntax tree representing the same
|
68
|
+
* document, returning an array of ranges whose syntactic structure has changed.
|
69
|
+
*
|
70
|
+
* For this to work correctly, the old syntax tree must have been edited such
|
71
|
+
* that its ranges match up to the new tree. Generally, you'll want to call
|
72
|
+
* this function right after calling one of the {Parser#parse} functions.
|
73
|
+
* You need to pass the old tree that was passed to parse, as well as the new
|
74
|
+
* tree that was returned from that function.
|
75
|
+
*
|
76
|
+
* @param old_tree [Tree]
|
77
|
+
* @param new_tree [Tree]
|
78
|
+
*
|
79
|
+
* @return [Array<Range>]
|
80
|
+
*/
|
81
|
+
static VALUE tree_changed_ranges(VALUE _self, VALUE old_tree, VALUE new_tree) {
|
82
|
+
TSTree *old = unwrap(old_tree)->data;
|
83
|
+
TSTree *new = unwrap(new_tree)->data;
|
84
|
+
uint32_t length;
|
85
|
+
TSRange *ranges = ts_tree_get_changed_ranges(old, new, &length);
|
86
|
+
VALUE res = rb_ary_new_capa(length);
|
87
|
+
|
88
|
+
for (uint32_t i = 0; i < length; i++) {
|
89
|
+
rb_ary_push(res, new_range(&ranges[i]));
|
90
|
+
}
|
91
|
+
|
92
|
+
if (ranges) {
|
93
|
+
free(ranges);
|
94
|
+
}
|
95
|
+
|
96
|
+
return res;
|
97
|
+
}
|
98
|
+
|
99
|
+
static VALUE tree_finalizer(VALUE _self) {
|
100
|
+
VALUE rc = rb_cv_get(cTree, "@@rc");
|
101
|
+
VALUE keys = rb_funcall(rc, rb_intern("keys"), 0);
|
102
|
+
long len = RARRAY_LEN(keys);
|
103
|
+
|
104
|
+
for (long i = 0; i < len; ++i) {
|
105
|
+
VALUE curr = RARRAY_AREF(keys, i);
|
106
|
+
unsigned int val = NUM2UINT(rb_hash_lookup(rc, curr));
|
107
|
+
if (val > 0) {
|
108
|
+
ts_tree_delete((TSTree *)NUM2ULONG(curr));
|
109
|
+
}
|
110
|
+
|
111
|
+
rb_hash_delete(rc, curr);
|
112
|
+
}
|
113
|
+
|
114
|
+
return Qnil;
|
115
|
+
}
|
116
|
+
|
117
|
+
/**
|
118
|
+
* Create a shallow copy of the syntax tree. This is very fast.
|
119
|
+
*
|
120
|
+
* You need to copy a syntax tree in order to use it on more than one thread at
|
121
|
+
* a time, as syntax trees are not thread safe.
|
122
|
+
*
|
123
|
+
* @return [Tree]
|
124
|
+
*/
|
125
|
+
static VALUE tree_copy(VALUE self) { return new_tree(ts_tree_copy(SELF)); }
|
126
|
+
|
127
|
+
/**
|
128
|
+
* Edit the syntax tree to keep it in sync with source code that has been
|
129
|
+
* edited.
|
130
|
+
*
|
131
|
+
* You must describe the edit both in terms of byte offsets and in terms of
|
132
|
+
* (row, column) coordinates.
|
133
|
+
*
|
134
|
+
* @param edit [InputEdit]
|
135
|
+
*
|
136
|
+
* @return [nil]
|
137
|
+
*/
|
138
|
+
static VALUE tree_edit(VALUE self, VALUE edit) {
|
139
|
+
TSInputEdit in = value_to_input_edit(edit);
|
140
|
+
ts_tree_edit(SELF, &in);
|
141
|
+
return Qnil;
|
142
|
+
}
|
143
|
+
|
144
|
+
/**
|
145
|
+
* Get the array of included ranges that was used to parse the syntax tree.
|
146
|
+
*
|
147
|
+
* @return [Array<Range>]
|
148
|
+
*/
|
149
|
+
static VALUE included_ranges(VALUE self) {
|
150
|
+
uint32_t length;
|
151
|
+
const TSRange *ranges = ts_tree_included_ranges(SELF, &length);
|
152
|
+
VALUE res = rb_ary_new_capa(length);
|
153
|
+
for (uint32_t i = 0; i < length; i++) {
|
154
|
+
rb_ary_push(res, new_range(&ranges[i]));
|
155
|
+
}
|
156
|
+
return res;
|
157
|
+
}
|
158
|
+
|
159
|
+
/**
|
160
|
+
* Get the language that was used to parse the syntax tree.
|
161
|
+
*
|
162
|
+
* @return [Language]
|
163
|
+
*/
|
164
|
+
static VALUE tree_language(VALUE self) {
|
165
|
+
return new_language(ts_tree_language(SELF));
|
166
|
+
}
|
167
|
+
|
168
|
+
/**
|
169
|
+
* Write a DOT graph describing the syntax tree to the given file.
|
170
|
+
*
|
171
|
+
* @param file [String]
|
172
|
+
*
|
173
|
+
* @return [nil]
|
174
|
+
*/
|
175
|
+
static VALUE tree_print_dot_graph(VALUE self, VALUE file) {
|
176
|
+
Check_Type(file, T_STRING);
|
177
|
+
char *path = StringValueCStr(file);
|
178
|
+
int fd = open(path, O_CREAT | O_WRONLY | O_TRUNC,
|
179
|
+
S_IWUSR | S_IRUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
|
180
|
+
if (fd < 0) {
|
181
|
+
rb_raise(rb_eRuntimeError, "Could not open file `%s'.\nReason:\n%s", path,
|
182
|
+
strerror(fd));
|
183
|
+
return Qnil;
|
184
|
+
}
|
185
|
+
ts_tree_print_dot_graph(SELF, fd);
|
186
|
+
close(fd);
|
187
|
+
return Qnil;
|
188
|
+
}
|
189
|
+
|
190
|
+
/**
|
191
|
+
* Get the root node of the syntax tree.
|
192
|
+
*
|
193
|
+
* @return [Node]
|
194
|
+
*/
|
195
|
+
static VALUE tree_root_node(VALUE self) {
|
196
|
+
return new_node_by_val(ts_tree_root_node(SELF));
|
197
|
+
}
|
198
|
+
|
199
|
+
/**
|
200
|
+
* Get the root node of the syntax tree, but with its position
|
201
|
+
* shifted forward by the given offset.
|
202
|
+
*
|
203
|
+
* @return [Node]
|
204
|
+
*/
|
205
|
+
static VALUE tree_root_node_with_offset(VALUE self, VALUE offset_bytes,
|
206
|
+
VALUE offset_extent) {
|
207
|
+
uint32_t bytes = NUM2UINT(offset_bytes);
|
208
|
+
TSPoint extent = value_to_point(offset_extent);
|
209
|
+
return new_node_by_val(ts_tree_root_node_with_offset(SELF, bytes, extent));
|
210
|
+
}
|
211
|
+
|
212
|
+
void init_tree(void) {
|
213
|
+
cTree = rb_define_class_under(mTreeSitter, "Tree", rb_cObject);
|
214
|
+
|
215
|
+
rb_undef_alloc_func(cTree);
|
216
|
+
|
217
|
+
/* Module methods */
|
218
|
+
rb_define_module_function(cTree, "changed_ranges", tree_changed_ranges, 2);
|
219
|
+
rb_define_module_function(cTree, "finalizer", tree_finalizer, 0);
|
220
|
+
|
221
|
+
/* Class methods */
|
222
|
+
rb_define_method(cTree, "copy", tree_copy, 0);
|
223
|
+
rb_define_method(cTree, "edit", tree_edit, 1);
|
224
|
+
rb_define_method(cTree, "included_ranges", included_ranges, 0);
|
225
|
+
rb_define_method(cTree, "language", tree_language, 0);
|
226
|
+
rb_define_method(cTree, "print_dot_graph", tree_print_dot_graph, 1);
|
227
|
+
rb_define_method(cTree, "root_node", tree_root_node, 0);
|
228
|
+
rb_define_method(cTree, "root_node_with_offset", tree_root_node_with_offset,
|
229
|
+
2);
|
230
|
+
|
231
|
+
// Reference-count created trees
|
232
|
+
VALUE rc = rb_hash_new();
|
233
|
+
rb_cv_set(cTree, "@@rc", rc);
|
234
|
+
}
|