rbind 0.0.1 → 0.0.2
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.
- data/lib/rbind/core.rb +1 -0
- data/lib/rbind/core/rnamespace.rb +4 -5
- data/lib/rbind/core/rvector.rb +27 -0
- data/lib/rbind/default_parser.rb +4 -2
- data/lib/rbind/generator_c.rb +3 -1
- data/lib/rbind/generator_ruby.rb +5 -3
- data/lib/rbind/logger.rb +1 -0
- data/lib/rbind/rbind.rb +59 -0
- data/lib/rbind/templates/ruby/rbind.rb +7 -1
- data/lib/rbind/tools/hdr_parser.py +870 -0
- data/rbind.gemspec +1 -1
- metadata +21 -32
- data/lib/rbind/.default_parser.rb.swp +0 -0
- data/lib/rbind/.generator_c.rb.swp +0 -0
- data/lib/rbind/core/.rbase.rb.swp +0 -0
- data/lib/rbind/core/.rclass.rb.swp +0 -0
- data/lib/rbind/core/.rdata_type.rb.swp +0 -0
data/lib/rbind/core.rb
CHANGED
@@ -4,7 +4,7 @@ module Rbind
|
|
4
4
|
class << self
|
5
5
|
attr_accessor :default_type_names
|
6
6
|
end
|
7
|
-
self.default_type_names = [:int,:int64,:bool,:double,:float,:void,:char,:size_t]
|
7
|
+
self.default_type_names = [:uint64,:int,:int64,:bool,:double,:float,:void,:char,:size_t]
|
8
8
|
|
9
9
|
attr_reader :operations
|
10
10
|
attr_reader :operation_alias
|
@@ -121,11 +121,11 @@ module Rbind
|
|
121
121
|
op.alias
|
122
122
|
elsif op.alias
|
123
123
|
name = "#{op.alias}#{@operations[op.name].size+1}"
|
124
|
-
::Rbind.log.
|
124
|
+
::Rbind.log.debug "name clash: aliasing #{op.alias} --> #{name}"
|
125
125
|
name
|
126
126
|
else
|
127
127
|
name = "#{op.name}#{@operations[op.name].size+1}"
|
128
|
-
::Rbind.log.
|
128
|
+
::Rbind.log.debug "name clash: #{op.name} --> #{name}"
|
129
129
|
name
|
130
130
|
end
|
131
131
|
@operations[op.name] << op
|
@@ -142,7 +142,7 @@ module Rbind
|
|
142
142
|
current_type = if temp
|
143
143
|
temp
|
144
144
|
else
|
145
|
-
::Rbind.log.
|
145
|
+
::Rbind.log.debug "missing namespace: add #{current_type.full_name unless current_type.root?}::#{name}"
|
146
146
|
current_type.add_type(RNamespace.new(name))
|
147
147
|
end
|
148
148
|
end
|
@@ -167,7 +167,6 @@ module Rbind
|
|
167
167
|
def add_default_types
|
168
168
|
add_simple_types RNamespace.default_type_names
|
169
169
|
add_type ::Rbind::RDataType.new("uchar").cname("unsigned char")
|
170
|
-
add_type ::Rbind::RDataType.new("uint64").typedef("unsigned long long")
|
171
170
|
add_type ::Rbind::RDataType.new("c_string").cname("char *")
|
172
171
|
add_type ::Rbind::RDataType.new("const_c_string").cname("const char *")
|
173
172
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Rbind
|
2
|
+
class RVector < RStruct
|
3
|
+
def initialize(name,root,type)
|
4
|
+
@vector_type = type
|
5
|
+
super(name)
|
6
|
+
add_operation ROperation.new(self.name,nil)
|
7
|
+
add_operation ROperation.new(self.name,nil,RParameter.new("other",self))
|
8
|
+
|
9
|
+
para = Array.new
|
10
|
+
para << RParameter.new("size",root.type("size_t"))
|
11
|
+
para << RParameter.new("val",type).default_value(type.full_name)
|
12
|
+
add_operation ROperation.new("resize",root.type("void"),para)
|
13
|
+
add_operation ROperation.new("size",root.type("size_t"))
|
14
|
+
add_operation ROperation.new("capacity",root.type("size_t"))
|
15
|
+
add_operation ROperation.new("empty",root.type("bool"))
|
16
|
+
add_operation ROperation.new("reserve",root.type("void"),RParameter.new("size",root.type("size_t")))
|
17
|
+
add_operation ROperation.new("operator[]",type,RParameter.new("size",root.type("size_t")))
|
18
|
+
add_operation ROperation.new("at",type,RParameter.new("size",root.type("size_t")))
|
19
|
+
add_operation ROperation.new("front",type)
|
20
|
+
add_operation ROperation.new("back",type)
|
21
|
+
add_operation ROperation.new("data",root.type("void *"))
|
22
|
+
add_operation ROperation.new("push_back",root.type("void"),RParameter.new("other",type))
|
23
|
+
add_operation ROperation.new("pop_back",root.type("void"))
|
24
|
+
add_operation ROperation.new("swap",root.type("void"),RParameter.new("other",self).add_flag(:IO))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/rbind/default_parser.rb
CHANGED
@@ -13,7 +13,7 @@ module Rbind
|
|
13
13
|
def normalize_flags(line_number,flags)
|
14
14
|
flags.map do |flag|
|
15
15
|
if flag =~ /(\w*)(.*)/
|
16
|
-
DefaultParser.log.
|
16
|
+
DefaultParser.log.debug "input line #{line_number}: ignoring flag #{$2}" unless $2.empty?
|
17
17
|
$1.to_sym
|
18
18
|
else
|
19
19
|
raise "cannot parse flag #{flag.inspect}"
|
@@ -113,7 +113,9 @@ module Rbind
|
|
113
113
|
parents = a[1]
|
114
114
|
parent_classes = if parents
|
115
115
|
parents.split(", ").map do |name|
|
116
|
-
type(RBase.normalize(name),
|
116
|
+
t = type(RBase.normalize(name),false)
|
117
|
+
# auto add parent class
|
118
|
+
t ||= add_type(RClass.new(RBase.normalize(name)))
|
117
119
|
end
|
118
120
|
end
|
119
121
|
t = RClass.new(name,*parent_classes)
|
data/lib/rbind/generator_c.rb
CHANGED
@@ -291,6 +291,7 @@ module Rbind
|
|
291
291
|
attr_accessor :library_name
|
292
292
|
attr_accessor :pkg_config
|
293
293
|
attr_accessor :generate_cmake
|
294
|
+
attr_accessor :output_path
|
294
295
|
|
295
296
|
def initialize(root,library_name)
|
296
297
|
raise "wrong type #{root}" unless root.is_a? RNamespace
|
@@ -310,7 +311,8 @@ module Rbind
|
|
310
311
|
@generate_cmake = true
|
311
312
|
end
|
312
313
|
|
313
|
-
def generate(path =
|
314
|
+
def generate(path = @output_path)
|
315
|
+
@output_path = path
|
314
316
|
FileUtils.mkdir_p(path) if path && !File.directory?(path)
|
315
317
|
file_types_hdr = File.new(File.join(path,"types.h"),"w")
|
316
318
|
file_types = File.new(File.join(path,"types.cc"),"w")
|
data/lib/rbind/generator_ruby.rb
CHANGED
@@ -31,7 +31,7 @@ module Rbind
|
|
31
31
|
elsif parameter.type.name == "double"
|
32
32
|
parameter.default_value.gsub(/\.$/,".0")
|
33
33
|
else
|
34
|
-
parameter.default_value
|
34
|
+
normalize_type_name(parameter.default_value)
|
35
35
|
end
|
36
36
|
else
|
37
37
|
if(parameter.default_value =~ /(\w*)\((.*)\)/)
|
@@ -282,7 +282,7 @@ module Rbind
|
|
282
282
|
|
283
283
|
def add_consts
|
284
284
|
@root.consts.map do |c|
|
285
|
-
" #{c.name} = #{c.value}\n"
|
285
|
+
" #{c.name} = #{GeneratorRuby::normalize_type_name(c.value)}\n"
|
286
286
|
end.join
|
287
287
|
end
|
288
288
|
|
@@ -333,6 +333,7 @@ module Rbind
|
|
333
333
|
|
334
334
|
attr_accessor :module_name
|
335
335
|
attr_accessor :library_name
|
336
|
+
attr_accessor :output_path
|
336
337
|
|
337
338
|
|
338
339
|
def initialize(root,module_name ="Rbind",library_name="rbind_lib")
|
@@ -342,7 +343,8 @@ module Rbind
|
|
342
343
|
@library_name = library_name
|
343
344
|
end
|
344
345
|
|
345
|
-
def generate(path
|
346
|
+
def generate(path=@output_path)
|
347
|
+
@output_path = path
|
346
348
|
FileUtils.mkdir_p(path) if path && !File.directory?(path)
|
347
349
|
file_rbind = File.new(File.join(path,"opencv.rb"),"w")
|
348
350
|
file_types = File.new(File.join(path,"opencv_types.rb"),"w")
|
data/lib/rbind/logger.rb
CHANGED
data/lib/rbind/rbind.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'open3'
|
2
|
+
|
1
3
|
module Rbind
|
2
4
|
class Rbind
|
3
5
|
attr_accessor :parser
|
@@ -23,16 +25,73 @@ module Rbind
|
|
23
25
|
end
|
24
26
|
end
|
25
27
|
|
28
|
+
def check_python
|
29
|
+
out = IO.popen("which python")
|
30
|
+
if(out.read.empty?)
|
31
|
+
raise 'Cannot find python interpreter needed for parsing header files'
|
32
|
+
end
|
33
|
+
in_,out,err = Open3.popen3("python --version")
|
34
|
+
str = err.read
|
35
|
+
str = if str.empty?
|
36
|
+
out.read
|
37
|
+
else
|
38
|
+
str
|
39
|
+
end
|
40
|
+
if(str =~ /[a-zA-Z]* (.*)/)
|
41
|
+
if $1.to_f < 2.7
|
42
|
+
raise "Wrong python version #{$1}. At least python 2.7 is needed for parsing header files"
|
43
|
+
end
|
44
|
+
else
|
45
|
+
raise 'Cannot determine python version needed for parsing header files'
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def parse_headers(*headers)
|
50
|
+
::Rbind.log.info "parse header files"
|
51
|
+
check_python
|
52
|
+
headers = if headers.empty?
|
53
|
+
includes
|
54
|
+
else
|
55
|
+
headers
|
56
|
+
end
|
57
|
+
headers = headers.map do |h|
|
58
|
+
"\"#{h}\""
|
59
|
+
end
|
60
|
+
path = File.join(File.dirname(__FILE__),'tools','hdr_parser.py')
|
61
|
+
out = IO.popen("python #{path} #{headers.join(" ")}")
|
62
|
+
parser.parse out.read
|
63
|
+
end
|
64
|
+
|
65
|
+
def build
|
66
|
+
::Rbind.log.info "build c wrappers"
|
67
|
+
path = File.join(generator_c.output_path,"build")
|
68
|
+
FileUtils.mkdir_p(path) if path && !File.directory?(path)
|
69
|
+
Dir.chdir(path) do
|
70
|
+
if !system("cmake -C ..")
|
71
|
+
raise "CMake Configure Error"
|
72
|
+
end
|
73
|
+
if !system("make")
|
74
|
+
raise "Make Build Error"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
if !system("cp #{File.join(path,"lib*.*")} #{generator_ruby.output_path}")
|
78
|
+
raise "cannot copy library to #{generator_ruby.output_path}"
|
79
|
+
end
|
80
|
+
::Rbind.log.info "all done !"
|
81
|
+
end
|
82
|
+
|
26
83
|
def generate(c_path = "src",ruby_path = "ruby/lib/#{name.downcase}")
|
27
84
|
generate_c c_path
|
28
85
|
generate_ruby ruby_path
|
29
86
|
end
|
30
87
|
|
31
88
|
def generate_ruby(path)
|
89
|
+
::Rbind.log.info "generate ruby ffi wrappers"
|
32
90
|
@generator_ruby.generate(path)
|
33
91
|
end
|
34
92
|
|
35
93
|
def generate_c(path)
|
94
|
+
::Rbind.log.info "generate c wrappers"
|
36
95
|
@generator_c.includes = includes
|
37
96
|
@generator_c.pkg_config = pkg_config
|
38
97
|
@generator_c.generate(path)
|
@@ -5,7 +5,13 @@ module <%= name %>
|
|
5
5
|
# low level accessors the wrapped library
|
6
6
|
module Rbind
|
7
7
|
extend FFI::Library
|
8
|
-
|
8
|
+
|
9
|
+
#load library <%= library_name %>
|
10
|
+
path = Dir.chdir(File.dirname(__FILE__)) do
|
11
|
+
path = Dir.glob("lib<%= library_name %>.*").first
|
12
|
+
File.absolute_path(path) if path
|
13
|
+
end
|
14
|
+
ffi_lib ["<%= library_name %>", path]
|
9
15
|
|
10
16
|
#add error checking
|
11
17
|
#rbindCreateMatrix -> create_matrix
|
@@ -0,0 +1,870 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
|
3
|
+
import os, sys, re, string
|
4
|
+
|
5
|
+
# the list only for debugging. The real list, used in the real OpenCV build, is specified in CMakeLists.txt
|
6
|
+
opencv_hdr_list = [
|
7
|
+
"../../core/include/opencv2/core.hpp",
|
8
|
+
"../../flann/include/opencv2/flann/miniflann.hpp",
|
9
|
+
"../../ml/include/opencv2/ml.hpp",
|
10
|
+
"../../imgproc/include/opencv2/imgproc.hpp",
|
11
|
+
"../../calib3d/include/opencv2/calib3d.hpp",
|
12
|
+
"../../features2d/include/opencv2/features2d.hpp",
|
13
|
+
"../../video/include/opencv2/video/tracking.hpp",
|
14
|
+
"../../video/include/opencv2/video/background_segm.hpp",
|
15
|
+
"../../objdetect/include/opencv2/objdetect.hpp",
|
16
|
+
"../../contrib/include/opencv2/contrib.hpp",
|
17
|
+
"../../highgui/include/opencv2/highgui.hpp"
|
18
|
+
]
|
19
|
+
|
20
|
+
"""
|
21
|
+
Each declaration is [funcname, return_value_type /* in C, not in Python */, <list_of_modifiers>, <list_of_arguments>],
|
22
|
+
where each element of <list_of_arguments> is 4-element list itself:
|
23
|
+
[argtype, argname, default_value /* or "" if none */, <list_of_modifiers>]
|
24
|
+
where the list of modifiers is yet another nested list of strings
|
25
|
+
(currently recognized are "/O" for output argument, "/S" for static (i.e. class) methods
|
26
|
+
and "/A value" for the plain C arrays with counters)
|
27
|
+
"""
|
28
|
+
|
29
|
+
class CppHeaderParser(object):
|
30
|
+
|
31
|
+
def __init__(self):
|
32
|
+
self.BLOCK_TYPE = 0
|
33
|
+
self.BLOCK_NAME = 1
|
34
|
+
self.PROCESS_FLAG = 2
|
35
|
+
self.PUBLIC_SECTION = 3
|
36
|
+
self.CLASS_DECL = 4
|
37
|
+
|
38
|
+
def batch_replace(self, s, pairs):
|
39
|
+
for before, after in pairs:
|
40
|
+
s = s.replace(before, after)
|
41
|
+
return s
|
42
|
+
|
43
|
+
def get_macro_arg(self, arg_str, npos):
|
44
|
+
npos2 = npos3 = arg_str.find("(", npos)
|
45
|
+
if npos2 < 0:
|
46
|
+
print "Error: no arguments for the macro at %d" % (self.lineno,)
|
47
|
+
sys.exit(-1)
|
48
|
+
balance = 1
|
49
|
+
while 1:
|
50
|
+
t, npos3 = self.find_next_token(arg_str, ['(', ')'], npos3+1)
|
51
|
+
if npos3 < 0:
|
52
|
+
print "Error: no matching ')' in the macro call at %d" % (self.lineno,)
|
53
|
+
sys.exit(-1)
|
54
|
+
if t == '(':
|
55
|
+
balance += 1
|
56
|
+
if t == ')':
|
57
|
+
balance -= 1
|
58
|
+
if balance == 0:
|
59
|
+
break
|
60
|
+
|
61
|
+
return arg_str[npos2+1:npos3].strip(), npos3
|
62
|
+
|
63
|
+
def parse_arg(self, arg_str, argno):
|
64
|
+
"""
|
65
|
+
Parses <arg_type> [arg_name]
|
66
|
+
Returns arg_type, arg_name, modlist, argno, where
|
67
|
+
modlist is the list of wrapper-related modifiers (such as "output argument", "has counter", ...)
|
68
|
+
and argno is the new index of an anonymous argument.
|
69
|
+
That is, if no arg_str is just an argument type without argument name, the argument name is set to
|
70
|
+
"arg" + str(argno), and then argno is incremented.
|
71
|
+
"""
|
72
|
+
modlist = []
|
73
|
+
|
74
|
+
# pass 0: extracts the modifiers
|
75
|
+
if "CV_OUT" in arg_str:
|
76
|
+
modlist.append("/O")
|
77
|
+
arg_str = arg_str.replace("CV_OUT", "")
|
78
|
+
|
79
|
+
if "CV_IN_OUT" in arg_str:
|
80
|
+
modlist.append("/IO")
|
81
|
+
arg_str = arg_str.replace("CV_IN_OUT", "")
|
82
|
+
|
83
|
+
isarray = False
|
84
|
+
npos = arg_str.find("CV_CARRAY")
|
85
|
+
if npos >= 0:
|
86
|
+
isarray = True
|
87
|
+
macro_arg, npos3 = self.get_macro_arg(arg_str, npos)
|
88
|
+
|
89
|
+
modlist.append("/A " + macro_arg)
|
90
|
+
arg_str = arg_str[:npos] + arg_str[npos3+1:]
|
91
|
+
|
92
|
+
npos = arg_str.find("CV_CUSTOM_CARRAY")
|
93
|
+
if npos >= 0:
|
94
|
+
isarray = True
|
95
|
+
macro_arg, npos3 = self.get_macro_arg(arg_str, npos)
|
96
|
+
|
97
|
+
modlist.append("/CA " + macro_arg)
|
98
|
+
arg_str = arg_str[:npos] + arg_str[npos3+1:]
|
99
|
+
|
100
|
+
arg_str = arg_str.strip()
|
101
|
+
word_start = 0
|
102
|
+
word_list = []
|
103
|
+
npos = -1
|
104
|
+
|
105
|
+
#print self.lineno, ":\t", arg_str
|
106
|
+
|
107
|
+
# pass 1: split argument type into tokens
|
108
|
+
while 1:
|
109
|
+
npos += 1
|
110
|
+
t, npos = self.find_next_token(arg_str, [" ", "&", "*", "<", ">", ","], npos)
|
111
|
+
w = arg_str[word_start:npos].strip()
|
112
|
+
if w == "operator":
|
113
|
+
word_list.append("operator " + arg_str[npos:].strip())
|
114
|
+
break
|
115
|
+
if w not in ["", "const"]:
|
116
|
+
word_list.append(w)
|
117
|
+
if t not in ["", " ", "&"]:
|
118
|
+
word_list.append(t)
|
119
|
+
if not t:
|
120
|
+
break
|
121
|
+
word_start = npos+1
|
122
|
+
npos = word_start - 1
|
123
|
+
|
124
|
+
arg_type = ""
|
125
|
+
arg_name = ""
|
126
|
+
angle_stack = []
|
127
|
+
|
128
|
+
#print self.lineno, ":\t", word_list
|
129
|
+
|
130
|
+
# pass 2: decrypt the list
|
131
|
+
wi = -1
|
132
|
+
prev_w = ""
|
133
|
+
for w in word_list:
|
134
|
+
wi += 1
|
135
|
+
if w == "*":
|
136
|
+
if prev_w == "char" and not isarray:
|
137
|
+
arg_type = arg_type[:-len("char")] + "c_string"
|
138
|
+
else:
|
139
|
+
arg_type += w
|
140
|
+
continue
|
141
|
+
elif w == "<":
|
142
|
+
arg_type += "_"
|
143
|
+
angle_stack.append(0)
|
144
|
+
elif w == "," or w == '>':
|
145
|
+
if not angle_stack:
|
146
|
+
print "Error at %d: argument contains ',' or '>' not within template arguments" % (self.lineno,)
|
147
|
+
sys.exit(-1)
|
148
|
+
if w == ",":
|
149
|
+
arg_type += "_and_"
|
150
|
+
elif w == ">":
|
151
|
+
if angle_stack[0] == 0:
|
152
|
+
print "Error at %s:%d: template has no arguments" % (self.hname, self.lineno)
|
153
|
+
sys.exit(-1)
|
154
|
+
if angle_stack[0] > 1:
|
155
|
+
arg_type += "_end_"
|
156
|
+
angle_stack[-1:] = []
|
157
|
+
elif angle_stack:
|
158
|
+
arg_type += w
|
159
|
+
angle_stack[-1] += 1
|
160
|
+
elif arg_type == "struct":
|
161
|
+
arg_type += " " + w
|
162
|
+
elif arg_type and arg_type != "~":
|
163
|
+
arg_name = " ".join(word_list[wi:])
|
164
|
+
break
|
165
|
+
else:
|
166
|
+
arg_type += w
|
167
|
+
prev_w = w
|
168
|
+
|
169
|
+
counter_str = ""
|
170
|
+
add_star = False
|
171
|
+
if ("[" in arg_name) and not ("operator" in arg_str):
|
172
|
+
#print arg_str
|
173
|
+
p1 = arg_name.find("[")
|
174
|
+
p2 = arg_name.find("]",p1+1)
|
175
|
+
if p2 < 0:
|
176
|
+
print "Error at %d: no closing ]" % (self.lineno,)
|
177
|
+
sys.exit(-1)
|
178
|
+
counter_str = arg_name[p1+1:p2].strip()
|
179
|
+
if counter_str == "":
|
180
|
+
counter_str = "?"
|
181
|
+
if not isarray:
|
182
|
+
modlist.append("/A " + counter_str.strip())
|
183
|
+
arg_name = arg_name[:p1]
|
184
|
+
add_star = True
|
185
|
+
|
186
|
+
if not arg_name:
|
187
|
+
if arg_type.startswith("operator"):
|
188
|
+
arg_type, arg_name = "", arg_type
|
189
|
+
else:
|
190
|
+
arg_name = "arg" + str(argno)
|
191
|
+
argno += 1
|
192
|
+
|
193
|
+
while arg_type.endswith("_end_"):
|
194
|
+
arg_type = arg_type[:-len("_end_")]
|
195
|
+
|
196
|
+
if add_star:
|
197
|
+
arg_type += "*"
|
198
|
+
|
199
|
+
arg_type = self.batch_replace(arg_type, [("std::", ""), ("cv::", ""), ("::", "_")])
|
200
|
+
|
201
|
+
return arg_type, arg_name, modlist, argno
|
202
|
+
|
203
|
+
def parse_enum(self, decl_str):
|
204
|
+
l = decl_str
|
205
|
+
ll = l.split(",")
|
206
|
+
prev_val = ""
|
207
|
+
prev_val_delta = -1
|
208
|
+
decl = []
|
209
|
+
for pair in ll:
|
210
|
+
pv = pair.split("=")
|
211
|
+
if len(pv) == 1:
|
212
|
+
prev_val_delta += 1
|
213
|
+
val = ""
|
214
|
+
if prev_val:
|
215
|
+
val = prev_val + "+"
|
216
|
+
val += str(prev_val_delta)
|
217
|
+
else:
|
218
|
+
prev_val_delta = 0
|
219
|
+
prev_val = val = pv[1].strip()
|
220
|
+
decl.append(["const " + self.get_dotted_name(pv[0].strip()), val, [], []])
|
221
|
+
return decl
|
222
|
+
|
223
|
+
def parse_class_decl(self, decl_str):
|
224
|
+
"""
|
225
|
+
Parses class/struct declaration start in the form:
|
226
|
+
{class|struct} [CV_EXPORTS] <class_name> [: public <base_class1> [, ...]]
|
227
|
+
Returns class_name1, <list of base_classes>
|
228
|
+
"""
|
229
|
+
l = decl_str
|
230
|
+
modlist = []
|
231
|
+
if "CV_EXPORTS_W_MAP" in l:
|
232
|
+
l = l.replace("CV_EXPORTS_W_MAP", "")
|
233
|
+
modlist.append("/Map")
|
234
|
+
if "CV_EXPORTS_W_SIMPLE" in l:
|
235
|
+
l = l.replace("CV_EXPORTS_W_SIMPLE", "")
|
236
|
+
modlist.append("/Simple")
|
237
|
+
npos = l.find("CV_EXPORTS_AS")
|
238
|
+
if npos >= 0:
|
239
|
+
macro_arg, npos3 = self.get_macro_arg(l, npos)
|
240
|
+
modlist.append("=" + macro_arg)
|
241
|
+
l = l[:npos] + l[npos3+1:]
|
242
|
+
|
243
|
+
l = self.batch_replace(l, [("CV_EXPORTS_W", ""), ("CV_EXPORTS", ""), ("public virtual ", " "), ("public ", " "), ("::", ".")]).strip()
|
244
|
+
ll = re.split(r'\s*[,:]?\s*', l)
|
245
|
+
ll = [le for le in ll if le]
|
246
|
+
classname = ll[1]
|
247
|
+
bases = ll[2:]
|
248
|
+
return classname, bases, modlist
|
249
|
+
|
250
|
+
def parse_func_decl_no_wrap(self, decl_str, static_method = False):
|
251
|
+
decl_str = (decl_str or "").strip()
|
252
|
+
virtual_method = False
|
253
|
+
explicit_method = False
|
254
|
+
if decl_str.startswith("explicit"):
|
255
|
+
decl_str = decl_str[len("explicit"):].lstrip()
|
256
|
+
explicit_method = True
|
257
|
+
if decl_str.startswith("virtual"):
|
258
|
+
decl_str = decl_str[len("virtual"):].lstrip()
|
259
|
+
virtual_method = True
|
260
|
+
if decl_str.startswith("static"):
|
261
|
+
decl_str = decl_str[len("static"):].lstrip()
|
262
|
+
static_method = True
|
263
|
+
|
264
|
+
fdecl = decl_str.replace("CV_OUT", "").replace("CV_IN_OUT", "")
|
265
|
+
fdecl = fdecl.strip().replace("\t", " ")
|
266
|
+
while " " in fdecl:
|
267
|
+
fdecl = fdecl.replace(" ", " ")
|
268
|
+
fname = fdecl[:fdecl.find("(")].strip()
|
269
|
+
fnpos = fname.rfind(" ")
|
270
|
+
if fnpos < 0:
|
271
|
+
fnpos = 0
|
272
|
+
fname = fname[fnpos:].strip()
|
273
|
+
rettype = fdecl[:fnpos].strip()
|
274
|
+
|
275
|
+
if rettype.endswith("operator"):
|
276
|
+
fname = ("operator " + fname).strip()
|
277
|
+
rettype = rettype[:rettype.rfind("operator")].strip()
|
278
|
+
if rettype.endswith("::"):
|
279
|
+
rpos = rettype.rfind(" ")
|
280
|
+
if rpos >= 0:
|
281
|
+
fname = rettype[rpos+1:].strip() + fname
|
282
|
+
rettype = rettype[:rpos].strip()
|
283
|
+
else:
|
284
|
+
fname = rettype + fname
|
285
|
+
rettype = ""
|
286
|
+
|
287
|
+
apos = fdecl.find("(")
|
288
|
+
if fname.endswith("operator"):
|
289
|
+
fname += " ()"
|
290
|
+
apos = fdecl.find("(", apos+1)
|
291
|
+
|
292
|
+
fname = "cv." + fname.replace("::", ".")
|
293
|
+
decl = [fname, rettype, [], []]
|
294
|
+
|
295
|
+
# inline constructor implementation
|
296
|
+
implmatch = re.match(r"(\(.*?\))\s*:\s*(\w+\(.*?\),?\s*)+", fdecl[apos:])
|
297
|
+
if bool(implmatch):
|
298
|
+
fdecl = fdecl[:apos] + implmatch.group(1)
|
299
|
+
|
300
|
+
args0str = fdecl[apos+1:fdecl.rfind(")")].strip()
|
301
|
+
|
302
|
+
if args0str != "" and args0str != "void":
|
303
|
+
args0str = re.sub(r"\([^)]*\)", lambda m: m.group(0).replace(',', "@comma@"), args0str)
|
304
|
+
args0 = args0str.split(",")
|
305
|
+
|
306
|
+
args = []
|
307
|
+
narg = ""
|
308
|
+
for arg in args0:
|
309
|
+
narg += arg.strip()
|
310
|
+
balance_paren = narg.count("(") - narg.count(")")
|
311
|
+
balance_angle = narg.count("<") - narg.count(">")
|
312
|
+
if balance_paren == 0 and balance_angle == 0:
|
313
|
+
args.append(narg.strip())
|
314
|
+
narg = ""
|
315
|
+
|
316
|
+
for arg in args:
|
317
|
+
dfpos = arg.find("=")
|
318
|
+
defval = ""
|
319
|
+
if dfpos >= 0:
|
320
|
+
defval = arg[dfpos+1:].strip()
|
321
|
+
else:
|
322
|
+
dfpos = arg.find("CV_DEFAULT")
|
323
|
+
if dfpos >= 0:
|
324
|
+
defval, pos3 = self.get_macro_arg(arg, dfpos)
|
325
|
+
else:
|
326
|
+
dfpos = arg.find("CV_WRAP_DEFAULT")
|
327
|
+
if dfpos >= 0:
|
328
|
+
defval, pos3 = self.get_macro_arg(arg, dfpos)
|
329
|
+
if dfpos >= 0:
|
330
|
+
defval = defval.replace("@comma@", ",")
|
331
|
+
arg = arg[:dfpos].strip()
|
332
|
+
pos = len(arg)-1
|
333
|
+
while pos >= 0 and (arg[pos] in "_[]" or arg[pos].isalpha() or arg[pos].isdigit()):
|
334
|
+
pos -= 1
|
335
|
+
if pos >= 0:
|
336
|
+
aname = arg[pos+1:].strip()
|
337
|
+
atype = arg[:pos+1].strip()
|
338
|
+
if aname.endswith("&") or aname.endswith("*") or (aname in ["int", "String", "Mat"]):
|
339
|
+
atype = (atype + " " + aname).strip()
|
340
|
+
aname = ""
|
341
|
+
else:
|
342
|
+
atype = arg
|
343
|
+
aname = ""
|
344
|
+
if aname.endswith("]"):
|
345
|
+
bidx = aname.find('[')
|
346
|
+
atype += aname[bidx:]
|
347
|
+
aname = aname[:bidx]
|
348
|
+
decl[3].append([atype, aname, defval, []])
|
349
|
+
|
350
|
+
if static_method:
|
351
|
+
decl[2].append("/S")
|
352
|
+
if virtual_method:
|
353
|
+
decl[2].append("/V")
|
354
|
+
if explicit_method:
|
355
|
+
decl[2].append("/E")
|
356
|
+
if bool(re.match(r".*\)\s*(const)?\s*=\s*0", decl_str)):
|
357
|
+
decl[2].append("/A")
|
358
|
+
if bool(re.match(r".*\)\s*const(\s*=\s*0)?", decl_str)):
|
359
|
+
decl[2].append("/C")
|
360
|
+
if "virtual" in decl_str:
|
361
|
+
print decl_str
|
362
|
+
return decl
|
363
|
+
|
364
|
+
def parse_func_decl(self, decl_str):
|
365
|
+
"""
|
366
|
+
Parses the function or method declaration in the form:
|
367
|
+
[([CV_EXPORTS] <rettype>) | CVAPI(rettype)]
|
368
|
+
[~]<function_name>
|
369
|
+
(<arg_type1> <arg_name1>[=<default_value1>] [, <arg_type2> <arg_name2>[=<default_value2>] ...])
|
370
|
+
[const] {; | <function_body>}
|
371
|
+
|
372
|
+
Returns the function declaration entry:
|
373
|
+
[<func name>, <return value C-type>, <list of modifiers>, <list of arguments>] (see above)
|
374
|
+
"""
|
375
|
+
|
376
|
+
if self.wrap_mode:
|
377
|
+
if not (("CV_EXPORTS_AS" in decl_str) or ("CV_EXPORTS_W" in decl_str) or \
|
378
|
+
("CV_WRAP" in decl_str) or ("CV_WRAP_AS" in decl_str)):
|
379
|
+
return []
|
380
|
+
|
381
|
+
# ignore old API in the documentation check (for now)
|
382
|
+
if "CVAPI(" in decl_str and self.wrap_mode:
|
383
|
+
return []
|
384
|
+
|
385
|
+
top = self.block_stack[-1]
|
386
|
+
func_modlist = []
|
387
|
+
|
388
|
+
npos = decl_str.find("CV_EXPORTS_AS")
|
389
|
+
if npos >= 0:
|
390
|
+
arg, npos3 = self.get_macro_arg(decl_str, npos)
|
391
|
+
func_modlist.append("="+arg)
|
392
|
+
decl_str = decl_str[:npos] + decl_str[npos3+1:]
|
393
|
+
npos = decl_str.find("CV_WRAP_AS")
|
394
|
+
if npos >= 0:
|
395
|
+
arg, npos3 = self.get_macro_arg(decl_str, npos)
|
396
|
+
func_modlist.append("="+arg)
|
397
|
+
decl_str = decl_str[:npos] + decl_str[npos3+1:]
|
398
|
+
|
399
|
+
# filter off some common prefixes, which are meaningless for Python wrappers.
|
400
|
+
# note that we do not strip "static" prefix, which does matter;
|
401
|
+
# it means class methods, not instance methods
|
402
|
+
decl_str = self.batch_replace(decl_str, [("virtual", ""), ("static inline", ""), ("inline", ""),\
|
403
|
+
("CV_EXPORTS_W", ""), ("CV_EXPORTS", ""), ("CV_CDECL", ""), ("CV_WRAP ", " "), ("CV_INLINE", "")]).strip()
|
404
|
+
|
405
|
+
static_method = False
|
406
|
+
context = top[0]
|
407
|
+
if decl_str.startswith("static") and (context == "class" or context == "struct"):
|
408
|
+
decl_str = decl_str[len("static"):].lstrip()
|
409
|
+
static_method = True
|
410
|
+
|
411
|
+
args_begin = decl_str.find("(")
|
412
|
+
if decl_str.startswith("CVAPI"):
|
413
|
+
rtype_end = decl_str.find(")", args_begin+1)
|
414
|
+
if rtype_end < 0:
|
415
|
+
print "Error at %d. no terminating ) in CVAPI() macro: %s" % (self.lineno, decl_str)
|
416
|
+
sys.exit(-1)
|
417
|
+
decl_str = decl_str[args_begin+1:rtype_end] + " " + decl_str[rtype_end+1:]
|
418
|
+
args_begin = decl_str.find("(")
|
419
|
+
if args_begin < 0:
|
420
|
+
print "Error at %d: no args in '%s'" % (self.lineno, decl_str)
|
421
|
+
sys.exit(-1)
|
422
|
+
|
423
|
+
decl_start = decl_str[:args_begin].strip()
|
424
|
+
# handle operator () case
|
425
|
+
if decl_start.endswith("operator"):
|
426
|
+
args_begin = decl_str.find("(", args_begin+1)
|
427
|
+
if args_begin < 0:
|
428
|
+
print "Error at %d: no args in '%s'" % (self.lineno, decl_str)
|
429
|
+
sys.exit(-1)
|
430
|
+
decl_start = decl_str[:args_begin].strip()
|
431
|
+
# TODO: normalize all type of operators
|
432
|
+
if decl_start.endswith("()"):
|
433
|
+
decl_start = decl_start[0:-2].rstrip() + " ()"
|
434
|
+
|
435
|
+
# constructor/destructor case
|
436
|
+
if bool(re.match(r'^(\w+::)*(?P<x>\w+)::~?(?P=x)$', decl_start)):
|
437
|
+
decl_start = "void " + decl_start
|
438
|
+
|
439
|
+
rettype, funcname, modlist, argno = self.parse_arg(decl_start, -1)
|
440
|
+
|
441
|
+
if argno >= 0:
|
442
|
+
classname = top[1]
|
443
|
+
if rettype == classname or rettype == "~" + classname:
|
444
|
+
rettype, funcname = "", rettype
|
445
|
+
else:
|
446
|
+
if bool(re.match('\w+\s+\(\*\w+\)\s*\(.*\)', decl_str)):
|
447
|
+
return [] # function typedef
|
448
|
+
elif bool(re.match('\w+\s+\(\w+::\*\w+\)\s*\(.*\)', decl_str)):
|
449
|
+
return [] # class method typedef
|
450
|
+
elif bool(re.match('[A-Z_]+', decl_start)):
|
451
|
+
return [] # it seems to be a macro instantiation
|
452
|
+
elif "__declspec" == decl_start:
|
453
|
+
return []
|
454
|
+
elif bool(re.match(r'\w+\s+\(\*\w+\)\[\d+\]', decl_str)):
|
455
|
+
return [] # exotic - dynamic 2d array
|
456
|
+
else:
|
457
|
+
#print rettype, funcname, modlist, argno
|
458
|
+
print "Error at %s:%d the function/method name is missing: '%s'" % (self.hname, self.lineno, decl_start)
|
459
|
+
sys.exit(-1)
|
460
|
+
|
461
|
+
if self.wrap_mode and (("::" in funcname) or funcname.startswith("~")):
|
462
|
+
# if there is :: in function name (and this is in the header file),
|
463
|
+
# it means, this is inline implementation of a class method.
|
464
|
+
# Thus the function has been already declared within the class and we skip this repeated
|
465
|
+
# declaration.
|
466
|
+
# Also, skip the destructors, as they are always wrapped
|
467
|
+
return []
|
468
|
+
|
469
|
+
funcname = self.get_dotted_name(funcname)
|
470
|
+
|
471
|
+
if not self.wrap_mode:
|
472
|
+
decl = self.parse_func_decl_no_wrap(decl_str, static_method)
|
473
|
+
decl[0] = funcname
|
474
|
+
return decl
|
475
|
+
|
476
|
+
arg_start = args_begin+1
|
477
|
+
npos = arg_start-1
|
478
|
+
balance = 1
|
479
|
+
angle_balance = 0
|
480
|
+
# scan the argument list; handle nested parentheses
|
481
|
+
args_decls = []
|
482
|
+
args = []
|
483
|
+
argno = 1
|
484
|
+
|
485
|
+
while balance > 0:
|
486
|
+
npos += 1
|
487
|
+
t, npos = self.find_next_token(decl_str, ["(", ")", ",", "<", ">"], npos)
|
488
|
+
if not t:
|
489
|
+
print "Error: no closing ')' at %d" % (self.lineno,)
|
490
|
+
print decl_str
|
491
|
+
print decl_str[arg_start:]
|
492
|
+
sys.exit(-1)
|
493
|
+
if t == "<":
|
494
|
+
angle_balance += 1
|
495
|
+
if t == ">":
|
496
|
+
angle_balance -= 1
|
497
|
+
if t == "(":
|
498
|
+
balance += 1
|
499
|
+
if t == ")":
|
500
|
+
balance -= 1
|
501
|
+
|
502
|
+
if (t == "," and balance == 1 and angle_balance == 0) or balance == 0:
|
503
|
+
# process next function argument
|
504
|
+
a = decl_str[arg_start:npos].strip()
|
505
|
+
#print "arg = ", a
|
506
|
+
arg_start = npos+1
|
507
|
+
if a:
|
508
|
+
eqpos = a.find("=")
|
509
|
+
defval = ""
|
510
|
+
modlist = []
|
511
|
+
if eqpos >= 0:
|
512
|
+
defval = a[eqpos+1:].strip()
|
513
|
+
else:
|
514
|
+
eqpos = a.find("CV_DEFAULT")
|
515
|
+
if eqpos >= 0:
|
516
|
+
defval, pos3 = self.get_macro_arg(a, eqpos)
|
517
|
+
else:
|
518
|
+
eqpos = a.find("CV_WRAP_DEFAULT")
|
519
|
+
if eqpos >= 0:
|
520
|
+
defval, pos3 = self.get_macro_arg(a, eqpos)
|
521
|
+
if defval == "NULL":
|
522
|
+
defval = "0"
|
523
|
+
if eqpos >= 0:
|
524
|
+
a = a[:eqpos].strip()
|
525
|
+
arg_type, arg_name, modlist, argno = self.parse_arg(a, argno)
|
526
|
+
if self.wrap_mode:
|
527
|
+
if arg_type == "InputArray":
|
528
|
+
arg_type = "Mat"
|
529
|
+
elif arg_type == "InputOutputArray":
|
530
|
+
arg_type = "Mat"
|
531
|
+
modlist.append("/IO")
|
532
|
+
elif arg_type == "OutputArray":
|
533
|
+
arg_type = "Mat"
|
534
|
+
modlist.append("/O")
|
535
|
+
elif arg_type == "InputArrayOfArrays":
|
536
|
+
arg_type = "vector_Mat"
|
537
|
+
elif arg_type == "InputOutputArrayOfArrays":
|
538
|
+
arg_type = "vector_Mat"
|
539
|
+
modlist.append("/IO")
|
540
|
+
elif arg_type == "OutputArrayOfArrays":
|
541
|
+
arg_type = "vector_Mat"
|
542
|
+
modlist.append("/O")
|
543
|
+
defval = self.batch_replace(defval, [("InputArrayOfArrays", "vector<Mat>"),
|
544
|
+
("InputOutputArrayOfArrays", "vector<Mat>"),
|
545
|
+
("OutputArrayOfArrays", "vector<Mat>"),
|
546
|
+
("InputArray", "Mat"),
|
547
|
+
("InputOutputArray", "Mat"),
|
548
|
+
("OutputArray", "Mat"),
|
549
|
+
("noArray", arg_type)]).strip()
|
550
|
+
args.append([arg_type, arg_name, defval, modlist])
|
551
|
+
npos = arg_start-1
|
552
|
+
|
553
|
+
npos = decl_str.replace(" ", "").find("=0", npos)
|
554
|
+
if npos >= 0:
|
555
|
+
# skip pure virtual functions
|
556
|
+
return []
|
557
|
+
|
558
|
+
if static_method:
|
559
|
+
func_modlist.append("/S")
|
560
|
+
|
561
|
+
return [funcname, rettype, func_modlist, args]
|
562
|
+
|
563
|
+
def get_dotted_name(self, name):
|
564
|
+
"""
|
565
|
+
adds the dot-separated container class/namespace names to the bare function/class name, e.g. when we have
|
566
|
+
|
567
|
+
namespace cv {
|
568
|
+
class A {
|
569
|
+
public:
|
570
|
+
f(int);
|
571
|
+
};
|
572
|
+
}
|
573
|
+
|
574
|
+
the function will convert "A" to "cv.A" and "f" to "cv.A.f".
|
575
|
+
"""
|
576
|
+
if not self.block_stack:
|
577
|
+
return name
|
578
|
+
if name.startswith("cv."):
|
579
|
+
return name
|
580
|
+
n = ""
|
581
|
+
for b in self.block_stack:
|
582
|
+
block_type, block_name = b[self.BLOCK_TYPE], b[self.BLOCK_NAME]
|
583
|
+
if block_type in ["file", "enum"]:
|
584
|
+
continue
|
585
|
+
if block_type not in ["struct", "class", "namespace"]:
|
586
|
+
print "Error at %d: there are non-valid entries in the current block stack " % (self.lineno, self.block_stack)
|
587
|
+
sys.exit(-1)
|
588
|
+
if block_name:
|
589
|
+
n += block_name + "."
|
590
|
+
return n + name.replace("::", ".")
|
591
|
+
|
592
|
+
def parse_stmt(self, stmt, end_token):
|
593
|
+
"""
|
594
|
+
parses the statement (ending with ';' or '}') or a block head (ending with '{')
|
595
|
+
|
596
|
+
The function calls parse_class_decl or parse_func_decl when necessary. It returns
|
597
|
+
<block_type>, <block_name>, <parse_flag>, <declaration>
|
598
|
+
where the first 3 values only make sense for blocks (i.e. code blocks, namespaces, classes, enums and such)
|
599
|
+
"""
|
600
|
+
stack_top = self.block_stack[-1]
|
601
|
+
context = stack_top[self.BLOCK_TYPE]
|
602
|
+
|
603
|
+
stmt_type = ""
|
604
|
+
if end_token == "{":
|
605
|
+
stmt_type = "block"
|
606
|
+
|
607
|
+
if context == "block":
|
608
|
+
print "Error at %d: should not call parse_stmt inside blocks" % (self.lineno,)
|
609
|
+
sys.exit(-1)
|
610
|
+
|
611
|
+
if context == "class" or context == "struct":
|
612
|
+
while 1:
|
613
|
+
colon_pos = stmt.find(":")
|
614
|
+
if colon_pos < 0:
|
615
|
+
break
|
616
|
+
w = stmt[:colon_pos].strip()
|
617
|
+
if w in ["public", "protected", "private"]:
|
618
|
+
if w == "public" or (not self.wrap_mode and w == "protected"):
|
619
|
+
stack_top[self.PUBLIC_SECTION] = True
|
620
|
+
else:
|
621
|
+
stack_top[self.PUBLIC_SECTION] = False
|
622
|
+
stmt = stmt[colon_pos+1:].strip()
|
623
|
+
break
|
624
|
+
|
625
|
+
# do not process hidden class members and template classes/functions
|
626
|
+
if not stack_top[self.PUBLIC_SECTION] or stmt.startswith("template"):
|
627
|
+
return stmt_type, "", False, None
|
628
|
+
|
629
|
+
if end_token == "{":
|
630
|
+
if not self.wrap_mode and stmt.startswith("typedef struct"):
|
631
|
+
stmt_type = "struct"
|
632
|
+
try:
|
633
|
+
classname, bases, modlist = self.parse_class_decl(stmt[len("typedef "):])
|
634
|
+
except:
|
635
|
+
print "Error at %s:%d" % (self.hname, self.lineno)
|
636
|
+
exit(1)
|
637
|
+
if classname.startswith("_Ipl"):
|
638
|
+
classname = classname[1:]
|
639
|
+
decl = [stmt_type + " " + self.get_dotted_name(classname), "", modlist, []]
|
640
|
+
if bases:
|
641
|
+
decl[1] = ": " + ", ".join([b if "::" in b else self.get_dotted_name(b).replace(".","::") for b in bases])
|
642
|
+
return stmt_type, classname, True, decl
|
643
|
+
|
644
|
+
if stmt.startswith("class") or stmt.startswith("struct"):
|
645
|
+
stmt_type = stmt.split()[0]
|
646
|
+
if stmt.strip() != stmt_type:
|
647
|
+
try:
|
648
|
+
classname, bases, modlist = self.parse_class_decl(stmt)
|
649
|
+
except:
|
650
|
+
print "Error at %s:%d" % (self.hname, self.lineno)
|
651
|
+
exit(1)
|
652
|
+
decl = []
|
653
|
+
if ("CV_EXPORTS_W" in stmt) or ("CV_EXPORTS_AS" in stmt) or (not self.wrap_mode):# and ("CV_EXPORTS" in stmt)):
|
654
|
+
decl = [stmt_type + " " + self.get_dotted_name(classname), "", modlist, []]
|
655
|
+
if bases:
|
656
|
+
decl[1] = ": " + ", ".join([b if "::" in b else self.get_dotted_name(b).replace(".","::") for b in bases])
|
657
|
+
return stmt_type, classname, True, decl
|
658
|
+
|
659
|
+
if stmt.startswith("enum"):
|
660
|
+
return "enum", "", True, None
|
661
|
+
|
662
|
+
if stmt.startswith("namespace"):
|
663
|
+
stmt_list = stmt.split()
|
664
|
+
if len(stmt_list) < 2:
|
665
|
+
stmt_list.append("<unnamed>")
|
666
|
+
return stmt_list[0], stmt_list[1], True, None
|
667
|
+
if stmt.startswith("extern") and "\"C\"" in stmt:
|
668
|
+
return "namespace", "", True, None
|
669
|
+
|
670
|
+
if end_token == "}" and context == "enum":
|
671
|
+
decl = self.parse_enum(stmt)
|
672
|
+
return "enum", "", False, decl
|
673
|
+
|
674
|
+
if end_token == ";" and stmt.startswith("typedef"):
|
675
|
+
# TODO: handle typedef's more intelligently
|
676
|
+
return stmt_type, "", False, None
|
677
|
+
|
678
|
+
paren_pos = stmt.find("(")
|
679
|
+
if paren_pos >= 0:
|
680
|
+
# assume it's function or method declaration,
|
681
|
+
# since we filtered off the other places where '(' can normally occur:
|
682
|
+
# - code blocks
|
683
|
+
# - function pointer typedef's
|
684
|
+
decl = self.parse_func_decl(stmt)
|
685
|
+
# we return parse_flag == False to prevent the parser to look inside function/method bodies
|
686
|
+
# (except for tracking the nested blocks)
|
687
|
+
return stmt_type, "", False, decl
|
688
|
+
|
689
|
+
if (context == "struct" or context == "class") and end_token == ";" and stmt:
|
690
|
+
# looks like it's member declaration; append the members to the class declaration
|
691
|
+
class_decl = stack_top[self.CLASS_DECL]
|
692
|
+
if ("CV_PROP" in stmt): # or (class_decl and ("/Map" in class_decl[2])):
|
693
|
+
var_modlist = []
|
694
|
+
if "CV_PROP_RW" in stmt:
|
695
|
+
var_modlist.append("/RW")
|
696
|
+
stmt = self.batch_replace(stmt, [("CV_PROP_RW", ""), ("CV_PROP", "")]).strip()
|
697
|
+
var_list = stmt.split(",")
|
698
|
+
var_type, var_name1, modlist, argno = self.parse_arg(var_list[0], -1)
|
699
|
+
var_list = [var_name1] + [i.strip() for i in var_list[1:]]
|
700
|
+
|
701
|
+
for v in var_list:
|
702
|
+
class_decl[3].append([var_type, v, "", var_modlist])
|
703
|
+
return stmt_type, "", False, None
|
704
|
+
|
705
|
+
# something unknown
|
706
|
+
return stmt_type, "", False, None
|
707
|
+
|
708
|
+
def find_next_token(self, s, tlist, p=0):
|
709
|
+
"""
|
710
|
+
Finds the next token from the 'tlist' in the input 's', starting from position 'p'.
|
711
|
+
Returns the first occured token and its position, or ("", len(s)) when no token is found
|
712
|
+
"""
|
713
|
+
token = ""
|
714
|
+
tpos = len(s)
|
715
|
+
for t in tlist:
|
716
|
+
pos = s.find(t, p)
|
717
|
+
if pos < 0:
|
718
|
+
continue
|
719
|
+
if pos < tpos:
|
720
|
+
tpos = pos
|
721
|
+
token = t
|
722
|
+
return token, tpos
|
723
|
+
|
724
|
+
def parse(self, hname, wmode=True):
|
725
|
+
"""
|
726
|
+
The main method. Parses the input file.
|
727
|
+
Returns the list of declarations (that can be print using print_decls)
|
728
|
+
"""
|
729
|
+
self.hname = hname
|
730
|
+
decls = []
|
731
|
+
f = open(hname, "rt")
|
732
|
+
linelist = list(f.readlines())
|
733
|
+
f.close()
|
734
|
+
|
735
|
+
# states:
|
736
|
+
SCAN = 0 # outside of a comment or preprocessor directive
|
737
|
+
COMMENT = 1 # inside a multi-line comment
|
738
|
+
DIRECTIVE = 2 # inside a multi-line preprocessor directive
|
739
|
+
|
740
|
+
state = SCAN
|
741
|
+
|
742
|
+
self.block_stack = [["file", hname, True, True, None]]
|
743
|
+
block_head = ""
|
744
|
+
self.lineno = 0
|
745
|
+
self.wrap_mode = wmode
|
746
|
+
|
747
|
+
for l0 in linelist:
|
748
|
+
self.lineno += 1
|
749
|
+
#print self.lineno
|
750
|
+
|
751
|
+
l = l0.strip()
|
752
|
+
|
753
|
+
if state == SCAN and l.startswith("#"):
|
754
|
+
state = DIRECTIVE
|
755
|
+
# fall through to the if state == DIRECTIVE check
|
756
|
+
|
757
|
+
if state == DIRECTIVE:
|
758
|
+
if not l.endswith("\\"):
|
759
|
+
state = SCAN
|
760
|
+
continue
|
761
|
+
|
762
|
+
if state == COMMENT:
|
763
|
+
pos = l.find("*/")
|
764
|
+
if pos < 0:
|
765
|
+
continue
|
766
|
+
l = l[pos+2:]
|
767
|
+
state = SCAN
|
768
|
+
|
769
|
+
if state != SCAN:
|
770
|
+
print "Error at %d: invlid state = %d" % (self.lineno, state)
|
771
|
+
sys.exit(-1)
|
772
|
+
|
773
|
+
while 1:
|
774
|
+
token, pos = self.find_next_token(l, [";", "\"", "{", "}", "//", "/*"])
|
775
|
+
|
776
|
+
if not token:
|
777
|
+
block_head += " " + l
|
778
|
+
break
|
779
|
+
|
780
|
+
if token == "//":
|
781
|
+
block_head += " " + l[:pos]
|
782
|
+
break
|
783
|
+
|
784
|
+
if token == "/*":
|
785
|
+
block_head += " " + l[:pos]
|
786
|
+
pos = l.find("*/", pos+2)
|
787
|
+
if pos < 0:
|
788
|
+
state = COMMENT
|
789
|
+
break
|
790
|
+
l = l[pos+2:]
|
791
|
+
continue
|
792
|
+
|
793
|
+
if token == "\"":
|
794
|
+
pos2 = pos + 1
|
795
|
+
while 1:
|
796
|
+
t2, pos2 = self.find_next_token(l, ["\\", "\""], pos2)
|
797
|
+
if t2 == "":
|
798
|
+
print "Error at %d: no terminating '\"'" % (self.lineno,)
|
799
|
+
sys.exit(-1)
|
800
|
+
if t2 == "\"":
|
801
|
+
break
|
802
|
+
pos2 += 2
|
803
|
+
|
804
|
+
block_head += " " + l[:pos2+1]
|
805
|
+
l = l[pos2+1:]
|
806
|
+
continue
|
807
|
+
|
808
|
+
stmt = (block_head + " " + l[:pos]).strip()
|
809
|
+
stmt = " ".join(stmt.split()) # normalize the statement
|
810
|
+
stack_top = self.block_stack[-1]
|
811
|
+
|
812
|
+
if stmt.startswith("@"):
|
813
|
+
# Objective C ?
|
814
|
+
break
|
815
|
+
|
816
|
+
decl = None
|
817
|
+
if stack_top[self.PROCESS_FLAG]:
|
818
|
+
# even if stack_top[PUBLIC_SECTION] is False, we still try to process the statement,
|
819
|
+
# since it can start with "public:"
|
820
|
+
stmt_type, name, parse_flag, decl = self.parse_stmt(stmt, token)
|
821
|
+
if decl:
|
822
|
+
if stmt_type == "enum":
|
823
|
+
for d in decl:
|
824
|
+
decls.append(d)
|
825
|
+
else:
|
826
|
+
decls.append(decl)
|
827
|
+
else:
|
828
|
+
stmt_type, name, parse_flag = "block", "", False
|
829
|
+
|
830
|
+
if token == "{":
|
831
|
+
if stmt_type == "class":
|
832
|
+
public_section = False
|
833
|
+
else:
|
834
|
+
public_section = True
|
835
|
+
self.block_stack.append([stmt_type, name, parse_flag, public_section, decl])
|
836
|
+
|
837
|
+
if token == "}":
|
838
|
+
if not self.block_stack:
|
839
|
+
print "Error at %d: the block stack is empty" % (self.lineno,)
|
840
|
+
self.block_stack[-1:] = []
|
841
|
+
if pos+1 < len(l) and l[pos+1] == ';':
|
842
|
+
pos += 1
|
843
|
+
|
844
|
+
block_head = ""
|
845
|
+
l = l[pos+1:]
|
846
|
+
|
847
|
+
return decls
|
848
|
+
|
849
|
+
def print_decls(self, decls):
|
850
|
+
"""
|
851
|
+
Prints the list of declarations, retrieived by the parse() method
|
852
|
+
"""
|
853
|
+
for d in decls:
|
854
|
+
print d[0], d[1], ";".join(d[2])
|
855
|
+
for a in d[3]:
|
856
|
+
print " ", a[0], a[1], a[2],
|
857
|
+
if a[3]:
|
858
|
+
print "; ".join(a[3])
|
859
|
+
else:
|
860
|
+
print
|
861
|
+
|
862
|
+
if __name__ == '__main__':
|
863
|
+
parser = CppHeaderParser()
|
864
|
+
decls = []
|
865
|
+
# for hname in opencv_hdr_list:
|
866
|
+
# decls += parser.parse(hname)
|
867
|
+
for hname in sys.argv[1:]:
|
868
|
+
decls += parser.parse(hname)
|
869
|
+
parser.print_decls(decls)
|
870
|
+
print len(decls)
|
data/rbind.gemspec
CHANGED
metadata
CHANGED
@@ -1,35 +1,25 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: rbind
|
3
|
-
version: !ruby/object:Gem::Version
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
4
5
|
prerelease:
|
5
|
-
version: 0.0.1
|
6
6
|
platform: ruby
|
7
|
-
authors:
|
7
|
+
authors:
|
8
8
|
- Alexander Duda
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
|
13
|
-
date: 2013-06-17 00:00:00 Z
|
12
|
+
date: 2013-06-17 00:00:00.000000000 Z
|
14
13
|
dependencies: []
|
15
|
-
|
16
|
-
|
17
|
-
email:
|
14
|
+
description: ''
|
15
|
+
email:
|
18
16
|
- Alexander.Duda@dfki.de
|
19
17
|
executables: []
|
20
|
-
|
21
18
|
extensions: []
|
22
|
-
|
23
19
|
extra_rdoc_files: []
|
24
|
-
|
25
|
-
files:
|
20
|
+
files:
|
26
21
|
- lib/rbind.rb
|
27
|
-
- lib/rbind/.default_parser.rb.swp
|
28
|
-
- lib/rbind/.generator_c.rb.swp
|
29
22
|
- lib/rbind/core.rb
|
30
|
-
- lib/rbind/core/.rbase.rb.swp
|
31
|
-
- lib/rbind/core/.rclass.rb.swp
|
32
|
-
- lib/rbind/core/.rdata_type.rb.swp
|
33
23
|
- lib/rbind/core/.roperation.rb.swp
|
34
24
|
- lib/rbind/core/rattribute.rb
|
35
25
|
- lib/rbind/core/rbase.rb
|
@@ -43,6 +33,7 @@ files:
|
|
43
33
|
- lib/rbind/core/rparameter.rb
|
44
34
|
- lib/rbind/core/rsetter.rb
|
45
35
|
- lib/rbind/core/rstruct.rb
|
36
|
+
- lib/rbind/core/rvector.rb
|
46
37
|
- lib/rbind/default_parser.rb
|
47
38
|
- lib/rbind/generator_c.rb
|
48
39
|
- lib/rbind/generator_ruby.rb
|
@@ -69,33 +60,31 @@ files:
|
|
69
60
|
- lib/rbind/templates/ruby/rstatic_method.rb
|
70
61
|
- lib/rbind/templates/ruby/rtype.rb
|
71
62
|
- lib/rbind/templates/ruby/rtype_constructor.rb
|
63
|
+
- lib/rbind/tools/hdr_parser.py
|
72
64
|
- rbind.gemspec
|
73
65
|
homepage: http://github.com/
|
74
66
|
licenses: []
|
75
|
-
|
76
67
|
post_install_message:
|
77
68
|
rdoc_options: []
|
78
|
-
|
79
|
-
require_paths:
|
69
|
+
require_paths:
|
80
70
|
- lib
|
81
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
71
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
82
72
|
none: false
|
83
|
-
requirements:
|
84
|
-
- -
|
85
|
-
- !ruby/object:Gem::Version
|
86
|
-
version:
|
87
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
88
78
|
none: false
|
89
|
-
requirements:
|
90
|
-
- -
|
91
|
-
- !ruby/object:Gem::Version
|
79
|
+
requirements:
|
80
|
+
- - ! '>='
|
81
|
+
- !ruby/object:Gem::Version
|
92
82
|
version: 1.3.6
|
93
83
|
requirements: []
|
94
|
-
|
95
84
|
rubyforge_project:
|
96
85
|
rubygems_version: 1.8.23
|
97
86
|
signing_key:
|
98
87
|
specification_version: 3
|
99
88
|
summary: Library for genereating automated ffi-bindings for c/c++ libraries
|
100
89
|
test_files: []
|
101
|
-
|
90
|
+
has_rdoc:
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|