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