]> git.buserror.net Git - polintos/scott/priv.git/blob - idlcomp/idlc.h
Random stuff.
[polintos/scott/priv.git] / idlcomp / idlc.h
1 // idlc.h -- Definitions used throughout idlc. 
2 // A lot of this should probably be factored out into more specific headers.
3 //
4 // This software is copyright (c) 2006 Scott Wood <scott@buserror.net>.
5 // 
6 // This software is provided 'as-is', without any express or implied warranty.
7 // In no event will the authors or contributors be held liable for any damages
8 // arising from the use of this software.
9 // 
10 // Permission is hereby granted to everyone, free of charge, to use, copy,
11 // modify, prepare derivative works of, publish, distribute, perform,
12 // sublicense, and/or sell copies of the Software, provided that the above
13 // copyright notice and disclaimer of warranty be included in all copies or
14 // substantial portions of this software.
15
16 #ifndef IDLC_H
17 #define IDLC_H
18
19 // inttypes.h on OSX assumes it can use restrict, but C++ doesn't have it.
20 // Hopefully C++ will catch up to C soon...
21
22 #define restrict
23
24 #include <stdint.h>
25 #include <inttypes.h>
26 #include <stdio.h>
27 #include <ctype.h>
28 #include <string>
29 #include <stack>
30 #include <list>
31 #include <map>
32 #include <vector>
33 #include <cstring>
34
35 #include "compileddef.h"
36
37 using std::list;
38 using std::stack;
39 using std::string;
40 using std::pair;
41 using std::map;
42 using std::vector;
43
44 int yylex();
45 int idl_lex();
46 #define cdl_lex idl_lex
47 void idl_error(const char *s);
48
49 #define cdl_error idl_error
50
51 void setup_idlparse();
52 void setup_cdlparse();
53
54 #ifdef __GNUC__
55 void yyerrorf(const char *s, ...) __attribute__((format(printf, 1, 2)));
56 void yyerrorfl(const char *file, int line, const char *s, ...)
57 __attribute__((format(printf, 3, 4)));
58 #else
59 void yyerrorf(const char *s, ...);
60 void yyerrorfl(const char *file, int line, const char *s, ...);
61 #endif
62
63 int idl_parse();
64 int cdl_parse();
65 int finish_lex();
66
67 extern int idl_debug, cdl_debug, curline, impl, num_err;
68 extern int current_pass;
69 extern FILE *yyin;
70 extern unsigned int enum_pos;
71 extern const char *cur_input_file;
72 extern int compiling_idl, compiling_cdl;
73 extern bool makedep;
74
75 struct InternalError
76 {
77         // Location in the IDLC source of the BUG()
78         const char *file;
79         int line;
80         
81         InternalError(const char *file, int line) :
82         file(file), line(line)
83         {
84         }
85 };
86
87 #define BUG() do { \
88         throw InternalError(__FILE__, __LINE__); \
89 } while (0)
90
91 #undef assert
92
93 #define assert(x) do { \
94         if (!(x)) BUG(); \
95 } while (0)
96
97 class Releasable {
98 public:
99         mutable int count;
100         
101         virtual ~Releasable()
102         {
103         }
104         
105         Releasable(int COUNT) : count(COUNT)
106         {
107         }
108
109         void release() const
110         {
111                 if (count <= 0) {
112                         fprintf(stderr, "Reference count is %d in release\n", count);
113                         BUG();
114                 }   
115                 
116                 if (!--count)
117                         delete this;
118         }
119 };
120
121 class AutoReleasePool {
122         list<const Releasable *> pool;
123
124 public:
125         void add(const Releasable *obj)
126         {
127                 pool.push_back(obj);
128         }
129         
130         void clean()
131         {
132                 for (list<const Releasable *>::iterator i = pool.begin();
133                      i != pool.end(); ++i)
134                 {
135                         const Releasable *obj = *i;
136                         obj->release();
137                 }
138                 
139                 pool.clear();
140         }
141 };
142
143 extern AutoReleasePool autorelease_pool;
144
145 template <typename T>
146 class RefCountable : public Releasable {
147 private:
148         // RefCountable objects should never be assigned to,
149         // as there could be references to the object remaining.
150         // The private assignment operator prevents this, unless
151         // a subclass defines its own assigment operator (don't
152         // do that).
153         void operator =(const RefCountable &rc)
154         {
155                 BUG();
156         }
157
158         RefCountable(const RefCountable &rc) : Releasable(1)
159         {
160                 BUG();
161         }
162         
163 public:
164         RefCountable() : Releasable(1)
165         {
166                 // Normally, this wouldn't be automatic, but this is what most
167                 // things in IDLC are going to want, and it elimanates problems
168                 // with needing to cast the return type of autorelease().
169                 //
170                 // The automatic autorelease() means that all refcountable objects
171                 // must be allocated with "new", not on the stack, as global
172                 // data, or as a class member.
173                 
174                 autorelease();
175         }
176         
177         virtual ~RefCountable()
178         {
179         }
180
181         const T *retain() const
182         {
183                 if (count <= 0) {
184                         fprintf(stderr, "Reference count is %d in retain\n", count);
185                         BUG();
186                 }   
187                 
188                 count++;
189                 return static_cast<const T *>(this);
190         }
191
192         T *retain()
193         {
194                 if (count <= 0) {
195                         fprintf(stderr, "Reference count is %d in retain\n", count);
196                         BUG();
197                 }   
198                 
199                 count++;
200                 return static_cast<T *>(this);
201         }
202         
203         const T *autorelease() const
204         {
205                 autorelease_pool.add(static_cast<Releasable *>(this));
206                 return static_cast<T *>(this);
207         }
208
209         T *autorelease()
210         {
211                 autorelease_pool.add(static_cast<Releasable *>(this));
212                 return static_cast<T *>(this);
213         }
214         
215         // This is only here because C++ obnoxiously requires it to
216         // be just because it's "called" from code excluded with an
217         // if (0) in a template.  No code is ever generated that calls
218         // it, but it still must exist.
219         
220         bool operator < (const RefCountable &rc)
221         {
222                 BUG();
223         }
224 };
225
226 // T must be RefCountable
227 template<typename T, bool compare_ptrs = true>
228 class Ref {
229         // STL containers like to use const on the items they
230         // contain; the mutable allows such containers to hold
231         // pointers to non-const data.  For truly const Refs,
232         // make T const, as in StringRef.  Unfortunately,
233         // it cannot be done in a more fine-grained manner,
234         // AFAICT.
235
236 public: 
237         mutable T *data;
238         
239 public:
240         Ref()
241         {
242                 data = NULL;
243         }
244
245         Ref(T *data) : data(data)
246         {
247                 if (data)
248                         data->retain();
249         }
250         
251         Ref(Ref &le) : data(le.data)
252         {
253                 if (data)
254                         data->retain();
255         }
256
257         Ref &operator =(const Ref &le)
258         {
259                 // The retain must come first, in case both Refs are the same
260                 if (le.data)
261                         le.data->retain();
262                 if (data)
263                         data->release();
264
265                 data = le.data;
266                 
267                 return *this;
268         }
269
270         Ref &operator =(T *new_data)
271         {
272                 // The retain must come first, in case both Refs are the same
273                 if (new_data)
274                         new_data->retain();
275                 if (data)
276                         data->release();
277
278                 data = new_data;
279                 
280                 return *this;
281         }
282         
283         ~Ref()
284         {
285                 if (data)
286                         data->release();
287         }
288         
289         operator T *() const
290         {
291                 return data;
292         }
293         
294         operator T &() const
295         {
296                 return *data;
297         }
298         
299         T *operator *() const
300         {
301                 return data;
302         }
303
304         T *operator ->() const
305         {
306                 return data;
307         }
308         
309         bool operator == (const Ref &le) const
310         {
311                 if (compare_ptrs)
312                         return data == le.data;
313                 else
314                         return *data == *le.data;
315         }
316
317         bool operator != (const Ref &le) const
318         {
319                 if (compare_ptrs)
320                         return data != le.data;
321                 else
322                         return *data != *le.data;
323         }
324
325         bool operator < (const Ref &le) const
326         {
327                 if (compare_ptrs)
328                         return reinterpret_cast<intptr_t>(data) < 
329                                reinterpret_cast<intptr_t>(le.data);
330                 else
331                         return *data < *le.data;
332         }
333 };
334
335 class String : public string, public RefCountable<String> {
336 public:
337         // Origin of the string, if from the IDL file.
338         // Otherwise, fill both values with zero.
339
340         const char *file;
341         int line;
342         int token;
343
344         String(const char *s = "") : string(s)
345         {
346                 file = "";
347                 line = 0;
348                 token = 0;
349         }
350
351         String(const String &s) : string(s)
352         {
353                 file = s.file;
354                 line = s.line;
355                 token = s.token;
356         }
357
358         String(const char *s, const char *file, int line, int token) :
359                string(s), file(file), line(line), token(token)
360         {}
361 };
362
363 extern String **yylval_string;
364 typedef Ref<const String, false> StringRef;
365
366 /* If a StrList is used for a namespace-qualified identifier, and
367    said identifier begins with ".." (i.e. starts from the root
368    namespace), the leading ".." is represented by a zero-length
369    String. 
370    
371    Note that list doesn't have a virtual destructor, so all deletions
372    should happen through either RefCountable or the wrapper List
373    class. */
374
375 class StrList : public list<StringRef>, public RefCountable<StrList> {
376 public:
377         StrList()
378         {
379         }
380         
381         // Parse a flat String into a StrList, using the specified delimeter.
382         StrList(const String *input, char delimiter = '.');
383
384         // Turn a StrList into a flat String, using the specified delimiter.
385         String *flatten(const char *delimiter = ".");
386 };
387
388 typedef Ref<StrList> StrListRef;
389
390 // ConList is like StrList, but with constant initializers
391
392 class Datum;
393
394 struct Con {
395         union {
396                 int64_t icon;
397                 uint64_t ucon;
398                 StrList *dcon;
399                 
400                 // FIXME: handle platforms with weird floating point endianness
401                 double fcon;
402                 
403                 char data[8];
404         } con;
405         
406         // TOK_ICON, TOK_UCON, TOK_FCON, TOK_BOOL, TOK_DCON, 
407         // TOK_INVALID, or TOK_NONE
408         // Constants are stored as signed (ICON) unless too
409         // large to fit in a signed 64-bit integer.  Additional size and
410         // signedness checks are mode when down casting to a smaller size
411         // to fit into a particular datum; such constants will have a
412         // value of zero.
413         //
414         // TOK_NONE is valid for maybeconst and size.  TOK_INVALID
415         // indicates a previously detected error; don't emit any further
416         // errors due to this constant.
417         //
418         // TOK_DCON is used for symbolic constants, whose value may
419         // not yet be known.
420         
421         int type;
422 };
423
424 extern Con *yylval_con;
425
426 struct ConInit {
427         StringRef str;
428         Con con;
429
430         ConInit(const String *str, Con &con) : str(str), con(con)
431         {
432         }
433
434         ConInit(const ConInit &coninit)
435         {
436                 *this = coninit;
437         }
438 };
439
440 class ConList : public list<ConInit>, public RefCountable<ConList> {};
441 typedef Ref<ConList> ConListRef;
442
443 // Like StrList, but is a list of possibly namespace-qualified identifiers.
444 class IDList : public list<StrListRef>, public RefCountable<IDList> {};
445 typedef Ref<IDList> IDListRef;
446
447
448 class NameSpace;
449 class LangCallback;
450
451 typedef Ref<NameSpace> NameSpaceRef;
452
453 // This is incremented when a chain of symbols is traversed to reset
454 // detection of already-visited symbols.  It is assumed that this
455 // will not have to happen billions of times.
456
457 extern int traversal;
458
459 class Symbol : public RefCountable<Symbol> {
460         NameSpace *ns;
461         
462         void init()
463         {
464                 ns = NULL;
465                 external = false;
466                 priv = false;
467                 lang_priv = NULL;
468         }
469         
470 public:
471         StringRef name;
472
473         // Symbol was loaded externally
474         bool external;
475         
476         // If set, the symbol is private, and will not be available
477         // for lookups except those made directly in the context of
478         // the containing namespace.  Private symbols do not get
479         // outputted.  They are used to implement imports of specific
480         // symbols (as aliases), rather than entire namespaces.
481         
482         bool priv;
483         
484         // Reserved for language binding use.
485         Releasable *lang_priv;
486
487         Symbol()
488         {
489                 init();
490         }
491         
492         Symbol(const String *_name) : name(_name)
493         {
494                 init();
495         }
496
497         virtual ~Symbol();
498
499         NameSpace *get_ns() const
500         {
501                 return ns;
502         }
503
504         const String *get_name() const
505         {
506                 return name;
507         }
508         
509         // If append is non-NULL, it is appended to non-user namespaces,
510         // to facilitate a language binding that cannot place nested types
511         // in the same language construct as the actual interface.  The
512         // recommended suffix is "_ns", which is a reserved ending in the
513         // IDL.  No suffix is placed on the final component of the name,
514         // even if it is a non-user namespace.  The not_last field is used
515         // to detect whether it is the final component; it is only used
516         // internally, and should always be false when called externally.
517         //
518         // This function does *NOT* add a null first element to indicate
519         // that the name is fully qualified.  If you need that, you have
520         // to add it yourself (call 'push_front(new String(""))' on the
521         // result).
522         
523         StrList *get_fq_name(const char *append = NULL,
524                              bool not_last = false) const;
525         
526         virtual void lookup_imports()
527         {
528         }
529         
530         virtual void lookup_chain()
531         {
532         }
533
534         virtual void lookup_misc()
535         {
536         }
537         
538         virtual void final_analysis()
539         {
540         }
541
542         // These two methods must be implemented by all IDL symbols, but are
543         // not needed in CDL symbols (and therefore are not pure virtual).
544
545         virtual void output(const char *root)
546         {
547         }
548
549         virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL)
550         {
551         }
552         
553         // Find and return the topmost symbol other than a user namespace
554         // containing this symbol.  If this symbol's parent is a user
555         // namespace, it returns itself.  May not be called on the
556         // toplevel namespace.
557         
558         Symbol *find_toplevel_type();
559
560         // Get the true type of the symbol, regardless of whether it is an
561         // alias.
562         
563         virtual Symbol *get_concrete_sym(bool follow_typedefs = true)
564         {
565                 return this;
566         }
567         
568         friend class NameSpace;
569 };
570
571 typedef Ref<Symbol> SymbolRef;
572
573 class SymList : public list<SymbolRef>, public RefCountable<SymList> {};
574 typedef Ref<SymList> SymListRef;
575
576 struct SymbolNotFound {
577 };
578
579 struct DuplicateSymbol {
580 };
581
582 struct InvalidArgument {
583 };
584
585 struct UserError {
586 };
587
588 class NameSpace : public virtual Symbol {
589 protected:
590         // Filesystem path to the external symbol storage, or NULL
591         // if not an import namespace.
592         //
593         // Import namespaces are read-only namespaces which are created
594         // for the importation of externally-declared symbols.  One is
595         // initially created for each "mount point" specified by the user;
596         // whenever such a namespace is searched, it checks the external
597         // storage, and if the lookup succeeds, the symbol is loaded and
598         // added to the namespace.  Failed lookups could be cached with a
599         // special BadSymbol or some such, as the imported namespace is
600         // assumed to be constant, but I don't think such an optimization
601         // is worthwhile, at least at this point.
602         
603         StringRef path;
604
605         // Load a symbol from external storage, constructing the relevant type
606         // of object, and adding it to this namespace.  Only called for
607         // import namespaces.
608
609         Symbol *load(const String *symname);
610
611         typedef map<StringRef, SymbolRef> tbl_type;
612         tbl_type tbl;
613         
614         list<StrListRef> import_strs;
615         list<NameSpaceRef> imports;
616
617 public:
618         // This is a counter for generating unique names for anonymous
619         // members of the namespace.
620         int anon;
621         
622         NameSpace() : anon(0)
623         {
624         }
625         
626         virtual ~NameSpace();
627         
628         // Return a description of the type of namespace, for
629         // error messages.
630         virtual const char *description()
631         {
632                 return "namespace";
633         }
634
635         virtual void output(const char *root);
636
637         typedef tbl_type::const_iterator const_iterator;
638         typedef tbl_type::value_type value_type;
639
640         // Derived classes can throw InvalidArgument if you give them
641         // a type of Symbol that they don't accept; see their comments
642         // for more details.  Unfortunately, this cannot be done
643         // with static type-checking, as there are places that know
644         // they've been given a namespace that can accept a particular
645         // type of symbol, but they don't know exactly what kind of
646         // namespace it is.  C++'s type system is not sufficient to
647         // express this (at least not while retaining any semblance
648         // of sanity).
649
650         // DuplicateSymbol is thrown if sym already exists in this namespace.
651         virtual void add(Symbol *sym, bool from_import)
652         {
653                 if (path && !from_import)
654                         throw InvalidArgument();
655                 
656                 if (path)
657                         sym->external = true;
658                 
659                 if (!sym->name.data)
660                         BUG();
661
662                 pair<const_iterator, bool> ret = tbl.insert(value_type(sym->name, sym));
663                 
664                 if (ret.second)
665                         sym->ns = this;
666                 else {
667                         throw DuplicateSymbol();
668                 }
669         }
670
671         // Add the symbol to this namespace, handling duplicate symbols by
672         // printing an error and throwing a UserError().  This should not be
673         // done in the symbol's constructor, as the parent may not accept
674         // the symbol until it is fully constructed (the RTTI information
675         // changes, and in general partially constructed objects shouldn't
676         // be exposed to the rest of the system).
677
678         void add_user(Symbol *sym);
679
680         // Like add_user, but used by the import code.  Duplicate
681         // symbols result in internal errors, and the add is done with
682         // from_import set to true.  InvalidArgument results in an error
683         // message and a reraise as UserError.
684         //
685         // All conditions checked by the parent namespace's add() method
686         // (such as constness of data) must be satisfied prior to calling
687         // add_import().  On the other hand, add_import() must be called
688         // before any recursive importation is done which could
689         // conceivably try to import the current symbol (thus causing
690         // infinite recursion).
691
692         void add_import(Symbol *sym, const char *filename);
693
694         // SymbolNotFound is thrown if sym is not in this namespace.
695         virtual void del(Symbol *sym)
696         {
697                 if (sym->ns != this)
698                         throw SymbolNotFound();
699
700                 sym->ns = NULL;
701                 int ret = tbl.erase(sym->name);
702                 assert(ret != 0);
703         }
704
705 private:        
706         Symbol *lookup_noex_noimport(const String *symname)
707         {
708                 const_iterator ret = tbl.find(symname);
709                 
710                 if (ret != tbl.end())
711                         return (*ret).second;
712                 
713                 return NULL;
714         }
715
716 public:
717         Symbol *lookup_noex(const String *symname, bool priv_ok = false)
718         {
719                 Symbol *ret = NameSpace::lookup_noex_noimport(symname);
720
721                 if (path && !ret)
722                         ret = load(symname);
723                 
724                 if (ret && !priv_ok && ret->priv)
725                         return NULL;
726         
727                 return ret;
728         }
729
730         Symbol *lookup(const String *symname, bool priv_ok = false)
731         {
732                 Symbol *ret = lookup_noex(symname, priv_ok);
733                 
734                 if (!ret)
735                         throw SymbolNotFound();
736                 
737                 return ret;
738         }
739         
740         // Like lookup_noex, but also checks imported namespaces,
741         // and returns the namespace containing the match rather
742         // than the match itself.
743         
744         NameSpace *search(const String *name, Symbol *exclude);
745         
746         void add_search(StrList *ns)
747         {
748                 import_strs.push_back(ns);
749         }
750
751         // Return a string containing case information manglement.
752         // See input.cc for more information.
753
754         static const String *mangle(const String *name);
755
756         const String *get_path()
757         {
758                 return path;
759         }
760         
761         // Import all members of this namespace.  A no-op if not an import
762         // namespace.  
763         void import_all();
764         
765         // As import_all, but also recursively applies to any sub-namespaces.
766         void import_all_recursive();
767         
768         const_iterator begin()
769         {
770                 return tbl.begin();
771         }
772
773         const_iterator end()
774         {
775                 return tbl.end();
776         }
777
778         virtual void lookup_imports();
779
780         virtual void lookup_chain()
781         {
782                 for (const_iterator i = begin(); i != end(); ++i) {
783                         Symbol *sym = (*i).second;
784                         sym->lookup_chain();
785                 }
786         }
787
788         virtual void lookup_misc()
789         {
790                 for (const_iterator i = begin(); i != end(); ++i) {
791                         Symbol *sym = (*i).second;
792                         sym->lookup_misc();
793                 }
794         }
795
796         virtual void final_analysis()
797         {
798                 for (const_iterator i = begin(); i != end(); ++i) {
799                         Symbol *sym = (*i).second;
800                         sym->final_analysis();
801                 }
802         }
803 };
804
805
806 extern NameSpaceRef cur_nspace;
807 extern list<NameSpaceRef> nspace_stack;
808         
809 typedef std::vector<StringRef> StringVec;
810
811 string *stringvec_to_path(StringVec &stringvec, const char *prepend);
812
813 // lookup_sym and lookup_type throw UserError on user error
814 // The context namespace is required for the proper
815 // set of namespaces to be searched.
816
817 Symbol *lookup_sym(NameSpace *topns, StrList *name, NameSpace *ctx,
818                    Symbol *exclude = NULL);
819
820 class Def {
821         const char *self;   // Pointer to the type-specific struct
822         int self_len;       // Length of the type-specific struct
823         
824 protected:
825         CompiledDefHeader hdr;
826
827         // sym is the symbol from which to get the path/name, and
828         // is_dir is true if it should be "name/.self" rather than 
829         // "name".
830         void output_self(const char *dir, Symbol *sym, bool is_dir);
831
832 public:
833         Def(const char *self, int self_len, CompiledDefHeader::Type type) :
834         self(self), self_len(self_len)
835         {
836                 hdr.magic = CompiledDefHeader::magic_normal;
837                 hdr.type = type;
838         }
839         
840         virtual ~Def()
841         {
842         }
843         
844         // Specific types may override this to output extra data
845         // to the .self file without having to reopen the file.
846         //
847         // Returns false on error.
848         
849         virtual bool output_extra(FILE *f)
850         {
851                 return true;
852         }
853 };
854
855 // Internal context struct used by input.cc to avoid passing
856 // lots of parameters around
857 struct ImportContext;
858
859 // This represents an actual IDL namespace {}, rather than
860 // a derived namespace such as a Struct or Interface.
861
862 class UserNameSpace : public NameSpace, public Def {
863 public:
864         CompiledNameSpace def;
865         StringRef mountpoint_name;
866
867         UserNameSpace(const String *name = NULL) :
868         Symbol(name),
869         Def((const char *)&def, sizeof(def), CompiledDefHeader::NameSpace)
870         {
871                 mountpoint_name = get_fq_name()->flatten();
872                 def.length = mountpoint_name->length();
873         }
874
875         virtual void output(const char *root);
876         bool output_extra(FILE *f);
877         
878         static void declare_import(const char *path);
879
880         static UserNameSpace *import(ImportContext &ctx);
881         virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
882 };
883
884 typedef Ref<UserNameSpace> UserNameSpaceRef;
885 extern UserNameSpaceRef toplevel, cdl_toplevel;
886 extern UserNameSpace *output_ns;
887
888 class Type : public virtual Symbol {
889 public:
890         Type()
891         {
892         }
893         
894         virtual ~Type()
895         {
896         }
897         
898         virtual int get_default_bf_size()
899         {
900                 // Only allow types in bitfields that explicitly
901                 // support it.
902                 
903                 return -1;
904         }
905 };
906
907 typedef Ref<Type> TypeRef;
908
909 // ctx can be NULL if basic_types_only is true
910 Type *lookup_type(StrList *sl, NameSpace *ctx, bool basic_types_only = false);
911
912 class BasicType : public Type, public Def {
913 public:
914         CompiledBasicType def;
915         bool complete;
916         
917         BasicType(const String *name) :
918         Symbol(name),
919         Def((const char *)&def, sizeof(def), CompiledDefHeader::BasicType)
920         {
921                 complete = false;
922                 memset(&def, 0, sizeof(def));
923         }
924
925         void init(CompiledBasicType &DEF)
926         {
927                 assert(!complete);
928         
929                 def = DEF;
930                 complete = true;
931         }
932
933         static BasicType *declare(const String *name, NameSpace *parent,
934                                   CompiledBasicType &DEF)
935         {
936                 BasicType *bt = new BasicType(name);
937                 bt->init(DEF);
938         
939                 if (parent)
940                         parent->add_user(bt);
941
942                 return bt;
943         }
944
945         virtual void output(const char *root);
946
947         static BasicType *import(ImportContext &ctx);
948         virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
949 };
950
951 static inline bool is_array(CompiledBasicType &bt)
952 {
953         return bt.array.bounds[0] || bt.array.bounds[1];
954 }
955
956 static inline bool is_array(CompiledBasicType *bt)
957 {
958         return is_array(*bt);
959 }
960
961 typedef Ref<Datum> DatumRef;
962
963 class Array : public RefCountable<Array>
964 {
965         NameSpace *lookup_ctx;
966         DatumRef datums[2];
967
968         // lower is [0], upper is [1]
969         StrListRef dcons[2];
970         
971         // Strings for error reporting on each constant.  If the constant
972         // is symbolic, then this is the fully qualified symbol name. 
973         // Otherwise, it is the numerical value converted to a string.  In
974         // each case, the file/line shall correspond to where the array
975         // bound was specified.
976         
977         StringRef strs[2];
978         
979 public:
980         Con cons[2];
981
982         // ca is not valid until after final_analysis() is called.
983         CompiledArray ca;
984
985         Array(NameSpace *LOOKUP_CTX);
986         void set_bound(Con &con, int bound);
987         void final_analysis();
988
989         void set_unbounded();
990 };
991
992 typedef Ref<Array> ArrayRef;
993
994 class Datum : public Symbol, public Def {
995         StrListRef type_name;
996         SymbolRef type_sym;
997         StringRef type_fq_name;
998
999         StrListRef const_val_name;
1000         SymbolRef const_val_sym;
1001         DatumRef const_val;
1002
1003         bool basic;      // Datum is of a BasicType
1004         bool complete;
1005         bool const_init; // Datum's constant has been initialized; this is
1006                          // true after a successful verify_const().
1007         CompiledBasicType *cbt;
1008
1009         int chain_traversed;
1010
1011         // Recursively retrieve the actual value of a const datum
1012         // initialized with another named const datum.  Returns
1013         // the "end" of an infinite loop, if one is found.  Once
1014         // the full infinite loop has been printed, UserError is
1015         // thrown.
1016
1017         Datum *resolve_constant_chain();
1018
1019         void init_const_early(Con *con);
1020         
1021         void use_anon_type(const CompiledBasicType &CBT)
1022         {
1023                 def.basictype = CBT;
1024                 cbt = &def.basictype;
1025                 basic = true;
1026                 type = NULL;
1027                 def.type.length = 0;
1028         }
1029         
1030         void process_type();
1031         
1032         void set_array(Array *ARRAY)
1033         {
1034                 if (ARRAY)
1035                         array = ARRAY;
1036         }
1037
1038 public:
1039         ArrayRef array;
1040         CompiledDatum def;
1041         TypeRef type;
1042
1043         int con_type;    // Used to store the TOK_[IUF]CON of the Con struct
1044                          // for type checking once the type is known.
1045
1046         Datum(const String *name) :
1047         Symbol(name), 
1048         Def((const char *)&def, sizeof(def), CompiledDefHeader::Datum)
1049         {
1050                 complete = false;
1051                 const_init = false;
1052                 chain_traversed = 0;
1053                 memset(&def, 0, sizeof(def));
1054         }
1055
1056         void init(StrList *type, Array *ARRAY, Con *con = NULL);
1057         void init(CompiledBasicType &cbt, Array *ARRAY, Con *con = NULL);
1058
1059         static Datum *declare(const String *name, NameSpace *parent,
1060                               StrList *type, Array *ARRAY,
1061                               Con *con = NULL)
1062         {
1063                 assert(parent);
1064                 
1065                 Datum *d = new Datum(name);
1066                 d->init(type, ARRAY, con);
1067
1068                 parent->add_user(d);
1069                 return d;
1070         }
1071
1072         static Datum *declare(const String *name, NameSpace *parent,
1073                               CompiledBasicType &type, 
1074                               Array *ARRAY, Con *con = NULL)
1075         {
1076                 assert(parent);
1077         
1078                 Datum *d = new Datum(name);
1079                 d->init(type, ARRAY, con);
1080
1081                 parent->add_user(d);
1082                 return d;
1083         }
1084         
1085         void set_inline()
1086         {
1087                 def.flags.field.Inline = 1;
1088         }
1089         
1090         bool is_inline()
1091         {
1092                 return def.flags.field.Inline;
1093         }
1094         
1095         void set_immutable()
1096         {
1097                 def.flags.field.Immutable = 1;
1098         }
1099         
1100         bool is_immutable()
1101         {
1102                 return def.flags.field.Immutable;
1103         }
1104
1105         // Returns true if the constant was acceptable, false otherwise (an
1106         // error is also output to the user in this case).
1107         
1108         bool verify_const();
1109
1110         virtual void lookup_chain()
1111         {
1112                 assert(complete);
1113
1114                 if (const_val_name)
1115                         const_val_sym = lookup_sym(toplevel, const_val_name, get_ns());
1116
1117                 if (type_name) {
1118                         assert(!basic);
1119                         type_sym = lookup_type(type_name, get_ns(), true);
1120                         if (!type_sym)
1121                                 type_sym = lookup_sym(toplevel, type_name, get_ns());
1122                 } else {
1123                         assert(basic);
1124                 }
1125         }
1126
1127         virtual void lookup_misc()
1128         {
1129                 if (def.flags.field.Const) {
1130                         if (!const_init) {
1131                                 assert(def.flags.field.Const);
1132         
1133                                 traversal++;
1134                                 Datum *d = resolve_constant_chain();
1135                                 assert(!d);
1136                         }
1137                 
1138                         assert(const_init);
1139                 } else {
1140                         process_type();
1141                 }
1142         }
1143         
1144         virtual void final_analysis();
1145
1146         virtual void output(const char *root);
1147         bool output_extra(FILE *f);
1148
1149         static Datum *import(ImportContext &ctx);
1150         virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
1151
1152         uint64_t get_ucon(const String *err_str)
1153         {
1154                 if (!def.flags.field.Const) {
1155                         yyerrorfl(err_str->file, err_str->line, 
1156                                   "\"%s\" is not a const Datum.\n",
1157                                   get_fq_name()->flatten()->c_str());
1158                         throw UserError();
1159                 }
1160                 
1161                 assert(const_init);
1162                 return def.ucon;
1163         }
1164
1165         bool is_array()
1166         {
1167                 return ::is_array(def.basictype);
1168         }
1169 };
1170
1171 template<typename T>
1172 bool output_list(T *sym, FILE *f);
1173
1174 class BitField : public NameSpace, public Type, public Def {
1175         list<DatumRef> entries;
1176
1177         void add_elem(Datum *d);
1178
1179 public:
1180         CompiledBitField def;
1181         int cur_pos;
1182
1183         BitField(const String *name) :
1184         Symbol(name),
1185         Def((const char *)&def, sizeof(def), CompiledDefHeader::BitField)
1186         {
1187                 memset(&def, 0, sizeof(def));
1188         }
1189
1190         void init(int bits, NameSpace *parent)
1191         {
1192                 if (bits < 0 || bits > 64) {
1193                         yyerrorf("\"%s\" has invalid bitfield size %d", 
1194                                  name->c_str(), bits);
1195
1196                         bits = bits < 0 ? 0 : 64;
1197                 }
1198         
1199                 def.bits = bits;
1200         }
1201
1202         static BitField *declare(const String *name, NameSpace *parent,
1203                                  int bits)
1204         {
1205                 assert(parent);
1206                 
1207                 BitField *bf = new BitField(name);
1208                 bf->init(bits, parent);
1209         
1210                 parent->add_user(bf);
1211                 return bf;
1212         }
1213
1214         // Only integral Datums, Enums, and BitFields can be added.
1215
1216         void add(Symbol *sym, bool from_import);
1217
1218         virtual const char *description()
1219         {
1220                 return "bitfield";
1221         }
1222
1223         virtual void lookup_misc()
1224         {
1225                 NameSpace::lookup_misc();
1226         }
1227         
1228         virtual void final_analysis()
1229         {
1230                 // FIXME: check total size of elements
1231         
1232                 NameSpace::final_analysis();
1233         }
1234
1235         int get_default_bf_size()
1236         {
1237                 return def.bits;
1238         }
1239
1240         virtual void output(const char *root);
1241         bool output_extra(FILE *f);
1242
1243         static BitField *import(ImportContext &ctx);
1244         virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
1245
1246         typedef list<DatumRef>::const_iterator entries_iterator;
1247         typedef list<DatumRef>::const_reverse_iterator entries_reverse_iterator;
1248
1249         entries_iterator entries_begin()
1250         {
1251                 return entries.begin();
1252         }
1253
1254         entries_iterator entries_end()
1255         {
1256                 return entries.end();
1257         }
1258
1259         entries_reverse_iterator entries_rbegin()
1260         {
1261                 return entries.rbegin();
1262         }
1263
1264         entries_reverse_iterator entries_rend()
1265         {
1266                 return entries.rend();
1267         }
1268 };
1269
1270 class Struct;
1271 typedef Ref<Struct> StructRef;
1272 extern StructRef System_VStruct;
1273
1274 // FIXME: typedefed superstructs
1275 class Struct : public NameSpace, public Type, public Def {
1276         list<DatumRef> entries;
1277         StructRef super;
1278         SymbolRef supersym;
1279         StrListRef supername;
1280         bool attrs_resolved;
1281
1282         // 0 = unknown, 1 = yes, 2 = no
1283         int plain_data;
1284         
1285         void add_elem(Datum *d);
1286
1287         void resolve_attrs()
1288         {
1289                 if (attrs_resolved)
1290                         return;
1291                 
1292                 if (super && !super->attrs_resolved)
1293                         super->resolve_attrs();
1294                 
1295                 if (super && super->def.flags.field.Virtual)
1296                         def.flags.field.Virtual = 1;
1297                 
1298                 attrs_resolved = true;
1299         }
1300         
1301 public:
1302         CompiledStruct def;
1303         
1304         // This is not maintained by the generic code, but can be
1305         // used by language bindings to cache the result of the
1306         // summation. 
1307         
1308         int chainlen;
1309         
1310         Struct(const String *name) :
1311         Symbol(name),
1312         Def((const char *)&def, sizeof(def), CompiledDefHeader::Struct)
1313         {
1314                 memset(&def, 0, sizeof(def));
1315                 attrs_resolved = 0;
1316         }
1317         
1318         void init(StrList *SUPERNAME)
1319         {
1320                 supername = SUPERNAME;
1321         }
1322
1323         static Struct *declare(const String *name, NameSpace *parent,
1324                                StrList *SUPERNAME)
1325         {
1326                 assert(parent);
1327         
1328                 Struct *st = new Struct(name);
1329                 st->init(SUPERNAME);
1330
1331                 parent->add_user(st);
1332                 return st;
1333         }
1334         
1335         void set_virtual()
1336         {
1337                 def.flags.field.Virtual = 1;
1338         }
1339
1340         void set_inline()
1341         {
1342                 def.flags.field.Inline = 1;
1343         }
1344
1345         bool is_virtual()
1346         {
1347                 return def.flags.field.Virtual;
1348         }
1349
1350         bool is_inline()
1351         {
1352                 return def.flags.field.Inline;
1353         }
1354         
1355         // Only Datums and Types can be added.
1356
1357         void add(Symbol *sym, bool from_import);
1358
1359         virtual const char *description()
1360         {
1361                 return "struct";
1362         }
1363         
1364         Struct *get_super()
1365         {
1366                 assert(current_pass >= 4);
1367                 return super;
1368         }
1369
1370         virtual void lookup_chain()
1371         {
1372                 if (supername) {
1373                         supersym = lookup_sym(toplevel, supername, get_ns());
1374                         assert(supersym);
1375                 }
1376
1377                 NameSpace::lookup_chain();
1378         }
1379
1380 private:
1381         void lookup_super()
1382         {
1383                 if (supersym && !super) {
1384                         super = dynamic_cast<Struct *>(supersym->get_concrete_sym());
1385                 
1386                         if (!super) {
1387                                 const String *str = supername->back();
1388                                 yyerrorfl(str->file, str->line,
1389                                           "\"%s\" is not a struct.",
1390                                           supersym->get_fq_name()->flatten()->c_str());
1391                         }
1392                         
1393                         def.flags.field.Super = 1;
1394                         super->lookup_super();
1395                         
1396                         if (super->is_virtual())
1397                                 set_virtual();
1398                 }
1399                 
1400                 if (is_virtual() && !supersym && !super) {
1401                         assert(System_VStruct);
1402                         if (this != System_VStruct) {
1403                                 def.flags.field.Super = 1;
1404                                 super = System_VStruct;
1405                         }
1406                 }
1407         }
1408         
1409 public:
1410         virtual void lookup_misc()
1411         {
1412                 lookup_super();
1413
1414                 if (is_virtual() && def.guid[0] == 0 && def.guid[1] == 0)
1415                         yyerrorfl(name->file, name->line,
1416                                   "Virtual struct \"%s\" is missing a GUID.",
1417                                   get_fq_name()->flatten()->c_str());
1418
1419                 NameSpace::lookup_misc();
1420         }
1421         
1422         virtual void final_analysis()
1423         {
1424                 // FIXME: check for infinite loops in struct inheritance
1425
1426                 resolve_attrs();
1427                 NameSpace::final_analysis();
1428         }
1429
1430         virtual void output(const char *root);
1431         bool output_extra(FILE *f);
1432
1433         static Struct *import(ImportContext &ctx);
1434         virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
1435
1436         typedef list<DatumRef>::const_iterator entries_iterator;
1437
1438         entries_iterator entries_begin()
1439         {
1440                 return entries.begin();
1441         }
1442
1443         entries_iterator entries_end()
1444         {
1445                 return entries.end();
1446         }
1447
1448         void set_guid(uint64_t guid[2])
1449         {
1450                 if (def.guid[0] || def.guid[1])
1451                         yyerrorf("\"%s\" already has a GUID.",
1452                                  get_fq_name()->flatten()->c_str());
1453         
1454                 def.guid[0] = guid[0];
1455                 def.guid[1] = guid[1];
1456         }
1457
1458         // A struct is "plain data" if it contains no object references,
1459         // no non-inline arrays or structs, and no inline non-plain structs.
1460         bool is_plain_data();
1461 };
1462
1463 class Param : public Symbol, public Def {
1464         StrListRef type_name;
1465         StringRef type_fq_name;
1466
1467         bool basic;      // Datum is of a BasicType
1468         bool complete;
1469         
1470         ArrayRef array;
1471
1472         void use_named_type(BasicType *bt)
1473         {
1474                 assert(!bt || bt->def.flags.field.TypeDef);
1475                 
1476                 basic = false;
1477
1478                 type_fq_name = type->get_fq_name()->flatten();
1479                 def.type.length = type_fq_name->length();
1480         }
1481         
1482         void use_anon_type(const CompiledBasicType &cbt)
1483         {
1484                 def.basictype = cbt;
1485                 basic = true;
1486                 type = NULL;
1487         }
1488
1489         void set_array(Array *ARRAY)
1490         {
1491                 if (ARRAY)
1492                         array = ARRAY;
1493         }
1494
1495 public:
1496         CompiledParam def;
1497         TypeRef type;
1498
1499         Param(const String *name) :
1500         Symbol(name),
1501         Def((const char *)&def, sizeof(def), CompiledDefHeader::Param)
1502         {
1503                 memset(&def, 0, sizeof(def));
1504         }
1505
1506         void init(StrList *TYPE, CompiledParam::Flags flags, Array *ARRAY)
1507         {
1508                 type_name = TYPE;
1509                 def.flags = flags;
1510                 set_array(ARRAY);
1511         }
1512
1513         static Param *declare(const String *name, NameSpace *parent,
1514                               StrList *TYPE, CompiledParam::Flags flags,
1515                               Array *ARRAY);
1516
1517         virtual void lookup_misc()
1518         {
1519                 type = lookup_type(type_name, get_ns());
1520         }
1521         
1522         virtual void final_analysis()
1523         {
1524                 BasicType *bt = dynamic_cast<BasicType *>(type->get_concrete_sym());
1525
1526                 if (bt && !bt->def.flags.field.TypeDef) {
1527                         use_anon_type(bt->def);
1528                 } else {
1529                         use_named_type(bt);
1530
1531                         Struct *str = dynamic_cast<Struct *>(*type);
1532                         if (str && str->is_inline())
1533                                 set_inline();
1534                         
1535                         if (!str && is_inline()) {
1536                                 yyerrorfl(name->file, name->line,
1537                                           "\"%s\" is static but not a struct.",
1538                                           get_fq_name()->flatten()->c_str());
1539                         }
1540                 }
1541         
1542                 if (array) {
1543                         array->final_analysis();
1544                         def.basictype.array = array->ca;
1545                 } else {
1546                         def.basictype.array.bounds[0] = 0;
1547                         def.basictype.array.bounds[1] = 0;
1548                 }
1549         }
1550
1551         void set_inline()
1552         {
1553                 def.flags.field.Inline = 1;
1554         }
1555
1556         bool is_inline()
1557         {
1558                 return def.flags.field.Inline;
1559         }
1560         
1561         bool is_in()
1562         {
1563                 return def.flags.field.In;
1564         }
1565
1566         bool is_out()
1567         {
1568                 return def.flags.field.Out;
1569         }
1570
1571         virtual void output(const char *root);
1572         bool output_extra(FILE *f);
1573
1574         static Param *import(ImportContext &ctx);
1575         virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
1576         
1577         bool is_array()
1578         {
1579                 return ::is_array(def.basictype);
1580         }
1581 };
1582
1583 typedef Ref<Param> ParamRef;
1584
1585 class Method : public NameSpace, public Def {
1586         list<ParamRef> entries;
1587
1588         void add_elem(Param *p);
1589
1590 public:
1591         CompiledMethod def;
1592         
1593         Method(const String *name) :
1594         Symbol(name), 
1595         Def((const char *)&def, sizeof(def), CompiledDefHeader::Method)
1596         {
1597                 memset(&def, 0, sizeof(def));
1598         }
1599
1600         void set_async()
1601         {
1602                 def.flags.field.Async = 1;
1603         }
1604         
1605         bool is_async()
1606         {
1607                 return def.flags.field.Async;
1608         }
1609         
1610         static Method *declare(const String *name, NameSpace *parent);
1611
1612         void add(Symbol *sym, bool from_import);
1613
1614         virtual const char *description()
1615         {
1616                 return "method";
1617         }
1618
1619         virtual void output(const char *root);
1620         bool output_extra(FILE *f);
1621
1622         static Method *import(ImportContext &ctx);
1623         virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
1624
1625         typedef list<ParamRef>::const_iterator entries_iterator;
1626
1627         entries_iterator entries_begin()
1628         {
1629                 return entries.begin();
1630         }
1631
1632         entries_iterator entries_end()
1633         {
1634                 return entries.end();
1635         }
1636 };
1637
1638 typedef Ref<Method> MethodRef;
1639
1640 class Interface;
1641 typedef Ref<Interface> InterfaceRef;
1642
1643 extern InterfaceRef System_Object;
1644
1645 // FIXME: typedefed superinterfaces
1646 class Interface : public NameSpace, public Type, public Def {
1647         list<MethodRef> methods;
1648         list<InterfaceRef> supers;
1649         IDListRef supernames;
1650
1651         void add_elem(Method *m);
1652
1653         // This is like Symbol::traversed[], but used internally by the
1654         // for_each_super function to ensure that common ancestors are only
1655         // visited once.
1656         
1657         int traversed_all_supers;
1658         static int all_supers_traversal;
1659         
1660 public:
1661         typedef void (*callback)(Interface *i, void *arg);
1662         
1663 private:
1664         template<callback cb>
1665         void for_each_super_internal(void *arg)
1666         {
1667                 for (supers_iterator i = supers_begin(); i != supers_end(); ++i) {
1668                         Interface *iface = *i;
1669                         
1670                         if (iface->traversed_all_supers < all_supers_traversal) {
1671                                 iface->traversed_all_supers = all_supers_traversal;
1672                                 cb(iface, arg);
1673                                 iface->for_each_super_internal<cb>(arg);
1674                         }
1675                 }
1676         }
1677
1678         // All interfaces in the map and vector are supers of this
1679         // interface, and thus retained that way, so plain pointers
1680         // can be used here.
1681
1682         typedef map<Interface *, int> chain_map_type;
1683         typedef chain_map_type::value_type chain_valtype;
1684         typedef chain_map_type::const_iterator chain_iter;
1685
1686         chain_map_type super_to_chain_map;
1687
1688 private:
1689         int num_chains;
1690         vector<Interface *> chain_heads;
1691
1692 public: 
1693         int super_to_chain(Interface *iface, bool must_find_it = true)
1694         {
1695                 chain_iter ret = super_to_chain_map.find(iface);
1696                 
1697                 if (ret == super_to_chain_map.end()) {
1698                         assert(!must_find_it);
1699                         return -1;
1700                 }
1701
1702                 return (*ret).second;
1703         }
1704
1705         Interface *get_chain_head(int chain)
1706         {
1707                 return chain_heads[chain];
1708         }
1709
1710         int get_num_chains()
1711         {
1712                 return num_chains;
1713         }
1714         
1715 private:        
1716         void set_chain(Interface *iface, int chain)
1717         {
1718                 pair<chain_iter, bool> ret = 
1719                         super_to_chain_map.insert(chain_valtype(iface, chain));
1720                 assert(ret.second);
1721         }
1722         
1723         // This is the inner depth-first search, which terminates
1724         // at each level upon finding that the node it had previously
1725         // recursed into found an unchained node.
1726         
1727         void pick_chain(Interface *iface, int chain)
1728         {
1729                 assert(super_to_chain(iface, false) == -1);
1730                 chain_heads.push_back(iface);
1731         
1732                 do {
1733                         set_chain(iface, chain);
1734                         
1735                         if (iface->supers.empty())
1736                                 break;
1737                         
1738                         iface = iface->supers.front();
1739                 } while (super_to_chain(iface, false) == -1);
1740         }
1741
1742         // This is the outer breadth-first-search, making sure every
1743         // super is assigned to a chain.
1744
1745         void sort_chains()
1746         {
1747                 list<Interface *> bfs;
1748                 num_chains = 0;
1749
1750                 bfs.push_back(this);
1751                 
1752                 while (!bfs.empty()) {
1753                         Interface *iface = bfs.front();
1754                         bfs.pop_front();
1755                 
1756                         for (supers_iterator i = iface->supers_begin();
1757                              i != iface->supers_end(); ++i)
1758                                 bfs.push_back(*i);
1759                 
1760                         if (super_to_chain(iface, false) == -1)
1761                                 pick_chain(iface, num_chains++);
1762                 }
1763         }
1764
1765 public:
1766         // Do not call after lookup_misc
1767         void add_super(Interface *i)
1768         {
1769                 assert(current_pass != 1);
1770         
1771                 supers.push_back(i);
1772                 def.num_supers++;
1773         }
1774
1775         CompiledInterface def;
1776         
1777         Interface(const String *name) :
1778         Symbol(name),
1779         Def((const char *)&def, sizeof(def), CompiledDefHeader::Interface)
1780         {
1781                 memset(&def, 0, sizeof(def));
1782                 traversed_all_supers = 0;
1783         }
1784         
1785         void init(IDList *SUPERNAMES)
1786         {
1787                 supernames = SUPERNAMES;
1788         }
1789
1790         static Interface *declare(const String *name, NameSpace *parent, 
1791                                   IDList *SUPERNAMES)
1792         {
1793                 assert(parent);
1794
1795                 Interface *i = new Interface(name);
1796                 i->init(SUPERNAMES);
1797                 
1798                 parent->add_user(i);
1799                 return i;
1800         }
1801         
1802         // Only Methods, Types, and const BasicType Datums can be added.
1803
1804         void add(Symbol *sym, bool from_import);
1805
1806         virtual const char *description()
1807         {
1808                 return "interface";
1809         }
1810
1811 private:
1812         void add_object_super()
1813         {
1814                 assert(System_Object);
1815                 if (this != System_Object && supers.empty())
1816                         add_super(System_Object);
1817         }
1818
1819 public: 
1820         virtual void lookup_misc()
1821         {
1822                 if (def.guid[0] == 0 && def.guid[1] == 0)
1823                         yyerrorfl(name->file, name->line,
1824                                   "Interface \"%s\" is missing a GUID.",
1825                                   get_fq_name()->flatten()->c_str());
1826         
1827                 if (supernames) {
1828                         for (IDList::iterator i = supernames->begin(); 
1829                              i != supernames->end(); ++i)
1830                         {
1831                                 Symbol *sym = lookup_sym(toplevel, *i, get_ns());
1832                                 Interface *iface = 
1833                                         dynamic_cast<Interface *>(sym->get_concrete_sym());
1834                                 
1835                                 if (!iface) {
1836                                         const String *str = (*i)->back();
1837                                         yyerrorfl(str->file, str->line,
1838                                                   "\"%s\" is not an interface.\n",
1839                                                   sym->get_fq_name()->flatten()->c_str());
1840         
1841                                         throw UserError();
1842                                 }
1843                                 
1844                                 add_super(iface);
1845                         }
1846                 }
1847                 
1848                 add_object_super();
1849                 NameSpace::lookup_misc();
1850         }
1851         
1852         virtual void final_analysis()
1853         {
1854                 // FIXME: check for infinite loops in inheritance
1855         
1856                 sort_chains();
1857                 NameSpace::final_analysis();
1858         }
1859         
1860         virtual void output(const char *root);
1861         bool output_extra(FILE *f);
1862
1863         static Interface *import(ImportContext &ctx);
1864         virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
1865
1866         typedef list<MethodRef>::const_iterator methods_iterator;
1867         typedef list<InterfaceRef>::const_iterator supers_iterator;
1868
1869         supers_iterator supers_begin()
1870         {
1871                 assert(current_pass != 1);
1872                 return supers.begin();
1873         }
1874
1875         supers_iterator supers_end()
1876         {
1877                 return supers.end();
1878         }
1879         
1880         bool supers_empty()
1881         {
1882                 assert(current_pass != 1);
1883                 return supers.empty();
1884         }
1885
1886         methods_iterator methods_begin()
1887         {
1888                 return methods.begin();
1889         }
1890
1891         methods_iterator methods_end()
1892         {
1893                 return methods.end();
1894         }
1895         
1896         template<callback cb>
1897         void for_each_super(void *arg)
1898         {
1899                 assert(current_pass >= 4);
1900         
1901                 all_supers_traversal++;
1902                 for_each_super_internal<cb>(arg);
1903         }
1904
1905         void finalize_class_iface()
1906         {
1907                 add_object_super();
1908                 sort_chains();
1909         }
1910         
1911         void set_guid(uint64_t guid[2])
1912         {
1913                 if (def.guid[0] || def.guid[1])
1914                         yyerrorf("\"%s\" already has a GUID.",
1915                                  get_fq_name()->flatten()->c_str());
1916         
1917                 def.guid[0] = guid[0];
1918                 def.guid[1] = guid[1];
1919         }
1920 };
1921
1922 class IFaceList : public list<InterfaceRef>,
1923                   public RefCountable<IFaceList> {};
1924
1925 class Enum : public NameSpace, public Type, public Def {
1926         list<DatumRef> entries;
1927
1928         void add_elem(Datum *d);
1929
1930 public:
1931         unsigned int next_val;
1932         CompiledEnum def;
1933
1934         Enum(const String *name) :
1935         Symbol(name),
1936         Def((const char *)&def, sizeof(def), CompiledDefHeader::Enum),
1937         next_val(0)
1938         {
1939                 memset(&def, 0, sizeof(def));
1940         }
1941
1942         void init(int bits)
1943         {
1944                 if (bits < 0 || bits > 64) {
1945                         yyerrorf("\"%s\" has invalid enum size %d", 
1946                                  name->c_str(), bits);
1947
1948                         bits = bits < 0 ? 0 : 64;
1949                 }
1950         
1951                 def.bits = bits;
1952         }
1953
1954         static Enum *declare(const String *name, NameSpace *parent,
1955                              int bits)
1956         {
1957                 assert(parent);
1958                 
1959                 Enum *e = new Enum(name);
1960                 e->init(bits);
1961                 
1962                 parent->add_user(e);
1963                 return e;
1964         }
1965
1966         // Only const unsigned integer BasicType Datums are allowed.
1967
1968         void add(Symbol *sym, bool from_import);
1969
1970         virtual const char *description()
1971         {
1972                 return "enumeration";
1973         }
1974
1975         int get_default_bf_size()
1976         {
1977                 return def.bits;
1978         }
1979
1980         virtual void output(const char *root);
1981         bool output_extra(FILE *f);
1982
1983         static Enum *import(ImportContext &ctx);
1984         virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
1985
1986         typedef list<DatumRef>::const_iterator entries_iterator;
1987
1988         entries_iterator entries_begin()
1989         {
1990                 return entries.begin();
1991         }
1992
1993         entries_iterator entries_end()
1994         {
1995                 return entries.end();
1996         }
1997 };
1998
1999 class Alias : public Symbol, public Def {
2000         bool lookup_begun;
2001         
2002         struct Cycle {
2003                 Alias *end;
2004                 
2005                 Cycle(Alias *END) : end(END)
2006                 {
2007                 }
2008         };
2009
2010 public:
2011         CompiledAlias def;
2012         
2013         SymbolRef real_sym;
2014         StringRef sym_fq_name;
2015         StrListRef sym_name;
2016         
2017         Alias(const String *name) :
2018         Symbol(name),
2019         Def((const char *)&def, sizeof(def), CompiledDefHeader::Alias)
2020         {
2021                 memset(&def, 0, sizeof(def));
2022                 lookup_begun = false;
2023         }
2024         
2025         void init(StrList *symname, bool is_private)
2026         {
2027                 sym_name = symname;
2028                 priv = is_private;
2029         }
2030
2031         static Alias *declare(const String *name, NameSpace *parent,
2032                               StrList *symname, bool is_private = false)
2033         {
2034                 assert(parent);
2035                 Alias *a = new Alias(name);
2036                 a->init(symname, is_private);
2037
2038                 parent->add_user(a);
2039                 return a;
2040         }
2041         
2042         void resolve_chain()
2043         {       
2044                 if (!real_sym) {
2045                         if (lookup_begun) {
2046                                 yyerrorfl(name->file, name->line,
2047                                           "Alias loop defining \"%s\"",
2048                                           get_fq_name()->flatten()->c_str());
2049                         
2050                                 throw Cycle(this);
2051                         }
2052                         
2053                         lookup_begun = true;
2054                         
2055                         try {
2056                                 real_sym = lookup_sym(toplevel, sym_name, get_ns(), this);
2057                         }
2058                         
2059                         catch (Cycle &c) {
2060                                 yyerrorfl(name->file, name->line, "   ...referenced by \"%s\"",
2061                                           get_fq_name()->flatten()->c_str());
2062
2063                                 if (c.end == this)
2064                                         throw UserError();
2065
2066                                 throw c;
2067                         }
2068                 }
2069         }
2070
2071         virtual Symbol *get_concrete_sym(bool follow_typedefs = true)
2072         {
2073                 resolve_chain();
2074                 return real_sym->get_concrete_sym(follow_typedefs);
2075         }
2076
2077         virtual void lookup_chain()
2078         {
2079                 get_concrete_sym(true);
2080         }
2081
2082         virtual void lookup_misc()
2083         {
2084                 real_sym = real_sym->get_concrete_sym(false);
2085                 sym_fq_name = real_sym->get_fq_name()->flatten();
2086                 
2087                 def.length = sym_fq_name->length();
2088         }
2089
2090         virtual void output(const char *root);
2091         bool output_extra(FILE *f);
2092
2093         static Alias *import(ImportContext &ctx);
2094         virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
2095 };
2096
2097 class TypeDef : public Alias {
2098 public:
2099         TypeDef(const String *name) : Alias(name)
2100         {
2101                 memset(&def, 0, sizeof(def));
2102                 hdr.type = CompiledDefHeader::TypeDef;
2103         }
2104         
2105         static TypeDef *declare(const String *name, NameSpace *parent,
2106                                 StrList *symname)
2107         {
2108                 assert(parent);
2109                 TypeDef *td = new TypeDef(name);
2110                 td->init(symname, false);
2111                 
2112                 parent->add_user(td);
2113                 return td;
2114         }
2115
2116         virtual Symbol *get_concrete_sym(bool follow_typedefs = true)
2117         {
2118                 if (follow_typedefs) {
2119                         resolve_chain();
2120                         return real_sym->get_concrete_sym(follow_typedefs);
2121                 }
2122                 
2123                 return this;
2124         }
2125
2126         static TypeDef *import(ImportContext &ctx);
2127         virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
2128 };
2129
2130 NameSpace *add_nspace(StrList *name, bool push);
2131 void pop_nspace();
2132
2133 // Declare an instance of "type" in "ns" for each element of "ids".
2134 // This function will report any errors, but not throw UserError.
2135
2136 void declare_data(NameSpace *ns, StrList *ids, StrList *type,
2137                   Array *array, StrList *attr);
2138 void declare_aliases(NameSpace *ns, StrList *ids, StrList *type,
2139                      bool is_typedef);
2140 void declare_basictypes(NameSpace *ns, StrList *ids,
2141                         BasicType *type, bool is_typedef);
2142
2143 // You'd think they'd have standard functions to do this these days.
2144 // All I could find that come close are the network-byte-order
2145 // functions, and they're no-ops on big-endian machines.
2146
2147 static inline uint32_t swap32(uint32_t in, bool swap)
2148 {
2149         if (swap)
2150                 return ((in & 0x000000ff) << 24) |
2151                        ((in & 0x0000ff00) <<  8) |
2152                        ((in & 0x00ff0000) >>  8) |
2153                        ((in & 0xff000000) >> 24);
2154         
2155         return in;
2156 }
2157
2158 static inline uint64_t swap64(uint64_t in, bool swap)
2159 {
2160         if (swap)
2161                 return (((uint64_t)swap32((uint32_t)in, true)) << 32) |
2162                        swap32((uint32_t)(in >> 32), true);
2163
2164         return in;
2165 }
2166
2167 struct File {
2168         FILE *f;
2169         
2170         File()
2171         {
2172                 f = NULL;
2173         }
2174         
2175         File(FILE *F)
2176         {
2177                 f = F;
2178         }
2179         
2180         File *operator =(FILE *F)
2181         {
2182                 f = F;
2183                 return this;
2184         }
2185         
2186         ~File()
2187         {
2188                 if (f)
2189                         fclose(f);
2190         }
2191         
2192         operator FILE *()
2193         {
2194                 return f;
2195         }
2196 };
2197
2198 // Verify that a prospective new import (or output namespace)
2199 // does not overlap an existing import.  Returns the conflicting
2200 // import, or NULL if none found.
2201
2202 NameSpace *check_for_imports(NameSpace *ns);
2203
2204 #endif