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.
Files changed (57) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +22 -0
  3. data/README.md +213 -0
  4. data/ext/tree_sitter/encoding.c +29 -0
  5. data/ext/tree_sitter/extconf.rb +149 -0
  6. data/ext/tree_sitter/input.c +127 -0
  7. data/ext/tree_sitter/input_edit.c +42 -0
  8. data/ext/tree_sitter/language.c +219 -0
  9. data/ext/tree_sitter/logger.c +228 -0
  10. data/ext/tree_sitter/macros.h +163 -0
  11. data/ext/tree_sitter/node.c +623 -0
  12. data/ext/tree_sitter/parser.c +398 -0
  13. data/ext/tree_sitter/point.c +26 -0
  14. data/ext/tree_sitter/quantifier.c +43 -0
  15. data/ext/tree_sitter/query.c +289 -0
  16. data/ext/tree_sitter/query_capture.c +28 -0
  17. data/ext/tree_sitter/query_cursor.c +231 -0
  18. data/ext/tree_sitter/query_error.c +41 -0
  19. data/ext/tree_sitter/query_match.c +44 -0
  20. data/ext/tree_sitter/query_predicate_step.c +83 -0
  21. data/ext/tree_sitter/range.c +35 -0
  22. data/ext/tree_sitter/repo.rb +128 -0
  23. data/ext/tree_sitter/symbol_type.c +46 -0
  24. data/ext/tree_sitter/tree.c +234 -0
  25. data/ext/tree_sitter/tree_cursor.c +269 -0
  26. data/ext/tree_sitter/tree_sitter.c +44 -0
  27. data/ext/tree_sitter/tree_sitter.h +107 -0
  28. data/lib/tree_sitter/3.0/tree_sitter.so +0 -0
  29. data/lib/tree_sitter/3.1/tree_sitter.so +0 -0
  30. data/lib/tree_sitter/3.2/tree_sitter.so +0 -0
  31. data/lib/tree_sitter/3.3/tree_sitter.so +0 -0
  32. data/lib/tree_sitter/helpers.rb +23 -0
  33. data/lib/tree_sitter/mixins/language.rb +167 -0
  34. data/lib/tree_sitter/node.rb +167 -0
  35. data/lib/tree_sitter/query.rb +191 -0
  36. data/lib/tree_sitter/query_captures.rb +30 -0
  37. data/lib/tree_sitter/query_cursor.rb +27 -0
  38. data/lib/tree_sitter/query_match.rb +100 -0
  39. data/lib/tree_sitter/query_matches.rb +39 -0
  40. data/lib/tree_sitter/query_predicate.rb +14 -0
  41. data/lib/tree_sitter/text_predicate_capture.rb +37 -0
  42. data/lib/tree_sitter/version.rb +8 -0
  43. data/lib/tree_sitter.rb +34 -0
  44. data/lib/tree_stand/ast_modifier.rb +30 -0
  45. data/lib/tree_stand/breadth_first_visitor.rb +54 -0
  46. data/lib/tree_stand/config.rb +19 -0
  47. data/lib/tree_stand/node.rb +351 -0
  48. data/lib/tree_stand/parser.rb +87 -0
  49. data/lib/tree_stand/range.rb +55 -0
  50. data/lib/tree_stand/tree.rb +123 -0
  51. data/lib/tree_stand/utils/printer.rb +73 -0
  52. data/lib/tree_stand/version.rb +7 -0
  53. data/lib/tree_stand/visitor.rb +127 -0
  54. data/lib/tree_stand/visitors/tree_walker.rb +37 -0
  55. data/lib/tree_stand.rb +48 -0
  56. data/tree_sitter.gemspec +34 -0
  57. metadata +135 -0
@@ -0,0 +1,219 @@
1
+ #include "tree_sitter.h"
2
+ #include <dlfcn.h>
3
+ #include <stdint.h>
4
+ #include <stdio.h>
5
+
6
+ typedef TSLanguage *(tree_sitter_lang)(void);
7
+ const char *tree_sitter_prefix = "tree_sitter_";
8
+
9
+ extern VALUE mTreeSitter;
10
+
11
+ VALUE cLanguage;
12
+
13
+ DATA_TYPE(TSLanguage *, language)
14
+ DATA_FREE(language)
15
+ DATA_MEMSIZE(language)
16
+ DATA_DECLARE_DATA_TYPE(language)
17
+ DATA_ALLOCATE(language)
18
+ DATA_UNWRAP(language)
19
+
20
+ TSLanguage *value_to_language(VALUE self) { return SELF; }
21
+
22
+ VALUE new_language(const TSLanguage *language) {
23
+ VALUE res = language_allocate(cLanguage);
24
+ unwrap(res)->data = (TSLanguage *)language;
25
+ return res;
26
+ }
27
+
28
+ /**
29
+ * Load a language parser from disk.
30
+ *
31
+ * @raise [RuntimeError] if the parser was not found, or if it's incompatible
32
+ * with this gem.
33
+ *
34
+ * @param name [String] the parser's name.
35
+ * @param path [String, Pathname] the parser's shared library (so, dylib) path on disk.
36
+ *
37
+ * @return [Language]
38
+ */
39
+ static VALUE language_load(VALUE self, VALUE name, VALUE path) {
40
+ VALUE path_s = rb_funcall(path, rb_intern("to_s"), 0);
41
+ char *path_cstr = StringValueCStr(path_s);
42
+ void *lib = dlopen(path_cstr, RTLD_NOW);
43
+ const char *err = dlerror();
44
+ if (err != NULL) {
45
+ rb_raise(rb_eRuntimeError,
46
+ "Could not load shared library `%s'.\nReason: %s", path_cstr, err);
47
+ }
48
+
49
+ char buf[256];
50
+ snprintf(buf, sizeof(buf), "tree_sitter_%s", StringValueCStr(name));
51
+ tree_sitter_lang *make_ts_language = dlsym(lib, buf);
52
+ err = dlerror();
53
+ if (err != NULL) {
54
+ dlclose(lib);
55
+ rb_raise(rb_eRuntimeError,
56
+ "Could not load symbol `%s' from library `%s'.\nReason:%s",
57
+ StringValueCStr(name), path_cstr, err);
58
+ }
59
+
60
+ TSLanguage *lang = make_ts_language();
61
+ if (lang == NULL) {
62
+ dlclose(lib);
63
+ rb_raise(rb_eRuntimeError,
64
+ "TSLanguage = NULL for language `%s' in library `%s'.\nCall your "
65
+ "local TSLanguage supplier.",
66
+ StringValueCStr(name), path_cstr);
67
+ }
68
+
69
+ uint32_t version = ts_language_version(lang);
70
+ if (version < TREE_SITTER_MIN_COMPATIBLE_LANGUAGE_VERSION) {
71
+ rb_raise(rb_eRuntimeError,
72
+ "Language %s (v%d) from `%s' is old.\nMinimum supported ABI: "
73
+ "v%d.\nCurrent ABI: v%d.",
74
+ StringValueCStr(name), version, path_cstr,
75
+ TREE_SITTER_MIN_COMPATIBLE_LANGUAGE_VERSION,
76
+ TREE_SITTER_LANGUAGE_VERSION);
77
+ }
78
+
79
+ return new_language(lang);
80
+ }
81
+
82
+ static VALUE language_equal(VALUE self, VALUE other) {
83
+ TSLanguage *this = SELF;
84
+ TSLanguage *that = unwrap(other)->data;
85
+ return this == that ? Qtrue : Qfalse;
86
+ }
87
+
88
+ /**
89
+ * Get the number of distinct field names in the language.
90
+ *
91
+ * @return [Integer]
92
+ */
93
+ static VALUE language_field_count(VALUE self) {
94
+ return UINT2NUM(ts_language_field_count(SELF));
95
+ }
96
+
97
+ /**
98
+ * Get the numerical id for the given field name string.
99
+ *
100
+ * @param name [String]
101
+ *
102
+ * @return [Integer]
103
+ */
104
+ static VALUE language_field_id_for_name(VALUE self, VALUE name) {
105
+ TSLanguage *language = SELF;
106
+ const char *str = StringValuePtr(name);
107
+ uint32_t length = (uint32_t)RSTRING_LEN(name);
108
+ return UINT2NUM(ts_language_field_id_for_name(language, str, length));
109
+ }
110
+
111
+ /**
112
+ * Get the field name string for the given numerical id.
113
+ *
114
+ * @param field_id [Integer]
115
+ *
116
+ * @return [String]
117
+ */
118
+ static VALUE language_field_name_for_id(VALUE self, VALUE field_id) {
119
+ return safe_str(ts_language_field_name_for_id(SELF, NUM2UINT(field_id)));
120
+ }
121
+
122
+ /**
123
+ * Get the next parse state. Combine this with lookahead iterators to generate
124
+ * completion suggestions or valid symbols in error nodes. Use
125
+ * {Node#grammar_symbol} for valid symbols.
126
+ */
127
+ static VALUE language_next_state(VALUE self, VALUE state, VALUE symbol) {
128
+ uint16_t sta = (uint16_t)NUM2UINT(state);
129
+ uint16_t sym = (uint16_t)NUM2UINT(symbol);
130
+ return UINT2NUM(ts_language_next_state(SELF, sta, sym));
131
+ }
132
+
133
+ /**
134
+ * Get the number of distinct node types in the language.
135
+ *
136
+ * @return [Integer]
137
+ */
138
+ static VALUE language_symbol_count(VALUE self) {
139
+ return UINT2NUM(ts_language_symbol_count(SELF));
140
+ }
141
+
142
+ /**
143
+ * Get a node type string for the given numerical id.
144
+ *
145
+ * @param symbol [Integer]
146
+ *
147
+ * @return [String]
148
+ */
149
+ static VALUE language_symbol_name(VALUE self, VALUE symbol) {
150
+ return safe_str(ts_language_symbol_name(SELF, NUM2UINT(symbol)));
151
+ }
152
+
153
+ /**
154
+ * Get the numerical id for the given node type string.
155
+ *
156
+ * @param string [Symbol]
157
+ * @param is_named [Boolean]
158
+ *
159
+ * @return [Integer]
160
+ */
161
+ static VALUE language_symbol_for_name(VALUE self, VALUE string,
162
+ VALUE is_named) {
163
+ const char *str = rb_id2name(SYM2ID(string));
164
+ uint32_t length = (uint32_t)strlen(str);
165
+ bool named = RTEST(is_named);
166
+ return UINT2NUM(ts_language_symbol_for_name(SELF, str, length, named));
167
+ }
168
+
169
+ /**
170
+ * Check whether the given node type id belongs to named nodes, anonymous nodes,
171
+ * or a hidden nodes.
172
+ *
173
+ * Hidden nodes are never returned from the API.
174
+ *
175
+ * @see Node#named?
176
+ *
177
+ * @param symbol [Integer]
178
+ *
179
+ * @return [SymbolType]
180
+ */
181
+ static VALUE language_symbol_type(VALUE self, VALUE symbol) {
182
+ return new_symbol_type(ts_language_symbol_type(SELF, NUM2UINT(symbol)));
183
+ }
184
+
185
+ /**
186
+ * Get the ABI version number for this language. This version number is used
187
+ * to ensure that languages were generated by a compatible version of
188
+ * Tree-sitter.
189
+ *
190
+ * @see Parser#language=
191
+ */
192
+ static VALUE language_version(VALUE self) {
193
+ return UINT2NUM(ts_language_version(SELF));
194
+ }
195
+
196
+ void init_language(void) {
197
+ cLanguage = rb_define_class_under(mTreeSitter, "Language", rb_cObject);
198
+
199
+ rb_define_alloc_func(cLanguage, language_allocate);
200
+
201
+ /* Module methods */
202
+ rb_define_module_function(cLanguage, "load", language_load, 2);
203
+
204
+ /* Operators */
205
+ rb_define_method(cLanguage, "==", language_equal, 1);
206
+
207
+ /* Class methods */
208
+ rb_define_method(cLanguage, "field_count", language_field_count, 0);
209
+ rb_define_method(cLanguage, "field_id_for_name", language_field_id_for_name,
210
+ 1);
211
+ rb_define_method(cLanguage, "field_name_for_id", language_field_name_for_id,
212
+ 1);
213
+ rb_define_method(cLanguage, "next_state", language_next_state, 2);
214
+ rb_define_method(cLanguage, "symbol_count", language_symbol_count, 0);
215
+ rb_define_method(cLanguage, "symbol_for_name", language_symbol_for_name, 2);
216
+ rb_define_method(cLanguage, "symbol_name", language_symbol_name, 1);
217
+ rb_define_method(cLanguage, "symbol_type", language_symbol_type, 1);
218
+ rb_define_method(cLanguage, "version", language_version, 0);
219
+ }
@@ -0,0 +1,228 @@
1
+ #include "tree_sitter.h"
2
+
3
+ extern VALUE mTreeSitter;
4
+
5
+ VALUE cLogger;
6
+
7
+ // This type is layed out in the DATA_* style.
8
+ // data: the TSLogger object
9
+ // payload: what will be used in TSLogger.log()
10
+ // therefore: data.payload = payload
11
+ // format: optional formatting string. Passed to "printf" if it exists
12
+ typedef struct {
13
+ TSLogger data;
14
+ VALUE payload;
15
+ VALUE format;
16
+ } logger_t;
17
+
18
+ static const char *logger_log_type_str(TSLogType log_type) {
19
+ switch (log_type) {
20
+ case TSLogTypeParse:
21
+ return "Parse:";
22
+ case TSLogTypeLex:
23
+ return "Lex :";
24
+ default:
25
+ return "?????:";
26
+ }
27
+ }
28
+
29
+ static void logger_log_printf(void *ptr, TSLogType log_type,
30
+ const char *message) {
31
+ logger_t *logger = (logger_t *)ptr;
32
+ VALUE type = safe_str(logger_log_type_str(log_type));
33
+ VALUE msg = safe_str(message);
34
+ rb_funcall(logger->payload, rb_intern("printf"), 3, logger->format, type,
35
+ msg);
36
+ }
37
+
38
+ static void logger_log_puts(void *ptr, TSLogType log_type,
39
+ const char *message) {
40
+ logger_t *logger = (logger_t *)ptr;
41
+ const char *format =
42
+ NIL_P(logger->format) ? "%s %s" : StringValueCStr(logger->format);
43
+ VALUE str = rb_sprintf(format, logger_log_type_str(log_type), message);
44
+ rb_funcall(logger->payload, rb_intern("puts"), 1, str);
45
+ }
46
+
47
+ static void logger_log_write(void *ptr, TSLogType log_type,
48
+ const char *message) {
49
+ logger_t *logger = (logger_t *)ptr;
50
+ const char *format =
51
+ NIL_P(logger->format) ? "%s %s\n" : StringValueCStr(logger->format);
52
+ VALUE str = rb_sprintf(format, logger_log_type_str(log_type), message);
53
+ rb_funcall(logger->payload, rb_intern("write"), 1, str);
54
+ }
55
+
56
+ static void logger_payload_set(logger_t *logger, VALUE value) {
57
+ logger->payload = value;
58
+ logger->data.payload = (void *)logger;
59
+
60
+ if (!NIL_P(logger->format) && !NIL_P(logger->payload)) {
61
+ if (rb_respond_to(logger->payload, rb_intern("printf"))) {
62
+ logger->data.log = logger_log_printf;
63
+ } else if (rb_respond_to(logger->payload, rb_intern("puts"))) {
64
+ logger->data.log = logger_log_puts;
65
+ } else {
66
+ logger->data.log = logger_log_write;
67
+ }
68
+ } else if (!NIL_P(logger->payload)) {
69
+ logger->data.log = logger_log_write;
70
+ }
71
+ }
72
+
73
+ static void logger_free(void *ptr) { xfree(ptr); }
74
+
75
+ static size_t logger_memsize(const void *ptr) {
76
+ logger_t *type = (logger_t *)ptr;
77
+ return sizeof(type);
78
+ }
79
+
80
+ static void logger_mark(void *ptr) {
81
+ logger_t *logger = (logger_t *)ptr;
82
+ rb_gc_mark_movable(logger->payload);
83
+ // we don't want format to move because its reference will be
84
+ // consumed by the parser.
85
+ //
86
+ // No funny things please.
87
+ rb_gc_mark(logger->format);
88
+ }
89
+
90
+ static void logger_compact(void *ptr) {
91
+ logger_t *logger = (logger_t *)ptr;
92
+ logger->payload = rb_gc_location(logger->payload);
93
+ }
94
+
95
+ const rb_data_type_t logger_data_type = {
96
+ .wrap_struct_name = "logger",
97
+ .function =
98
+ {
99
+ .dmark = logger_mark,
100
+ .dfree = logger_free,
101
+ .dsize = logger_memsize,
102
+ .dcompact = logger_compact,
103
+ },
104
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
105
+ };
106
+
107
+ DATA_UNWRAP(logger)
108
+
109
+ static VALUE logger_allocate(VALUE klass) {
110
+ logger_t *logger;
111
+ return TypedData_Make_Struct(klass, logger_t, &logger_data_type, logger);
112
+ }
113
+
114
+ VALUE new_logger(const TSLogger *ptr) {
115
+ if (ptr != NULL) {
116
+ VALUE res = logger_allocate(cLogger);
117
+ logger_t *logger = unwrap(res);
118
+
119
+ logger->data.payload = logger;
120
+
121
+ VALUE payload = Qnil;
122
+ VALUE format = Qnil;
123
+ if (ptr->payload != NULL) {
124
+ logger_t *old_logger = (logger_t *)ptr->payload;
125
+ payload = old_logger->payload;
126
+ format = old_logger->format;
127
+ }
128
+ logger_payload_set(logger, payload);
129
+ logger->format = format;
130
+
131
+ return res;
132
+ } else {
133
+ return Qnil;
134
+ }
135
+ }
136
+
137
+ VALUE new_logger_by_val(TSLogger val) { return new_logger(&val); }
138
+
139
+ TSLogger value_to_logger(VALUE self) { return SELF; }
140
+
141
+ static void logger_initialize_stderr(logger_t *logger) {
142
+ VALUE stderr = rb_gv_get("$stderr");
143
+ if (!NIL_P(stderr)) {
144
+ logger_payload_set(logger, stderr);
145
+ } else {
146
+ logger_payload_set(logger, Qnil);
147
+ }
148
+ }
149
+
150
+ /**
151
+ * Create a new logger.
152
+ *
153
+ * By default, it logs to stderr.
154
+ *
155
+ * You can provide your proper backend. You have to make sure that it
156
+ * exposes a +printf+, +puts+, or +write+ (lookup is done in that specific
157
+ * order). {::StringIO} is a perfect candidate.
158
+ *
159
+ * You can also provide a format ({::String}) if your backend supports a +printf+.
160
+ *
161
+ * @example
162
+ * backend = StringIO.new
163
+ * parser.logger = TreeSitter::Logger.new(backend)
164
+ *
165
+ * @param args [Array] The first argument is always a backend. The second
166
+ * argument is the format.
167
+ */
168
+ static VALUE logger_initialize(int argc, VALUE *argv, VALUE self) {
169
+ // TODO:
170
+ // For now, we only take:
171
+ // argv[0] = stream
172
+ // argv[1] = format : String
173
+ // We need to add support for argv[1] : lambda/block
174
+ // case argv[1]
175
+ // in lambda => lambda
176
+ // in String => puts || printf || write
177
+ // else => write
178
+ // end
179
+ logger_t *logger = unwrap(self);
180
+
181
+ VALUE payload;
182
+ VALUE format;
183
+ rb_scan_args(argc, argv, "02", &payload, &format);
184
+
185
+ logger->format = format;
186
+
187
+ if (argc == 0) {
188
+ logger_initialize_stderr(logger);
189
+ } else {
190
+ logger_payload_set(logger, payload);
191
+ }
192
+
193
+ return self;
194
+ }
195
+
196
+ static VALUE logger_inspect(VALUE self) {
197
+ logger_t *logger = unwrap(self);
198
+ return rb_sprintf("{payload=%+" PRIsVALUE ", format=%+" PRIsVALUE "}",
199
+ logger->payload, logger->format);
200
+ }
201
+
202
+ DATA_FAST_FORWARD_FNV(logger, write, payload)
203
+ DATA_FAST_FORWARD_FNV(logger, puts, payload)
204
+ DATA_FAST_FORWARD_FNV(logger, printf, payload)
205
+
206
+ DEFINE_ACCESSOR(logger, format)
207
+ DEFINE_GETTER(logger, payload)
208
+
209
+ static VALUE logger_set_payload(VALUE self, VALUE payload) {
210
+ logger_payload_set(unwrap(self), payload);
211
+ return Qnil;
212
+ }
213
+
214
+ void init_logger(void) {
215
+ cLogger = rb_define_class_under(mTreeSitter, "Logger", rb_cObject);
216
+
217
+ rb_define_alloc_func(cLogger, logger_allocate);
218
+
219
+ /* Class methods */
220
+ rb_define_method(cLogger, "initialize", logger_initialize, -1);
221
+ DECLARE_ACCESSOR(cLogger, logger, format)
222
+ DECLARE_ACCESSOR(cLogger, logger, payload)
223
+ rb_define_method(cLogger, "write", logger_write, -1);
224
+ rb_define_method(cLogger, "puts", logger_puts, -1);
225
+ rb_define_method(cLogger, "printf", logger_printf, -1);
226
+ rb_define_method(cLogger, "inspect", logger_inspect, 0);
227
+ rb_define_method(cLogger, "to_s", logger_inspect, 0);
228
+ }
@@ -0,0 +1,163 @@
1
+ #ifndef _RB_TREE_SITTER_MACROS_H
2
+ #define _RB_TREE_SITTER_MACROS_H
3
+
4
+ #define DECLARE_GETTER(klass, type, field) \
5
+ rb_define_method(klass, #field, type##_get_##field, 0);
6
+
7
+ #define DECLARE_SETTER(klass, type, field) \
8
+ rb_define_method(klass, #field "=", type##_set_##field, 1);
9
+
10
+ #define DECLARE_ACCESSOR(klass, type, field) \
11
+ DECLARE_GETTER(klass, type, field) \
12
+ DECLARE_SETTER(klass, type, field)
13
+
14
+ // Plain DEFINE_GETTER/DEFINE_SETTER/etc are for TypedData structs, reaching
15
+ // their top-level fields, and are of type VALUE
16
+ //
17
+ // DATA_* are for TypeData structs, raching their data field
18
+ // which can be of an arbitraty tuype.
19
+
20
+ #define DEFINE_GETTER(type, field) \
21
+ static VALUE type##_get_##field(VALUE self) { return (unwrap(self))->field; }
22
+
23
+ #define DEFINE_SETTER(type, field) \
24
+ static VALUE type##_set_##field(VALUE self, VALUE val) { \
25
+ unwrap(self)->field = val; \
26
+ return Qnil; \
27
+ }
28
+
29
+ #define DEFINE_ACCESSOR(type, field) \
30
+ DEFINE_GETTER(type, field) \
31
+ DEFINE_SETTER(type, field)
32
+
33
+ #define DATA_WRAP(base, type) \
34
+ DATA_TYPE(TS##base, type) \
35
+ DATA_FREE(type) \
36
+ DATA_MEMSIZE(type) \
37
+ DATA_DECLARE_DATA_TYPE(type) \
38
+ DATA_ALLOCATE(type) \
39
+ DATA_UNWRAP(type) \
40
+ DATA_NEW(c##base, TS##base, type) \
41
+ DATA_FROM_VALUE(TS##base, type)
42
+
43
+ #define DATA_PTR_WRAP(base, type) \
44
+ DATA_TYPE(TS##base *, type) \
45
+ DATA_FREE_PTR(type) \
46
+ DATA_MEMSIZE(type) \
47
+ DATA_DECLARE_DATA_TYPE(type) \
48
+ DATA_ALLOCATE(type) \
49
+ DATA_UNWRAP(type) \
50
+ DATA_PTR_NEW(c##base, TS##base, type) \
51
+ DATA_FROM_VALUE(TS##base *, type)
52
+
53
+ #define DATA_TYPE(klass, type) \
54
+ typedef struct { \
55
+ klass data; \
56
+ } type##_t;
57
+
58
+ #define DATA_FREE(type) \
59
+ static void type##_free(void *ptr) { xfree(ptr); }
60
+
61
+ #define DATA_FREE_PTR(type) \
62
+ static void type##_free(void *ptr) { \
63
+ type##_t *type = (type##_t *)ptr; \
64
+ if (type->data != NULL) { \
65
+ ts_##type##_delete(type->data); \
66
+ } \
67
+ xfree(ptr); \
68
+ }
69
+
70
+ #define DATA_MEMSIZE(type) \
71
+ static size_t type##_memsize(const void *ptr) { \
72
+ type##_t *type = (type##_t *)ptr; \
73
+ return sizeof(type); \
74
+ }
75
+
76
+ #define DATA_DECLARE_DATA_TYPE(type) \
77
+ const rb_data_type_t type##_data_type = { \
78
+ .wrap_struct_name = #type "", \
79
+ .function = \
80
+ { \
81
+ .dmark = NULL, \
82
+ .dfree = type##_free, \
83
+ .dsize = type##_memsize, \
84
+ .dcompact = NULL, \
85
+ }, \
86
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY, \
87
+ };
88
+
89
+ #define DATA_ALLOCATE(type) \
90
+ static VALUE type##_allocate(VALUE klass) { \
91
+ type##_t *type; \
92
+ return TypedData_Make_Struct(klass, type##_t, &type##_data_type, type); \
93
+ }
94
+
95
+ #define DATA_UNWRAP(type) \
96
+ static type##_t *unwrap(VALUE self) { \
97
+ type##_t *type; \
98
+ TypedData_Get_Struct(self, type##_t, &type##_data_type, type); \
99
+ return type; \
100
+ }
101
+
102
+ #define SELF unwrap(self)->data
103
+
104
+ #define DATA_NEW(klass, struct, type) \
105
+ VALUE new_##type(const struct *ptr) { \
106
+ if (ptr == NULL) { \
107
+ return Qnil; \
108
+ } \
109
+ VALUE res = type##_allocate(klass); \
110
+ type##_t *type = unwrap(res); \
111
+ type->data = *ptr; \
112
+ return res; \
113
+ } \
114
+ VALUE new_##type##_by_val(struct ptr) { \
115
+ VALUE res = type##_allocate(klass); \
116
+ type##_t *type = unwrap(res); \
117
+ type->data = ptr; \
118
+ return res; \
119
+ }
120
+
121
+ #define DATA_FROM_VALUE(struct, type) \
122
+ struct value_to_##type(VALUE self) { \
123
+ return (unwrap(self))->data; \
124
+ }
125
+
126
+ #define DATA_PTR_NEW(klass, struct, type) \
127
+ VALUE new_##type(struct *ptr) { \
128
+ if (ptr == NULL) { \
129
+ return Qnil; \
130
+ } \
131
+ VALUE res = type##_allocate(klass); \
132
+ type##_t *type = unwrap(res); \
133
+ type->data = ptr; \
134
+ return res; \
135
+ }
136
+
137
+ #define DATA_DEFINE_GETTER(type, field, cast) \
138
+ static VALUE type##_get_##field(VALUE self) { \
139
+ return cast((unwrap(self))->data.field); \
140
+ }
141
+
142
+ #define DATA_DEFINE_SETTER(type, field, cast) \
143
+ static VALUE type##_set_##field(VALUE self, VALUE val) { \
144
+ type##_t *type = unwrap(self); \
145
+ type->data.field = cast(val); \
146
+ return Qnil; \
147
+ }
148
+
149
+ #define DATA_DEFINE_ACCESSOR(type, field, cast_get, cast_set) \
150
+ DATA_DEFINE_GETTER(type, field, cast_get) \
151
+ DATA_DEFINE_SETTER(type, field, cast_set)
152
+
153
+ #define DATA_FAST_FORWARD_FNV(type, fn, field) \
154
+ static VALUE type##_##fn(int argc, VALUE *argv, VALUE self) { \
155
+ type##_t *type = unwrap(self); \
156
+ if (!NIL_P(type->field)) { \
157
+ return rb_funcallv(type->field, rb_intern(#fn ""), argc, argv); \
158
+ } else { \
159
+ return Qnil; \
160
+ } \
161
+ }
162
+
163
+ #endif