Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 209 lines (184 sloc) 8.552 kB
8603286 Initial repo set-up
Elias Karakoulakis authored
1 # a Thrift server generator for OpenZWave
2 # transform a server skeleton file into a fully operational server
3 # a.k.a. "fills in the blanks for you"
4 #
5 # (c) 2011 Elias Karakoulakis <elias.karakoulakis@gmail.com>
6 #
7 require 'rubygems'
8 require 'rbgccxml'
9
10 OverloadedRE = /([^_]*)(?:_(.*))/
11
12 MANAGER_INCLUDES = [
13 "gen_cpp",
14 "/usr/local/include/thrift/",
15 "/home/ekarak/ozw/open-zwave-read-only/cpp/tinyxml",
16 "/home/ekarak/ozw/open-zwave-read-only/cpp/src",
17 "/home/ekarak/ozw/open-zwave-read-only/cpp/src/value_classes",
18 "/home/ekarak/ozw/open-zwave-read-only/cpp/src/command_classes",
19 "/home/ekarak/ozw/open-zwave-read-only/cpp/src/platform",
20 ]
21
22 #
23 # must load all source files in a single batch (RbGCCXML gets confused otherwise...)
24 #
25 files = [
26 "/home/ekarak/ozw/thrift4ozw/gen-cpp/RemoteManager_server.skeleton.cpp",
27 "/home/ekarak/ozw/open-zwave-read-only/cpp/src/Manager.cpp"
28 ]
29 puts "Parsing:" + files.join("\n\t")
30 RootNode = RbGCCXML.parse(files, :includes => MANAGER_INCLUDES)
31
32 # read skeleton file in memory as an array
33 output = File.open("gen-cpp/RemoteManager_server.skeleton.cpp").readlines
34
35 def ValueID_converter(arg)
36 return "*g_values[#{arg}]"
37 end
38
39 # fix the constructor
40 lineno = RootNode.classes("RemoteManagerHandler").constructors[1]['line'].to_i
41 #~ output[lineno] = Constructor
42 # add our extra hidden sauce
43 #lineno = foo.classes("RemoteManagerHandler").constructors[1]['endline'].to_i
44 #output[lineno] = Converter
45
46 RootNode.classes("RemoteManagerHandler").methods.each { |meth|
47 # find line number, insert critical section enter code
48 lineno = meth['line'].to_i
49 #puts "Method #{meth.name} at line #{lineno}-------------------------"
50 output[lineno] = "\tManager* mgr = Manager::Get();\n\tg_criticalSection.lock();\n"
51 #
52 target_method = nil
53 target_method_name = nil
54 disambiguation_hint = nil
55
56 # skeleton function's name has underscore => Overloaded. Needs disambiguation.
57 if md = OverloadedRE.match(meth.name) then
58 target_method_name = md[1]
59 disambiguation_hint = md[2]
60 else
61 target_method_name = meth.name
62 end
63
64 #
65 # SEARCH FOR MATCHING FUNCTION IN OPENZWAVE::MANAGER
66 #
67 search_result = RootNode.namespaces("OpenZWave").classes("Manager").methods.find(:name => target_method_name, :access => :public)
68 #puts "search result: #{search_result.class.name}"
69 case search_result
70 when RbGCCXML::QueryResult then
71 raise "#{target_method_name}(): no disambiguation hint given!!!" unless disambiguation_hint
72 #puts " ...Overloaded method: #{meth.name}"
73 search_result.each { |node|
74 # last argument's type must match disambiguation_hint
75 target_method = node if node.arguments[-1].cpp_type.to_cpp =~ Regexp.new(disambiguation_hint, Regexp::IGNORECASE)
76 # FIXME:: ListString => list<string>
77 }
78 when RbGCCXML::Method then
79 #puts " ...exact match for #{meth.name}"
80 target_method = search_result
81 end
82
83 raise "Unable to resolve target method! (#{meth.name})" unless target_method
84
85 #
86 # TIME TO BOOGEY
87 #
88
89 puts "CREATING MAPPING for (#{meth.return_type.to_cpp}) #{meth.name}"
90
91 #Thrift transforms methods with complex return types (string, vector<...>, user-defined structs etc)
92 # example 1:
93 # (C++) string GetLibraryVersion( uint32 const _homeId );
94 # (thrift) string GetLibraryVersion( 1:i32 _homeId );
95 # (skeleton) void GetLibraryVersion(std::string& _return, const int32_t _homeId)
96 #
97 # example 2:
98 # (C++) uint32 GetNodeNeighbors( uint32 const _homeId, uint8 const _nodeId, uint8** _nodeNeighbors );
99 # (thrift) UInt32_NeighborMap GetNodeNeighbors( 1:i32 _homeId, 2:byte _nodeId);
100 # (skeleton) void GetNodeNeighbors(UInt32_ListByte& _return, const int32_t _homeId, const int8_t _nodeId)
101 # ozw_types.h: class UInt32_ListByte {
102 # int32_t retval;
103 # std::vector<int8_t> arg; *** notice manual copying needed from C-style pointer to pointers of uint8's (not very C++ish)
104 # }
105 #
106 # example 3:
107 # (C++) bool GetValueListItems( ValueID const& _id, vector<string>* o_value );
108 # (thrift) Bool_ListString GetValueListItems( 1:RemoteValueID _id );
109 # (skeleton) void GetValueListItems(Bool_ListString& _return, const RemoteValueID _id)
110 # ozw_types.h:class Bool_ListString {
111 # bool retval;
112 # std::vector<std::string> arg;
113 # }
114 #
115
116 # is the skeleton function's return type composite?
117 composite_return = false
a41ce7d 1) fix Makefile to produce binaries in their directories
Elias Karakoulakis authored
118 #
8603286 Initial repo set-up
Elias Karakoulakis authored
119 function_return_clause = ''
a41ce7d 1) fix Makefile to produce binaries in their directories
Elias Karakoulakis authored
120 #
8603286 Initial repo set-up
Elias Karakoulakis authored
121 returnarg = nil
a41ce7d 1) fix Makefile to produce binaries in their directories
Elias Karakoulakis authored
122 #
123 last_argument = nil
8603286 Initial repo set-up
Elias Karakoulakis authored
124
125 # gather all required arguments
126 # key = target_method_argument (RbGCCXML::Node)
127 # value => source argument cpp definition (string) - e.g. "(cast) argname"
128
129 #arr = target_method.arguments.map {|tma| meth.arguments.select { |a| a.name == tma.name}[0]}
130
a41ce7d 1) fix Makefile to produce binaries in their directories
Elias Karakoulakis authored
131 args = {} # source node => target node
132 meth.arguments.each {|a| args[a] = target_method.arguments.select { |tma| a.name == tma.name}[0]}
8603286 Initial repo set-up
Elias Karakoulakis authored
133
134 #
135 # create the function call
136 #
137 arg_array = []
138 #
a41ce7d 1) fix Makefile to produce binaries in their directories
Elias Karakoulakis authored
139 meth.arguments.each { | src_arg|
140 tgt_arg= args[src_arg]
141 puts "src=#{src_arg and src_arg.qualified_name} \t tgt=#{tgt_arg and tgt_arg.qualified_name}"
142
143 if tgt_arg then # argument names matched
144 ampersand = (tgt_arg.cpp_type.to_cpp.include?('*') ? '&' : '')
8603286 Initial repo set-up
Elias Karakoulakis authored
145 # maybe it's an OpenZWave::ValueID ???
146 if (tgt_arg.to_cpp =~ /ValueID/) then
a41ce7d 1) fix Makefile to produce binaries in their directories
Elias Karakoulakis authored
147 arg_array << ValueID_converter(src_arg.name)
8603286 Initial repo set-up
Elias Karakoulakis authored
148 else
149 arg_array << "(#{tgt_arg.cpp_type.to_cpp}) #{ampersand}#{src_arg.name}"
150 end
151 else # source argument not found by name, search elsewhere
a41ce7d 1) fix Makefile to produce binaries in their directories
Elias Karakoulakis authored
152 puts "method #{meth.name}, argument #{src_arg.name} not found by name..."
8603286 Initial repo set-up
Elias Karakoulakis authored
153 # 1) try searching through thrift's special '_return' argument (if there is one)
154 if (returnarg = meth.arguments.select{ |a| a.name == "_return"}[0]).is_a?(RbGCCXML::Argument) then
155 puts "Thrift special _return argument detected!"
156 last_argument_type = target_method.arguments[-1].cpp_type.to_cpp
a41ce7d 1) fix Makefile to produce binaries in their directories
Elias Karakoulakis authored
157 ampersand = (last_argument_type.include?('*') ? '&' : '')
8603286 Initial repo set-up
Elias Karakoulakis authored
158 if md = OverloadedRE.match(returnarg.cpp_type.to_cpp) then
159 # ...and it's a complex type (Thrift struct)
160 # 1st match is the function's return type
161 composite_return = true
162 function_return_clause = " _return.retval = "
163 # 2nd match is function's last argument type
a41ce7d 1) fix Makefile to produce binaries in their directories
Elias Karakoulakis authored
164 last_argument = "(#{last_argument_type}) #{ampersand}_return#{composite_return ? '.arg' : ''}"
8603286 Initial repo set-up
Elias Karakoulakis authored
165 else
a41ce7d 1) fix Makefile to produce binaries in their directories
Elias Karakoulakis authored
166 # _return is a simple data type used
167 if meth.return_type.name == "void" then
168 #_return is used as the main function return clause
169 function_return_clause = " _return = "
170 else
171 # _return is the last argument to target function
172 last_argument = "(#{last_argument_type}) #{ampersand}_return"
173 end
8603286 Initial repo set-up
Elias Karakoulakis authored
174 end
175 else
a41ce7d 1) fix Makefile to produce binaries in their directories
Elias Karakoulakis authored
176 raise "ERROR:couldn't match argument '#{src_arg.name}' in method '#{meth.name}'!!!"
8603286 Initial repo set-up
Elias Karakoulakis authored
177 end
178 end
179 }
180
a41ce7d 1) fix Makefile to produce binaries in their directories
Elias Karakoulakis authored
181 # add last argument to array (it's about time...)
182 arg_array << last_argument
8603286 Initial repo set-up
Elias Karakoulakis authored
183 # unleash the beast
a41ce7d 1) fix Makefile to produce binaries in their directories
Elias Karakoulakis authored
184 fcall = "#{function_return_clause} mgr->#{target_method.name}(#{arg_array.compact.join(', ')})"
8603286 Initial repo set-up
Elias Karakoulakis authored
185
186 #
187 # FUNCTION RETURN CLAUSE
188 #
189 case meth.return_type.name
190 when "void"
191 output[lineno+1] = "\t#{fcall};\n"
192 else
193 output[lineno+1] = "\t#{meth.return_type.to_cpp} function_result = #{fcall};\n"
194 end
195
196 # unlock the critical section
197 output[lineno+1] << "\tg_criticalSection.unlock();\n"
198 # output return statement (unless rettype == void)
199 unless meth.return_type.name == "void"
200 output[lineno+1] << "\treturn(function_result);\n"
201 end
202
203 }
204
205 output[0] = "// Automatically generated OpenZWave::Manager_server wrapper\n"
206 output[1] = "// (c) 2011 Elias Karakoulakis <elias.karakoulakis@gmail.com>\n"
207 # write out the generated file
208 File.new("gen-cpp/RemoteManager_server.cpp", File::CREAT|File::TRUNC|File::RDWR, 0644) << output.join
Something went wrong with that request. Please try again.