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