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