Switch to a simple X11-style license.
[polintos/scott/priv.git] / idlcomp / languages / c++ / main.cc
1 // idlcomp/languages/c++/main.cc -- C++ IDL binding
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 condition:
11 // 
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
14 // 
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
21 // SOFTWARE.
22
23 // FIXME: escape C++ reserved words
24
25 #include <cerrno>
26
27 #include <sys/types.h>
28 #include <sys/stat.h>
29
30 #include <targets.h>
31 #include "c++.h"
32
33 CPPBinding cppbinding;
34
35 CPPFile::CPPFile(UserNameSpace *NS, const char *dir) :
36 dirname(dir)
37 {
38         indent.indent_level = 0;
39         indent.align_spaces = 0;
40         do_extra_newline = true;
41         ns = NS;
42
43         dirname.append(1, '/');
44         dirname.append(ns->name);
45         string headername(dirname);
46         headername.append(".h");
47
48         file.open(headername.c_str());
49         if (!file.is_open()) {
50                 fprintf(stderr, "Could not create output file \"%s\": %s.\n",
51                         headername.c_str(), strerror(errno));
52
53                 throw UserError();
54         }
55         
56         if (mkdir(dirname.c_str(), 0777) < 0) {
57                 fprintf(stderr, "Could not create output directory \"%s\": %s.\n",
58                         dir, strerror(errno));
59
60                 throw UserError();
61         }
62         
63         file <<   "// " << *ns->get_fq_name()->flatten(".")
64              << "\n// This is a C++ language binding generated by idlc.\n"
65              <<   "// Do not modify this file directly.\n\n";
66
67         fqname = ns->get_fq_name();
68         String *fqname_flat = ns->get_fq_name()->flatten("_IDLNS_");
69         file <<   "#ifndef IDL_HDR_" << *fqname_flat
70              << "\n#define IDL_HDR_" << *fqname_flat << "\n\n";
71         
72         file << "#include <orb.h>\n";
73
74         first_traversal = ++traversal;
75         assert(first_traversal >= 0);
76         
77         for (NameSpace::const_iterator i = ns->begin(); i != ns->end(); ++i) {
78                 Symbol *sym = (*i).second;
79                 UserNameSpace *uns = dynamic_cast<UserNameSpace *>(sym);
80                 
81                 if (uns) {
82                         file << "#include \"" << **ns->name << '/' << **uns->name << ".h\"\n";
83                         
84                         // Process namespaces first, to minimize duplicate definitions
85                         // if this namespace depends on something declared in a sub
86                         // namespace.
87                         
88                         output(uns);
89                 }
90         }
91
92         for (NameSpace::const_iterator i = ns->begin(); i != ns->end(); ++i) {
93                 Symbol *sym = (*i).second;
94                 UserNameSpace *uns = dynamic_cast<UserNameSpace *>(sym);
95                 
96                 if (!uns)
97                         output_pass(sym, trav_nsdecl);
98         }
99
100         for (NameSpace::const_iterator i = ns->begin(); i != ns->end(); ++i) {
101                 Symbol *sym = (*i).second;
102                 UserNameSpace *uns = dynamic_cast<UserNameSpace *>(sym);
103                 
104                 if (!uns)
105                         output_pass(sym, trav_full);
106         }
107 }
108
109 CPPFile::~CPPFile()
110 {
111         file << "#endif\n";
112         
113         assert(indent.indent_level == 0);
114 }
115
116 void CPPFile::ifndef_in(Symbol *sym, const char *extra)
117 {
118         StrList *fqname = sym->get_fq_name();
119         String *fqname_flat = fqname->flatten("_IDLNS_");
120
121         assert(indent.indent_level == 0);
122
123         file << "\n#ifndef IDL_DUP_" << extra << *fqname_flat
124              << "\n#define IDL_DUP_" << extra << *fqname_flat << "\n";
125 }
126
127 void CPPFile::ifndef_out()
128 {
129         file << "\n#endif\n";
130 }
131
132 void CPPFile::ns_in(Symbol *sym, const char *extra)
133 {
134         // Only output user namespaces here; if we're defining a nested type,
135         // it will have been forward declared already, and thus the
136         // non-user-namespaces can be specified directly in the definition.
137         //
138         // For non-forward-declarables such as metadata, use all_ns_in.
139         
140         StrList *ns_fqname = sym->find_toplevel_type()->get_ns()->get_fq_name();
141
142         ifndef_in(sym, extra);
143
144         for (StrList::const_iterator i = ns_fqname->begin();
145              i != ns_fqname->end(); ++i) {
146                 const String *str = *i;
147                 file << "namespace " << *str << " {\n";
148         }
149         
150         downscope();
151 }
152
153 void CPPFile::ns_out(Symbol *sym)
154 {
155         upscope();
156         assert(indent.indent_level == 0);
157
158         for (Symbol *s = sym->find_toplevel_type()->get_ns(); s != toplevel;
159              s = s->get_ns())
160                 file << "}";
161
162         ifndef_out();
163 }
164
165 void CPPFile::all_ns_in(Symbol *sym, bool include_self, const char *extra)
166 {
167         NameSpace *ns = sym->find_toplevel_type()->get_ns();
168         StrList *ns_fqname = ns->get_fq_name();
169
170         ifndef_in(sym, extra);
171
172         for (StrList::const_iterator i = ns_fqname->begin();
173              i != ns_fqname->end(); ++i) {
174                 const String *str = *i;
175                 file << "namespace " << *str << " {\n";
176         }
177         
178         stack<SymbolRef> typens;
179         
180         if (!include_self)
181                 sym = sym->get_ns();
182         
183         for (Symbol *s = sym; s != ns; s = s->get_ns())
184                 typens.push(s);
185         
186         while (!typens.empty()) {
187                 Symbol *s = typens.top();
188                 typens.pop();
189                 file << "namespace " << **s->name << "_ns {\n";
190         }
191         
192         downscope();
193 }
194
195 void CPPFile::all_ns_out(Symbol *sym, bool include_self)
196 {
197         upscope();
198         assert(indent.indent_level == 0);
199
200         if (!include_self)
201                 sym = sym->get_ns();
202
203         for (Symbol *s = sym; s != toplevel; s = s->get_ns())
204                 file << "}";
205
206         ifndef_out();
207 }
208
209 String &CPPFile::get_definition_name(Symbol *sym, const char *prefix)
210 {
211         NameSpace *ns = sym->get_ns();
212         UserNameSpace *uns = dynamic_cast<UserNameSpace *>(ns);
213         String *str;
214         
215         if (!uns) {
216                 str = &get_definition_name(ns);
217                 str->append("_ns::");
218         } else {
219                 str = new String();
220         }
221         
222         str->append(prefix);
223         str->append(**sym->name);
224         return *str;
225 }
226
227 void cpp_output_name(ostream &file, Symbol *sym, const char *prefix)
228 {
229         StrList *sl = sym->get_fq_name("_ns");
230         sl->pop_back();
231
232         file << "::" << *sl->flatten("::") << "::" << prefix << **sym->name;
233 }
234
235 void CPPFile::output(UserNameSpace *sym, int pass, void *arg2)
236 {
237         assert(indent.indent_level == 0);
238         delete new CPPFile(sym, dirname.c_str());
239 }
240
241 static inline int round_up_bits(int bits)
242 {
243         assert(bits >= 1 && bits <= 64);
244         
245         if (bits > 32)
246                 return 64;
247         if (bits > 16)
248                 return 32;
249         if (bits > 8)
250                 return 16;
251
252         return 8;
253 }
254
255 // FIXME: Inline arrays...
256 void cpp_output_type(ostream &file, Type *t, bool array, bool is_mutable)
257 {
258         if (array) {
259                 file << "::System::RunTime::";
260                 
261                 if (is_mutable)
262                         file << "Mutable";
263                 
264                 file << "Array< ";
265         }
266
267         cpp_output_name(file, t);
268
269         if (array)
270                 file << ">";
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 << '>';
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())
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 << "static const __attribute__((unused)) union {\n"
397              << indent << "\tunsigned char c[16];\n"
398              << indent << "\tunsigned long l[];\n"
399              << indent << "} _guid = {\n"
400              << indent << "\t{ ";
401         
402         for (int i = 0; i < 16; i++) {
403                 if (i == 8)
404                         file << '\n' << indent << "\t  ";
405                 
406                 sprintf(guidhex, "0x%02x, ", *guid++);
407                 file << guidhex;
408         }
409
410         file << "}\n"
411              << indent << "};\n";
412
413         do_extra_newline = true;
414 }
415
416 void CPPFile::output_nsdecl(NameSpace *ns, nsdecl_callback cb)
417 {
418         // If indent level is not zero, this is a nested struct or interface.
419         if (indent.indent_level == 0)
420                 ns_in(ns, "NS_");
421         else
422                 extra_newline();
423
424         file << indent << "namespace " << **ns->name << "_ns {\n";
425         downscope();
426         
427         if (cb)
428                 cb(this, ns);
429         
430         for (NameSpace::const_iterator i = ns->begin(); i != ns->end(); ++i) {
431                 Symbol *sym = (*i).second;
432
433                 assert(pass_needed(sym, trav_forward));
434                 assert(pass_needed(sym, trav_nsdecl));
435                 
436                 // If it's a Method or a non-const Datum, this is a no-op.
437                 output_pass(sym, trav_forward);
438                 output_pass(sym, trav_nsdecl);
439         }
440         
441         upscope();
442         
443         file << indent << "}\n";
444
445         if (indent.indent_level == 1)
446                 ns_out(ns);
447 }
448
449 void CPPFile::output_aliases_and_types(NameSpace *ns)
450 {
451         for (NameSpace::const_iterator i = ns->begin(); i != ns->end(); ++i) {
452                 Symbol *sym = (*i).second;
453                 if (dynamic_cast<Alias *>(sym) || dynamic_cast<Type *>(sym))
454                         output_pass(sym, trav_full);
455         }
456 }               
457
458 void CPPFile::output_vstruct_ns(CPPFile *cpp, NameSpace *sym)
459 {
460         Struct *str = dynamic_cast<Struct *>(sym);
461         assert(str);
462         assert(str->is_virtual());
463         
464         cpp->output_guid(str->def.guid);
465 }
466
467 void CPPFile::output_vstruct_info(Struct *sym)
468 {
469         all_ns_in(sym, true, "VINFO_");
470
471         file << indent << "static const __attribute__((unused)) "
472                           "unsigned long *const _guids[] = {\n";
473         
474         stack<StructRef> supers;
475         sym->chainlen = 0;
476                         
477         for (Struct *i = sym; i; i = i->get_super()) {
478                 sym->chainlen++;
479                 supers.push(i);
480         }
481         
482         for (int i = 0; i < sym->chainlen; i++) {
483                 Struct *super = supers.top();
484                 supers.pop();
485
486                 file << indent << '\t';
487                 cpp_output_name(file, super);
488                 file << "_ns::_guid.l,\n";
489         }
490
491         file << indent << "};\n\n"
492              << indent << "static const __attribute__((unused)) "
493                           "::System::RunTime::VStructInfo _info = {\n"
494              << indent << "\t_guids, " << sym->chainlen << '\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 " << 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 (sym->is_virtual()) {
648                                 output_nsdecl(sym, output_vstruct_ns);
649                         } else {
650                                 output_nsdecl(sym);
651                         }
652
653                         break;
654                 
655                 case trav_forward: {
656                         bool nested = indent.indent_level != 0;
657
658                         if (!nested)
659                                 ns_in(sym, "FWD_");
660                         else
661                                 extra_newline();
662
663                         file << indent << "struct " << **sym->name << ";\n";
664                         
665                         if (!nested)
666                                 ns_out(sym);
667                                 
668                         break;
669                 }
670                 
671                 case trav_full: {
672                         output_pass(sym, trav_nsdecl);
673                         Struct *super = sym->get_super();
674
675                         if (super)
676                                 output_pass(super, trav_full);
677                         
678                         if (sym->is_virtual())
679                                 output_vstruct_info(sym);
680
681                         declare_dependencies(sym);
682                         ns_in(sym);
683
684                         file << indent << "struct " << get_definition_name(sym);
685
686                         if (super) {
687                                 const String *supername = super->get_fq_name("_ns")
688                                                                ->flatten("::");
689                                 file << " :\n" << indent << "public ::" << *supername;
690                         }
691         
692                         file << "\n" << indent << "{\n";
693                         downscope();
694                         
695                         if (sym->is_virtual())
696                                 output_vstruct_main(sym);
697
698                         int offset = 0;
699                         for (Struct::entries_iterator i = sym->entries_begin();
700                              i != sym->entries_end(); ++i)
701                         {
702                                 extra_newline();
703                                 Datum *d = *i;
704                                 file << indent;
705                                 offset = output_datum(sym, d, offset);
706                                 file << **d->name << ";\n";
707                         }
708                         
709                         bool empty_struct = true;
710                         for (Struct *s = sym; s; s = s->get_super()) {
711                                 if (s->entries_begin() != s->entries_end()) {
712                                         empty_struct = false;
713                                         break;
714                                 } 
715                         }
716                         
717                         if (!empty_struct) {
718                                 output_struct_ctor(sym, false);
719                                 
720                                 if (sym->is_virtual())
721                                         output_struct_ctor(sym, true);
722                         }
723
724                         upscope();
725                         file << indent << "};\n";
726         
727                         ns_out(sym);
728                         
729                         output_aliases_and_types(sym);
730                         
731                         for (NameSpace::const_iterator i = sym->begin(); i != sym->end(); ++i) {
732                                 Symbol *sym2 = (*i).second;
733                                 output_pass(sym2, trav_full);
734                         }
735
736                         break;
737                 }
738                 
739                 default:
740                         BUG();
741         }
742 }
743
744 void CPPFile::output_iface_ns(CPPFile *file, NameSpace *sym)
745 {
746         Interface *i = dynamic_cast<Interface *>(sym);
747         assert(i);
748         
749         file->output_guid(i->def.guid);
750 }
751
752 void CPPFile::output(Interface *sym, int pass, void *arg2)
753 {
754         switch (pass) {
755                 case trav_nsdecl:
756                         output_nsdecl(sym, output_iface_ns);
757                         break;
758                 
759                 case trav_forward: {
760                         bool nested = indent.indent_level != 0;
761
762                         if (!nested)
763                                 ns_in(sym, "FWD_");
764                         else
765                                 extra_newline();
766
767                         file << indent << "struct " << **sym->name << ";\n"
768                              << indent << "struct _i_" << **sym->name << ";\n";
769
770                         if (!nested)
771                                 ns_out(sym);
772
773                         break;
774                 }
775                 
776                 case trav_obj_stub: {
777                         output_pass(sym, trav_forward);
778
779                         for (Interface::supers_iterator i = sym->supers_begin();
780                              i != sym->supers_end(); ++i)
781                         {
782                                 Interface *super = *i;
783                                 output_pass(super, trav_obj_stub);
784                         }
785
786                         declare_dependencies(sym);
787                         ns_in(sym, "STUB_");
788                         
789                         file << indent << "struct "
790                              << get_definition_name(sym) << " {\n";
791
792                         downscope();
793
794                         output_wrapper(sym);
795
796                         upscope();
797                         file << indent << "};\n";
798
799                         ns_out(sym);
800                         break;
801                 }
802                 
803                 case trav_obj_def: {
804                         output_pass(sym, trav_obj_stub);
805
806                         for (Interface::supers_iterator i = sym->supers_begin();
807                              i != sym->supers_end(); ++i)
808                         {
809                                 Interface *super = *i;
810                                 output_pass(super, trav_full);
811                         }
812                         
813                         declare_dependencies(sym);
814                         ns_in(sym, "OBJDEF_");
815
816                         file << indent << "struct ";
817                         file << get_definition_name(sym, "_i_") << " {\n";
818
819                         downscope();
820
821                         output_internal(sym);
822
823                         upscope();
824                         file << indent << "};\n\n";
825
826                         output_casts(sym);
827
828                         ns_out(sym);
829                         break;
830                         
831                 case trav_full:
832                         output_pass(sym, trav_obj_def);
833
834                         declare_dependencies(sym, true);
835                         ns_in(sym);
836                         
837                         output_method_defs(sym);
838                         
839                         ns_out(sym);
840                         output_aliases_and_types(sym);
841
842                         for (NameSpace::const_iterator i = sym->begin(); i != sym->end(); ++i) {
843                                 Symbol *sym2 = (*i).second;
844                                 output_pass(sym2, trav_full);
845                         }
846         
847                         break;
848                 
849                 default:
850                         BUG();
851                 }
852         }
853 }
854
855 void CPPFile::output_bf_elem(Datum *d, int pos, int bits,
856                              string &prefix)
857 {
858         Type *t = d->type;
859         BitField *bf = dynamic_cast<BitField *>(t);
860         Enum *en = dynamic_cast<Enum *>(t);
861         
862         string fieldname;
863
864         if (!d->name->compare(0, 4, "get_") ||
865             !d->name->compare(0, 4, "set_"))
866                 fieldname = '_';
867         
868         fieldname.append(**d->name);
869         
870         if (bf) {
871                 string newprefix(prefix);
872                 newprefix.append(**d->name);
873                 newprefix.append("_IDLNS_");
874                 output_bf(bf, d->def.icon, bits, newprefix);
875                 
876                 // FIXME: getters and setters
877         } else if (en || !t) {
878                 file << indent << "uint" << bits << "_t "
879                      << prefix << fieldname << ':' << d->def.icon << ";\n";
880         } else {
881                 // This is checked here rather than in input.cc, because
882                 // I'm lazy.
883                 
884                 fprintf(stderr, "idlc: Bad input: \"%s\" cannot be the type of \"%s\"\n",
885                         t->get_fq_name()->flatten()->c_str(),
886                         d->get_fq_name()->flatten()->c_str());
887         
888                 throw UserError();
889         }
890 }
891
892 void CPPFile::output_bf(BitField *sym, int bits, int typebits,
893                         string &prefix)
894 {
895         int size = 0;
896         
897         assert(bits == sym->def.bits || bits == typebits);
898         
899         for (BitField::entries_iterator i = sym->entries_begin();
900              i != sym->entries_end(); ++i)
901                 size += (*i)->def.icon;
902         
903         if (size > sym->def.bits) {
904                 // FIXME: This isn't detected in the front end,
905                 // but even once it is, this should stay as a
906                 // replacement for input.cc checking.
907                 
908                 fprintf(stderr, "idlc: \"%s\" is too small (%d bits) for its "
909                                 "contents (%d bits)\n",
910                         sym->get_fq_name()->flatten()->c_str(),
911                         sym->def.bits, size);
912         
913                 throw UserError();
914         }
915         
916         if (target->bitfield_big_endian) {
917                 if (size != bits) {
918                         // The prefix is put at the end, so that we can avoid
919                         // consecutive underscores or an underscore followed
920                         // by a capital, both of which are reserved in C++.
921                 
922                         file << indent << "uint" << bits << "_t _pad_" << prefix
923                              << ':' << bits - size << ";\n";
924                 }
925
926                 int pos = sym->def.bits;
927
928                 for (BitField::entries_reverse_iterator i = sym->entries_rbegin();
929                      i != sym->entries_rend(); ++i)
930                 {
931                         Datum *d = *i;
932                         pos -= d->def.icon;
933                         output_bf_elem(d, pos, typebits, prefix);
934                 }
935         } else {
936                 int pos = 0;
937         
938                 for (BitField::entries_iterator i = sym->entries_begin();
939                      i != sym->entries_end(); ++i)
940                 {
941                         Datum *d = *i;
942                         output_bf_elem(d, pos, typebits, prefix);
943                         pos += d->def.icon;
944                 }
945         }
946 }
947
948 void CPPFile::output(BitField *sym, int pass, void *arg2)
949 {
950         switch (pass) {
951                 case trav_nsdecl:
952                         output_nsdecl(sym);
953                         break;
954
955                 case trav_forward:
956                         extra_newline();
957                         file << indent << "union " << **sym->name << ";\n";
958                         break;
959                 
960                 case trav_full: {
961                         int bits = round_up_bits(sym->def.bits);
962                         ns_in(sym);
963
964                         file << indent << "union ";
965                         file << get_definition_name(sym) << " {\n";
966                         downscope();
967                         
968                         file << indent << "struct {\n";
969
970                         downscope();
971                         string nullprefix;
972                         output_bf(sym, bits, bits, nullprefix);
973                         upscope();
974                         
975                         file << indent << "};\n\n"
976                              << indent << "uint" << bits << "_t _raw;\n\n"
977                              << indent << **sym->name << "()\n"
978                              << indent << "{\n"
979                              << indent << "\t_raw = 0;\n"
980                              << indent << "}\n\n"
981                              << indent << **sym->name << "(uint" << bits << "_t _init)\n"
982                              << indent << "{\n"
983                              << indent << "\t_raw = _init;\n"
984                              << indent << "}\n\n"
985                              << indent << "operator uint" << bits << "_t()\n"
986                              << indent << "{\n"
987                              << indent << "\treturn _raw;\n"
988                              << indent << "}\n";
989                         
990                         upscope();
991                         file << indent << "};\n";
992
993                         ns_out(sym);
994                         output_aliases_and_types(sym);
995                         break;
996                 }
997
998                 default:
999                         BUG();
1000         }
1001 }
1002
1003
1004 void CPPFile::output(Enum *sym, int pass, void *arg2)
1005 {
1006         switch (pass) {
1007                 case trav_nsdecl:
1008                         /* no-op */
1009                         break;
1010
1011                 case trav_forward: {
1012                         bool do_ns_out = false;
1013                         
1014                         if (indent.indent_level == 0) {
1015                                 ns_in(sym);
1016                                 do_ns_out = true;
1017                         } else {
1018                                 extra_newline();
1019                         }
1020                         
1021                         file << indent << "struct " << **sym->name << " {\n";
1022                         downscope();
1023                         
1024                         for (Enum::entries_iterator i = sym->entries_begin();
1025                              i != sym->entries_end(); ++i)
1026                         {
1027                                 Datum *d = *i;
1028                                 
1029                                 file << indent << "static const uint" 
1030                                      << round_up_bits(sym->def.bits) << "_t "
1031                                      << **d->name << " = " << d->def.ucon << ";\n";
1032                         }
1033                         
1034                         file << '\n' << indent << "unsigned int _val;\n\n";
1035
1036                         file << indent << **sym->name << "()\n"
1037                              << indent << "{\n"
1038                              << indent << "\t_val = 0;\n"
1039                              << indent << "}\n\n";
1040
1041                         file << indent << **sym->name << "(unsigned int val)\n"
1042                              << indent << "{\n"
1043                              << indent << "\t_val = val;\n"
1044                              << indent << "}\n\n";
1045
1046                         file << indent << "operator unsigned int()\n"
1047                              << indent << "{\n"
1048                              << indent << "\treturn _val;\n"
1049                              << indent << "}\n\n";
1050                         
1051                         upscope();
1052                         file << indent << "};\n";
1053
1054                         if (do_ns_out)
1055                                 ns_out(sym);
1056
1057                         break;
1058                 }
1059                 
1060                 case trav_full:
1061                         // Nothing particular to do here, other than to make sure
1062                         // that trav_forward has happened (which will always need to
1063                         // be done here if it's not a nested type).
1064                         
1065                         output_pass(sym, trav_forward);
1066                         break;
1067
1068                 default:
1069                         BUG();
1070         }
1071 }
1072
1073 void CPPFile::output(BasicType *sym, int pass, void *arg2)
1074 {
1075         switch (pass) {
1076                 case trav_nsdecl:
1077                         /* no-op */
1078                         break;
1079
1080                 case trav_forward: {
1081                         bool do_ns_out = false;
1082                         
1083                         if (indent.indent_level == 0) {
1084                                 ns_in(sym);
1085                                 do_ns_out = true;
1086                         } else {
1087                                 extra_newline();
1088                         }
1089                         
1090                         file << indent << "typedef ";
1091                         assert(!is_array(sym->def));
1092                         cpp_output_type(file, sym->def, false);
1093                         file << **sym->name << ";\n";
1094
1095                         if (do_ns_out)
1096                                 ns_out(sym);
1097
1098                         break;
1099                 }
1100                 
1101                 case trav_full:
1102                         output_pass(sym, trav_forward);
1103                         break;
1104
1105                 default:
1106                         BUG();
1107         }
1108 }
1109
1110 void CPPFile::output(Alias *sym, int pass, void *arg2)
1111 {
1112         switch (pass) {
1113                 case trav_nsdecl:
1114                         /* no-op */
1115                         break;
1116
1117                 case trav_forward: {
1118                         bool do_ns_out = false;
1119                         
1120                         if (indent.indent_level == 0) {
1121                                 all_ns_in(sym);
1122                                 do_ns_out = true;
1123                         } else {
1124                                 extra_newline();
1125                         }
1126                         
1127                         const String *type = sym->get_concrete_sym()->get_fq_name("_ns")
1128                                                 ->flatten("::");
1129
1130                         file << indent << "typedef " << *type << " " 
1131                              << **sym->name << ";\n";
1132
1133                         if (do_ns_out)
1134                                 all_ns_out(sym);
1135
1136                         break;
1137                 }
1138                 
1139                 case trav_full:
1140                         output_pass(sym, trav_forward);
1141                         break;
1142
1143                 default:
1144                         BUG();
1145         }
1146 }
1147
1148 void CPPFile::output(TypeDef *sym, int pass, void *arg2)
1149 {
1150         switch (pass) {
1151                 case trav_nsdecl:
1152                 case trav_forward:
1153                         /* no-op */
1154                         break;
1155
1156                 case trav_full: {
1157                         output_pass(sym->get_concrete_sym(), trav_forward);
1158                         
1159                         bool do_ns_out = false;
1160                         
1161                         if (indent.indent_level == 0) {
1162                                 all_ns_in(sym);
1163                                 do_ns_out = true;
1164                         } else {
1165                                 extra_newline();
1166                         }
1167                         
1168                         const String *type = sym->get_concrete_sym()->get_fq_name("_ns")
1169                                                 ->flatten("::");
1170
1171                         file << indent << "typedef " << *type << " " 
1172                              << **sym->name << ";\n";
1173
1174                         if (do_ns_out)
1175                                 all_ns_out(sym);
1176
1177                         break;
1178                 }
1179                 
1180                 default:
1181                         BUG();
1182         }
1183 }
1184
1185 void CPPFile::output(Datum *sym, int pass, void *arg2)
1186 {
1187         assert(sym->def.flags.field.Const);
1188         
1189         switch (pass) {
1190                 case trav_nsdecl:
1191                 case trav_forward:
1192                         /* no-op */
1193                         break;
1194
1195                 case trav_full: {
1196                         if (sym->type)
1197                                 declare_type_dependency(sym->type, false);
1198
1199                         bool do_ns_out = false;
1200                         
1201                         if (indent.indent_level == 0) {
1202                                 all_ns_in(sym);
1203                                 do_ns_out = true;
1204                         } else {
1205                                 extra_newline();
1206                         }
1207                         
1208                         file << indent << "static const ";
1209                         
1210                         assert(!is_array(sym->def.basictype));
1211                         
1212                         if (sym->type)
1213                                 cpp_output_type(file, sym->type, false, false);
1214                         else
1215                                 cpp_output_type(file, sym->def.basictype, false);
1216
1217                         file << **sym->name << " = ";
1218                         
1219                         CompiledBasicType *def;
1220                         if (sym->type) {
1221                                 Symbol *real_type = sym->type->get_concrete_sym();
1222                                 BasicType *bt = dynamic_cast<BasicType *>(real_type);
1223                                 assert(bt);
1224                                 
1225                                 def = &bt->def;
1226                         } else {
1227                                 def = &sym->def.basictype;
1228                         }
1229                         
1230                         if (def->flags.field.Float) {
1231                                 file << sym->def.fcon;
1232                         } else if (def->flags.field.Bool) {
1233                                 if (sym->def.ucon == 0)
1234                                         file << "false";
1235                                 else
1236                                         file << "true";
1237                         } else {
1238                                 if (def->flags.field.Unsigned) {
1239                                         file << "0x" << std::hex << sym->def.ucon << std::dec << 'U';
1240                                 } else {
1241                                         file << sym->def.icon;
1242                                 }
1243
1244                                 file << "LL";
1245                         }
1246                         
1247                         file << ";\n";
1248
1249                         if (do_ns_out)
1250                                 all_ns_out(sym);
1251
1252                         break;
1253                 }
1254
1255                 default:
1256                         BUG();
1257         }
1258 }
1259
1260 void CPPBinding::output_root(UserNameSpace *ns, const char *dir)
1261 {
1262         delete new CPPFile(ns, dir);
1263 }