ruby-bindgen 1.0.0
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/CHANGELOG.md +7 -0
- data/LICENSE +25 -0
- data/README.md +68 -0
- data/Rakefile +8 -0
- data/bin/ruby-bindgen +133 -0
- data/docs/architecture.md +238 -0
- data/docs/c/c_bindings.md +65 -0
- data/docs/c/constants.md +21 -0
- data/docs/c/customizing.md +19 -0
- data/docs/c/filtering.md +24 -0
- data/docs/c/getting_started.md +56 -0
- data/docs/c/library_loading.md +53 -0
- data/docs/c/output.md +96 -0
- data/docs/c/types.md +61 -0
- data/docs/c/version_guards.md +105 -0
- data/docs/cmake/cmake_bindings.md +19 -0
- data/docs/cmake/filtering.md +26 -0
- data/docs/cmake/getting_started.md +52 -0
- data/docs/cmake/output.md +110 -0
- data/docs/configuration.md +351 -0
- data/docs/contributing.md +68 -0
- data/docs/cpp/buffers.md +24 -0
- data/docs/cpp/classes.md +139 -0
- data/docs/cpp/cpp_bindings.md +29 -0
- data/docs/cpp/customizing.md +124 -0
- data/docs/cpp/enums.md +42 -0
- data/docs/cpp/filtering.md +35 -0
- data/docs/cpp/getting_started.md +80 -0
- data/docs/cpp/iterators.md +94 -0
- data/docs/cpp/operators.md +170 -0
- data/docs/cpp/output.md +125 -0
- data/docs/cpp/templates.md +114 -0
- data/docs/examples.md +133 -0
- data/docs/index.md +133 -0
- data/docs/prior_art.md +37 -0
- data/docs/troubleshooting.md +243 -0
- data/docs/type_spelling.md +200 -0
- data/docs/updating_bindings.md +55 -0
- data/docs/version_guards.md +69 -0
- data/lib/ruby-bindgen/config.rb +63 -0
- data/lib/ruby-bindgen/generators/cmake/cmake.rb +171 -0
- data/lib/ruby-bindgen/generators/cmake/directory.erb +29 -0
- data/lib/ruby-bindgen/generators/cmake/guard.rb +55 -0
- data/lib/ruby-bindgen/generators/cmake/presets.erb +232 -0
- data/lib/ruby-bindgen/generators/cmake/project.erb +89 -0
- data/lib/ruby-bindgen/generators/ffi/callback.erb +1 -0
- data/lib/ruby-bindgen/generators/ffi/constant.erb +1 -0
- data/lib/ruby-bindgen/generators/ffi/enum_constant_decl.erb +1 -0
- data/lib/ruby-bindgen/generators/ffi/enum_decl.erb +4 -0
- data/lib/ruby-bindgen/generators/ffi/enum_decl_anonymous.erb +4 -0
- data/lib/ruby-bindgen/generators/ffi/ffi.rb +687 -0
- data/lib/ruby-bindgen/generators/ffi/field_decl.erb +1 -0
- data/lib/ruby-bindgen/generators/ffi/function.erb +5 -0
- data/lib/ruby-bindgen/generators/ffi/library.erb +39 -0
- data/lib/ruby-bindgen/generators/ffi/project.erb +18 -0
- data/lib/ruby-bindgen/generators/ffi/struct.erb +6 -0
- data/lib/ruby-bindgen/generators/ffi/translation_unit.erb +9 -0
- data/lib/ruby-bindgen/generators/ffi/typedef_decl.erb +1 -0
- data/lib/ruby-bindgen/generators/ffi/union.erb +6 -0
- data/lib/ruby-bindgen/generators/ffi/variable.erb +1 -0
- data/lib/ruby-bindgen/generators/ffi/version.erb +9 -0
- data/lib/ruby-bindgen/generators/ffi/version_method.erb +5 -0
- data/lib/ruby-bindgen/generators/generator.rb +52 -0
- data/lib/ruby-bindgen/generators/rice/auto_generated_base_class.erb +5 -0
- data/lib/ruby-bindgen/generators/rice/class.erb +31 -0
- data/lib/ruby-bindgen/generators/rice/class_template.erb +9 -0
- data/lib/ruby-bindgen/generators/rice/class_template_specialization.erb +10 -0
- data/lib/ruby-bindgen/generators/rice/constant.erb +9 -0
- data/lib/ruby-bindgen/generators/rice/constructor.erb +1 -0
- data/lib/ruby-bindgen/generators/rice/conversion_function.erb +4 -0
- data/lib/ruby-bindgen/generators/rice/cxx_iterator_method.erb +1 -0
- data/lib/ruby-bindgen/generators/rice/cxx_method.erb +6 -0
- data/lib/ruby-bindgen/generators/rice/enum_constant_decl.erb +7 -0
- data/lib/ruby-bindgen/generators/rice/enum_decl.erb +6 -0
- data/lib/ruby-bindgen/generators/rice/field_decl.erb +8 -0
- data/lib/ruby-bindgen/generators/rice/function.erb +6 -0
- data/lib/ruby-bindgen/generators/rice/function_pointer.rb +68 -0
- data/lib/ruby-bindgen/generators/rice/incomplete_class.erb +3 -0
- data/lib/ruby-bindgen/generators/rice/iterator_alias.erb +1 -0
- data/lib/ruby-bindgen/generators/rice/iterator_collector.rb +159 -0
- data/lib/ruby-bindgen/generators/rice/namespace.erb +5 -0
- data/lib/ruby-bindgen/generators/rice/non_member_operator_binary.erb +4 -0
- data/lib/ruby-bindgen/generators/rice/non_member_operator_inspect.erb +6 -0
- data/lib/ruby-bindgen/generators/rice/non_member_operator_unary.erb +4 -0
- data/lib/ruby-bindgen/generators/rice/operator[].erb +4 -0
- data/lib/ruby-bindgen/generators/rice/project.cpp.erb +18 -0
- data/lib/ruby-bindgen/generators/rice/project.hpp.erb +13 -0
- data/lib/ruby-bindgen/generators/rice/reference_qualifier.rb +495 -0
- data/lib/ruby-bindgen/generators/rice/rice.rb +1724 -0
- data/lib/ruby-bindgen/generators/rice/rice_include.hpp.erb +7 -0
- data/lib/ruby-bindgen/generators/rice/signature_builder.rb +230 -0
- data/lib/ruby-bindgen/generators/rice/template_resolver.rb +585 -0
- data/lib/ruby-bindgen/generators/rice/translation_unit.cpp.erb +40 -0
- data/lib/ruby-bindgen/generators/rice/translation_unit.hpp.erb +7 -0
- data/lib/ruby-bindgen/generators/rice/translation_unit.ipp.erb +3 -0
- data/lib/ruby-bindgen/generators/rice/type_index.rb +117 -0
- data/lib/ruby-bindgen/generators/rice/type_speller.rb +509 -0
- data/lib/ruby-bindgen/generators/rice/union.erb +5 -0
- data/lib/ruby-bindgen/generators/rice/variable.erb +5 -0
- data/lib/ruby-bindgen/inputter.rb +54 -0
- data/lib/ruby-bindgen/name_mapper.rb +65 -0
- data/lib/ruby-bindgen/namer.rb +138 -0
- data/lib/ruby-bindgen/outputter.rb +40 -0
- data/lib/ruby-bindgen/parser.rb +82 -0
- data/lib/ruby-bindgen/refinements/cursor.rb +57 -0
- data/lib/ruby-bindgen/refinements/string.rb +41 -0
- data/lib/ruby-bindgen/symbol_candidates.rb +282 -0
- data/lib/ruby-bindgen/symbol_entry.rb +21 -0
- data/lib/ruby-bindgen/symbols.rb +107 -0
- data/lib/ruby-bindgen/type_pointer_formatter.rb +35 -0
- data/lib/ruby-bindgen/version.rb +3 -0
- data/lib/ruby-bindgen.rb +19 -0
- data/ruby-bindgen.gemspec +52 -0
- metadata +260 -0
|
@@ -0,0 +1,585 @@
|
|
|
1
|
+
module RubyBindgen
|
|
2
|
+
module Generators
|
|
3
|
+
class Rice
|
|
4
|
+
# Resolves template specializations, omitted defaults, and inherited template
|
|
5
|
+
# bases using libclang's semantic APIs plus source-written fallback text when
|
|
6
|
+
# libclang does not expose a complete argument string.
|
|
7
|
+
class TemplateResolver
|
|
8
|
+
# Captures the semantic and source-written pieces for one template argument.
|
|
9
|
+
# TemplateResolver builds these first, then later code renders them into
|
|
10
|
+
# emitted C++ text.
|
|
11
|
+
TemplateArgumentInfo = Struct.new(:kind, :type, :value, :unsigned_value, :source_text, keyword_init: true)
|
|
12
|
+
|
|
13
|
+
def initialize(reference_qualifier:, type_speller:, namer:)
|
|
14
|
+
@reference_qualifier = reference_qualifier
|
|
15
|
+
@type_speller = type_speller
|
|
16
|
+
@namer = namer
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Get full template arguments including default values.
|
|
20
|
+
# When a typedef uses a template with default arguments, libclang reports
|
|
21
|
+
# only the written arguments. Type arguments come from the semantic type
|
|
22
|
+
# API, while non-type and template-template args fall back to source text
|
|
23
|
+
# so expressions like `1 + 2` and names like `Box` are preserved.
|
|
24
|
+
#
|
|
25
|
+
# Examples:
|
|
26
|
+
# ExprValue<1 + 2>
|
|
27
|
+
# stays
|
|
28
|
+
# ExprValue_instantiate<1 + 2>
|
|
29
|
+
#
|
|
30
|
+
# Matrix<int, 2>
|
|
31
|
+
# becomes
|
|
32
|
+
# Matrix_instantiate<int, 2, 1>
|
|
33
|
+
def full_template_arguments(cursor, underlying_type, template_cursor)
|
|
34
|
+
actual_args = specialization_template_arguments(cursor, underlying_type, template_cursor)
|
|
35
|
+
|
|
36
|
+
return actual_args if template_cursor.nil?
|
|
37
|
+
|
|
38
|
+
params = template_parameters(template_cursor)
|
|
39
|
+
return actual_args if actual_args.length >= params.length
|
|
40
|
+
|
|
41
|
+
argument_cursor = specialization_argument_cursor(underlying_type)
|
|
42
|
+
missing_params = params.drop(actual_args.length)
|
|
43
|
+
default_values = missing_params.each_with_index.map do |param, offset|
|
|
44
|
+
template_param_default(param, argument_cursor: argument_cursor, argument_index: actual_args.length + offset)
|
|
45
|
+
end.compact
|
|
46
|
+
|
|
47
|
+
return actual_args if default_values.length != missing_params.length
|
|
48
|
+
|
|
49
|
+
actual_args + default_values
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Build the C++ specialization spelling for a typedef/alias specialization
|
|
53
|
+
# using the semantic template cursor plus the written template arguments.
|
|
54
|
+
#
|
|
55
|
+
# This is narrower than `full_template_arguments`: the Data_Type<T> side
|
|
56
|
+
# should preserve the number of arguments written at the use site rather
|
|
57
|
+
# than eagerly expanding omitted defaults. When libclang does not expose a
|
|
58
|
+
# complete argument list for a non-type specialization, fall back to the
|
|
59
|
+
# type speller's direct output.
|
|
60
|
+
#
|
|
61
|
+
# Examples:
|
|
62
|
+
# typedef FunctionTemplate<callback_ints> FunctionTemplateCallback;
|
|
63
|
+
# => Tests::FunctionTemplate<&Tests::callback_ints>
|
|
64
|
+
#
|
|
65
|
+
# typedef MultiDefault<int> MultiDefaultInt;
|
|
66
|
+
# => MultiDefault<int>
|
|
67
|
+
def specialization_spelling(specialization_cursor, specialized_type, template_cursor)
|
|
68
|
+
return @type_speller.type_spelling(specialized_type) unless template_cursor
|
|
69
|
+
|
|
70
|
+
actual_args = specialization_template_arguments(specialization_cursor, specialized_type, template_cursor)
|
|
71
|
+
count = specialized_type.num_template_arguments
|
|
72
|
+
return @type_speller.type_spelling(specialized_type) if count <= 0
|
|
73
|
+
return @type_speller.type_spelling(specialized_type) unless actual_args.length == count
|
|
74
|
+
|
|
75
|
+
"#{template_cursor.qualified_name}<#{actual_args.join(', ')}>"
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def template_parameters(template_cursor)
|
|
79
|
+
template_parameter_kinds = [:cursor_template_type_parameter,
|
|
80
|
+
:cursor_non_type_template_parameter,
|
|
81
|
+
:cursor_template_template_parameter]
|
|
82
|
+
template_cursor.find_by_kind(false, *template_parameter_kinds).to_a
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Render a class template parameter for the instantiate helper's own
|
|
86
|
+
# template declaration.
|
|
87
|
+
#
|
|
88
|
+
# Examples:
|
|
89
|
+
# `typename T`
|
|
90
|
+
# stays
|
|
91
|
+
# `typename T`
|
|
92
|
+
#
|
|
93
|
+
# `int N = 4`
|
|
94
|
+
# becomes
|
|
95
|
+
# `int N`
|
|
96
|
+
#
|
|
97
|
+
# `void (*Fn)(int, int)`
|
|
98
|
+
# stays
|
|
99
|
+
# `void (*Fn)(int, int)`
|
|
100
|
+
#
|
|
101
|
+
# `template<typename> class Container = Box`
|
|
102
|
+
# becomes
|
|
103
|
+
# `template<typename> class Container`
|
|
104
|
+
#
|
|
105
|
+
# `template<typename U = int> class Container = Box`
|
|
106
|
+
# becomes
|
|
107
|
+
# `template<typename U = int> class Container`
|
|
108
|
+
def template_parameter_signature(template_parameter)
|
|
109
|
+
case template_parameter.kind
|
|
110
|
+
when :cursor_template_type_parameter
|
|
111
|
+
declaration = template_parameter.extent.text
|
|
112
|
+
declaration = nil unless usable_template_parameter_declaration?(template_parameter, declaration)
|
|
113
|
+
return "typename #{template_parameter_argument(template_parameter)}" if declaration.nil? || declaration.empty?
|
|
114
|
+
|
|
115
|
+
separator_offset = @reference_qualifier.top_level_default_separator_offset(declaration)
|
|
116
|
+
signature = separator_offset ? declaration.byteslice(0, separator_offset).rstrip : declaration.rstrip
|
|
117
|
+
|
|
118
|
+
signature.sub(/\A(\s*)class\b/, '\1typename')
|
|
119
|
+
when :cursor_non_type_template_parameter
|
|
120
|
+
declaration = template_parameter.extent.text
|
|
121
|
+
declaration = nil unless usable_template_parameter_declaration?(template_parameter, declaration)
|
|
122
|
+
return "int #{template_parameter.spelling}" if declaration.nil? || declaration.empty?
|
|
123
|
+
|
|
124
|
+
separator_offset = @reference_qualifier.top_level_default_separator_offset(declaration)
|
|
125
|
+
return declaration.rstrip unless separator_offset
|
|
126
|
+
|
|
127
|
+
declaration.byteslice(0, separator_offset).rstrip
|
|
128
|
+
when :cursor_template_template_parameter
|
|
129
|
+
declaration = template_parameter.extent.text
|
|
130
|
+
declaration = nil unless usable_template_parameter_declaration?(template_parameter, declaration)
|
|
131
|
+
return "template<typename> class #{template_parameter.spelling}" if declaration.nil? || declaration.empty?
|
|
132
|
+
|
|
133
|
+
separator_offset = @reference_qualifier.top_level_default_separator_offset(declaration)
|
|
134
|
+
return declaration.rstrip unless separator_offset
|
|
135
|
+
|
|
136
|
+
declaration.byteslice(0, separator_offset).rstrip
|
|
137
|
+
else
|
|
138
|
+
raise("Unsupported template parameter kind: #{template_parameter.kind}")
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def template_parameter_argument(template_parameter)
|
|
143
|
+
name = template_parameter.spelling
|
|
144
|
+
return name if name.empty?
|
|
145
|
+
|
|
146
|
+
declaration = template_parameter.extent.text
|
|
147
|
+
return name unless declaration&.match?(/\.\.\.\s*#{Regexp.escape(name)}\b/)
|
|
148
|
+
|
|
149
|
+
"#{name}..."
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def usable_template_parameter_declaration?(template_parameter, declaration)
|
|
153
|
+
return false if declaration.nil? || declaration.empty?
|
|
154
|
+
|
|
155
|
+
parent_declaration = template_parameter.semantic_parent&.extent&.text
|
|
156
|
+
declaration != parent_declaration
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Split a comma-separated template argument list while keeping nested
|
|
160
|
+
# templates, function pointer signatures, and string literals intact.
|
|
161
|
+
#
|
|
162
|
+
# Examples:
|
|
163
|
+
# 'unsigned char, 2, 1'
|
|
164
|
+
# => ['unsigned char', '2', '1']
|
|
165
|
+
#
|
|
166
|
+
# 'void (*)(int, int)'
|
|
167
|
+
# => ['void (*)(int, int)']
|
|
168
|
+
#
|
|
169
|
+
# 'Support::Box<Support::Tag>, callback_t'
|
|
170
|
+
# => ['Support::Box<Support::Tag>', 'callback_t']
|
|
171
|
+
def template_argument_texts(args_text)
|
|
172
|
+
return [] if args_text.nil? || args_text.empty?
|
|
173
|
+
|
|
174
|
+
result = []
|
|
175
|
+
current = String.new
|
|
176
|
+
angle_depth = 0
|
|
177
|
+
paren_depth = 0
|
|
178
|
+
bracket_depth = 0
|
|
179
|
+
brace_depth = 0
|
|
180
|
+
quote = nil
|
|
181
|
+
escaped = false
|
|
182
|
+
|
|
183
|
+
args_text.each_char do |char|
|
|
184
|
+
current << char
|
|
185
|
+
|
|
186
|
+
if quote
|
|
187
|
+
if escaped
|
|
188
|
+
escaped = false
|
|
189
|
+
elsif char == '\\'
|
|
190
|
+
escaped = true
|
|
191
|
+
elsif char == quote
|
|
192
|
+
quote = nil
|
|
193
|
+
end
|
|
194
|
+
next
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
case char
|
|
198
|
+
when '"', "'"
|
|
199
|
+
quote = char
|
|
200
|
+
when '<'
|
|
201
|
+
angle_depth += 1
|
|
202
|
+
when '>'
|
|
203
|
+
angle_depth -= 1 if angle_depth > 0
|
|
204
|
+
when '('
|
|
205
|
+
paren_depth += 1
|
|
206
|
+
when ')'
|
|
207
|
+
paren_depth -= 1 if paren_depth > 0
|
|
208
|
+
when '['
|
|
209
|
+
bracket_depth += 1
|
|
210
|
+
when ']'
|
|
211
|
+
bracket_depth -= 1 if bracket_depth > 0
|
|
212
|
+
when '{'
|
|
213
|
+
brace_depth += 1
|
|
214
|
+
when '}'
|
|
215
|
+
brace_depth -= 1 if brace_depth > 0
|
|
216
|
+
when ','
|
|
217
|
+
if angle_depth.zero? && paren_depth.zero? && bracket_depth.zero? && brace_depth.zero?
|
|
218
|
+
current.chop!
|
|
219
|
+
piece = current.strip
|
|
220
|
+
result << piece unless piece.empty?
|
|
221
|
+
current = String.new
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
piece = current.strip
|
|
227
|
+
result << piece unless piece.empty?
|
|
228
|
+
result
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
# Extract only the outer template argument list from a fully resolved
|
|
232
|
+
# instantiation spelling.
|
|
233
|
+
#
|
|
234
|
+
# Examples:
|
|
235
|
+
# 'Tests::Matx<unsigned char, 2, 1>'
|
|
236
|
+
# => 'unsigned char, 2, 1'
|
|
237
|
+
#
|
|
238
|
+
# 'Tests::CallbackBase<void (*)(int, int)>'
|
|
239
|
+
# => 'void (*)(int, int)'
|
|
240
|
+
def template_argument_list_text(spelling)
|
|
241
|
+
start_index = spelling.index('<')
|
|
242
|
+
return nil unless start_index
|
|
243
|
+
|
|
244
|
+
suffix, = balanced_template_suffix(spelling, start_index)
|
|
245
|
+
return nil if suffix.empty?
|
|
246
|
+
|
|
247
|
+
suffix[1..-2]
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
# Generate Ruby class name from a C++ template instantiation spelling
|
|
251
|
+
# e.g., "Tests::Matx<unsigned char, 2, 1>" -> "MatxUnsignedChar21"
|
|
252
|
+
def ruby_name_from_template(base_spelling, template_arguments)
|
|
253
|
+
base_name = base_spelling.sub(/<.*>\z/, "").split("::").last.camelize
|
|
254
|
+
argument_values = template_arguments.is_a?(Array) ? template_arguments : template_argument_texts(template_arguments)
|
|
255
|
+
args_name = argument_values.map { |argument| ruby_name_from_template_argument(argument) }.join
|
|
256
|
+
@namer.apply_rename_types(base_name + args_name)
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
# Given a typedef cursor and its underlying type, resolve the base class
|
|
260
|
+
# to an actual instantiated type (e.g., PtrStep<unsigned char> instead of PtrStep<T>).
|
|
261
|
+
# Correctly handles cases where derived and base templates have different numbers of
|
|
262
|
+
# template parameters (e.g., Vec<_Tp, cn> : public Matx<_Tp, cn, 1>).
|
|
263
|
+
# Returns the resolved base class spelling or nil if no base class exists.
|
|
264
|
+
def resolve_base_instantiation(cursor, underlying_type)
|
|
265
|
+
derived_template = specialized_template_cursor(underlying_type)
|
|
266
|
+
if derived_template.nil?
|
|
267
|
+
template_ref = cursor.find_first_by_kind(false, :cursor_template_ref)
|
|
268
|
+
derived_template = template_ref&.referenced
|
|
269
|
+
end
|
|
270
|
+
return nil unless derived_template
|
|
271
|
+
|
|
272
|
+
base_spec = derived_template.find_first_by_kind(false, :cursor_cxx_base_specifier)
|
|
273
|
+
return nil unless base_spec
|
|
274
|
+
|
|
275
|
+
base_template_ref = base_spec.find_first_by_kind(false, :cursor_template_ref)
|
|
276
|
+
|
|
277
|
+
unless base_template_ref
|
|
278
|
+
base_type_ref = base_spec.find_first_by_kind(false, :cursor_type_ref)
|
|
279
|
+
return base_type_ref&.referenced&.qualified_name
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
template_params = template_parameters(derived_template).map(&:spelling)
|
|
283
|
+
template_arg_values = full_template_arguments(cursor, underlying_type, derived_template)
|
|
284
|
+
|
|
285
|
+
substitutions = {}
|
|
286
|
+
template_params.each_with_index do |param, index|
|
|
287
|
+
substitutions[param] = template_arg_values[index] if template_arg_values[index]
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
resolve_base_specifier_spelling(base_spec, substitutions: substitutions)
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
# Resolve a template base specifier by rewriting the written source with
|
|
294
|
+
# semantic names and any current template-parameter substitutions.
|
|
295
|
+
#
|
|
296
|
+
# Examples:
|
|
297
|
+
# substitutions = { 'T' => 'unsigned char' }
|
|
298
|
+
# source = 'BasePtr<T>'
|
|
299
|
+
# => 'Tests::BasePtr<unsigned char>'
|
|
300
|
+
#
|
|
301
|
+
# substitutions = { 'Result' => 'void', 'Left' => 'int', 'Right' => 'int' }
|
|
302
|
+
# source = 'CallbackBase<Result (*)(Left, Right)>'
|
|
303
|
+
# => 'Tests::CallbackBase<void (*)(int, int)>'
|
|
304
|
+
def resolve_base_specifier_spelling(base_specifier, substitutions: {})
|
|
305
|
+
base_template_ref = base_specifier.find_first_by_kind(false, :cursor_template_ref)
|
|
306
|
+
|
|
307
|
+
unless base_template_ref
|
|
308
|
+
base_type_ref = base_specifier.find_first_by_kind(false, :cursor_type_ref)
|
|
309
|
+
return base_type_ref&.referenced&.qualified_name
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
source = base_specifier_source(base_specifier, base_template_ref)
|
|
313
|
+
return nil unless source
|
|
314
|
+
|
|
315
|
+
source_text, source_offset = source
|
|
316
|
+
@reference_qualifier.qualify_source_references(base_specifier, source_text, source_offset, substitutions: substitutions)
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
private
|
|
320
|
+
|
|
321
|
+
def specialized_template_cursor(type)
|
|
322
|
+
[type, type.canonical].each do |check_type|
|
|
323
|
+
declaration = check_type.declaration
|
|
324
|
+
next if declaration.kind == :cursor_no_decl_found
|
|
325
|
+
|
|
326
|
+
template = declaration.specialized_template
|
|
327
|
+
return template unless template.kind == :cursor_invalid_file
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
nil
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
def specialization_template_arguments(specialization_cursor, specialized_type, template_cursor)
|
|
334
|
+
specialization_template_argument_infos(specialization_cursor, specialized_type, template_cursor)
|
|
335
|
+
.filter_map { |argument_info| specialization_template_argument_text(argument_info) }
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
def specialization_argument_cursor(specialized_type)
|
|
339
|
+
declaration = specialized_type.declaration
|
|
340
|
+
return nil if declaration.kind == :cursor_no_decl_found
|
|
341
|
+
return declaration if declaration.num_template_arguments >= 0
|
|
342
|
+
|
|
343
|
+
nil
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
def specialization_template_argument_infos(specialization_cursor, specialized_type, template_cursor)
|
|
347
|
+
argument_cursor = specialization_argument_cursor(specialized_type)
|
|
348
|
+
# The specialized declaration cursor includes omitted default arguments,
|
|
349
|
+
# but the type API reports only the arguments written at the use site.
|
|
350
|
+
count = specialized_type.num_template_arguments
|
|
351
|
+
return [] if count <= 0
|
|
352
|
+
|
|
353
|
+
source_fallbacks = specialization_template_argument_source_texts(specialization_cursor, template_cursor)
|
|
354
|
+
|
|
355
|
+
count.times.filter_map do |index|
|
|
356
|
+
specialization_template_argument_info(argument_cursor, specialized_type, index, source_fallbacks)
|
|
357
|
+
end
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
def specialization_template_argument_info(argument_cursor, specialized_type, index, source_fallbacks)
|
|
361
|
+
specialized_arg_type = specialized_type.template_argument_type(index)
|
|
362
|
+
|
|
363
|
+
if argument_cursor
|
|
364
|
+
kind = argument_cursor.template_argument_kind(index)
|
|
365
|
+
case kind
|
|
366
|
+
when :template_argument_type
|
|
367
|
+
arg_type = argument_cursor.template_argument_type(index)
|
|
368
|
+
arg_type = specialized_arg_type if arg_type.kind == :type_invalid
|
|
369
|
+
return nil if arg_type.kind == :type_invalid
|
|
370
|
+
|
|
371
|
+
return TemplateArgumentInfo.new(kind: kind, type: arg_type)
|
|
372
|
+
when :template_argument_pack, :template_argument_invalid
|
|
373
|
+
# Variadic type aliases can surface here as a pack plus invalid
|
|
374
|
+
# cursor-argument kinds even though the specialized semantic type
|
|
375
|
+
# still exposes each concrete template argument correctly.
|
|
376
|
+
unless specialized_arg_type.kind == :type_invalid
|
|
377
|
+
source_fallbacks.shift
|
|
378
|
+
return TemplateArgumentInfo.new(kind: :template_argument_type, type: specialized_arg_type)
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
return TemplateArgumentInfo.new(kind: kind, source_text: source_fallbacks.shift)
|
|
382
|
+
when :template_argument_integral
|
|
383
|
+
return TemplateArgumentInfo.new(kind: kind,
|
|
384
|
+
value: argument_cursor.template_argument_value(index),
|
|
385
|
+
unsigned_value: argument_cursor.template_argument_unsigned_value(index),
|
|
386
|
+
source_text: source_fallbacks.shift)
|
|
387
|
+
when :template_argument_null_ptr
|
|
388
|
+
return TemplateArgumentInfo.new(kind: kind, source_text: source_fallbacks.shift)
|
|
389
|
+
when :template_argument_template, :template_argument_template_expansion,
|
|
390
|
+
:template_argument_expression, :template_argument_declaration,
|
|
391
|
+
:template_argument_pack
|
|
392
|
+
return TemplateArgumentInfo.new(kind: kind, source_text: source_fallbacks.shift)
|
|
393
|
+
end
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
return nil if specialized_arg_type.kind == :type_invalid
|
|
397
|
+
|
|
398
|
+
TemplateArgumentInfo.new(kind: :template_argument_type, type: specialized_arg_type)
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
def specialization_template_argument_text(argument_info)
|
|
402
|
+
case argument_info.kind
|
|
403
|
+
when :template_argument_type
|
|
404
|
+
@type_speller.type_spelling(argument_info.type)
|
|
405
|
+
when :template_argument_integral
|
|
406
|
+
argument_info.source_text || argument_info.value.to_s
|
|
407
|
+
when :template_argument_null_ptr
|
|
408
|
+
argument_info.source_text || "nullptr"
|
|
409
|
+
when :template_argument_template, :template_argument_template_expansion,
|
|
410
|
+
:template_argument_expression, :template_argument_declaration,
|
|
411
|
+
:template_argument_pack
|
|
412
|
+
argument_info.source_text
|
|
413
|
+
end
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
# Collect source-written template arguments that libclang does not expose
|
|
417
|
+
# through the cursor template-argument APIs.
|
|
418
|
+
#
|
|
419
|
+
# Examples:
|
|
420
|
+
# typedef Vec<unsigned char, 2> Vec2b;
|
|
421
|
+
# => ['2']
|
|
422
|
+
#
|
|
423
|
+
# typedef Holder<int, Support::Box> HolderInt;
|
|
424
|
+
# => ['Support::Box']
|
|
425
|
+
#
|
|
426
|
+
# We skip the outer template name itself and any child cursors that are
|
|
427
|
+
# only details of a type argument, such as the `int` parameter cursors
|
|
428
|
+
# inside `void (*)(int, int)`.
|
|
429
|
+
def specialization_template_argument_source_texts(specialization_cursor, template_cursor)
|
|
430
|
+
specialization_cursor.each(false).filter_map do |child|
|
|
431
|
+
next if child.kind == :cursor_namespace_ref
|
|
432
|
+
next if child.kind == :cursor_parm_decl
|
|
433
|
+
next if child.kind == :cursor_type_ref
|
|
434
|
+
next if child.kind == :cursor_template_ref && child.referenced == template_cursor
|
|
435
|
+
|
|
436
|
+
source_text = child.extent.text
|
|
437
|
+
source_offset = child.extent.start.offset
|
|
438
|
+
|
|
439
|
+
if child.kind == :cursor_template_ref
|
|
440
|
+
range = child.reference_name_range([:want_qualifier, :want_template_args, :want_single_piece])
|
|
441
|
+
source_text = range&.text || source_text
|
|
442
|
+
ref = child.referenced
|
|
443
|
+
if ref && !ref.spelling.empty? && ref.spelling != ref.qualified_name
|
|
444
|
+
source_text = @reference_qualifier.replacement_from_name_span(source_text, ref.spelling, ref.qualified_name) || source_text
|
|
445
|
+
end
|
|
446
|
+
else
|
|
447
|
+
source_text = @reference_qualifier.qualify_source_references(child, source_text, source_offset)
|
|
448
|
+
|
|
449
|
+
ref = child.referenced
|
|
450
|
+
if ref &&
|
|
451
|
+
[:cursor_function, :cursor_function_template, :cursor_cxx_method].include?(ref.kind) &&
|
|
452
|
+
!source_text.lstrip.start_with?('&')
|
|
453
|
+
source_text = "&#{source_text}"
|
|
454
|
+
end
|
|
455
|
+
end
|
|
456
|
+
|
|
457
|
+
source_text
|
|
458
|
+
rescue ArgumentError
|
|
459
|
+
child.extent.text
|
|
460
|
+
end
|
|
461
|
+
end
|
|
462
|
+
|
|
463
|
+
def template_param_default(param, argument_cursor: nil, argument_index: nil)
|
|
464
|
+
case param.kind
|
|
465
|
+
when :cursor_non_type_template_parameter
|
|
466
|
+
qualify_template_non_type_default(param)
|
|
467
|
+
when :cursor_template_type_parameter
|
|
468
|
+
specialization_type_default(argument_cursor, argument_index) || qualify_template_type_default(param)
|
|
469
|
+
when :cursor_template_template_parameter
|
|
470
|
+
qualify_template_template_default(param)
|
|
471
|
+
end
|
|
472
|
+
end
|
|
473
|
+
|
|
474
|
+
def specialization_type_default(argument_cursor, argument_index)
|
|
475
|
+
return nil unless argument_cursor && argument_index
|
|
476
|
+
return nil unless argument_cursor.template_argument_kind(argument_index) == :template_argument_type
|
|
477
|
+
|
|
478
|
+
arg_type = argument_cursor.template_argument_type(argument_index)
|
|
479
|
+
return nil if arg_type.kind == :type_invalid
|
|
480
|
+
|
|
481
|
+
@type_speller.type_spelling(arg_type)
|
|
482
|
+
end
|
|
483
|
+
|
|
484
|
+
def qualify_template_type_default(param)
|
|
485
|
+
extracted = @reference_qualifier.extract_default_text(param)
|
|
486
|
+
return nil unless extracted
|
|
487
|
+
|
|
488
|
+
default_text, default_text_offset = extracted
|
|
489
|
+
@reference_qualifier.qualify_source_references(param, default_text, default_text_offset, qualify_decl_refs: false)
|
|
490
|
+
end
|
|
491
|
+
|
|
492
|
+
def qualify_template_non_type_default(param)
|
|
493
|
+
extracted = @reference_qualifier.extract_default_text(param)
|
|
494
|
+
return nil unless extracted
|
|
495
|
+
|
|
496
|
+
default_text, default_text_offset = extracted
|
|
497
|
+
@reference_qualifier.qualify_source_references(param, default_text, default_text_offset)
|
|
498
|
+
end
|
|
499
|
+
|
|
500
|
+
def qualify_template_template_default(param)
|
|
501
|
+
extracted = @reference_qualifier.extract_default_text(param)
|
|
502
|
+
return nil unless extracted
|
|
503
|
+
|
|
504
|
+
default_text, default_text_offset = extracted
|
|
505
|
+
@reference_qualifier.qualify_source_references(param, default_text, default_text_offset, qualify_decl_refs: false)
|
|
506
|
+
end
|
|
507
|
+
|
|
508
|
+
# Collapse one template argument spelling into a Ruby-safe class-name
|
|
509
|
+
# fragment for auto-generated base classes.
|
|
510
|
+
#
|
|
511
|
+
# Examples:
|
|
512
|
+
# 'unsigned char'
|
|
513
|
+
# => 'UnsignedChar'
|
|
514
|
+
#
|
|
515
|
+
# 'void (*)(int, int)'
|
|
516
|
+
# => 'VoidPtrIntInt'
|
|
517
|
+
#
|
|
518
|
+
# 'Support::Box<Support::Tag>'
|
|
519
|
+
# => 'BoxTag'
|
|
520
|
+
def ruby_name_from_template_argument(argument)
|
|
521
|
+
tokens = argument.scan(/::|&&|&|\*|[A-Za-z_]\w*|\d+/)
|
|
522
|
+
|
|
523
|
+
tokens.each_with_index.filter_map do |token, index|
|
|
524
|
+
next_token = tokens[index + 1]
|
|
525
|
+
|
|
526
|
+
case token
|
|
527
|
+
when '::'
|
|
528
|
+
nil
|
|
529
|
+
when '&&'
|
|
530
|
+
'RvalueRef'
|
|
531
|
+
when '&'
|
|
532
|
+
'Ref'
|
|
533
|
+
when '*'
|
|
534
|
+
'Ptr'
|
|
535
|
+
else
|
|
536
|
+
next if next_token == '::'
|
|
537
|
+
|
|
538
|
+
token.camelize
|
|
539
|
+
end
|
|
540
|
+
end.join
|
|
541
|
+
end
|
|
542
|
+
|
|
543
|
+
# Extract the written base instantiation starting at the template name so
|
|
544
|
+
# access specifiers do not leak into the generated spelling.
|
|
545
|
+
#
|
|
546
|
+
# Examples:
|
|
547
|
+
# 'public CallbackBase<Result (*)(Left, Right)>'
|
|
548
|
+
# => ['CallbackBase<Result (*)(Left, Right)>', offset of the C]
|
|
549
|
+
#
|
|
550
|
+
# 'public Support::ForeignBase<T>'
|
|
551
|
+
# => ['ForeignBase<T>', offset of the F]
|
|
552
|
+
def base_specifier_source(base_specifier, base_template_ref)
|
|
553
|
+
base_extent = base_specifier.extent
|
|
554
|
+
source_text = base_extent.text
|
|
555
|
+
source_offset = base_template_ref.extent.start.offset
|
|
556
|
+
start_index = source_offset - base_extent.start.offset
|
|
557
|
+
return nil if start_index.negative? || start_index >= source_text.bytesize
|
|
558
|
+
|
|
559
|
+
[source_text.byteslice(start_index..), source_offset]
|
|
560
|
+
rescue ArgumentError
|
|
561
|
+
nil
|
|
562
|
+
end
|
|
563
|
+
|
|
564
|
+
def balanced_template_suffix(text, start_index)
|
|
565
|
+
return ["", start_index] unless text[start_index] == '<'
|
|
566
|
+
|
|
567
|
+
depth = 0
|
|
568
|
+
index = start_index
|
|
569
|
+
while index < text.length
|
|
570
|
+
case text[index]
|
|
571
|
+
when '<'
|
|
572
|
+
depth += 1
|
|
573
|
+
when '>'
|
|
574
|
+
depth -= 1
|
|
575
|
+
return [text[start_index..index], index + 1] if depth == 0
|
|
576
|
+
end
|
|
577
|
+
index += 1
|
|
578
|
+
end
|
|
579
|
+
|
|
580
|
+
["", start_index]
|
|
581
|
+
end
|
|
582
|
+
end
|
|
583
|
+
end
|
|
584
|
+
end
|
|
585
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// Generated by ruby-bindgen (<%= RubyBindgen::VERSION %>)
|
|
2
|
+
|
|
3
|
+
<%- includes.reject { |inc| inc.include?('.ipp') }.each do |include| -%>
|
|
4
|
+
<%= include %>
|
|
5
|
+
<%- end -%>
|
|
6
|
+
<%- unless incomplete_iterators.empty? -%>
|
|
7
|
+
|
|
8
|
+
// Iterator traits specializations for iterators missing std::iterator_traits
|
|
9
|
+
namespace std
|
|
10
|
+
{
|
|
11
|
+
<%- incomplete_iterators.each do |iterator_name, inference| -%>
|
|
12
|
+
template<>
|
|
13
|
+
struct iterator_traits<<%= iterator_name %>>
|
|
14
|
+
{
|
|
15
|
+
using iterator_category = forward_iterator_tag;
|
|
16
|
+
using value_type = <%= inference.value_type %>;
|
|
17
|
+
using difference_type = ptrdiff_t;
|
|
18
|
+
using pointer = <%= inference.value_type %>*;
|
|
19
|
+
using reference = <%= inference.is_const ? "const #{inference.value_type}&" : "#{inference.value_type}&" %>;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
<%- end -%>
|
|
23
|
+
}
|
|
24
|
+
<%- end -%>
|
|
25
|
+
|
|
26
|
+
using namespace Rice;
|
|
27
|
+
|
|
28
|
+
<%- includes.select { |inc| inc.include?('.ipp') }.each do |include| -%>
|
|
29
|
+
<%= include %>
|
|
30
|
+
<%- end -%>
|
|
31
|
+
<%- if rice_ipp -%>
|
|
32
|
+
#include "<%= rice_ipp %>"
|
|
33
|
+
<%- else -%>
|
|
34
|
+
<%= class_templates %>
|
|
35
|
+
<%- end -%>
|
|
36
|
+
|
|
37
|
+
void <%= init_name %>()
|
|
38
|
+
{
|
|
39
|
+
<%= content %>
|
|
40
|
+
}
|