ruby_tree_sitter 1.6.0-x86_64-darwin

Sign up to get free protection for your applications and to get access to all the features.
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.bundle +0 -0
  29. data/lib/tree_sitter/3.1/tree_sitter.bundle +0 -0
  30. data/lib/tree_sitter/3.2/tree_sitter.bundle +0 -0
  31. data/lib/tree_sitter/3.3/tree_sitter.bundle +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