Class: RubyBindgen::Generators::Rice::TypeSpeller
- Inherits:
-
Object
- Object
- RubyBindgen::Generators::Rice::TypeSpeller
- Defined in:
- lib/ruby-bindgen/generators/rice/type_speller.rb
Overview
Builds fully qualified C++ type spellings for generated Rice code and applies the extra template/class qualification rules that libclang does not handle on its own for emitted binding code.
Instance Attribute Summary collapse
-
#printing_policy ⇒ Object
writeonly
Sets the attribute printing_policy.
Instance Method Summary collapse
- #clear ⇒ Object
-
#initialize(type_index:) ⇒ TypeSpeller
constructor
A new instance of TypeSpeller.
- #preserve_template_parameter_names(spelling, template_cursor) ⇒ Object
-
#qualified_class_name(cursor) ⇒ Object
Get the fully qualified class/struct type used in generated bindings.
-
#qualified_display_name(cursor) ⇒ Object
Get qualified display name for a cursor.
-
#qualify_class_static_members(spelling, class_cursor) ⇒ Object
Qualify bare class members used as non-type template args.
-
#qualify_class_template_typedefs(spelling, class_template) ⇒ Object
Qualify nested typedefs from a class template in a type spelling e.g., “std::reverse_iterator<iterator>” -> “std::reverse_iterator<cv::Mat_<_Tp>::iterator>”.
-
#type_spelling(type) ⇒ Object
Returns a fully-qualified C++ type spelling suitable for use in generated Rice bindings.
- #type_spellings(cursor) ⇒ Object
Constructor Details
#initialize(type_index:) ⇒ TypeSpeller
Returns a new instance of TypeSpeller.
12 13 14 15 |
# File 'lib/ruby-bindgen/generators/rice/type_speller.rb', line 12 def initialize(type_index:) @type_index = type_index clear end |
Instance Attribute Details
#printing_policy=(value) ⇒ Object (writeonly)
Sets the attribute printing_policy
10 11 12 |
# File 'lib/ruby-bindgen/generators/rice/type_speller.rb', line 10 def printing_policy=(value) @printing_policy = value end |
Instance Method Details
#clear ⇒ Object
17 18 19 20 |
# File 'lib/ruby-bindgen/generators/rice/type_speller.rb', line 17 def clear @class_template_typedefs = {} @class_static_members = {} end |
#preserve_template_parameter_names(spelling, template_cursor) ⇒ Object
207 208 209 210 211 212 213 214 215 216 217 218 |
# File 'lib/ruby-bindgen/generators/rice/type_speller.rb', line 207 def preserve_template_parameter_names(spelling, template_cursor) return spelling unless template_cursor&.kind == :cursor_class_template result = spelling.dup template_parameter_names(template_cursor).each do |name| qualified_name = @type_index.qualified_name_for(name) next if qualified_name.nil? || qualified_name == name result = result.gsub(/(?<![:\w])#{Regexp.escape(qualified_name)}(?![:\w])/, name) end result end |
#qualified_class_name(cursor) ⇒ Object
Get the fully qualified class/struct type used in generated bindings.
Examples:
outer::Locale::Facet<Locale>
becomes
outer::Locale::Facet<outer::Locale>
This goes through type_spelling(cursor.type) instead of cursor-specific string surgery. A class cursor’s first child can be an unrelated type_ref, which makes first-match substitution double-qualify nested specializations like outer::outer::Locale::Facet<outer::Locale>.
33 34 35 |
# File 'lib/ruby-bindgen/generators/rice/type_speller.rb', line 33 def qualified_class_name(cursor) type_spelling(cursor.type) end |
#qualified_display_name(cursor) ⇒ Object
Get qualified display name for a cursor. Qualifies any template arguments that need namespace prefixes. Used for generating fully qualified names in enum constants, etc.
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/ruby-bindgen/generators/rice/type_speller.rb', line 40 def qualified_display_name(cursor) if cursor&.kind == :cursor_class_template template_arguments = template_parameter_arguments(cursor) return "#{cursor.qualified_name}<#{template_arguments.join(', ')}>" unless template_arguments.empty? end display_name = qualify_template_parameter_packs(cursor.qualified_display_name, cursor) # For members of template specializations, use the parent's type for qualification # e.g., TypeTraits<lowercase_type>::type needs lowercase_type qualified, # but cursor.type is just 'const int' which has no template args type = cursor.type parent = cursor.semantic_parent if parent && parent.type.num_template_arguments > 0 type = parent.type end qualify_template_args(display_name, type, ignored_names: template_parameter_names(cursor)) end |
#qualify_class_static_members(spelling, class_cursor) ⇒ Object
Qualify bare class members used as non-type template args. Within a class like GPCPatchDescriptor, a member can write Vec<double, nFeatures> but the generated binding code is outside the class, so it needs Vec<double, GPCPatchDescriptor::nFeatures>. qualify_template_args then handles qualifying GPCPatchDescriptor to cv::optflow::GPCPatchDescriptor.
Unscoped enum constants need the same treatment:
FixedBuffer<int, Size>
becomes
FixedBuffer<int, Tests::EnumSized<N>::Size>
Class templates need their template parameters preserved:
FixedBuffer<int, Size>
becomes
FixedBuffer<int, Tests::StaticSized<N>::Size>
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 |
# File 'lib/ruby-bindgen/generators/rice/type_speller.rb', line 161 def qualify_class_static_members(spelling, class_cursor) return spelling unless class_cursor parent_kind = class_cursor.kind return spelling unless parent_kind == :cursor_class_decl || parent_kind == :cursor_struct || parent_kind == :cursor_class_template cache_key = class_cursor.usr member_info = @class_static_members[cache_key] ||= begin names = [] class_cursor.each(false) do |child| if child.kind == :cursor_variable names << child.spelling elsif child.kind == :cursor_enum_decl && !child.enum_scoped? child.each(false) do |enum_child| names << enum_child.spelling if enum_child.kind == :cursor_enum_constant_decl end end end qualified_parent = if parent_kind == :cursor_class_template qualified_display_name(class_cursor) else class_cursor.qualified_name end { names: names, qualified_parent: qualified_parent } end return spelling if member_info[:names].empty? result = spelling.dup qualified_parent = member_info[:qualified_parent] display_name = class_cursor.display_name member_info[:names].each do |name| if display_name && !display_name.empty? && display_name != qualified_parent partially_qualified = /(?<![:\w])#{Regexp.escape(display_name)}::#{Regexp.escape(name)}(?![:\w])/ result = result.gsub(partially_qualified, "#{qualified_parent}::#{name}") end unqualified = /(?<![:\w])#{Regexp.escape(name)}(?![:\w])/ result = result.gsub(unqualified, "#{qualified_parent}::#{name}") end result end |
#qualify_class_template_typedefs(spelling, class_template) ⇒ Object
Qualify nested typedefs from a class template in a type spelling e.g., “std::reverse_iterator<iterator>” -> “std::reverse_iterator<cv::Mat_<_Tp>::iterator>”
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
# File 'lib/ruby-bindgen/generators/rice/type_speller.rb', line 97 def qualify_class_template_typedefs(spelling, class_template) return spelling unless class_template&.kind == :cursor_class_template cache_key = class_template.usr typedef_info = @class_template_typedefs[cache_key] ||= begin names = [] class_template.each(false) do |child| child_kind = child.kind if child_kind == :cursor_typedef_decl || child_kind == :cursor_type_alias_decl names << child.spelling end end { names: names, qualified_parent: class_template.qualified_display_name } end return spelling if typedef_info[:names].empty? result = spelling.dup qualified_parent = typedef_info[:qualified_parent] qualified_name = class_template.qualified_name display_name = class_template.display_name simple_name = class_template.spelling typedef_info[:names].each do |name| fully_qualified = /(?<![:\w])(?:typename\s+)?#{Regexp.escape(qualified_parent)}::#{Regexp.escape(name)}(?![:\w])/ result = result.gsub(fully_qualified, "typename #{qualified_parent}::#{name}") if qualified_name && !qualified_name.empty? && qualified_name != qualified_parent qualified_without_args = /(?<![:\w])#{Regexp.escape(qualified_name)}::#{Regexp.escape(name)}(?![:\w])/ result = result.gsub(qualified_without_args, "typename #{qualified_parent}::#{name}") end if display_name && !display_name.empty? && display_name != qualified_parent partially_qualified = /(?<![:\w])#{Regexp.escape(display_name)}::#{Regexp.escape(name)}(?![:\w])/ result = result.gsub(partially_qualified, "typename #{qualified_parent}::#{name}") end if simple_name && !simple_name.empty? uninstantiated_class = /(?<![:\w])#{Regexp.escape(simple_name)}::#{Regexp.escape(name)}(?![:\w])/ result = result.gsub(uninstantiated_class, "typename #{qualified_parent}::#{name}") end unqualified = /(?<![:\w])#{Regexp.escape(name)}(?![:\w])/ result = result.gsub(unqualified, "typename #{qualified_parent}::#{name}") end result end |
#type_spelling(type) ⇒ Object
Returns a fully-qualified C++ type spelling suitable for use in generated Rice bindings. Most type kinds are handled by Type#fully_qualified_name. This method only intercepts declared types that need generator-level context:
-
Class template types: fqn resolves template params, but template builders need them generic
-
Typedefs inside class templates: need ‘typename’ keyword for dependent types
-
Template instantiations: need qualify_template_args post-processing with TypeIndex
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/ruby-bindgen/generators/rice/type_speller.rb', line 72 def type_spelling(type) case type.kind when :type_pointer type_spelling_pointer(type) when :type_lvalue_ref "#{type_spelling(type.non_reference_type)} &" when :type_rvalue_ref "#{type_spelling(type.non_reference_type)} &&" when :type_constant_array "#{type_spelling(type.element_type)}[#{type.size}]" when :type_incomplete_array "#{type_spelling(type.element_type)}[]" when :type_elaborated type_spelling_declared(type) when :type_typedef type_spelling_declared(type) when :type_unexposed type_spelling_unexposed(type) else type.fully_qualified_name(@printing_policy) end end |
#type_spellings(cursor) ⇒ Object
60 61 62 63 64 |
# File 'lib/ruby-bindgen/generators/rice/type_speller.rb', line 60 def type_spellings(cursor) cursor.type.arg_types.map do |arg_type| type_spelling(arg_type) end end |