3e921e5eb94f9a236381ca76535380faed9fa9b2
[polintos/scott/priv.git] / idlcomp / languages / c++ / main.cc
1 // idlcomp/languages/c++/main.cc -- C++ IDL binding
2 //
3 // A lot of the complexity in here would just go away if C++ could handle
4 // out-of-order declarations.
5 //
6 // This software is copyright (c) 2006 Scott Wood <scott@buserror.net>.
7 // 
8 // This software is provided 'as-is', without any express or implied warranty.
9 // In no event will the authors or contributors be held liable for any damages
10 // arising from the use of this software.
11 // 
12 // Permission is hereby granted to everyone, free of charge, to use, copy,
13 // modify, prepare derivative works of, publish, distribute, perform,
14 // sublicense, and/or sell copies of the Software, provided that the above
15 // copyright notice and disclaimer of warranty be included in all copies or
16 // substantial portions of this software.
17
18 // FIXME: escape C++ reserved words
19
20 #include <cerrno>
21
22 #include <sys/types.h>
23 #include <sys/stat.h>
24
25 #include <targets.h>
26 #include "c++.h"
27
28 CPPBinding cppbinding;
29
30 CPPFile::CPPFile(UserNameSpace *NS, const char *dir) :
31 dirname(dir)
32 {
33         indent.indent_level = 0;
34         indent.align_spaces = 0;
35         do_extra_newline = true;
36         ns = NS;
37
38         dirname.append(1, '/');
39         dirname.append(ns->name);
40         string headername(dirname);
41         headername.append(".h");
42
43         file.open(headername.c_str());
44         if (!file.is_open()) {
45                 fprintf(stderr, "Could not create output file \"%s\": %s.\n",
46                         headername.c_str(), strerror(errno));
47
48                 throw UserError();
49         }
50         
51         if (mkdir(dirname.c_str(), 0777) < 0) {
52                 fprintf(stderr, "Could not create output directory \"%s\": %s.\n",
53                         dir, strerror(errno));
54
55                 throw UserError();
56         }
57         
58         file <<   "// " << *ns->get_fq_name()->flatten()
59              << "\n// This is a C++ language binding generated by idlc.\n"
60              <<   "// Do not modify this file directly.\n\n";
61
62         fqname = ns->get_fq_name();
63         String *fqname_flat = ns->get_fq_name()->flatten("_IDLNS_");
64         file <<   "#ifndef IDL_HDR_" << *fqname_flat
65              << "\n#define IDL_HDR_" << *fqname_flat << "\n\n";
66         
67         file << "#include <orb.h>\n";
68
69         first_traversal = ++traversal;
70         assert(first_traversal >= 0);
71         
72         for (NameSpace::const_iterator i = ns->begin(); i != ns->end(); ++i) {
73                 Symbol *sym = (*i).second;
74                 UserNameSpace *uns = dynamic_cast<UserNameSpace *>(sym);
75                 
76                 if (uns) {
77                         file << "#include \"" << **ns->name << '/' << **uns->name << ".h\"\n";
78                         
79                         // Process namespaces first, to minimize duplicate definitions
80                         // if this namespace depends on something declared in a sub
81                         // namespace.
82                         
83                         output(uns);
84                 }
85         }
86
87         for (NameSpace::const_iterator i = ns->begin(); i != ns->end(); ++i) {
88                 Symbol *sym = (*i).second;
89                 UserNameSpace *uns = dynamic_cast<UserNameSpace *>(sym);
90                 
91                 if (!uns)
92                         output_pass(sym, trav_nsdecl);
93         }
94
95         for (NameSpace::const_iterator i = ns->begin(); i != ns->end(); ++i) {
96                 Symbol *sym = (*i).second;
97                 UserNameSpace *uns = dynamic_cast<UserNameSpace *>(sym);
98                 
99                 if (!uns)
100                         output_pass(sym, trav_full);
101         }
102 }
103
104 CPPFile::~CPPFile()
105 {
106         file << "#endif\n";
107         
108         assert(indent.indent_level == 0);
109 }
110
111 void CPPFile::ifndef_in(Symbol *sym, const char *extra)
112 {
113         StrList *fqname = sym->get_fq_name();
114         String *fqname_flat = fqname->flatten("_IDLNS_");
115
116         assert(indent.indent_level == 0);
117
118         file << "\n#ifndef IDL_DUP_" << extra << *fqname_flat
119              << "\n#define IDL_DUP_" << extra << *fqname_flat << "\n";
120 }
121
122 void CPPFile::ifndef_out()
123 {
124         file << "\n#endif\n";
125 }
126
127 void CPPFile::ns_in(Symbol *sym, const char *extra)
128 {
129         // Only output user namespaces here; if we're defining a nested type,
130         // it will have been forward declared already, and thus the
131         // non-user-namespaces can be specified directly in the definition.
132         //
133         // For non-forward-declarables such as metadata, use all_ns_in.
134         
135         StrList *ns_fqname = sym->find_toplevel_type()->get_ns()->get_fq_name();
136
137         ifndef_in(sym, extra);
138
139         for (StrList::const_iterator i = ns_fqname->begin();
140              i != ns_fqname->end(); ++i) {
141                 const String *str = *i;
142                 file << "namespace " << *str << " {\n";
143         }
144         
145         downscope();
146 }
147
148 void CPPFile::ns_out(Symbol *sym)
149 {
150         upscope();
151         assert(indent.indent_level == 0);
152
153         for (Symbol *s = sym->find_toplevel_type()->get_ns(); s != toplevel;
154              s = s->get_ns())
155                 file << "}";
156
157         ifndef_out();
158 }
159
160 void CPPFile::all_ns_in(Symbol *sym, bool include_self, const char *extra)
161 {
162         NameSpace *ns = sym->find_toplevel_type()->get_ns();
163         StrList *ns_fqname = ns->get_fq_name();
164
165         ifndef_in(sym, extra);
166
167         for (StrList::const_iterator i = ns_fqname->begin();
168              i != ns_fqname->end(); ++i) {
169                 const String *str = *i;
170                 file << "namespace " << *str << " {\n";
171         }
172         
173         stack<SymbolRef> typens;
174         
175         if (!include_self)
176                 sym = sym->get_ns();
177         
178         for (Symbol *s = sym; s != ns; s = s->get_ns())
179                 typens.push(s);
180         
181         while (!typens.empty()) {
182                 Symbol *s = typens.top();
183                 typens.pop();
184                 file << "namespace " << **s->name << "_ns {\n";
185         }
186         
187         downscope();
188 }
189
190 void CPPFile::all_ns_out(Symbol *sym, bool include_self)
191 {
192         upscope();
193         assert(indent.indent_level == 0);
194
195         if (!include_self)
196                 sym = sym->get_ns();
197
198         for (Symbol *s = sym; s != toplevel; s = s->get_ns())
199                 file << "}";
200
201         ifndef_out();
202 }
203
204 String &CPPFile::get_definition_name(Symbol *sym, const char *prefix)
205 {
206         NameSpace *ns = sym->get_ns();
207         UserNameSpace *uns = dynamic_cast<UserNameSpace *>(ns);
208         String *str;
209         
210         if (!uns) {
211                 str = &get_definition_name(ns);
212                 str->append("_ns::");
213         } else {
214                 str = new String();
215         }
216         
217         str->append(prefix);
218         str->append(**sym->name);
219         return *str;
220 }
221
222 void cpp_output_name(ostream &file, Symbol *sym, const char *prefix)
223 {
224         StrList *sl = sym->get_fq_name("_ns");
225         sl->pop_back();
226
227         file << "::" << *sl->flatten("::") << "::" << prefix << **sym->name;
228 }
229
230 void CPPFile::output(UserNameSpace *sym, int pass, void *arg2)
231 {
232         assert(indent.indent_level == 0);
233         delete new CPPFile(sym, dirname.c_str());
234 }
235
236 static inline int round_up_bits(int bits)
237 {
238         assert(bits >= 1 && bits <= 64);
239         
240         if (bits > 32)
241                 return 64;
242         if (bits > 16)
243                 return 32;
244         if (bits > 8)
245                 return 16;
246
247         return 8;
248 }
249
250 // FIXME: Inline arrays...
251 void cpp_output_type(ostream &file, Type *t, bool array, bool is_mutable)
252 {
253         if (array) {
254                 file << "::System::RunTime::";
255                 
256                 if (is_mutable)
257                         file << "Mutable";
258                 
259                 file << "Array< ";
260         }
261
262         cpp_output_name(file, t);
263
264         if (array) {
265                 Struct *str = dynamic_cast<Struct *>(t);
266                 if (str)
267                         file << " *";
268                 
269                 file << ", ::System::RunTime::ORBMM>";
270         }
271
272         file << ' ';
273 }
274
275 // FIXME: Inline arrays...
276 void cpp_output_type(ostream &file, CompiledBasicType &t, bool is_mutable)
277 {
278         if (is_array(t)) {
279                 file << "::System::RunTime::";
280                 
281                 if (is_mutable)
282                         file << "Mutable";
283                 
284                 file << "Array< ";
285         }
286
287         if (t.flags.field.Bool) {
288                 // Don't rely on C++ to provide any particular representation
289                 // of bool...
290                 file << "uint8_t";
291         } else if (t.flags.field.Float) {
292                 if (t.bits == 32)
293                         file << "float";
294                 else
295                         file << "double";
296         } else {
297                 if (t.flags.field.Unsigned)
298                         file << 'u';
299
300                 file << "int" << round_up_bits(t.bits) << "_t";
301         }
302         
303         if (is_array(t))
304                 file << ", ::System::RunTime::ORBMM>";
305         
306         file << ' ';
307 }
308
309 // FIXME: implement padding
310 int CPPFile::output_datum(Struct *ns, Datum *d, int offset)
311 {
312         if (d->type) {
313                 cpp_output_type(file, d->type, is_array(d->def.basictype),
314                                 !d->def.flags.field.Immutable);
315
316                 Struct *dtype = dynamic_cast<Struct *>(*d->type);
317                 if (dtype && !dtype->is_inline() && !d->is_array())
318                         file << '*';
319         } else {
320                 cpp_output_type(file, d->def.basictype,
321                                 !d->def.flags.field.Immutable);
322         }
323
324         return offset;
325 }
326
327 void CPPFile::declare_type_dependency(Type *t, bool need_obj_def)
328 {
329         Symbol *toplevel_type = t->find_toplevel_type();
330
331         assert(indent.indent_level == 0);
332         
333         output_pass(toplevel_type, trav_nsdecl);
334         
335         if (t == toplevel_type)
336                 output_pass(t, trav_forward);
337
338         if (dynamic_cast<Interface *>(t))
339                 output_pass(t, need_obj_def ? trav_obj_def : trav_obj_stub);
340         else if (!dynamic_cast<Struct *>(t) || need_obj_def)
341                 output_pass(t, trav_full);
342 }
343
344 void CPPFile::declare_dependencies(Interface *iface, bool need_obj_def)
345 {
346         for (Interface::methods_iterator i = iface->methods_begin();
347              i != iface->methods_end(); ++i)
348         {
349                 Method *m = *i;
350                 for (Method::entries_iterator j = m->entries_begin();
351                      j != m->entries_end(); ++j)
352                 {
353                         Param *p = *j;
354                         if (p->type)
355                                 declare_type_dependency(p->type, need_obj_def);
356                 }
357         }
358
359         for (Interface::supers_iterator i = iface->supers_begin();
360              i != iface->supers_end(); ++i)
361         {
362                 Interface *super = *i;
363                 declare_type_dependency(super);
364         }
365 }
366
367 void CPPFile::declare_dependencies(Struct *str)
368 {
369         for (NameSpace::const_iterator i = str->begin(); i != str->end(); ++i) {
370                 Symbol *sym = (*i).second;
371                 Datum *d = dynamic_cast<Datum *>(sym);
372                 if (d) {
373                         if (d->type)
374                                 declare_type_dependency(d->type, d->is_inline());
375                         
376                         continue;
377                 }
378
379                 Struct *mstr = dynamic_cast<Struct *>(sym);
380                 if (mstr) {
381                         declare_dependencies(mstr);
382                         continue;
383                 }
384                 
385                 Interface *miface = dynamic_cast<Interface *>(sym);
386                 if (miface)
387                         declare_dependencies(miface);
388         }
389 }
390
391 void CPPFile::output_guid(const uint64_t *guid64)
392 {
393         const unsigned char *guid = reinterpret_cast<const unsigned char *>(guid64);
394         char guidhex[7];
395         
396         file << indent << "__attribute__((weak))\n"
397              << indent << "::System::RunTime::GUID _guid = {\n"
398              << indent << "\t{ ";
399         
400         for (int i = 0; i < 16; i++) {
401                 if (i == 8)
402                         file << '\n' << indent << "\t  ";
403                 
404                 sprintf(guidhex, "0x%02x, ", *guid++);
405                 file << guidhex;
406         }
407
408         file << "}\n"
409              << indent << "};\n";
410
411         do_extra_newline = true;
412 }
413
414 void CPPFile::output_nsdecl_begin(NameSpace *ns)
415 {
416         // If indent level is not zero, this is a nested struct or interface.
417         if (indent.indent_level == 0)
418                 ns_in(ns, "NS_");
419         else
420                 extra_newline();
421
422         file << indent << "namespace " << **ns->name << "_ns {\n";
423         downscope();
424 }       
425         
426 void CPPFile::output_nsdecl_children(NameSpace *ns)
427 {       
428         for (NameSpace::const_iterator i = ns->begin(); i != ns->end(); ++i) {
429                 Symbol *sym = (*i).second;
430
431                 assert(pass_needed(sym, trav_forward));
432                 assert(pass_needed(sym, trav_nsdecl));
433                 
434                 // If it's a Method or a non-const Datum, this is a no-op.
435                 output_pass(sym, trav_forward);
436                 output_pass(sym, trav_nsdecl);
437         }
438 }
439
440 void CPPFile::output_nsdecl_end(NameSpace *ns)
441 {
442         upscope();
443         
444         file << indent << "}\n";
445
446         if (indent.indent_level == 1)
447                 ns_out(ns);
448 }
449
450 void CPPFile::output_nsdecl(NameSpace *ns)
451 {
452         output_nsdecl_begin(ns);
453         output_nsdecl_children(ns);
454         output_nsdecl_end(ns);
455 }
456
457 void CPPFile::output_aliases_and_types(NameSpace *ns)
458 {
459         for (NameSpace::const_iterator i = ns->begin(); i != ns->end(); ++i) {
460                 Symbol *sym = (*i).second;
461                 if (dynamic_cast<Alias *>(sym) || dynamic_cast<Type *>(sym))
462                         output_pass(sym, trav_full);
463         }
464 }               
465
466 void CPPFile::output_vstruct_info(Struct *sym)
467 {
468         all_ns_in(sym, true, "VINFO_");
469
470         file << indent << "__attribute__((weak)) "
471                           "unsigned long * _guids[] = {\n";
472         
473         stack<StructRef> supers;
474         sym->chainlen = 0;
475                         
476         for (Struct *i = sym; i; i = i->get_super()) {
477                 sym->chainlen++;
478                 supers.push(i);
479         }
480         
481         for (int i = 0; i < sym->chainlen; i++) {
482                 Struct *super = supers.top();
483                 supers.pop();
484
485                 file << indent << '\t';
486                 cpp_output_name(file, super);
487                 file << "_ns::_guid.l,\n";
488         }
489
490         file << indent << "};\n\n"
491              << indent << "__attribute__((weak)) "
492                           "::System::RunTime::VStructInfo _info = {\n"
493              << indent << "\t_guids, " << sym->chainlen << ",\n"
494 //           << indent << "\t_marshall, _unmarshall,\n"
495              << indent << "};\n";
496
497         
498         all_ns_out(sym, true);
499 }
500
501 void CPPFile::output_vstruct_main(Struct *sym)
502 {
503         assert(sym->is_virtual());
504         Struct *super = sym->get_super();
505
506         const char *name = sym->name->c_str();
507
508         if (!super) {
509                 assert(sym == System_VStruct);
510                 file << indent << "const ::System::RunTime::VStructInfo "
511                                   "*const _infoptr;\n\n";
512         }
513         
514         file << indent << name
515              << "(const ::System::RunTime::VStructInfo *realinfo = &"
516              << name << "_ns::_info) :\n"
517              << indent;
518
519         if (!super)
520                 file << "_infoptr";
521         else
522                 cpp_output_name(file, super);
523         
524         file << "(realinfo)\n"
525              << indent << "{\n"
526              << indent << "}\n";
527
528         if (super)
529                 file << '\n'
530                      << indent << "static __attribute__((weak)) " << name << " *downcast(::System::VStruct *base)\n"
531                      << indent << "{\n"
532                      << indent << "\tif (!base)\n"
533                      << indent << "\t\treturn NULL;\n\n"
534                      << indent << "\tconst ::System::RunTime::VStructInfo *info = base->_infoptr;\n\n"
535                      << indent << "\tif (info->chainlen < " << sym->chainlen << ")\n"
536                      << indent << "\t\treturn NULL;\n\n"
537                      << indent << "\tif (::System::RunTime::guids_equal(info->guids["
538                                << sym->chainlen - 1 << "], " << name << "_ns::_guid.l))\n"
539                      << indent << "\t\treturn static_cast<" << name << " *>(base);\n\n"
540                      << indent << "\treturn NULL;\n"
541                      << indent << "}\n";
542
543         do_extra_newline = true;
544 }
545
546 // Output an init method that initializes all the elements in the
547 // struct; this is useful for throwing exceptions.  Due to the
548 // annoying, apparently unwaiveable-by-the-struct requirement that any
549 // struct with a ctor be initialized using the ctor (and thus at
550 // runtime, not statically), this can't be an actual ctor in
551 // non-virtual structs.
552 //
553 // In virtual structs, there's already a ctor, so it wouldn't
554 // matter.  It'd generally be best to be consistent and use the
555 // init method for both, but the main intended use for this is
556 // throwing exceptions (which are virtual), and it'd be
557 // unfortunate to cripple 99% of the uses with unnecessary
558 // syntactic cruft.  The init method will remain available
559 // for vstructs so that things won't break if a non-vstruct
560 // gets made virtual (or if a user really wants to be consistent
561 // between both types in their own code).
562
563 void CPPFile::output_struct_ctor(Struct *sym, bool extra_vstruct)
564 {
565         const char *method_name = extra_vstruct ? sym->name->c_str() : " _init";
566
567         file << '\n' << indent << **sym->name;
568         indent.align_spaces = sym->name->length() + 1;
569
570         if (!extra_vstruct) {
571                 file << " &_init";
572                 indent.align_spaces += 7;
573         }
574
575         file << '(';
576         output_struct_ctor_rec1(sym, 0);
577         
578         if (extra_vstruct) {
579                 Struct *super = sym->get_super();
580
581                 file << ",\n" << indent
582                      << "const ::System::RunTime::VStructInfo *_realinfo = &"
583                      << **sym->name << "_ns::_info) :\n";
584
585                 indent.align_spaces = 0;
586                 file << indent;
587
588                 if (!super)
589                         file << "_infoptr";
590                 else
591                         cpp_output_name(file, super);
592
593                 file << "(_realinfo";
594         }
595         
596         indent.align_spaces = 0;
597         file << ")\n" << indent << "{\n";
598         
599         indent.indent_level++;
600
601         output_struct_ctor_rec2(sym, 0);
602         
603         if (!extra_vstruct) 
604                 file << indent << "return *this;\n";
605         
606         indent.indent_level--;
607         file << indent << "}\n";
608 }
609
610 int CPPFile::output_struct_ctor_rec1(Struct *sym, int num)
611 {
612         if (sym->get_super())
613                 num = output_struct_ctor_rec1(sym->get_super(), num);
614         
615         for (Struct::entries_iterator i = sym->entries_begin();
616              i != sym->entries_end(); ++i)
617         {
618                 if (num++)
619                         file << ",\n" << indent;
620                 
621                 output_datum(sym, *i, -1);
622                 file << "_arg" << num;
623         }
624         
625         return num;
626 }
627
628 int CPPFile::output_struct_ctor_rec2(Struct *sym, int num)
629 {
630         if (sym->get_super())
631                 num = output_struct_ctor_rec2(sym->get_super(), num);
632         
633         for (Struct::entries_iterator i = sym->entries_begin();
634              i != sym->entries_end(); ++i)
635         {
636                 Datum *d = *i;
637                 file << indent << **d->name << " = _arg" << ++num << ";\n";
638         }
639         
640         return num;
641 }
642
643 void CPPFile::output(Struct *sym, int pass, void *arg2)
644 {
645         switch (pass) {
646                 case trav_nsdecl:
647                         // If indent level is not zero, this is a nested struct or interface.
648                         if (indent.indent_level == 0)
649                                 output_pass(sym, trav_forward);
650
651                         if (sym->is_virtual()) {
652                                 output_nsdecl_begin(sym);
653                                 output_nsdecl_children(sym);
654                                 output_guid(sym->def.guid);
655                                 output_marshall_pass(sym, trav_nsdecl);
656                                 output_nsdecl_end(sym);
657                         } else {
658                                 output_nsdecl_begin(sym);
659                                 output_nsdecl_children(sym);
660                                 output_marshall_pass(sym, trav_nsdecl);
661                                 output_nsdecl_end(sym);
662                         }
663
664                         break;
665                 
666                 case trav_forward: {
667                         bool nested = indent.indent_level != 0;
668
669                         if (!nested)
670                                 ns_in(sym, "FWD_");
671                         else
672                                 extra_newline();
673
674                         file << indent << "struct " << **sym->name << ";\n";
675                         
676                         if (!nested)
677                                 ns_out(sym);
678                                 
679                         break;
680                 }
681                 
682                 case trav_full: {
683                         output_pass(sym, trav_nsdecl);
684                         Struct *super = sym->get_super();
685
686                         if (super)
687                                 output_pass(super, trav_full);
688                         
689                         if (sym->is_virtual())
690                                 output_vstruct_info(sym);
691
692                         declare_dependencies(sym);
693                         ns_in(sym);
694
695                         file << indent << "struct " << get_definition_name(sym);
696
697                         if (super) {
698                                 const String *supername = super->get_fq_name("_ns")
699                                                                ->flatten("::");
700                                 file << " :\n" << indent << "public ::" << *supername;
701                         }
702         
703                         file << "\n" << indent << "{\n";
704                         downscope();
705                         
706                         if (sym->is_virtual())
707                                 output_vstruct_main(sym);
708
709                         int offset = 0;
710                         for (Struct::entries_iterator i = sym->entries_begin();
711                              i != sym->entries_end(); ++i)
712                         {
713                                 extra_newline();
714                                 Datum *d = *i;
715                                 file << indent;
716                                 offset = output_datum(sym, d, offset);
717                                 file << **d->name << ";\n";
718                         }
719                         
720                         bool empty_struct = true;
721                         for (Struct *s = sym; s; s = s->get_super()) {
722                                 if (s->entries_begin() != s->entries_end()) {
723                                         empty_struct = false;
724                                         break;
725                                 } 
726                         }
727                         
728                         if (!empty_struct) {
729                                 output_struct_ctor(sym, false);
730                                 
731                                 if (sym->is_virtual())
732                                         output_struct_ctor(sym, true);
733                         }
734                         
735                         upscope();
736                         file << indent << "};\n";
737
738                         ns_out(sym);
739
740                         all_ns_in(sym, true, "MARSHALL_");
741                         output_marshall_pass(sym, trav_full);
742                         all_ns_out(sym, true);
743                         
744                         output_aliases_and_types(sym);
745                         
746                         for (NameSpace::const_iterator i = sym->begin(); i != sym->end(); ++i) {
747                                 Symbol *sym2 = (*i).second;
748                                 output_pass(sym2, trav_full);
749                         }
750
751                         break;
752                 }
753
754                 case trav_marshall:
755                         output_marshall(sym, static_cast<Datum *>(arg2));
756                         break;
757                 
758                 default:
759                         BUG();
760         }
761 }
762
763 void CPPFile::output(Interface *sym, int pass, void *arg2)
764 {
765         switch (pass) {
766                 case trav_nsdecl:
767                         output_nsdecl_begin(sym);
768                         output_nsdecl_children(sym);
769
770                         output_guid(sym->def.guid);
771                         output_ifaceinfo(sym);
772
773                         output_nsdecl_end(sym);
774                         break;
775                 
776                 case trav_forward: {
777                         bool nested = indent.indent_level != 0;
778
779                         if (!nested)
780                                 ns_in(sym, "FWD_");
781                         else
782                                 extra_newline();
783
784                         file << indent << "struct " << **sym->name << ";\n"
785                              << indent << "struct _i_" << **sym->name << ";\n";
786
787                         if (!nested)
788                                 ns_out(sym);
789
790                         break;
791                 }
792                 
793                 case trav_obj_stub: {
794                         output_pass(sym, trav_forward);
795
796                         for (Interface::supers_iterator i = sym->supers_begin();
797                              i != sym->supers_end(); ++i)
798                         {
799                                 Interface *super = *i;
800                                 output_pass(super, trav_obj_stub);
801                         }
802
803                         declare_dependencies(sym);
804                         ns_in(sym, "STUB_");
805                         
806                         file << indent << "struct "
807                              << get_definition_name(sym) << " {\n";
808
809                         downscope();
810
811                         output_wrapper(sym);
812
813                         upscope();
814                         file << indent << "};\n";
815
816                         ns_out(sym);
817                         break;
818                 }
819                 
820                 case trav_obj_def: {
821                         output_pass(sym, trav_obj_stub);
822
823                         for (Interface::supers_iterator i = sym->supers_begin();
824                              i != sym->supers_end(); ++i)
825                         {
826                                 Interface *super = *i;
827                                 output_pass(super, trav_full);
828                         }
829                         
830                         declare_dependencies(sym);
831                         ns_in(sym, "OBJDEF_");
832
833                         file << indent << "struct ";
834                         file << get_definition_name(sym, "_i_") << " {\n";
835
836                         downscope();
837
838                         output_internal(sym);
839
840                         upscope();
841                         file << indent << "};\n\n";
842
843                         output_casts(sym);
844
845                         ns_out(sym);
846                         break;
847                         
848                 case trav_full:
849                         output_pass(sym, trav_obj_def);
850
851                         declare_dependencies(sym, true);
852                         ns_in(sym);
853                         
854                         output_method_defs(sym);
855                         
856                         ns_out(sym);
857                         output_aliases_and_types(sym);
858
859                         for (NameSpace::const_iterator i = sym->begin(); i != sym->end(); ++i) {
860                                 Symbol *sym2 = (*i).second;
861                                 output_pass(sym2, trav_full);
862                         }
863         
864                         break;
865
866                 case trav_marshall:
867                         output_marshall(sym, static_cast<Datum *>(arg2));
868                         break;
869                 
870                 default:
871                         BUG();
872                 }
873         }
874 }
875
876 void CPPFile::output_bf_elem(Datum *d, int pos, int bits,
877                              string &prefix)
878 {
879         Type *t = d->type;
880         BitField *bf = dynamic_cast<BitField *>(t);
881         Enum *en = dynamic_cast<Enum *>(t);
882         
883         string fieldname;
884
885         if (!d->name->compare(0, 4, "get_") ||
886             !d->name->compare(0, 4, "set_"))
887                 fieldname = '_';
888         
889         fieldname.append(**d->name);
890         
891         if (bf) {
892                 string newprefix(prefix);
893                 newprefix.append(**d->name);
894                 newprefix.append("_IDLNS_");
895                 output_bf(bf, d->def.icon, bits, newprefix);
896                 
897                 // FIXME: getters and setters
898         } else if (en || !t) {
899                 file << indent << "uint" << bits << "_t "
900                      << prefix << fieldname << ':' << d->def.icon << ";\n";
901         } else {
902                 // This is checked here rather than in input.cc, because
903                 // I'm lazy.
904                 
905                 fprintf(stderr, "idlc: Bad input: \"%s\" cannot be the type of \"%s\"\n",
906                         t->get_fq_name()->flatten()->c_str(),
907                         d->get_fq_name()->flatten()->c_str());
908         
909                 throw UserError();
910         }
911 }
912
913 void CPPFile::output_bf(BitField *sym, int bits, int typebits,
914                         string &prefix)
915 {
916         int size = 0;
917         
918         assert(bits == sym->def.bits || bits == typebits);
919         
920         for (BitField::entries_iterator i = sym->entries_begin();
921              i != sym->entries_end(); ++i)
922                 size += (*i)->def.icon;
923         
924         if (size > sym->def.bits) {
925                 // FIXME: This isn't detected in the front end,
926                 // but even once it is, this should stay as a
927                 // replacement for input.cc checking.
928                 
929                 fprintf(stderr, "idlc: \"%s\" is too small (%d bits) for its "
930                                 "contents (%d bits)\n",
931                         sym->get_fq_name()->flatten()->c_str(),
932                         sym->def.bits, size);
933         
934                 throw UserError();
935         }
936         
937         if (target->bitfield_big_endian) {
938                 if (size != bits) {
939                         // The prefix is put at the end, so that we can avoid
940                         // consecutive underscores or an underscore followed
941                         // by a capital, both of which are reserved in C++.
942                 
943                         file << indent << "uint" << bits << "_t _pad_" << prefix
944                              << ':' << bits - size << ";\n";
945                 }
946
947                 int pos = sym->def.bits;
948
949                 for (BitField::entries_reverse_iterator i = sym->entries_rbegin();
950                      i != sym->entries_rend(); ++i)
951                 {
952                         Datum *d = *i;
953                         pos -= d->def.icon;
954                         output_bf_elem(d, pos, typebits, prefix);
955                 }
956         } else {
957                 int pos = 0;
958         
959                 for (BitField::entries_iterator i = sym->entries_begin();
960                      i != sym->entries_end(); ++i)
961                 {
962                         Datum *d = *i;
963                         output_bf_elem(d, pos, typebits, prefix);
964                         pos += d->def.icon;
965                 }
966         }
967 }
968
969 void CPPFile::output(BitField *sym, int pass, void *arg2)
970 {
971         switch (pass) {
972                 case trav_nsdecl:
973                         output_nsdecl(sym);
974                         break;
975
976                 case trav_forward:
977                         extra_newline();
978                         file << indent << "union " << **sym->name << ";\n";
979                         break;
980                 
981                 case trav_full: {
982                         int bits = round_up_bits(sym->def.bits);
983                         ns_in(sym);
984
985                         file << indent << "union ";
986                         file << get_definition_name(sym) << " {\n";
987                         downscope();
988                         
989                         file << indent << "struct {\n";
990
991                         downscope();
992                         string nullprefix;
993                         output_bf(sym, bits, bits, nullprefix);
994                         upscope();
995                         
996                         file << indent << "};\n\n"
997                              << indent << "uint" << bits << "_t _raw;\n\n"
998                              << indent << **sym->name << "()\n"
999                              << indent << "{\n"
1000                              << indent << "\t_raw = 0;\n"
1001                              << indent << "}\n\n"
1002                              << indent << **sym->name << "(uint" << bits << "_t _init)\n"
1003                              << indent << "{\n"
1004                              << indent << "\t_raw = _init;\n"
1005                              << indent << "}\n\n"
1006                              << indent << "operator uint" << bits << "_t()\n"
1007                              << indent << "{\n"
1008                              << indent << "\treturn _raw;\n"
1009                              << indent << "}\n";
1010                         
1011                         upscope();
1012                         file << indent << "};\n";
1013
1014                         ns_out(sym);
1015                         output_aliases_and_types(sym);
1016                         break;
1017                 }
1018
1019                 case trav_marshall:
1020                         output_marshall(sym, static_cast<Datum *>(arg2));
1021                         break;
1022
1023                 default:
1024                         BUG();
1025         }
1026 }
1027
1028 void CPPFile::output(Enum *sym, int pass, void *arg2)
1029 {
1030         switch (pass) {
1031                 case trav_nsdecl:
1032                         /* no-op */
1033                         break;
1034
1035                 case trav_forward: {
1036                         bool do_ns_out = false;
1037                         
1038                         if (indent.indent_level == 0) {
1039                                 ns_in(sym);
1040                                 do_ns_out = true;
1041                         } else {
1042                                 extra_newline();
1043                         }
1044                         
1045                         file << indent << "struct " << **sym->name << " {\n";
1046                         downscope();
1047                         
1048                         for (Enum::entries_iterator i = sym->entries_begin();
1049                              i != sym->entries_end(); ++i)
1050                         {
1051                                 Datum *d = *i;
1052                                 
1053                                 file << indent << "static const uint" 
1054                                      << round_up_bits(sym->def.bits) << "_t "
1055                                      << **d->name << " = " << d->def.ucon << ";\n";
1056                         }
1057                         
1058                         file << '\n' << indent << "unsigned int _val;\n\n";
1059
1060                         file << indent << **sym->name << "()\n"
1061                              << indent << "{\n"
1062                              << indent << "\t_val = 0;\n"
1063                              << indent << "}\n\n";
1064
1065                         file << indent << **sym->name << "(unsigned int val)\n"
1066                              << indent << "{\n"
1067                              << indent << "\t_val = val;\n"
1068                              << indent << "}\n\n";
1069
1070                         file << indent << "operator unsigned int()\n"
1071                              << indent << "{\n"
1072                              << indent << "\treturn _val;\n"
1073                              << indent << "}\n\n";
1074                         
1075                         upscope();
1076                         file << indent << "};\n";
1077
1078                         if (do_ns_out)
1079                                 ns_out(sym);
1080
1081                         break;
1082                 }
1083                 
1084                 case trav_full:
1085                         // Nothing particular to do here, other than to make sure
1086                         // that trav_forward has happened (which will always need to
1087                         // be done here if it's not a nested type).
1088                         
1089                         output_pass(sym, trav_forward);
1090                         break;
1091
1092                 case trav_marshall:
1093                         output_marshall(sym, static_cast<Datum *>(arg2));
1094                         break;
1095
1096                 default:
1097                         BUG();
1098         }
1099 }
1100
1101 void CPPFile::output(BasicType *sym, int pass, void *arg2)
1102 {
1103         switch (pass) {
1104                 case trav_nsdecl:
1105                         /* no-op */
1106                         break;
1107
1108                 case trav_forward: {
1109                         bool do_ns_out = false;
1110                         
1111                         if (indent.indent_level == 0) {
1112                                 ns_in(sym);
1113                                 do_ns_out = true;
1114                         } else {
1115                                 extra_newline();
1116                         }
1117                         
1118                         file << indent << "typedef ";
1119                         assert(!is_array(sym->def));
1120                         cpp_output_type(file, sym->def, false);
1121                         file << **sym->name << ";\n";
1122
1123                         if (do_ns_out)
1124                                 ns_out(sym);
1125
1126                         break;
1127                 }
1128                 
1129                 case trav_full:
1130                         output_pass(sym, trav_forward);
1131                         break;
1132
1133                 case trav_marshall:
1134                         output_marshall(sym, static_cast<Datum *>(arg2));
1135                         break;
1136
1137                 default:
1138                         BUG();
1139         }
1140 }
1141
1142 void CPPFile::output(Alias *sym, int pass, void *arg2)
1143 {
1144         switch (pass) {
1145                 case trav_nsdecl:
1146                         /* no-op */
1147                         break;
1148
1149                 case trav_forward: {
1150                         bool do_ns_out = false;
1151                         
1152                         if (indent.indent_level == 0) {
1153                                 all_ns_in(sym);
1154                                 do_ns_out = true;
1155                         } else {
1156                                 extra_newline();
1157                         }
1158                         
1159                         const String *type = sym->get_concrete_sym()->get_fq_name("_ns")
1160                                                 ->flatten("::");
1161
1162                         file << indent << "typedef " << *type << " " 
1163                              << **sym->name << ";\n";
1164
1165                         if (do_ns_out)
1166                                 all_ns_out(sym);
1167
1168                         break;
1169                 }
1170                 
1171                 case trav_full:
1172                         output_pass(sym, trav_forward);
1173                         break;
1174
1175                 default:
1176                         BUG();
1177         }
1178 }
1179
1180 void CPPFile::output(TypeDef *sym, int pass, void *arg2)
1181 {
1182         switch (pass) {
1183                 case trav_nsdecl:
1184                 case trav_forward:
1185                         /* no-op */
1186                         break;
1187
1188                 case trav_full: {
1189                         output_pass(sym->get_concrete_sym(), trav_forward);
1190                         
1191                         bool do_ns_out = false;
1192                         
1193                         if (indent.indent_level == 0) {
1194                                 all_ns_in(sym);
1195                                 do_ns_out = true;
1196                         } else {
1197                                 extra_newline();
1198                         }
1199                         
1200                         const String *type = sym->get_concrete_sym()->get_fq_name("_ns")
1201                                                 ->flatten("::");
1202
1203                         file << indent << "typedef " << *type << " " 
1204                              << **sym->name << ";\n";
1205
1206                         if (do_ns_out)
1207                                 all_ns_out(sym);
1208
1209                         break;
1210                 }
1211                 
1212                 default:
1213                         BUG();
1214         }
1215 }
1216
1217 void CPPFile::output(Datum *sym, int pass, void *arg2)
1218 {
1219         assert(sym->def.flags.field.Const);
1220         
1221         switch (pass) {
1222                 case trav_nsdecl:
1223                 case trav_forward:
1224                         /* no-op */
1225                         break;
1226
1227                 case trav_full: {
1228                         if (sym->type)
1229                                 declare_type_dependency(sym->type, false);
1230
1231                         bool do_ns_out = false;
1232                         
1233                         if (indent.indent_level == 0) {
1234                                 all_ns_in(sym);
1235                                 do_ns_out = true;
1236                         } else {
1237                                 extra_newline();
1238                         }
1239                         
1240                         file << indent << "static const ";
1241                         
1242                         assert(!is_array(sym->def.basictype));
1243                         
1244                         if (sym->type)
1245                                 cpp_output_type(file, sym->type, false, false);
1246                         else
1247                                 cpp_output_type(file, sym->def.basictype, false);
1248
1249                         file << **sym->name << " = ";
1250                         
1251                         CompiledBasicType *def;
1252                         if (sym->type) {
1253                                 Symbol *real_type = sym->type->get_concrete_sym();
1254                                 BasicType *bt = dynamic_cast<BasicType *>(real_type);
1255                                 assert(bt);
1256                                 
1257                                 def = &bt->def;
1258                         } else {
1259                                 def = &sym->def.basictype;
1260                         }
1261                         
1262                         if (def->flags.field.Float) {
1263                                 file << sym->def.fcon;
1264                         } else if (def->flags.field.Bool) {
1265                                 if (sym->def.ucon == 0)
1266                                         file << "false";
1267                                 else
1268                                         file << "true";
1269                         } else {
1270                                 if (def->flags.field.Unsigned) {
1271                                         file << "0x" << std::hex << sym->def.ucon << std::dec << 'U';
1272                                 } else {
1273                                         file << sym->def.icon;
1274                                 }
1275
1276                                 file << "LL";
1277                         }
1278                         
1279                         file << ";\n";
1280
1281                         if (do_ns_out)
1282                                 all_ns_out(sym);
1283
1284                         break;
1285                 }
1286
1287                 default:
1288                         BUG();
1289         }
1290 }
1291
1292 void CPPBinding::output_root(UserNameSpace *ns, const char *dir)
1293 {
1294         delete new CPPFile(ns, dir);
1295 }