]> git.buserror.net Git - polintos/scott/priv.git/blob - idlcomp/types.cc
parser: remove unnecessary retains
[polintos/scott/priv.git] / idlcomp / types.cc
1 // Semantic actions for types and namespaces
2 //
3 // This software is copyright (c) 2006 Scott Wood <scott@buserror.net>.
4 // 
5 // This software is provided 'as-is', without any express or implied warranty.
6 // In no event will the authors or contributors be held liable for any damages
7 // arising from the use of this software.
8 // 
9 // Permission is hereby granted to everyone, free of charge, to use, copy,
10 // modify, prepare derivative works of, publish, distribute, perform,
11 // sublicense, and/or sell copies of the Software, provided that the above
12 // copyright notice and disclaimer of warranty be included in all copies or
13 // substantial portions of this software.
14
15 #include <cfloat>
16 #include <sstream>
17
18 #include <idlc.h>
19 #include <parser.h>
20 #include <lang.h>
21
22 bool Datum::verify_const()
23 {
24         assert(def.flags.field.Const);
25         
26         // TOK_INVALID should have caused an abort in an earlier pass, and
27         // TOK_DCON should have been replaced by the final constant by now.
28         
29         assert(con_type == TOK_ICON || con_type == TOK_UCON || 
30                con_type == TOK_FCON || con_type == TOK_BOOL);
31
32         if (cbt->flags.field.Float) {
33                 if (con_type == TOK_UCON)
34                         def.fcon = static_cast<double>(def.ucon);
35                 else if (con_type == TOK_ICON)
36                         def.fcon = static_cast<double>(def.icon);
37                 else if (con_type == TOK_BOOL) {
38                         yyerrorfl(name->file, name->line, 
39                                   "%s is of floating-point type, but is initialized with "
40                                   "a boolean constant.", name->c_str());
41
42                         return false;
43                 }
44
45                 con_type = TOK_FCON;
46                 
47                 if (cbt->bits == 32) {
48                         if (def.fcon > FLT_MAX || def.fcon < FLT_MIN) {
49                                 yyerrorfl(name->file, name->line, 
50                                           "%s is out of range for a single-precision FP datum.",
51                                           name->c_str());
52                                 
53                                 return false;
54                         }
55                 }
56                 
57                 const_init = true;
58                 return true;
59         }
60
61         if (con_type == TOK_FCON) {
62                 yyerrorfl(name->file, name->line, 
63                           "%s is of %s type, but is initialized with "
64                           "a floating-point constant.", 
65                           cbt->flags.field.Bool ? "boolean" : "integral",
66                           name->c_str());
67
68                 return false;
69         }
70         
71         if (cbt->flags.field.Bool) {
72                 if (con_type != TOK_BOOL) {
73                         yyerrorfl(name->file, name->line, 
74                                   "%s is of boolean type, but is initialized with "
75                                   "a non-boolean constant.", name->c_str());
76
77                         return false;
78                 }
79                 
80                 assert(def.ucon == 0 || def.ucon == 1);
81                 
82                 const_init = true;
83                 return true;
84         }
85
86         if (con_type == TOK_BOOL) {
87                 yyerrorfl(name->file, name->line, 
88                           "%s is of integral type, but is initialized with "
89                           "a boolean constant.", name->c_str());
90
91                 return false;
92         }
93
94         if (cbt->flags.field.Unsigned) {
95                 if (con_type == TOK_ICON && def.icon < 0) {
96                         yyerrorfl(name->file, name->line, 
97                                   "Initializer for \"%s\" is out of range.",
98                                   name->c_str());
99                         return false;
100                 }
101
102                 if (cbt->bits < 64) {
103                         uint64_t max = (1ULL << cbt->bits) - 1;
104                         
105                         if (def.ucon > max) {
106                                 yyerrorfl(name->file, name->line, 
107                                           "Initializer for \"%s\" is out of range.",
108                                           name->c_str());
109                                 return false;
110                         }
111                 }
112         } else {
113                 if (con_type == TOK_UCON && def.icon < 0) {
114                         yyerrorfl(name->file, name->line, 
115                                   "Initializer for \"%s\" is out of range.",
116                                   name->c_str());
117                         return false;
118                 }
119                 
120                 if (cbt->bits < 64) {
121                         // Yes, the constant should be unsigned before conversion,
122                         // as the temporary value could overflow a signed datum
123                         // before the one is subtracted if bits == 63.  It won't
124                         // matter on most machines, but you never know...
125                         
126                         int64_t max = (1ULL << (cbt->bits - 1)) - 1;
127                         
128                         if (def.icon > max || def.icon < -max + 1) {
129                                 yyerrorfl(name->file, name->line, 
130                                           "Initializer for \"%s\" is out of range.",
131                                           name->c_str());
132                                 return false;
133                         }
134                 }
135         }
136
137         const_init = true;
138         return true;
139 }
140
141 void Datum::init_const_early(Con *con)
142 {
143         if (con) {
144                 if (con->type == TOK_DCON) {
145                         assert(current_pass == 1);
146                         const_val_name = con->con.dcon;
147                 }
148
149                 def.flags.field.Const = 1;
150                 con_type = con->type;
151                 def.ucon = con->con.ucon;
152         }
153 }
154
155 void Datum::init(StrList *type, Array *ARRAY, Con *con)
156 {
157         assert(!complete);
158         
159         type_name = type;
160         cbt = NULL;
161         
162         basic = false;
163         complete = true;
164
165         set_array(ARRAY);
166         init_const_early(con);
167 }
168
169 void Datum::init(CompiledBasicType &CBT, Array *ARRAY, Con *con)
170 {
171         assert(!complete);
172         
173         def.basictype = CBT;
174         cbt = &def.basictype;
175
176         basic = true;
177         complete = true;
178         
179         set_array(ARRAY);
180         init_const_early(con);
181 }
182
183 void Datum::process_type()
184 {
185         assert(current_pass >= 4);
186
187         if (cbt)
188                 return;
189         
190         assert(!type_fq_name);
191         assert(type_sym);
192         
193         Symbol *sym = type_sym->get_concrete_sym(false);
194         type = dynamic_cast<Type *>(sym);
195         
196         if (!type) {
197                 const String *str = type_name->back();
198                 yyerrorfl(str->file, str->line, "\"%s\" is not a type.",
199                           sym->get_fq_name()->flatten()->c_str());
200
201                 throw UserError();
202         }
203         
204         BasicType *bt = dynamic_cast<BasicType *>(type->get_concrete_sym());
205         
206         if (bt) {
207                 if (!bt->def.flags.field.TypeDef)
208                         use_anon_type(bt->def);
209                 else
210                         cbt = &bt->def;
211         } else if (const_val) {
212                 const String *str = type_name->back();
213                 yyerrorfl(str->file, str->line, 
214                           "\"%s\" is not a basic type (and thus \"%s\" cannot "
215                           "be const).",
216                           type->get_fq_name()->flatten()->c_str(),
217                           name->c_str());
218                 throw UserError();
219         }
220         
221         if (!basic) {
222                 type_fq_name = type->get_fq_name()->flatten();
223                 def.type.length = type_fq_name->length();
224         }
225 }
226
227 Datum *Datum::resolve_constant_chain()
228 {
229         if (chain_traversed == traversal) {
230                 yyerrorfl(name->file, name->line, 
231                           "Initialization of \"%s\" forms an infinite loop:",
232                           get_fq_name()->flatten()->c_str());
233                 return this;
234         }
235
236         chain_traversed = traversal;
237         
238         assert(!const_val);
239         assert(!const_init);
240
241         process_type();
242
243         if (const_val_sym) {
244                 const_val = dynamic_cast<Datum *>(const_val_sym->get_concrete_sym());
245                 
246                 if (!const_val) {
247                         const String *str = const_val_name->back();
248                         yyerrorfl(str->file, str->line, "\"%s\" is not a datum.",
249                                   const_val_sym->get_fq_name()->flatten()->c_str());
250                         throw UserError();
251                 }
252                 
253                 if (!const_val->def.flags.field.Const) {
254                         const String *str = const_val_name->back();
255                         yyerrorfl(str->file, str->line, "\"%s\" is not a constant.",
256                                   const_val->get_fq_name()->flatten()->c_str());
257                         throw UserError();
258                 }
259         
260                 if (!const_val->const_init) {
261                         Datum *d = const_val->resolve_constant_chain();
262                         if (d) {
263                                 yyerrorfl(name->file, name->line, "...initializes \"%s\"",
264                                           get_fq_name()->flatten()->c_str());
265                 
266                                 if (d == this)
267                                         throw UserError();
268                                 
269                                 return d;
270                         }
271                 }
272                 
273                 assert(const_val->const_init);
274         
275                 con_type = const_val->con_type;
276                 def.ucon = const_val->def.ucon;
277         }
278
279         if (!verify_const())
280                 throw UserError();
281
282         assert(const_init);
283         return NULL;
284 }
285
286 // FIXME: Check for inline struct loops.
287 void Datum::final_analysis()
288 {
289         Struct *str = dynamic_cast<Struct *>(*type);
290         if (str && str->is_inline())
291                 set_inline();
292
293         if (array) {
294                 array->final_analysis();
295                 def.basictype.array = array->ca;
296         } else {
297                 def.basictype.array.bounds[0] = 0;
298                 def.basictype.array.bounds[1] = 0;
299         }
300         
301         BitField *bfparent = dynamic_cast<BitField *>(get_ns());
302         if (bfparent) {
303                 assert(!array);
304                 int defsize;
305                 
306                 if (basic)
307                         defsize = 1;
308                 else
309                         defsize = type->get_default_bf_size();
310                 
311                 if (defsize == -1) {
312                         yyerrorfl(name->file, name->line,
313                                   "\"%s\" may not be the named type of bitfield entry "
314                                   "\"%s\", as it is not a bitfield or enumeration.",
315                                   type->get_fq_name()->flatten()->c_str(),
316                                   get_fq_name()->flatten()->c_str());
317                 } else if (def.icon == -1) {
318                         def.ucon = defsize;
319                 } else if (def.ucon < (unsigned int)defsize) {
320                         yyerrorfl(name->file, name->line,
321                                   "Explicit size %llu on \"%s\" is too small for "
322                                   "type \"%s\", which has a minimum size of %u",
323                                   (unsigned long long)def.ucon,
324                                   get_fq_name()->flatten()->c_str(),
325                                   type->get_fq_name()->flatten()->c_str(), defsize);
326                 }
327         }
328 }
329
330 void Struct::add(Symbol *sym, bool from_import)
331 {
332         Datum *datum = dynamic_cast<Datum *>(sym);
333         
334         if (!datum && !dynamic_cast<Alias *>(sym) && 
335             !dynamic_cast<Type *>(sym) &&
336             !dynamic_cast<Method *>(sym))
337                 throw InvalidArgument();
338         
339         NameSpace::add(sym, from_import);
340
341         if (!from_import && datum && !datum->def.flags.field.Const)
342                 add_elem(datum);
343 }
344
345 void Struct::add_elem(Datum *d)
346 {
347         entries.push_back(d);
348         def.num_entries++;
349 }
350
351 bool Struct::is_plain_data()
352 {
353         if (!plain_data) {
354                 plain_data = 1;
355                 for (Struct::entries_iterator i = entries_begin(); i != entries_end(); ++i)
356                 {
357                         Datum *d = *i;
358                         if (d->is_array() && !d->def.flags.field.Inline)
359                                 goto complex;
360
361                         if (!d->type)
362                                 continue;
363
364                         Type *type = dynamic_cast<Type *>(d->type->get_concrete_sym());
365                         assert(type);
366
367                         if (dynamic_cast<Interface *>(type))
368                                 goto complex;
369
370                         Struct *str = dynamic_cast<Struct *>(type);
371                         if (str) {
372                                 if (!d->def.flags.field.Inline)
373                                         goto complex;
374
375                                 // FIXME: check for inline struct loops
376                                 if (str->is_plain_data())
377                                         goto complex;
378                         }
379                 }
380         }
381         
382         assert(plain_data == 1 || plain_data == 2);
383         return plain_data == 1;
384
385 complex:
386         plain_data = 2;
387         return false;
388 }
389
390 Param *Param::declare(const String *name, NameSpace *parent,
391                            StrList *TYPE, CompiledParam::Flags flags,
392                            Array *array)
393 {
394         assert(parent);
395         assert(dynamic_cast<Method *>(parent));
396         
397         Param *p = new Param(name);
398         p->init(TYPE, flags, array);
399         
400         parent->add_user(p);
401         return p;
402 }
403
404 Method *Method::declare(const String *name, NameSpace *parent)
405 {
406         assert(parent);
407         assert(dynamic_cast<Interface *>(parent));
408
409         Method *m = new Method(name);
410
411         parent->add_user(m);
412         return m;
413 }
414
415 void Interface::add(Symbol *sym, bool from_import)
416 {
417         Datum *datum = dynamic_cast<Datum *>(sym);
418         Method *method = dynamic_cast<Method *>(sym);
419
420         if (!datum && !method && 
421             !dynamic_cast<Alias *>(sym) && 
422             !dynamic_cast<Type *>(sym))
423                 throw InvalidArgument();
424
425         if (datum && !datum->def.flags.field.Const)
426                 throw InvalidArgument();
427         
428         NameSpace::add(sym, from_import);
429         
430         if (!from_import && method)
431                 add_elem(method);
432 }
433
434 // FIXME: check for duplicate and looping inheritance
435 void Interface::add_elem(Method *method)
436 {
437         methods.push_back(method);
438         def.num_methods++;
439 }
440
441 void Enum::add(Symbol *sym, bool from_import)
442 {
443         Datum *datum = dynamic_cast<Datum *>(sym);
444
445         // It also must be const unsigned, but the const won't
446         // have been initialized yet.
447
448         if (!datum)
449                 throw InvalidArgument();
450         
451         NameSpace::add(sym, from_import);
452         
453         if (!from_import)
454                 add_elem(datum);
455 }
456
457 void Enum::add_elem(Datum *datum)
458 {
459         entries.push_back(datum);
460         def.num_entries++;
461 }
462
463 void BitField::add(Symbol *sym, bool from_import)
464 {
465         Datum *datum = dynamic_cast<Datum *>(sym);
466
467         if (!datum && !dynamic_cast<Enum *>(sym) &&
468             !dynamic_cast<BitField *>(sym))
469                 throw InvalidArgument();
470
471         NameSpace::add(sym, from_import);
472
473         if (!from_import && datum)
474                 add_elem(datum);
475 }
476
477 void BitField::add_elem(Datum *datum)
478 {
479         entries.push_back(datum);
480         def.num_entries++;
481 }
482
483 void Method::add(Symbol *sym, bool from_import)
484 {
485         Param *param = dynamic_cast<Param *>(sym);
486
487         if (!param)
488                 throw InvalidArgument();
489
490         NameSpace::add(sym, from_import);
491         if (!from_import)
492                 add_elem(param);
493 }
494
495 void Method::add_elem(Param *param)
496 {
497         entries.push_back(param);
498         def.num_entries++;
499 }
500
501 // Use this rather than lookup_sym if you want to check for built-in types.
502 // If only constructed types are valid, use lookup_sym.  If basic_types_only
503 // is set, then NULL will be returned if sl does not describe a built-in
504 // basic type (such as int, flong, octet, etc).  This option is used so that
505 // the first-pass code in idlparse.y can decide whether to create a BasicType
506 // or an Alias/TypeDef.
507
508 Type *lookup_type(StrList *sl, NameSpace *ctx, bool basic_types_only)
509 {
510         Type *type;
511         int token = sl->front()->token;
512
513         // These tokens aren't valid types, but the names can be
514         // used as identifiers.
515         switch (token) {
516                 case TOK_ASYNC:
517                 case TOK_INOUT:
518                 case TOK_OUT:
519                         token = TOK_IDENT;
520         }
521         
522         // Treat it as a user-defined type if it's either not a reserved word,
523         // or if there are multiple components.
524
525         if (token == TOK_IDENT || sl->front() != sl->back()) {
526                 if (basic_types_only)
527                         return false;
528         
529                 Symbol *sym = lookup_sym(toplevel, sl, ctx);
530                 type = dynamic_cast<Type *>(sym->get_concrete_sym(false));
531                 
532                 if (!type) {
533                         const String *str = sl->back();
534                         yyerrorfl(str->file, str->line, "\"%s\" is not a type.",
535                                   sym->get_fq_name()->flatten()->c_str());
536
537                         throw UserError();
538                 }
539         } else {
540                 CompiledBasicType cbt;
541                 memset(&cbt, 0, sizeof(cbt));
542                 
543                 switch (token) {
544                         case TOK_BOOL:
545                                 cbt.bits = 0;
546                                 cbt.flags.field.Bool = 1;
547                                 break;
548                         
549                         case TOK_OCTET:
550                         case TOK_CHAR:
551                                 cbt.bits = 8;
552                                 cbt.flags.field.Unsigned = 1;
553                                 break;
554                         
555                         case TOK_SHORT:
556                                 cbt.bits = 16;
557                                 break;
558                         
559                         case TOK_INT:
560                                 cbt.bits = 32;
561                                 break;
562                         
563                         case TOK_LONG:
564                                 cbt.bits = 64;
565                                 break;
566                         
567                         case TOK_USHORT:
568                                 cbt.bits = 16;
569                                 cbt.flags.field.Unsigned = 1;
570                                 break;
571                         
572                         case TOK_UINT:
573                                 cbt.bits = 32;
574                                 cbt.flags.field.Unsigned = 1;
575                                 break;
576                         
577                         case TOK_ULONG:
578                                 cbt.bits = 64;
579                                 cbt.flags.field.Unsigned = 1;
580                                 break;
581                         
582                         case TOK_FSHORT:
583                                 cbt.bits = 32;
584                                 cbt.flags.field.Float = 1;
585                                 break;
586                         
587                         case TOK_FLONG:
588                                 cbt.bits = 64;
589                                 cbt.flags.field.Float = 1;
590                                 break;
591                         
592                         default:
593                                 fprintf(stderr, "token %d\n", token);
594                                 BUG();
595                 }
596                 
597                 type = BasicType::declare(sl->front(), NULL, cbt);
598         }
599         
600         return type;
601 }
602
603 void declare_data(NameSpace *ns, StrList *ids, StrList *type,
604                   Array *array, StrList *attr)
605 {
606         bool is_inline = false;
607         bool is_immutable = false;
608         
609         if (attr) {
610                 for (StrList::iterator i = attr->begin(); i != attr->end(); ++i) {
611                         const String *this_attr = *i;
612         
613                         switch (this_attr->token) {
614                                 case TOK_INLINE:
615                                         is_inline = true;
616                                         break;
617                                 
618                                 case TOK_IMMUTABLE:
619                                         is_immutable = true;
620                                         break;
621                                 
622                                 default:
623                                         yyerrorfl(this_attr->file, this_attr->line,
624                                                   "Invalid attribute \"%s\"", (*i)->c_str());
625                         }
626                 }
627         }
628         
629         for (StrList::iterator i = ids->begin(); i != ids->end(); ++i) {
630                 try {
631                         Datum *d = Datum::declare(*i, ns, type, array);
632                         
633                         if (is_inline)
634                                 d->set_inline();
635                         
636                         if (is_immutable)
637                                 d->set_immutable();
638                 }
639         
640                 catch (UserError) {
641                         // An error has already been displayed, but try to
642                         // continue and find more errors.
643                 }
644         }
645 }
646
647 void declare_aliases(NameSpace *ns, StrList *ids, StrList *type,
648                      bool is_typedef)
649 {
650         StrList::iterator i;
651
652         for (i = ids->begin(); i != ids->end(); ++i) {
653                 try {
654                         if (is_typedef)
655                                 TypeDef::declare(*i, ns, type);
656                         else
657                                 Alias::declare(*i, ns, type);
658                 }
659         
660                 catch (UserError) {
661                         // An error has already been displayed, but try to
662                         // continue and find more errors.
663                 }
664         }
665 }
666
667 void declare_basictypes(NameSpace *ns, StrList *ids, 
668                         BasicType *type, bool is_typedef)
669 {
670         assert(!type->def.flags.field.TypeDef);
671         StrList::iterator i;
672         
673         for (i = ids->begin(); i != ids->end(); ++i) {
674                 try {
675                         BasicType *bt =
676                                 BasicType::declare(*i, ns, type->def);
677                         
678                         bt->def.flags.field.TypeDef = is_typedef;
679                 }
680         
681                 catch (UserError) {
682                         // An error has already been displayed, but try to
683                         // continue and find more errors.
684                 }
685         }
686 }
687
688 Array::Array(NameSpace *LOOKUP_CTX)
689 {
690         lookup_ctx = LOOKUP_CTX;
691         
692         for (int i = 0; i < 2; i++) {
693                 cons[i].con.ucon = 0;
694                 cons[i].type = TOK_UCON;
695         }
696 }
697
698 void Array::set_unbounded()
699 {
700         for (int i = 0; i < 2; i++)
701                 cons[i].type = TOK_NONE;
702 }
703
704 void Array::final_analysis()
705 {
706         for (int i = 0; i < 2; i++) {
707                 if (cons[i].type == TOK_NONE) {
708                         if (i == 0)
709                                 ca.bounds[0] = 0;
710                         else
711                                 ca.bounds[1] = -1;
712                         
713                         continue;
714                 }
715         
716                 if (cons[i].type == TOK_DCON) {
717                         Symbol *sym = lookup_sym(toplevel, dcons[i], lookup_ctx);
718                         datums[i] = dynamic_cast<Datum *>(sym);
719                         if (!datums[i]) {
720                                 const String *str = dcons[i]->back();
721                                 yyerrorfl(str->file, str->line, "\"%s\" is not a Datum.",
722                                           sym->get_fq_name()->flatten()->c_str());
723                                 continue;
724                         }
725                         
726                         ca.bounds[i] = datums[i]->get_ucon(dcons[i]->back());
727                         cons[i].type = datums[i]->con_type;
728                 } else {
729                         ca.bounds[i] = cons[i].con.ucon;
730                 }
731                 
732                 if (cons[i].type == TOK_FCON) {
733                         yyerrorfl(strs[i]->file, strs[i]->line, 
734                                   "\"%s\" is not an integral Datum.",
735                                   strs[i]->c_str());
736                         throw UserError();
737                 }
738
739                 if (ca.bounds[i] < 0) {
740                         yyerrorfl(strs[i]->file, strs[i]->line, 
741                                   "\"%s\" %s.", strs[i]->c_str(),
742                                   cons[i].type == TOK_UCON ?
743                                   "does not fit in a signed 64-bit integer" :
744                                   "is negative");
745                         throw UserError();
746                 }
747         }
748         
749         if (ca.bounds[1] >= 0 && ca.bounds[0] > ca.bounds[1]) {
750                 yyerrorfl(strs[0]->file, strs[0]->line,
751                           "\"%s\" is larger than \"%s\".",
752                           strs[0]->c_str(), strs[1]->c_str());
753                 throw UserError();
754         }
755 }
756
757 void Array::set_bound(Con &con, int bound)
758 {
759         assert(current_pass == 1);
760
761         if (con.type == TOK_FCON) {
762                 yyerrorf("Array limits must be integers.");
763                 throw UserError();
764         }
765         
766         if (con.type == TOK_ICON && con.con.icon <= 0) {
767                 yyerrorf("Array limits must be positive");
768                 throw UserError();
769         }
770
771         if (con.type == TOK_UCON && con.con.icon <= 0) {
772                 yyerrorf("Array limits must fit in a signed 64-bit integer");
773                 throw UserError();
774         }
775         
776         cons[bound] = con;
777         
778         if (con.type == TOK_DCON) {
779                 assert(con.con.dcon);
780                 dcons[bound] = con.con.dcon;
781                 strs[bound] = con.con.dcon->flatten();
782         } else {
783                 std::ostringstream ss(std::ostringstream::out);
784                 
785                 switch (con.type) {
786                         case TOK_FCON:
787                                 ss << con.con.fcon;
788                                 break;
789                         
790                         case TOK_UCON:
791                                 ss << con.con.ucon;
792                                 break;
793                         
794                         case TOK_ICON:
795                                 ss << con.con.icon;
796                                 break;
797                         
798                         case TOK_NONE:
799                                 if (bound == 0)
800                                         ss << "0";
801
802                                 break;
803                         
804                         default:
805                                 BUG();
806                 }
807                 
808                 strs[bound] = new String(ss.str().c_str(), cur_input_file, 
809                                          curline, con.type);
810         }
811 }
812
813
814 void UserNameSpace::output_lang(LangCallback *lcb, int arg1, void *arg2)
815 {
816         lcb->output(this, arg1, arg2);
817 }
818
819 void BasicType::output_lang(LangCallback *lcb, int arg1, void *arg2)
820 {
821         lcb->output(this, arg1, arg2);
822 }
823
824 void Interface::output_lang(LangCallback *lcb, int arg1, void *arg2)
825 {
826         lcb->output(this, arg1, arg2);
827 }
828
829 void Struct::output_lang(LangCallback *lcb, int arg1, void *arg2)
830 {
831         lcb->output(this, arg1, arg2);
832 }
833
834 void BitField::output_lang(LangCallback *lcb, int arg1, void *arg2)
835 {
836         lcb->output(this, arg1, arg2);
837 }
838
839 void Enum::output_lang(LangCallback *lcb, int arg1, void *arg2)
840 {
841         lcb->output(this, arg1, arg2);
842 }
843
844 void Alias::output_lang(LangCallback *lcb, int arg1, void *arg2)
845 {
846         lcb->output(this, arg1, arg2);
847 }
848
849 void TypeDef::output_lang(LangCallback *lcb, int arg1, void *arg2)
850 {
851         lcb->output(this, arg1, arg2);
852 }
853
854 void Datum::output_lang(LangCallback *lcb, int arg1, void *arg2)
855 {
856         if (def.flags.field.Const)
857                 lcb->output(this, arg1, arg2);
858 }
859
860 void Method::output_lang(LangCallback *lcb, int arg1, void *arg2)
861 {
862 }
863
864 void Param::output_lang(LangCallback *lcb, int arg1, void *arg2)
865 {
866 }
867
868 int Interface::all_supers_traversal;