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 conditions:
12 // * Redistributions of source code must retain the above copyright notice,
13 // this list of conditions and the following disclaimers.
15 // * Redistributions in binary form must reproduce the above copyright notice,
16 // this list of conditions and the following disclaimers in the
17 // documentation and/or other materials provided with the distribution.
19 // * The names of the Software's authors and/or contributors
20 // may not be used to endorse or promote products derived from
21 // this Software without specific prior written permission.
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
25 // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
34 struct callback_data {
41 void CPPFile::output_iface_tbl_entry(Interface *iface, Interface *super)
43 file << indent << "::System::RunTime::IFaceTable "
44 << *super->get_fq_name()->flatten("_IDLNS_") << ";\n";
47 void CPPFile::tbl_callback(Interface *super, void *arg)
49 const callback_data *data = static_cast<const callback_data *>(arg);
50 data->file->output_iface_tbl_entry(data->iface, super);
53 void CPPFile::output_iface_tbl(Interface *iface)
55 file << indent << "struct iface_table {\n";
57 indent.indent_level++;
59 output_iface_tbl_entry(iface, iface);
61 callback_data data = { this, iface };
63 iface->for_each_super<tbl_callback>(&data);
64 file << indent << "unsigned char *_end;\n";
66 indent.indent_level--;
68 file << indent << "} iface_table;\n\n";
71 void cpp_output_one_param(ostream &file, Param *p,
72 bool is_server, bool is_copy)
74 bool is_mutable = p->def.flags.field.Shared ||
75 p->def.flags.field.Push ||
77 (p->def.flags.field.Inline ||
80 if (dynamic_cast<Interface *>(*p->type)) {
81 cpp_output_name(file, p->type);
84 cpp_output_type(file, p->type, p->is_array(), is_mutable);
86 cpp_output_type(file, p->def.basictype, is_mutable);
89 if (p->def.flags.field.Out)
92 if (dynamic_cast<Struct *>(*p->type) && !p->is_inline())
98 void CPPFile::output_one_method(Interface *iface, Method *m,
99 bool prototype, bool retval)
101 const String &nsname = get_definition_name(iface);
103 file << '\n' << indent << "inline ";
109 file << get_definition_name(iface) << "::";
111 file << **m->name << '(';
114 indent.align_spaces = m->name->length() + 8;
116 indent.align_spaces = m->name->length() + nsname.length() + 10;
119 indent.align_spaces += 5;
122 for (Method::entries_iterator i = m->entries_begin();
123 i != m->entries_end(); ++i)
126 file << ",\n" << indent;
130 cpp_output_one_param(file, *i, false);
134 indent.align_spaces = 0;
141 file << '\n' << indent << "{\n";
144 // FIXME: It'd be nice to skip the NULL test in this cast,
147 file << indent << "_ptr->info->methods." << **m->name
150 cpp_output_name(file, m->get_ns());
152 file << ">(*this)._ptr";
154 indent.align_spaces = m->name->length() + 21;
156 for (Method::entries_iterator i = m->entries_begin();
157 i != m->entries_end(); ++i)
160 file << ",\n" << indent << **p->name;
164 indent.align_spaces = 0;
167 file << indent << "}\n";
170 void CPPFile::output_methods(Interface *iface, Interface *super, bool prototype)
172 for (Interface::methods_iterator m = super->methods_begin();
173 m != super->methods_end(); ++m)
175 output_one_method(iface, *m, prototype, false);
178 if (method has at least one out parameter)
179 output_one_method(iface, *m, prototype, true);
184 void CPPFile::output_one_method_ptr(Method *m, Interface *iface)
186 Interface *super = static_cast<Interface *>(m->get_ns());
189 file << indent << "void (*" << **m->name << ")(void *_this";
190 indent.align_spaces = m->name->length() + 9;
192 for (Method::entries_iterator p = m->entries_begin();
193 p != m->entries_end(); ++p)
195 file << ",\n" << indent;
196 cpp_output_one_param(file, *p, false);
200 indent.align_spaces = 0;
203 void CPPFile::output_method_ptrs_callback(Interface *super, void *arg)
205 const callback_data *data = static_cast<const callback_data *>(arg);
207 for (Interface::methods_iterator m = super->methods_begin();
208 m != super->methods_end(); ++m)
209 data->file->output_one_method_ptr(*m, data->iface);
212 void CPPFile::output_method_ptrs(Interface *iface)
214 file << indent << "struct methods {\n";
217 callback_data data = { this, iface };
219 output_method_ptrs_callback(iface, &data);
220 iface->for_each_super<output_method_ptrs_callback>(&data);
223 file << indent << "} methods;\n";
226 void CPPFile::output_internal(Interface *iface)
228 file << indent << "struct info_type {\n";
230 indent.indent_level++;
233 if (iface->supers_empty()) {
234 // No supers. If it's System.Object, output the top-level
235 // info_type. Otherwise, inherit from System.Object.
237 if (iface != System_Object) {
238 yyerrorf("Interface \"%s\" has no superinterface and "
239 "is not \"System.Object\".",
240 iface->get_fq_name()->flatten()->c_str());
245 file << indent << "ptrdiff_t concrete;\n"
246 << indent << "::System::RunTime::IFaceTable "
247 "*concrete_IFaceTable;\n";
249 Interface *super = *iface->supers_begin();
252 cpp_output_name(file, super, "_i_");
253 file << "::info_type parent;\n";
258 output_iface_tbl(iface);
259 output_method_ptrs(iface);
261 indent.indent_level--;
263 file << indent << "};\n\n"
264 << indent << "const info_type *const info;\n";
266 file << '\n' << indent << "_i_" << **iface->name << '(';
267 indent.align_spaces = iface->name->length() + 4;
268 cpp_output_name(file, iface, "_i_");
270 file << "::info_type *INFO) :\n"
271 << indent << "info(INFO)\n";
273 indent.align_spaces = 0;
274 file << indent << "{}\n";
277 void CPPFile::output_downcast_proto(Interface *iface, Interface *super)
279 file << '\n' << indent << "static inline " << **iface->name << " downcast(";
280 cpp_output_type(file, super, false, false);
281 file << "oldptr);\n";
284 void CPPFile::output_downcast(Interface *iface, Interface *super)
286 const String &name = get_definition_name(iface);
287 const String &iname = get_definition_name(iface, "_i_");
289 file << '\n' << indent << "inline " << name << ' '
290 << name << "::downcast(";
291 cpp_output_type(file, super, false, false);
294 file << "\n" << indent << "{\n";
296 indent.indent_level++;
298 file << indent << "::System::_i_Object *_llptr = \n"
299 << indent << "\treinterpret_cast< ::System::_i_Object *>(oldptr._ptr);\n"
300 << indent << "return " << name << "(reinterpret_cast< "
302 << indent << "\t(::System::RunTime::downcast(_llptr, "
303 << name << "_ns::_guid.l)));\n";
305 indent.indent_level--;
307 file << indent << "}\n";
310 void CPPFile::output_upcast_proto(Interface *iface, Interface *super)
312 const String &supername = *super->get_fq_name("_ns")->flatten("::");
313 file << indent << "inline operator ::" << supername << "();\n";
316 void CPPFile::output_upcast(Interface *iface, Interface *super)
318 const String &supername = *super->get_fq_name("_ns")->flatten("::");
320 file << '\n' << indent << "inline "
321 << get_definition_name(iface)
322 << "::operator ::" << supername << "()\n"
325 indent.indent_level++;
327 // A space is added after the final '<', as GCC gives a parse
328 // error otherwise. I'm not sure exactly why...
330 file << indent << "uintptr_t ptr = reinterpret_cast<uintptr_t>(_ptr);\n\n"
331 << indent << "if (!_ptr)\n"
332 << indent << "\treturn NULL;\n\n"
333 << indent << "ptr += _ptr->info->iface_table."
334 << *super->get_fq_name()->flatten("_IDLNS_")
336 << indent << "return ::" << supername << "(reinterpret_cast< ";
338 cpp_output_name(file, super, "_i_");
340 file << " *>(ptr));\n";
342 indent.indent_level--;
344 file << indent << "}\n";
347 void CPPFile::wrapper_cast_callback(Interface *super, void *arg)
349 const callback_data *data = static_cast<const callback_data *>(arg);
351 data->file->output_downcast(data->iface, super);
352 data->file->output_upcast(data->iface, super);
355 void CPPFile::wrapper_cast_proto_callback(Interface *super, void *arg)
357 const callback_data *data = static_cast<const callback_data *>(arg);
359 data->file->output_downcast_proto(data->iface, super);
360 data->file->output_upcast_proto(data->iface, super);
363 void CPPFile::output_wrapper(Interface *iface)
365 const String &name = **iface->name;
367 file << indent << "_i_" << name << " *_ptr;\n\n";
369 file << indent << name << "()\n"
371 << indent << "\t_ptr = NULL;\n"
372 << indent << "}\n\n";
374 file << indent << name << "(_i_" << name << " *_other)\n"
376 << indent << "\t_ptr = _other;\n"
377 << indent << "}\n\n";
379 file << indent << "operator _i_" << name << " *()\n"
381 << indent << "\treturn _ptr;\n"
384 do_extra_newline = true;
386 callback_data data = { this, iface, true };
388 iface->for_each_super<wrapper_cast_proto_callback>(&data);
390 output_methods(iface, iface, true);
391 iface->for_each_super<wrapper_method_callback>(&data);
394 void CPPFile::output_casts(Interface *iface)
396 callback_data data = { this, iface };
398 iface->for_each_super<wrapper_cast_callback>(&data);
401 void CPPFile::wrapper_method_callback(Interface *super, void *arg)
403 const callback_data *data = static_cast<const callback_data *>(arg);
405 data->file->output_methods(data->iface, super, data->prototype);
408 void CPPFile::output_method_defs(Interface *iface)
410 output_methods(iface, iface, false);
412 callback_data data = { this, iface, false };
413 iface->for_each_super<wrapper_method_callback>(&data);