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