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