1 // idlcomp/languages/c++/interface-caller.cc -- caller-side interface definitions
3 // This software is copyright (c) 2006 Scott Wood <scott@buserror.net>.
5 // Permission is hereby granted, free of charge, to any person obtaining a copy of
6 // this software and associated documentation files (the "Software"), to deal with
7 // the Software without restriction, including without limitation the rights to
8 // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9 // of the Software, and to permit persons to whom the Software is furnished to do
10 // so, subject to the following condition:
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
26 struct callback_data {
33 void CPPFile::output_iface_tbl_entry(Interface *iface, Interface *super)
35 file << indent << "::System::RunTime::IFaceTable "
36 << *super->get_fq_name()->flatten("_IDLNS_") << ";\n";
39 void CPPFile::tbl_callback(Interface *super, void *arg)
41 const callback_data *data = static_cast<const callback_data *>(arg);
42 data->file->output_iface_tbl_entry(data->iface, super);
45 void CPPFile::output_iface_tbl(Interface *iface)
47 file << indent << "struct iface_table {\n";
49 indent.indent_level++;
51 output_iface_tbl_entry(iface, iface);
53 callback_data data = { this, iface };
55 iface->for_each_super<tbl_callback>(&data);
56 file << indent << "unsigned char *_end;\n";
58 indent.indent_level--;
60 file << indent << "} iface_table;\n\n";
63 void cpp_output_one_param(ostream &file, Param *p,
64 bool is_server, bool is_copy)
66 bool is_mutable = p->def.flags.field.Shared ||
67 p->def.flags.field.Push ||
69 (p->def.flags.field.Inline ||
72 if (dynamic_cast<Interface *>(*p->type)) {
73 cpp_output_name(file, p->type);
76 cpp_output_type(file, p->type, p->is_array(), is_mutable);
78 cpp_output_type(file, p->def.basictype, is_mutable);
81 if (p->def.flags.field.Out)
84 if (dynamic_cast<Struct *>(*p->type) && !p->is_inline())
90 void CPPFile::output_one_method(Interface *iface, Method *m,
91 bool prototype, bool retval)
93 const String &nsname = get_definition_name(iface);
95 file << '\n' << indent << "inline ";
101 file << get_definition_name(iface) << "::";
103 file << **m->name << '(';
106 indent.align_spaces = m->name->length() + 8;
108 indent.align_spaces = m->name->length() + nsname.length() + 10;
111 indent.align_spaces += 5;
114 for (Method::entries_iterator i = m->entries_begin();
115 i != m->entries_end(); ++i)
118 file << ",\n" << indent;
122 cpp_output_one_param(file, *i, false);
126 indent.align_spaces = 0;
133 file << '\n' << indent << "{\n";
136 // FIXME: It'd be nice to skip the NULL test in this cast,
139 file << indent << "_ptr->info->methods." << **m->name
142 cpp_output_name(file, m->get_ns());
144 file << ">(*this)._ptr";
146 indent.align_spaces = m->name->length() + 21;
148 for (Method::entries_iterator i = m->entries_begin();
149 i != m->entries_end(); ++i)
152 file << ",\n" << indent << **p->name;
156 indent.align_spaces = 0;
159 file << indent << "}\n";
162 void CPPFile::output_methods(Interface *iface, Interface *super, bool prototype)
164 for (Interface::methods_iterator m = super->methods_begin();
165 m != super->methods_end(); ++m)
167 output_one_method(iface, *m, prototype, false);
170 if (method has at least one out parameter)
171 output_one_method(iface, *m, prototype, true);
176 void CPPFile::output_one_method_ptr(Method *m, Interface *iface)
178 Interface *super = static_cast<Interface *>(m->get_ns());
181 file << indent << "void (*" << **m->name << ")(void *_this";
182 indent.align_spaces = m->name->length() + 9;
184 for (Method::entries_iterator p = m->entries_begin();
185 p != m->entries_end(); ++p)
187 file << ",\n" << indent;
188 cpp_output_one_param(file, *p, false);
192 indent.align_spaces = 0;
195 void CPPFile::output_method_ptrs_callback(Interface *super, void *arg)
197 const callback_data *data = static_cast<const callback_data *>(arg);
199 for (Interface::methods_iterator m = super->methods_begin();
200 m != super->methods_end(); ++m)
201 data->file->output_one_method_ptr(*m, data->iface);
204 void CPPFile::output_method_ptrs(Interface *iface)
206 file << indent << "struct methods {\n";
209 callback_data data = { this, iface };
211 output_method_ptrs_callback(iface, &data);
212 iface->for_each_super<output_method_ptrs_callback>(&data);
215 file << indent << "} methods;\n";
218 void CPPFile::output_internal(Interface *iface)
220 file << indent << "struct info_type {\n";
222 indent.indent_level++;
225 if (iface->supers_empty()) {
226 // No supers. If it's System.Object, output the top-level
227 // info_type. Otherwise, inherit from System.Object.
229 if (iface != System_Object) {
230 yyerrorf("Interface \"%s\" has no superinterface and "
231 "is not \"System.Object\".",
232 iface->get_fq_name()->flatten()->c_str());
237 file << indent << "ptrdiff_t concrete;\n"
238 << indent << "::System::RunTime::IFaceTable "
239 "*concrete_IFaceTable;\n";
241 Interface *super = *iface->supers_begin();
244 cpp_output_name(file, super, "_i_");
245 file << "::info_type parent;\n";
250 output_iface_tbl(iface);
251 output_method_ptrs(iface);
253 indent.indent_level--;
255 file << indent << "};\n\n"
256 << indent << "const info_type *const info;\n";
258 file << '\n' << indent << "_i_" << **iface->name << '(';
259 indent.align_spaces = iface->name->length() + 4;
260 cpp_output_name(file, iface, "_i_");
262 file << "::info_type *INFO) :\n"
263 << indent << "info(INFO)\n";
265 indent.align_spaces = 0;
266 file << indent << "{}\n";
269 void CPPFile::output_downcast_proto(Interface *iface, Interface *super)
271 file << '\n' << indent << "static inline " << **iface->name << " downcast(";
272 cpp_output_type(file, super, false, false);
273 file << "oldptr);\n";
276 void CPPFile::output_downcast(Interface *iface, Interface *super)
278 const String &name = get_definition_name(iface);
279 const String &iname = get_definition_name(iface, "_i_");
281 file << '\n' << indent << "inline " << name << ' '
282 << name << "::downcast(";
283 cpp_output_type(file, super, false, false);
286 file << "\n" << indent << "{\n";
288 indent.indent_level++;
290 file << indent << "::System::_i_Object *_llptr = \n"
291 << indent << "\treinterpret_cast< ::System::_i_Object *>(oldptr._ptr);\n"
292 << indent << "return " << name << "(reinterpret_cast< "
294 << indent << "\t(::System::RunTime::downcast(_llptr, "
295 << name << "_ns::_guid.l)));\n";
297 indent.indent_level--;
299 file << indent << "}\n";
302 void CPPFile::output_upcast_proto(Interface *iface, Interface *super)
304 const String &supername = *super->get_fq_name("_ns")->flatten("::");
305 file << indent << "inline operator ::" << supername << "();\n";
308 void CPPFile::output_upcast(Interface *iface, Interface *super)
310 const String &supername = *super->get_fq_name("_ns")->flatten("::");
312 file << '\n' << indent << "inline "
313 << get_definition_name(iface)
314 << "::operator ::" << supername << "()\n"
317 indent.indent_level++;
319 // A space is added after the final '<', as GCC gives a parse
320 // error otherwise. I'm not sure exactly why...
322 file << indent << "uintptr_t ptr = reinterpret_cast<uintptr_t>(_ptr);\n\n"
323 << indent << "if (!_ptr)\n"
324 << indent << "\treturn NULL;\n\n"
325 << indent << "ptr += _ptr->info->iface_table."
326 << *super->get_fq_name()->flatten("_IDLNS_")
328 << indent << "return ::" << supername << "(reinterpret_cast< ";
330 cpp_output_name(file, super, "_i_");
332 file << " *>(ptr));\n";
334 indent.indent_level--;
336 file << indent << "}\n";
339 void CPPFile::wrapper_cast_callback(Interface *super, void *arg)
341 const callback_data *data = static_cast<const callback_data *>(arg);
343 data->file->output_downcast(data->iface, super);
344 data->file->output_upcast(data->iface, super);
347 void CPPFile::wrapper_cast_proto_callback(Interface *super, void *arg)
349 const callback_data *data = static_cast<const callback_data *>(arg);
351 data->file->output_downcast_proto(data->iface, super);
352 data->file->output_upcast_proto(data->iface, super);
355 void CPPFile::output_wrapper(Interface *iface)
357 const String &name = **iface->name;
359 file << indent << "_i_" << name << " *_ptr;\n\n";
361 file << indent << name << "()\n"
363 << indent << "\t_ptr = NULL;\n"
364 << indent << "}\n\n";
366 file << indent << name << "(_i_" << name << " *_other)\n"
368 << indent << "\t_ptr = _other;\n"
369 << indent << "}\n\n";
371 file << indent << "operator _i_" << name << " *()\n"
373 << indent << "\treturn _ptr;\n"
376 do_extra_newline = true;
378 callback_data data = { this, iface, true };
380 iface->for_each_super<wrapper_cast_proto_callback>(&data);
382 output_methods(iface, iface, true);
383 iface->for_each_super<wrapper_method_callback>(&data);
386 void CPPFile::output_casts(Interface *iface)
388 callback_data data = { this, iface };
390 iface->for_each_super<wrapper_cast_callback>(&data);
393 void CPPFile::wrapper_method_callback(Interface *super, void *arg)
395 const callback_data *data = static_cast<const callback_data *>(arg);
397 data->file->output_methods(data->iface, super, data->prototype);
400 void CPPFile::output_method_defs(Interface *iface)
402 output_methods(iface, iface, false);
404 callback_data data = { this, iface, false };
405 iface->for_each_super<wrapper_method_callback>(&data);