dub 0.5.1 → 0.6.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.

Potentially problematic release.


This version of dub might be problematic. Click here for more details.

data/History.txt CHANGED
@@ -1,3 +1,12 @@
1
+ == 0.6.0 2010-03-11
2
+
3
+ * 4 enhancements
4
+ * added support for custom tostring methods for classes
5
+ * fixed parsing of templated return types
6
+ * static class methods are now registered in the namespace as Klass_method
7
+ * removing functions and methods with class pointer arguments (could use lists later on)
8
+ * better parsing of complex types (including nested template arguments)
9
+
1
10
  == 0.5.1 2010-03-05
2
11
 
3
12
  * 2 minor enhancements
data/dub.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{dub}
8
- s.version = "0.5.1"
8
+ s.version = "0.6.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Gaspard Bucher"]
12
- s.date = %q{2010-03-05}
12
+ s.date = %q{2010-03-11}
13
13
  s.description = %q{This is a tool to ease the creation of scripting language bindings for a C++ library.
14
14
  It is currently developed to crete the OpenCV bindings for Lua in Rubyk (http://rubyk.org). The generator uses the xml output from Doxygen to avoid parsing C++ code by itself.}
15
15
  s.email = %q{gaspard@teti.ch}
@@ -148,6 +148,7 @@ Gem::Specification.new do |s|
148
148
  "test/fixtures/app/xml/namespacedub.xml",
149
149
  "test/fixtures/classcv_1_1_mat.xml",
150
150
  "test/fixtures/classcv_1_1_point__.xml",
151
+ "test/fixtures/classcv_1_1_scalar__.xml",
151
152
  "test/fixtures/classcv_1_1_size__.xml",
152
153
  "test/fixtures/group___magic_type.xml",
153
154
  "test/fixtures/namespacecv.xml",
data/lib/dub/argument.rb CHANGED
@@ -4,8 +4,8 @@ module Dub
4
4
  class Argument
5
5
  include Dub::EntitiesUnescape
6
6
  attr_reader :name, :default, :function, :xml
7
- attr_accessor :type
8
-
7
+ attr_accessor :type, :is_list, :is_list_count
8
+ TYPE_REGEXP = %r{^\s*(\w+\s+|)(const\s+|)([\w\:]+|\.\.\.)(\s*<(.+)>|)(\s*\*+|\s*&|)$}
9
9
  NUMBER_TYPES = [
10
10
  'float',
11
11
  'double',
@@ -14,6 +14,7 @@ module Dub
14
14
  'uint',
15
15
  'int',
16
16
  'size_t',
17
+ 'time_t',
17
18
  'unsigned int',
18
19
  'uint',
19
20
  'bool',
@@ -141,6 +142,18 @@ module Dub
141
142
  @type == '...'
142
143
  end
143
144
 
145
+ def complex?
146
+ @is_complex
147
+ end
148
+
149
+ def is_list?
150
+ @is_list
151
+ end
152
+
153
+ def is_list_count?
154
+ @is_list_count
155
+ end
156
+
144
157
  def create_type
145
158
  resolve_type if @template_params
146
159
  (is_const? ? 'const ' : '') +
@@ -199,39 +212,32 @@ module Dub
199
212
  end
200
213
 
201
214
  type = type.innerHTML
215
+ type = unescape(type).strip
202
216
 
203
- # Strip CV_EXPORT .....
204
- if type =~ /^([^ ]+)\s+([a-zA-Z_]+.*)$/
205
- if $1 == 'const'
206
- @const = true
207
- end
208
- type = $2
209
- end
217
+ if type =~ TYPE_REGEXP
218
+ res = $~.to_a
210
219
 
211
- # Strip const .....
212
- if type =~ /^const\s+(.+)$/
213
- type = $1.strip
214
- @const = true
215
- end
220
+ if res[1].strip == 'const'
221
+ res[2] = res[1]
222
+ res[1] = ""
223
+ end
216
224
 
217
- # Strip ..... &
218
- if type =~ /^(.+)&amp;$/
219
- type = $1.strip
220
- @ref = true
221
- end
225
+ @const = res[2].strip == 'const'
226
+ @type = res[3]
222
227
 
223
- # Strip ..... *
224
- if type =~ /^(.+)(\*+)\s*$/
225
- type = $1.strip
226
- @pointer = $2
227
- end
228
+ if res[6] == ''
229
+ @pointer = nil
230
+ @res = nil
231
+ elsif res[6] =~ /^\s*(\*+)\s*$/
232
+ @pointer = $1
233
+ else
234
+ @ref = res[6].strip
235
+ end
228
236
 
229
- # Strip .....< ... >
230
- if type =~ /^(.+)\s*&lt;\s*(.+)\s*&gt;/
231
- type = $1.strip
232
- @template_params = $2.split(',').map(&:strip)
237
+ @template_params = res[5] ? res[5].split(',').map(&:strip) : nil
238
+ else
239
+ # ERROR
233
240
  end
234
- @type = type
235
241
  end
236
242
 
237
243
  # Replace something like AUTO_STEP by cv::Mat::AUTO_STEP
@@ -245,21 +251,23 @@ module Dub
245
251
  end
246
252
 
247
253
  def resolve_type
254
+ params = @template_params
255
+ @template_params = nil
248
256
  if container = @function.parent
249
257
  if container.kind_of?(Klass)
250
258
  container = container.parent
251
259
  end
252
260
  if container && tclass = container.template_class(@type)
253
- if instanciation = tclass.instanciations[@template_params]
261
+ if instanciation = tclass.instanciations[params]
254
262
  @type = instanciation.name
255
- else
256
- Dub.logger.warn "Could not resolve templated type #{@type}<#{@template_params.join(', ')}>"
263
+ return
257
264
  end
258
- else
259
- Dub.logger.warn "Could not find class for type #{@type}<#{@template_params.join(', ')}>"
260
265
  end
261
266
  end
262
- @template_params = nil
267
+
268
+ @type = "#{@type}< #{params.join(', ')} >"
269
+ Dub.logger.warn "Could not resolve templated type #{@type}"
270
+ @is_complex = true
263
271
  end
264
272
  end
265
273
  end # Namespace
data/lib/dub/function.rb CHANGED
@@ -11,13 +11,14 @@ module Dub
11
11
  @parent, @name = parent, name
12
12
  @xml, @prefix, @overloaded_index = xml, prefix, overloaded_index
13
13
  parse_xml
14
+ parse_template_params
14
15
  end
15
-
16
+
16
17
  def set_as_constructor
17
18
  @return_value = Argument.new(self, (Hpricot::XML("<type>#{name} *</type>")/''))
18
19
  @is_constructor = true
19
20
  end
20
-
21
+
21
22
  def bind(generator)
22
23
  @gen = generator.function_generator
23
24
  end
@@ -42,6 +43,10 @@ module Dub
42
43
  @is_constructor
43
44
  end
44
45
 
46
+ def static?
47
+ @is_static
48
+ end
49
+
45
50
  alias gen generator
46
51
 
47
52
  def name=(n)
@@ -51,6 +56,14 @@ module Dub
51
56
  end
52
57
  end
53
58
 
59
+ def call_name
60
+ if klass
61
+ static? ? "#{klass.name}::#{name}" : name
62
+ else
63
+ name
64
+ end
65
+ end
66
+
54
67
  def source
55
68
  loc = (@xml/'location').first.attributes
56
69
  "#{loc['file'].split('/')[-3..-1].join('/')}:#{loc['line']}"
@@ -70,10 +83,33 @@ module Dub
70
83
  @has_array_arguments = !@arguments.detect {|a| a.array_suffix }.nil?
71
84
  end
72
85
 
86
+ def has_class_pointer_arguments?
87
+ return @has_class_pointer_arguments if defined?(@has_class_pointer_arguments)
88
+ @has_class_pointer_arguments = !@arguments.detect {|a| !a.is_native? && a.is_pointer? }.nil?
89
+ end
90
+
91
+ def has_complex_arguments?
92
+ return @has_complex_arguments if defined?(@has_complex_arguments)
93
+ @has_complex_arguments = !(@arguments + [@return_value]).compact.detect {|a| a.complex? }.nil?
94
+ end
95
+
73
96
  def vararg?
74
97
  @arguments.last && @arguments.last.vararg?
75
98
  end
76
99
 
100
+ def arg_is_list(list_position, count_position)
101
+ @arguments[list_position ].is_list = true
102
+ @arguments[count_position].is_list_count = true
103
+ end
104
+
105
+ def template?
106
+ !@template_params.nil?
107
+ end
108
+
109
+ def template_params
110
+ @template_params
111
+ end
112
+
77
113
  def inspect
78
114
  "#<Function #{@prefix}_#{@name}(#{@arguments.inspect[1..-2]})>"
79
115
  end
@@ -100,12 +136,24 @@ module Dub
100
136
  end
101
137
 
102
138
  raw_type = (@xml/'/type').innerHTML
139
+
103
140
  if raw_type.strip == ''
104
141
  # no return type
105
142
  else
106
143
  arg = Argument.new(self, (@xml/'/type'))
107
144
  @return_value = arg unless arg.create_type =~ /void\s*$/
108
145
  end
146
+
147
+ @is_static = @xml[:static] == 'yes'
148
+ end
149
+
150
+ def parse_template_params
151
+ template_params = (@xml/'/templateparamlist/param')
152
+ if !template_params.empty?
153
+ @template_params = template_params.map do |param|
154
+ (param/'/type').innerHTML.gsub(/^\s*(typename|class)\s+/,'')
155
+ end
156
+ end
109
157
  end
110
158
  end
111
159
  end # Namespace
@@ -35,10 +35,6 @@ module Dub
35
35
  generator.group(self)
36
36
  end
37
37
 
38
- def name
39
- first.name
40
- end
41
-
42
38
  def method_name(overloaded_index = nil)
43
39
  first.method_name(overloaded_index)
44
40
  end
@@ -63,12 +59,14 @@ module Dub
63
59
  nil
64
60
  end
65
61
 
66
- def prefix
67
- first.prefix
68
- end
69
-
70
62
  def <=>(other)
71
63
  name <=> other.name
72
64
  end
65
+
66
+ private
67
+ def method_missing(method, *args)
68
+ first.send(method, *args)
69
+ end
70
+
73
71
  end
74
72
  end
data/lib/dub/group.rb CHANGED
@@ -6,5 +6,19 @@ module Dub
6
6
  super
7
7
  parse_defines
8
8
  end
9
+
10
+ def arg_is_list(argument_pos, count_pos)
11
+ each do |f|
12
+ f.arg_is_list(argument_pos, count_pos)
13
+ end
14
+ end
15
+
16
+ def members
17
+ if self.generator
18
+ @gen_members ||= self.generator.members_list(super, @ignores)
19
+ else
20
+ super
21
+ end
22
+ end
9
23
  end
10
24
  end
data/lib/dub/klass.rb CHANGED
@@ -8,7 +8,7 @@ module Dub
8
8
  class Klass
9
9
  include MemberExtraction
10
10
  attr_reader :name, :xml, :prefix, :constructor, :alias_names, :enums, :parent, :instanciations
11
- attr_accessor :header
11
+ attr_accessor :header, :string_format, :string_args
12
12
 
13
13
  def initialize(parent, name, xml, prefix = '')
14
14
  @parent, @name, @xml, @prefix = parent, name, xml, prefix
@@ -63,7 +63,7 @@ module Dub
63
63
  end
64
64
 
65
65
  def <=>(other)
66
- name <=> other.name
66
+ (name || "") <=> (other.name || "")
67
67
  end
68
68
 
69
69
  def [](name)
@@ -23,7 +23,11 @@ static int <%= @class.destructor_name %>(lua_State *L) {
23
23
 
24
24
  static int <%= @class.tostring_name %>(lua_State *L) {
25
25
  <%= @class.name %> **userdata = (<%= @class.name %>**)luaL_checkudata(L, 1, <%= @class.id_name.inspect %>);
26
- lua_pushfstring(L, "<%= @class.id_name %>: %p", *userdata);
26
+ <% if @class.string_format %>
27
+ lua_pushfstring(L, "<<%= @class.id_name %>: %p <%= @class.string_format %>>", *userdata, <%= @class.string_args %>);
28
+ <% else %>
29
+ lua_pushfstring(L, "<<%= @class.id_name %>: %p>", *userdata);
30
+ <% end %>
27
31
  return 1;
28
32
  }
29
33
 
@@ -56,7 +60,7 @@ static const struct lua_constants_Reg <%= @class.name %>_namespace_constants[] =
56
60
 
57
61
  void luaopen_<%= @class.lib_name %>(lua_State *L) {
58
62
  // Create the metatable which will contain all the member methods
59
- luaL_newmetatable(L, <%= @class.id_name.inspect %>); // "dub.Matrix"
63
+ luaL_newmetatable(L, <%= @class.id_name.inspect %>);
60
64
 
61
65
  // metatable.__index = metatable (find methods in the table itself)
62
66
  lua_pushvalue(L, -1);
@@ -65,7 +69,7 @@ void luaopen_<%= @class.lib_name %>(lua_State *L) {
65
69
  // register member methods
66
70
  luaL_register(L, NULL, <%= @class.name %>_member_methods);
67
71
 
68
- // register class methods in a global table like "dub"
72
+ // register class methods in a global namespace table
69
73
  luaL_register(L, <%= @class.prefix.inspect %>, <%= @class.name %>_namespace_methods);
70
74
 
71
75
  <% if @class.has_constants? %>
@@ -20,8 +20,9 @@ module Dub
20
20
 
21
21
  def method_registration(klass = @class)
22
22
  member_methods = (klass.members || []).map do |method|
23
+ next if method.static?
23
24
  "{%-20s, #{method.method_name(0)}}" % method.name.inspect
24
- end
25
+ end.compact
25
26
 
26
27
  member_methods << "{%-20s, #{klass.tostring_name}}" % "__tostring".inspect
27
28
  member_methods << "{%-20s, #{klass.destructor_name}}" % "__gc".inspect
@@ -29,10 +30,17 @@ module Dub
29
30
  member_methods.join(",\n")
30
31
  end
31
32
 
32
- def namespace_methods_registration
33
- @class.names.map do |name|
34
- "{%-20s, #{@class.constructor.method_name(0)}}" % name.inspect
35
- end.join(",\n")
33
+ def namespace_methods_registration(klass = @class)
34
+ global_methods = klass.names.map do |name|
35
+ "{%-20s, #{klass.constructor.method_name(0)}}" % name.inspect
36
+ end
37
+
38
+ (klass.members || []).map do |method|
39
+ next unless method.static?
40
+ global_methods << "{%-20s, #{method.method_name(0)}}" % "#{klass.name}_#{method.name}".inspect
41
+ end
42
+
43
+ global_methods.join(",\n")
36
44
  end
37
45
 
38
46
  def constants_registration(klass = @class)
@@ -61,10 +69,10 @@ module Dub
61
69
  def ignore_member?(member)
62
70
  if member.name =~ /^~/ || # do not build constructor
63
71
  member.name =~ /^operator/ || # no conversion operators
64
- member.original_signature =~ />/ || # no complex types in signature
72
+ member.has_complex_arguments? || # no complex arguments or return values
65
73
  member.has_array_arguments? ||
66
74
  member.vararg? ||
67
- member.original_signature =~ /void\s+\*/
75
+ member.original_signature =~ /void\s+\*/ # used to detect return value and parameters
68
76
  true # ignore
69
77
  elsif return_value = member.return_value
70
78
  return_value.type =~ />$/ || # no complex return types
@@ -4,9 +4,10 @@ require 'erb'
4
4
  module Dub
5
5
  module Lua
6
6
  class FunctionGen < Dub::Generator
7
- FLOAT_TYPES = [
7
+ NUMBER_TYPES = [
8
8
  'float',
9
9
  'double',
10
+ 'time_t',
10
11
  ]
11
12
 
12
13
  INT_TYPES = [
@@ -29,7 +30,11 @@ module Dub
29
30
  # Produce bindings for a group of overloaded functions
30
31
  def group(group)
31
32
  @group = group
32
- @group_template.result(binding)
33
+ if @group.members
34
+ @group_template.result(binding)
35
+ else
36
+ ''
37
+ end
33
38
  end
34
39
 
35
40
  def function(function)
@@ -45,6 +50,17 @@ module Dub
45
50
  Dub::Lua.namespace_generator
46
51
  end
47
52
 
53
+ def chooser_body(group = @group)
54
+ decision_tree = Argument.decision_tree(group.members)
55
+ res = []
56
+ res << "int type__ = lua_type(L, 1);"
57
+ if flatten_hash(decision_tree).include?(nil)
58
+ res << "int top__ = lua_gettop(L);"
59
+ end
60
+ res << switch(decision_tree)
61
+ res.join("\n")
62
+ end
63
+
48
64
  # Create a switch to choose the correct method from argument types (overloaded functions)
49
65
  def switch(hash_or_function, depth = 1)
50
66
  if hash_or_function.kind_of?(Function)
@@ -62,7 +78,7 @@ module Dub
62
78
  when :string
63
79
  res << "#{else_prefix}if (type__ == LUA_TSTRING) {"
64
80
  when nil
65
- res << "#{else_prefix}if (type__ == LUA_TNONE) {"
81
+ res << "#{else_prefix}if (top__ < #{depth}) {"
66
82
  else
67
83
  res << "#{else_prefix}if (type__ == LUA_TUSERDATA && is_userdata(L, #{depth}, \"#{type}\")) {"
68
84
  end
@@ -89,7 +105,7 @@ module Dub
89
105
  def body(func)
90
106
  res = []
91
107
 
92
- if func.member_method? && !func.constructor?
108
+ if func.member_method? && !func.constructor? && !func.static?
93
109
  klass = func.parent
94
110
  res << "#{klass.name} *self__ = *((#{klass.name}**)luaL_checkudata(L, 1, #{klass.id_name.inspect}));"
95
111
  res << "lua_remove(L, 1);"
@@ -132,16 +148,17 @@ module Dub
132
148
  "return #{method_name(func)}(L);"
133
149
  end
134
150
 
135
- def call_string(func, upto_arg)
151
+ def call_string(func, upto_arg = nil)
152
+ upto_arg ||= func.arguments.count
136
153
  if upto_arg == 0
137
- call_string = "#{func.name}();"
154
+ call_string = "#{func.call_name}();"
138
155
  else
139
- call_string = "#{func.name}(#{func.arguments[0..(upto_arg-1)].map{|arg| arg.in_call_type}.join(', ')});"
156
+ call_string = "#{func.call_name}(#{func.arguments[0..(upto_arg-1)].map{|arg| arg.in_call_type}.join(', ')});"
140
157
  end
141
158
 
142
159
  if func.constructor?
143
160
  call_string = "new #{call_string}"
144
- elsif func.member_method?
161
+ elsif func.member_method? && !func.static?
145
162
  call_string = "self__->#{call_string}"
146
163
  end
147
164
 
@@ -198,7 +215,7 @@ module Dub
198
215
  "#{type_def} = ptr_#{arg.name}(L, #{stack_pos});"
199
216
  end
200
217
  else
201
- if FLOAT_TYPES.include?(arg.type)
218
+ if NUMBER_TYPES.include?(arg.type)
202
219
  "#{type_def} = luaL_checknumber(L, #{stack_pos});"
203
220
  elsif BOOL_TYPES.include?(arg.type)
204
221
  "#{type_def} = lua_toboolean(L, #{stack_pos});"
@@ -214,12 +231,15 @@ module Dub
214
231
  end
215
232
 
216
233
  def flatten_hash(hash)
234
+ list = []
217
235
  hash.each do |k, v|
218
236
  if v.kind_of?(Hash)
219
- hash[k] = flatten_hash(v)
237
+ list << [k, flatten_hash(v)]
238
+ else
239
+ list << [k, v]
220
240
  end
221
241
  end
222
- hash.to_a.flatten
242
+ list.flatten
223
243
  end
224
244
 
225
245
  end # FunctionGen
@@ -5,6 +5,5 @@
5
5
 
6
6
  /** Overloaded function chooser for <%= @group.name %>(...) */
7
7
  <%= signature(@group.first, 0) %> {
8
- int type__ = lua_type(L, 1);
9
- <%= indent(switch(Argument.decision_tree(@group.members)), 2) %>
8
+ <%= indent(chooser_body, 2) %>
10
9
  }
@@ -50,7 +50,7 @@ module Dub
50
50
  end
51
51
 
52
52
  def members_list(all_members, ignore_list = [])
53
- list = all_members.map do |member_or_group|
53
+ list = (all_members || []).map do |member_or_group|
54
54
  if ignore_list.include?(member_or_group.name)
55
55
  nil
56
56
  elsif member_or_group.kind_of?(Array)
@@ -72,7 +72,9 @@ module Dub
72
72
  member.original_signature =~ />/ || # no complex types in signature
73
73
  member.has_array_arguments? ||
74
74
  member.vararg? ||
75
- member.original_signature =~ /void\s+\*/
75
+ member.original_signature =~ /void\s+\*/ ||
76
+ member.has_class_pointer_arguments?
77
+
76
78
  true # ignore
77
79
  elsif return_value = member.return_value
78
80
  return_value.type =~ />$/ || # no complex return types
@@ -17,7 +17,7 @@ module Dub
17
17
  @t_members_hash = {}
18
18
  # TODO: template functions
19
19
  (@xml/'memberdef').each do |member|
20
- Dub.logger.info "Parsing #{member.name}"
20
+ Dub.logger.info "Parsing #{(member/'name').innerHTML}"
21
21
  name = (member/"name").innerHTML
22
22
  if (member/'templateparamlist').first
23
23
  insert_member(member, name, @t_members_hash)
@@ -38,7 +38,7 @@ module Dub
38
38
  end
39
39
 
40
40
  def member(name)
41
- get_member(name.to_s)
41
+ get_member(name.to_s, @members_hash)
42
42
  end
43
43
 
44
44
  def members
@@ -52,9 +52,13 @@ module Dub
52
52
  end
53
53
  end
54
54
 
55
+ def template_method(name)
56
+ get_member(name.to_s, @t_members_hash)
57
+ end
58
+
55
59
  # Lazy construction of members
56
- def get_member(name)
57
- if member_or_group = @members_hash[name]
60
+ def get_member(name, source = @members_hash)
61
+ if member_or_group = source[name]
58
62
  if member_or_group.kind_of?(Array)
59
63
  if member_or_group.first.kind_of?(Hpricot::Elem)
60
64
  list = Dub::FunctionGroup.new(self)
@@ -65,7 +69,7 @@ module Dub
65
69
  member_or_group = nil if member_or_group == []
66
70
  end
67
71
  elsif member_or_group.kind_of?(Hpricot::Elem)
68
- @members_hash[name] = member_or_group = make_member(name, member_or_group)
72
+ source[name] = member_or_group = make_member(name, member_or_group)
69
73
  end
70
74
  end
71
75
  member_or_group
data/lib/dub/namespace.rb CHANGED
@@ -197,7 +197,8 @@ module Dub
197
197
  old_name = (ref_class/'/compoundname').first.innerHTML.gsub(/^.*::/,'')
198
198
 
199
199
  # replace class name
200
- class_def = ref_class.to_s.gsub(/#{old_name}&lt;.*?&gt;::/,"#{new_name}::")
200
+ # <type><ref refid="classcv_1_1_scalar__" kindref="compound">Scalar_</ref>&lt; _Tp &gt;</type>
201
+ class_def = ref_class.to_s.gsub(/<ref .*>#{old_name}<\/ref>&lt;.*?&gt;/, new_name)
201
202
  class_def = class_def.gsub(/#{old_name}/, new_name)
202
203
 
203
204
  # replace template types
@@ -220,7 +221,7 @@ module Dub
220
221
  class_xml = (Hpricot::XML(class_def)/'compounddef').first
221
222
 
222
223
  (class_xml/'*[@prot=private]').remove
223
- (class_xml/'templateparamlist').remove
224
+ (class_xml/'/templateparamlist').remove
224
225
  (class_xml/'').append("<originaltemplate>#{old_name}</originaltemplate>")
225
226
  (ref_class/'').append("<instanciation><name>#{new_name}</name><param>#{instanciations_params.join('</param><param>')}</param></instanciation>")
226
227
 
data/lib/dub/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Dub
2
- VERSION = '0.5.1'
2
+ VERSION = '0.6.0'
3
3
  end