]> git.buserror.net Git - polintos/scott/priv.git/blob - idlcomp/languages/c++/interface-caller.cc
c6e87a1f3a447252a63511bea540a5322978d7ef
[polintos/scott/priv.git] / idlcomp / languages / c++ / interface-caller.cc
1 // idlcomp/languages/c++/interface-caller.cc -- caller-side interface definitions
2 //
3 // This software is copyright (c) 2006 Scott Wood <scott@buserror.net>.
4 // 
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:
11 // 
12 //     * Redistributions of source code must retain the above copyright notice,
13 //       this list of conditions and the following disclaimers.
14 // 
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.
18 // 
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.
22 // 
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
29 // SOFTWARE.
30
31 #include <targets.h>
32 #include "c++.h"
33
34 struct callback_data {
35         CPPFile *file;
36         Interface *iface;
37         bool prototype;
38         int count;
39 };
40
41 void CPPFile::output_iface_tbl_entry(Interface *iface, Interface *super)
42 {
43         file << indent << "::System::RunTime::IFaceTable "
44              << *super->get_fq_name()->flatten("_IDLNS_") << ";\n";
45 }
46
47 void CPPFile::tbl_callback(Interface *super, void *arg)
48 {
49         const callback_data *data = static_cast<const callback_data *>(arg);
50         data->file->output_iface_tbl_entry(data->iface, super);
51 }
52
53 void CPPFile::output_iface_tbl(Interface *iface)
54 {
55         file << indent << "struct iface_table {\n";
56
57         indent.indent_level++;
58
59         output_iface_tbl_entry(iface, iface);
60
61         callback_data data = { this, iface };
62         
63         iface->for_each_super<tbl_callback>(&data);
64         file << indent << "unsigned char *_end;\n";
65
66         indent.indent_level--;
67         
68         file << indent << "} iface_table;\n\n";
69 }
70
71 void cpp_output_one_param(ostream &file, Param *p,
72                           bool is_server, bool is_copy)
73 {
74         bool is_mutable = p->def.flags.field.Shared ||
75                           p->def.flags.field.Push ||
76                           (is_server && 
77                            (p->def.flags.field.Inline ||
78                             is_copy));
79  
80         if (dynamic_cast<Interface *>(*p->type)) {
81                 cpp_output_name(file, p->type);
82                 file << ' ';
83         } else if (p->type) {
84                 cpp_output_type(file, p->type, p->is_array(), is_mutable);
85         } else {
86                 cpp_output_type(file, p->def.basictype, is_mutable);
87         }
88
89         if (p->def.flags.field.Out)
90                 file << '*';
91         
92         if (dynamic_cast<Struct *>(*p->type) && !p->is_inline())
93                 file << '*';
94
95         file << **p->name;
96 }
97
98 void CPPFile::output_one_method(Interface *iface, Method *m, 
99                                 bool prototype, bool retval)
100 {
101         const String &nsname = get_definition_name(iface);
102
103         file << '\n' << indent << "inline ";
104         
105         if (!retval)
106                 file << "void ";
107         
108         if (!prototype)
109                 file << get_definition_name(iface) << "::";
110         
111         file << **m->name << '(';
112
113         if (prototype)
114                 indent.align_spaces = m->name->length() + 8;
115         else
116                 indent.align_spaces = m->name->length() + nsname.length() + 10;
117
118         if (!retval)
119                 indent.align_spaces += 5;
120         
121         bool first = true;
122         for (Method::entries_iterator i = m->entries_begin();
123              i != m->entries_end(); ++i)
124         {
125                 if (!first)
126                         file << ",\n" << indent;
127                 
128                 first = false;
129                 
130                 cpp_output_one_param(file, *i, false);
131         }
132         
133         file << ")";
134         indent.align_spaces = 0;
135
136         if (prototype) {
137                 file << ";\n";
138                 return;
139         }
140         
141         file << '\n' << indent << "{\n";
142         downscope();
143
144         // FIXME: It'd be nice to skip the NULL test in this cast,
145         // as 
146
147         file << indent << "_ptr->info->methods." << **m->name
148              << "(static_cast< ";
149
150         cpp_output_name(file, m->get_ns());
151
152         file << ">(*this)._ptr";
153
154         indent.align_spaces = m->name->length() + 21;
155         
156         for (Method::entries_iterator i = m->entries_begin();
157              i != m->entries_end(); ++i)
158         {
159                 Param *p = *i;
160                 file << ",\n" << indent << **p->name;
161         }
162         
163         file << ");\n";
164         indent.align_spaces = 0;
165
166         upscope();
167         file << indent << "}\n";
168 }
169
170 void CPPFile::output_methods(Interface *iface, Interface *super, bool prototype)
171 {
172         for (Interface::methods_iterator m = super->methods_begin();
173              m != super->methods_end(); ++m)
174         {
175                 output_one_method(iface, *m, prototype, false);
176                 
177                 /*
178                 if (method has at least one out parameter)
179                         output_one_method(iface, *m, prototype, true);
180                 */
181         }
182 }
183
184 void CPPFile::output_one_method_ptr(Method *m, Interface *iface)
185 {
186         Interface *super = static_cast<Interface *>(m->get_ns());
187         extra_newline();
188
189         file << indent << "void (*" << **m->name << ")(void *_this";
190         indent.align_spaces = m->name->length() + 9;
191         
192         for (Method::entries_iterator p = m->entries_begin();
193              p != m->entries_end(); ++p)
194         {
195                 file << ",\n" << indent;
196                 cpp_output_one_param(file, *p, false);
197         }
198         
199         file << ");\n";
200         indent.align_spaces = 0;
201 }
202
203 void CPPFile::output_method_ptrs_callback(Interface *super, void *arg)
204 {
205         const callback_data *data = static_cast<const callback_data *>(arg);
206
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);
210 }
211
212 void CPPFile::output_method_ptrs(Interface *iface)
213 {
214         file << indent << "struct methods {\n";
215         downscope();
216         
217         callback_data data = { this, iface };
218
219         output_method_ptrs_callback(iface, &data);
220         iface->for_each_super<output_method_ptrs_callback>(&data);
221
222         upscope();
223         file << indent << "} methods;\n";
224 }
225
226 void CPPFile::output_internal(Interface *iface)
227 {
228         file << indent << "struct info_type {\n";
229
230         indent.indent_level++;
231         int super_count = 0;
232         
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.
236                 
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());
241
242                         throw UserError();
243                 }
244                         
245                 file << indent << "ptrdiff_t concrete;\n"
246                      << indent << "::System::RunTime::IFaceTable "
247                                   "*concrete_IFaceTable;\n";
248         } else {
249                 Interface *super = *iface->supers_begin();
250
251                 file << indent;
252                 cpp_output_name(file, super, "_i_");
253                 file << "::info_type parent;\n";
254         }
255
256         file << '\n';
257
258         output_iface_tbl(iface);
259         output_method_ptrs(iface);
260         
261         indent.indent_level--;
262         
263         file << indent << "};\n\n"
264              << indent << "const info_type *const info;\n";
265
266         file << '\n' << indent << "_i_" << **iface->name << '(';
267         indent.align_spaces = iface->name->length() + 4;
268         cpp_output_name(file, iface, "_i_");
269
270         file << "::info_type *INFO) :\n"
271              << indent << "info(INFO)\n";
272         
273         indent.align_spaces = 0;
274         file << indent << "{}\n";
275 }
276
277 void CPPFile::output_downcast_proto(Interface *iface, Interface *super)
278 {
279         file << '\n' << indent << "static inline " << **iface->name << " downcast(";
280         cpp_output_type(file, super, false, false);
281         file << "oldptr);\n";
282 }
283
284 void CPPFile::output_downcast(Interface *iface, Interface *super)
285 {
286         const String &name = get_definition_name(iface);
287         const String &iname = get_definition_name(iface, "_i_");
288
289         file << '\n' << indent << "inline " << name << ' '
290              << name << "::downcast(";
291         cpp_output_type(file, super, false, false);
292         file << "oldptr)";
293         
294         file << "\n" << indent << "{\n";
295
296         indent.indent_level++;
297         
298         file << indent << "::System::_i_Object *_llptr = \n"
299              << indent << "\treinterpret_cast< ::System::_i_Object *>(oldptr._ptr);\n"
300              << indent << "return " << name << "(reinterpret_cast< "
301              << iname << " *>\n"
302              << indent << "\t(::System::RunTime::downcast(_llptr, " 
303              << name << "_ns::_guid.l)));\n";
304         
305         indent.indent_level--;
306         
307         file << indent << "}\n";
308 }
309
310 void CPPFile::output_upcast_proto(Interface *iface, Interface *super)
311 {
312         const String &supername = *super->get_fq_name("_ns")->flatten("::");
313         file << indent << "inline operator ::" << supername << "();\n";
314 }
315
316 void CPPFile::output_upcast(Interface *iface, Interface *super)
317 {
318         const String &supername = *super->get_fq_name("_ns")->flatten("::");
319
320         file << '\n' << indent << "inline "
321              << get_definition_name(iface)
322              << "::operator ::" << supername << "()\n"
323              << indent << "{\n";
324         
325         indent.indent_level++;
326         
327         // A space is added after the final '<', as GCC gives a parse
328         // error otherwise.  I'm not sure exactly why...
329         
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_") 
335              << ".offset;\n"
336              << indent << "return ::" << supername << "(reinterpret_cast< ";
337         
338         cpp_output_name(file, super, "_i_");
339         
340         file << " *>(ptr));\n";
341         
342         indent.indent_level--;
343         
344         file << indent << "}\n";
345 }
346
347 void CPPFile::wrapper_cast_callback(Interface *super, void *arg)
348 {
349         const callback_data *data = static_cast<const callback_data *>(arg);
350         
351         data->file->output_downcast(data->iface, super);
352         data->file->output_upcast(data->iface, super);
353 }
354
355 void CPPFile::wrapper_cast_proto_callback(Interface *super, void *arg)
356 {
357         const callback_data *data = static_cast<const callback_data *>(arg);
358         
359         data->file->output_downcast_proto(data->iface, super);
360         data->file->output_upcast_proto(data->iface, super);
361 }
362
363 void CPPFile::output_wrapper(Interface *iface)
364 {
365         const String &name = **iface->name;
366
367         file << indent << "_i_" << name << " *_ptr;\n\n";
368         
369         file << indent << name << "()\n"
370              << indent << "{\n"
371              << indent << "\t_ptr = NULL;\n"
372              << indent << "}\n\n";
373
374         file << indent << name << "(_i_" << name << " *_other)\n"
375              << indent << "{\n"
376              << indent << "\t_ptr = _other;\n"
377              << indent << "}\n\n";
378
379         file << indent << "operator _i_" << name << " *()\n"
380              << indent << "{\n"
381              << indent << "\treturn _ptr;\n"
382              << indent << "}\n";
383
384         do_extra_newline = true;
385         
386         callback_data data = { this, iface, true };
387
388         iface->for_each_super<wrapper_cast_proto_callback>(&data);
389
390         output_methods(iface, iface, true);
391         iface->for_each_super<wrapper_method_callback>(&data);
392 }
393
394 void CPPFile::output_casts(Interface *iface)
395 {
396         callback_data data = { this, iface };
397
398         iface->for_each_super<wrapper_cast_callback>(&data);
399 }
400
401 void CPPFile::wrapper_method_callback(Interface *super, void *arg)
402 {
403         const callback_data *data = static_cast<const callback_data *>(arg);
404
405         data->file->output_methods(data->iface, super, data->prototype);
406 }
407
408 void CPPFile::output_method_defs(Interface *iface)
409 {
410         output_methods(iface, iface, false);
411
412         callback_data data = { this, iface, false };
413         iface->for_each_super<wrapper_method_callback>(&data);
414 }