]> git.buserror.net Git - polintos/scott/priv.git/blob - idlcomp/idlc.h
Add distributors to liability disclaimer. Need to update file headers.
[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(const 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 typedef Ref<NameSpace> NameSpaceRef;
451
452 // This is incremented when a chain of symbols is traversed to reset
453 // detection of already-visited symbols.  It is assumed that this
454 // will not have to happen billions of times.
455
456 extern int traversal;
457
458 class Symbol : public RefCountable<Symbol> {
459         NameSpace *ns;
460         
461         void init()
462         {
463                 ns = NULL;
464                 external = false;
465                 priv = false;
466                 lang_priv = NULL;
467         }
468         
469 public:
470         StringRef name;
471
472         // Symbol was loaded externally
473         bool external;
474         
475         // If set, the symbol is private, and will not be available
476         // for lookups except those made directly in the context of
477         // the containing namespace.  Private symbols do not get
478         // outputted.  They are used to implement imports of specific
479         // symbols (as aliases), rather than entire namespaces.
480         
481         bool priv;
482         
483         // Reserved for language binding use.
484         Releasable *lang_priv;
485
486         Symbol()
487         {
488                 init();
489         }
490         
491         Symbol(const String *_name) : name(_name)
492         {
493                 init();
494         }
495
496         virtual ~Symbol();
497
498         NameSpace *get_ns() const
499         {
500                 return ns;
501         }
502
503         const String *get_name() const
504         {
505                 return name;
506         }
507         
508         // If append is non-NULL, it is appended to non-user namespaces,
509         // to facilitate a language binding that cannot place nested types
510         // in the same language construct as the actual interface.  The
511         // recommended suffix is "_ns", which is a reserved ending in the
512         // IDL.  No suffix is placed on the final component of the name,
513         // even if it is a non-user namespace.  The not_last field is used
514         // to detect whether it is the final component; it is only used
515         // internally, and should always be false when called externally.
516         //
517         // This function does *NOT* add a null first element to indicate
518         // that the name is fully qualified.  If you need that, you have
519         // to add it yourself (call 'push_front(new String(""))' on the
520         // result).
521         
522         StrList *get_fq_name(const char *append = NULL,
523                              bool not_last = false) const;
524         
525         virtual void lookup_imports()
526         {
527         }
528         
529         virtual void lookup_chain()
530         {
531         }
532
533         virtual void lookup_misc()
534         {
535         }
536         
537         virtual void final_analysis()
538         {
539         }
540
541         // These two methods must be implemented by all IDL symbols, but are
542         // not needed in CDL symbols (and therefore are not pure virtual).
543
544         virtual void output(const char *root)
545         {
546         }
547
548         virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL)
549         {
550         }
551         
552         // Find and return the topmost symbol other than a user namespace
553         // containing this symbol.  If this symbol's parent is a user
554         // namespace, it returns itself.  May not be called on the
555         // toplevel namespace.
556         
557         Symbol *find_toplevel_type();
558
559         // Get the true type of the symbol, regardless of whether it is an
560         // alias.
561         
562         virtual Symbol *get_concrete_sym(bool follow_typedefs = true)
563         {
564                 return this;
565         }
566         
567         friend class NameSpace;
568 };
569
570 typedef Ref<Symbol> SymbolRef;
571
572 class SymList : public list<SymbolRef>, public RefCountable<SymList> {};
573 typedef Ref<SymList> SymListRef;
574
575 struct SymbolNotFound {
576 };
577
578 struct DuplicateSymbol {
579 };
580
581 struct InvalidArgument {
582 };
583
584 struct UserError {
585 };
586
587 class NameSpace : public virtual Symbol {
588 protected:
589         // Filesystem path to the external symbol storage, or NULL
590         // if not an import namespace.
591         //
592         // Import namespaces are read-only namespaces which are created
593         // for the importation of externally-declared symbols.  One is
594         // initially created for each "mount point" specified by the user;
595         // whenever such a namespace is searched, it checks the external
596         // storage, and if the lookup succeeds, the symbol is loaded and
597         // added to the namespace.  Failed lookups could be cached with a
598         // special BadSymbol or some such, as the imported namespace is
599         // assumed to be constant, but I don't think such an optimization
600         // is worthwhile, at least at this point.
601         
602         StringRef path;
603
604         // Load a symbol from external storage, constructing the relevant type
605         // of object, and adding it to this namespace.  Only called for
606         // import namespaces.
607
608         Symbol *load(const String *symname);
609
610         typedef map<StringRef, SymbolRef> tbl_type;
611         tbl_type tbl;
612         
613         list<StrListRef> import_strs;
614         list<NameSpaceRef> imports;
615
616 public:
617         // This is a counter for generating unique names for anonymous
618         // members of the namespace.
619         int anon;
620         
621         NameSpace() : anon(0)
622         {
623         }
624         
625         virtual ~NameSpace();
626         
627         // Return a description of the type of namespace, for
628         // error messages.
629         virtual const char *description()
630         {
631                 return "namespace";
632         }
633
634         virtual void output(const char *root);
635
636         typedef tbl_type::const_iterator const_iterator;
637         typedef tbl_type::value_type value_type;
638
639         // Derived classes can throw InvalidArgument if you give them
640         // a type of Symbol that they don't accept; see their comments
641         // for more details.  Unfortunately, this cannot be done
642         // with static type-checking, as there are places that know
643         // they've been given a namespace that can accept a particular
644         // type of symbol, but they don't know exactly what kind of
645         // namespace it is.  C++'s type system is not sufficient to
646         // express this (at least not while retaining any semblance
647         // of sanity).
648
649         // DuplicateSymbol is thrown if sym already exists in this namespace.
650         virtual void add(Symbol *sym, bool from_import)
651         {
652                 if (path && !from_import)
653                         throw InvalidArgument();
654                 
655                 if (path)
656                         sym->external = true;
657                 
658                 if (!sym->name.data)
659                         BUG();
660
661                 pair<const_iterator, bool> ret = tbl.insert(value_type(sym->name, sym));
662                 
663                 if (ret.second)
664                         sym->ns = this;
665                 else {
666                         throw DuplicateSymbol();
667                 }
668         }
669
670         // Add the symbol to this namespace, handling duplicate symbols by
671         // printing an error and throwing a UserError().  This should not be
672         // done in the symbol's constructor, as the parent may not accept
673         // the symbol until it is fully constructed (the RTTI information
674         // changes, and in general partially constructed objects shouldn't
675         // be exposed to the rest of the system).
676
677         void add_user(Symbol *sym);
678
679         // Like add_user, but used by the import code.  Duplicate
680         // symbols result in internal errors, and the add is done with
681         // from_import set to true.  InvalidArgument results in an error
682         // message and a reraise as UserError.
683         //
684         // All conditions checked by the parent namespace's add() method
685         // (such as constness of data) must be satisfied prior to calling
686         // add_import().  On the other hand, add_import() must be called
687         // before any recursive importation is done which could
688         // conceivably try to import the current symbol (thus causing
689         // infinite recursion).
690
691         void add_import(Symbol *sym, const char *filename);
692
693         // SymbolNotFound is thrown if sym is not in this namespace.
694         virtual void del(Symbol *sym)
695         {
696                 if (sym->ns != this)
697                         throw SymbolNotFound();
698
699                 sym->ns = NULL;
700                 int ret = tbl.erase(sym->name);
701                 assert(ret != 0);
702         }
703
704 private:        
705         Symbol *lookup_noex_noimport(const String *symname)
706         {
707                 const_iterator ret = tbl.find(symname);
708                 
709                 if (ret != tbl.end())
710                         return (*ret).second;
711                 
712                 return NULL;
713         }
714
715 public:
716         Symbol *lookup_noex(const String *symname, bool priv_ok = false)
717         {
718                 Symbol *ret = NameSpace::lookup_noex_noimport(symname);
719
720                 if (path && !ret)
721                         ret = load(symname);
722                 
723                 if (ret && !priv_ok && ret->priv)
724                         return NULL;
725         
726                 return ret;
727         }
728
729         Symbol *lookup(const String *symname, bool priv_ok = false)
730         {
731                 Symbol *ret = lookup_noex(symname, priv_ok);
732                 
733                 if (!ret)
734                         throw SymbolNotFound();
735                 
736                 return ret;
737         }
738         
739         // Like lookup_noex, but also checks imported namespaces,
740         // and returns the namespace containing the match rather
741         // than the match itself.
742         
743         NameSpace *search(const String *name, Symbol *exclude);
744         
745         void add_search(StrList *ns)
746         {
747                 import_strs.push_back(ns);
748         }
749
750         // Return a string containing case information manglement.
751         // See input.cc for more information.
752
753         static const String *mangle(const String *name);
754
755         const String *get_path()
756         {
757                 return path;
758         }
759         
760         // Import all members of this namespace.  A no-op if not an import
761         // namespace.  
762         void import_all();
763         
764         // As import_all, but also recursively applies to any sub-namespaces.
765         void import_all_recursive();
766         
767         const_iterator begin()
768         {
769                 return tbl.begin();
770         }
771
772         const_iterator end()
773         {
774                 return tbl.end();
775         }
776
777         virtual void lookup_imports();
778
779         virtual void lookup_chain()
780         {
781                 for (const_iterator i = begin(); i != end(); ++i) {
782                         Symbol *sym = (*i).second;
783                         sym->lookup_chain();
784                 }
785         }
786
787         virtual void lookup_misc()
788         {
789                 for (const_iterator i = begin(); i != end(); ++i) {
790                         Symbol *sym = (*i).second;
791                         sym->lookup_misc();
792                 }
793         }
794
795         virtual void final_analysis()
796         {
797                 for (const_iterator i = begin(); i != end(); ++i) {
798                         Symbol *sym = (*i).second;
799                         sym->final_analysis();
800                 }
801         }
802 };
803
804
805 extern NameSpaceRef cur_nspace;
806 extern list<NameSpaceRef> nspace_stack;
807         
808 typedef std::vector<StringRef> StringVec;
809
810 string *stringvec_to_path(StringVec &stringvec, const char *prepend);
811
812 // lookup_sym and lookup_type throw UserError on user error
813 // The context namespace is required for the proper
814 // set of namespaces to be searched.
815
816 Symbol *lookup_sym(NameSpace *topns, StrList *name, NameSpace *ctx,
817                    Symbol *exclude = NULL);
818
819 class Def {
820         const char *self;   // Pointer to the type-specific struct
821         int self_len;       // Length of the type-specific struct
822         
823 protected:
824         CompiledDefHeader hdr;
825
826         // sym is the symbol from which to get the path/name, and
827         // dir is true if it should be "name/.self" rather than 
828         // "name".
829         void output_self(const char *dir, Symbol *sym, bool dir);
830
831 public:
832         Def(const char *self, int self_len, CompiledDefHeader::Type type) :
833         self(self), self_len(self_len)
834         {
835                 hdr.magic = CompiledDefHeader::magic_normal;
836                 hdr.type = type;
837         }
838         
839         virtual ~Def()
840         {
841         }
842         
843         // Specific types may override this to output extra data
844         // to the .self file without having to reopen the file.
845         //
846         // Returns false on error.
847         
848         virtual bool output_extra(FILE *f)
849         {
850                 return true;
851         }
852 };
853
854 // Internal context struct used by input.cc to avoid passing
855 // lots of parameters around
856 struct ImportContext;
857
858 // This represents an actual IDL namespace {}, rather than
859 // a derived namespace such as a Struct or Interface.
860
861 class UserNameSpace : public NameSpace, public Def {
862 public:
863         CompiledNameSpace def;
864         StringRef mountpoint_name;
865
866         UserNameSpace(const String *name = NULL) :
867         Symbol(name),
868         Def((const char *)&def, sizeof(def), CompiledDefHeader::NameSpace)
869         {
870                 mountpoint_name = get_fq_name()->flatten();
871                 def.length = mountpoint_name->length();
872         }
873
874         virtual void output(const char *root);
875         bool output_extra(FILE *f);
876         
877         static void declare_import(const char *path);
878
879         static UserNameSpace *import(ImportContext &ctx);
880         virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
881 };
882
883 typedef Ref<UserNameSpace> UserNameSpaceRef;
884 extern UserNameSpaceRef toplevel, cdl_toplevel;
885 extern UserNameSpace *output_ns;
886
887 class Type : public virtual Symbol {
888 public:
889         Type()
890         {
891         }
892         
893         virtual ~Type()
894         {
895         }
896         
897         virtual int get_default_bf_size()
898         {
899                 // Only allow types in bitfields that explicitly
900                 // support it.
901                 
902                 return -1;
903         }
904 };
905
906 typedef Ref<Type> TypeRef;
907
908 // ctx can be NULL if basic_types_only is true
909 Type *lookup_type(StrList *sl, NameSpace *ctx, bool basic_types_only = false);
910
911 class BasicType : public Type, public Def {
912 public:
913         CompiledBasicType def;
914         bool complete;
915         
916         BasicType(const String *name) :
917         Symbol(name),
918         Def((const char *)&def, sizeof(def), CompiledDefHeader::BasicType)
919         {
920                 complete = false;
921                 memset(&def, 0, sizeof(def));
922         }
923
924         void init(CompiledBasicType &DEF)
925         {
926                 assert(!complete);
927         
928                 def = DEF;
929                 complete = true;
930         }
931
932         static BasicType *declare(const String *name, NameSpace *parent,
933                                   CompiledBasicType &DEF)
934         {
935                 BasicType *bt = new BasicType(name);
936                 bt->init(DEF);
937         
938                 if (parent)
939                         parent->add_user(bt);
940
941                 return bt;
942         }
943
944         virtual void output(const char *root);
945
946         static BasicType *import(ImportContext &ctx);
947         virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
948 };
949
950 static inline bool is_array(CompiledBasicType &bt)
951 {
952         return bt.array.bounds[0] || bt.array.bounds[1];
953 }
954
955 static inline bool is_array(CompiledBasicType *bt)
956 {
957         return is_array(*bt);
958 }
959
960 typedef Ref<Datum> DatumRef;
961
962 class Array : public RefCountable<Array>
963 {
964         NameSpace *lookup_ctx;
965         DatumRef datums[2];
966
967         // lower is [0], upper is [1]
968         StrListRef dcons[2];
969         Con cons[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         // ca is not valid until after final_analysis() is called.
981         CompiledArray ca;
982
983         Array(NameSpace *LOOKUP_CTX);
984         void set_bound(Con &con, int bound);
985         void final_analysis();
986
987         void set_unbounded();
988 };
989
990 typedef Ref<Array> ArrayRef;
991
992 class Datum : public Symbol, public Def {
993         StrListRef type_name;
994         SymbolRef type_sym;
995         StringRef type_fq_name;
996
997         StrListRef const_val_name;
998         SymbolRef const_val_sym;
999         DatumRef const_val;
1000
1001         bool basic;      // Datum is of a BasicType
1002         bool complete;
1003         bool const_init; // Datum's constant has been initialized; this is
1004                          // true after a successful verify_const().
1005         CompiledBasicType *cbt;
1006         
1007         ArrayRef array;
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         CompiledDatum def;
1040         TypeRef type;
1041
1042         int con_type;    // Used to store the TOK_[IUF]CON of the Con struct
1043                          // for type checking once the type is known.
1044
1045         Datum(const String *name) :
1046         Symbol(name), 
1047         Def((const char *)&def, sizeof(def), CompiledDefHeader::Datum)
1048         {
1049                 complete = false;
1050                 const_init = false;
1051                 chain_traversed = 0;
1052                 memset(&def, 0, sizeof(def));
1053         }
1054
1055         void init(StrList *type, Array *ARRAY, Con *con = NULL);
1056         void init(CompiledBasicType &cbt, Array *ARRAY, Con *con = NULL);
1057
1058         static Datum *declare(const String *name, NameSpace *parent,
1059                               StrList *type, Array *ARRAY,
1060                               Con *con = NULL)
1061         {
1062                 assert(parent);
1063                 
1064                 Datum *d = new Datum(name);
1065                 d->init(type, ARRAY, con);
1066
1067                 parent->add_user(d);
1068                 return d;
1069         }
1070
1071         static Datum *declare(const String *name, NameSpace *parent,
1072                               CompiledBasicType &type, 
1073                               Array *ARRAY, Con *con = NULL)
1074         {
1075                 assert(parent);
1076         
1077                 Datum *d = new Datum(name);
1078                 d->init(type, ARRAY, con);
1079
1080                 parent->add_user(d);
1081                 return d;
1082         }
1083         
1084         void set_inline()
1085         {
1086                 def.flags.field.Inline = 1;
1087         }
1088         
1089         bool is_inline()
1090         {
1091                 return def.flags.field.Inline;
1092         }
1093         
1094         void set_immutable()
1095         {
1096                 def.flags.field.Immutable = 1;
1097         }
1098         
1099         bool is_immutable()
1100         {
1101                 return def.flags.field.Immutable;
1102         }
1103
1104         // Returns true if the constant was acceptable, false otherwise (an
1105         // error is also output to the user in this case).
1106         
1107         bool verify_const();
1108
1109         virtual void lookup_chain()
1110         {
1111                 assert(complete);
1112
1113                 if (const_val_name)
1114                         const_val_sym = lookup_sym(toplevel, const_val_name, get_ns());
1115
1116                 if (type_name) {
1117                         assert(!basic);
1118                         type_sym = lookup_type(type_name, get_ns(), true);
1119                         if (!type_sym)
1120                                 type_sym = lookup_sym(toplevel, type_name, get_ns());
1121                 } else {
1122                         assert(basic);
1123                 }
1124         }
1125
1126         virtual void lookup_misc()
1127         {
1128                 if (def.flags.field.Const) {
1129                         if (!const_init) {
1130                                 assert(def.flags.field.Const);
1131         
1132                                 traversal++;
1133                                 Datum *d = resolve_constant_chain();
1134                                 assert(!d);
1135                         }
1136                 
1137                         assert(const_init);
1138                 } else {
1139                         process_type();
1140                 }
1141         }
1142         
1143         virtual void final_analysis();
1144
1145         virtual void output(const char *root);
1146         bool output_extra(FILE *f);
1147
1148         static Datum *import(ImportContext &ctx);
1149         virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
1150
1151         uint64_t get_ucon(const String *err_str)
1152         {
1153                 if (!def.flags.field.Const) {
1154                         yyerrorfl(err_str->file, err_str->line, 
1155                                   "\"%s\" is not a const Datum.\n",
1156                                   get_fq_name()->flatten()->c_str());
1157                         throw UserError();
1158                 }
1159                 
1160                 assert(const_init);
1161                 return def.ucon;
1162         }
1163
1164         bool is_array()
1165         {
1166                 return ::is_array(def.basictype);
1167         }
1168 };
1169
1170 template<typename T>
1171 bool output_list(T *sym, FILE *f);
1172
1173 class BitField : public NameSpace, public Type, public Def {
1174         list<DatumRef> entries;
1175
1176         void add_elem(Datum *d);
1177
1178 public:
1179         CompiledBitField def;
1180         int cur_pos;
1181
1182         BitField(const String *name) :
1183         Symbol(name),
1184         Def((const char *)&def, sizeof(def), CompiledDefHeader::BitField)
1185         {
1186                 memset(&def, 0, sizeof(def));
1187         }
1188
1189         void init(int bits, NameSpace *parent)
1190         {
1191                 if (bits < 0 || bits > 64) {
1192                         yyerrorf("\"%s\" has invalid bitfield size %d", 
1193                                  name->c_str(), bits);
1194
1195                         bits = bits < 0 ? 0 : 64;
1196                 }
1197         
1198                 def.bits = bits;
1199         }
1200
1201         static BitField *declare(const String *name, NameSpace *parent,
1202                                  int bits)
1203         {
1204                 assert(parent);
1205                 
1206                 BitField *bf = new BitField(name);
1207                 bf->init(bits, parent);
1208         
1209                 parent->add_user(bf);
1210                 return bf;
1211         }
1212
1213         // Only integral Datums, Enums, and BitFields can be added.
1214
1215         void add(Symbol *sym, bool from_import);
1216
1217         virtual const char *description()
1218         {
1219                 return "bitfield";
1220         }
1221
1222         virtual void lookup_misc()
1223         {
1224                 NameSpace::lookup_misc();
1225         }
1226         
1227         virtual void final_analysis()
1228         {
1229                 // FIXME: check total size of elements
1230         
1231                 NameSpace::final_analysis();
1232         }
1233
1234         int get_default_bf_size()
1235         {
1236                 return def.bits;
1237         }
1238
1239         virtual void output(const char *root);
1240         bool output_extra(FILE *f);
1241
1242         static BitField *import(ImportContext &ctx);
1243         virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
1244
1245         typedef list<DatumRef>::const_iterator entries_iterator;
1246         typedef list<DatumRef>::const_reverse_iterator entries_reverse_iterator;
1247
1248         entries_iterator entries_begin()
1249         {
1250                 return entries.begin();
1251         }
1252
1253         entries_iterator entries_end()
1254         {
1255                 return entries.end();
1256         }
1257
1258         entries_reverse_iterator entries_rbegin()
1259         {
1260                 return entries.rbegin();
1261         }
1262
1263         entries_reverse_iterator entries_rend()
1264         {
1265                 return entries.rend();
1266         }
1267 };
1268
1269 class Struct;
1270 typedef Ref<Struct> StructRef;
1271 extern StructRef System_VStruct;
1272
1273 // FIXME: typedefed superstructs
1274 class Struct : public NameSpace, public Type, public Def {
1275         list<DatumRef> entries;
1276         StructRef super;
1277         SymbolRef supersym;
1278         StrListRef supername;
1279         bool attrs_resolved;
1280
1281         // 0 = unknown, 1 = yes, 2 = no
1282         int plain_data;
1283         
1284         void add_elem(Datum *d);
1285
1286         void resolve_attrs()
1287         {
1288                 if (attrs_resolved)
1289                         return;
1290                 
1291                 if (super && !super->attrs_resolved)
1292                         super->resolve_attrs();
1293                 
1294                 if (super && super->def.flags.field.Virtual)
1295                         def.flags.field.Virtual = 1;
1296                 
1297                 attrs_resolved = true;
1298         }
1299         
1300 public:
1301         CompiledStruct def;
1302         
1303         // This is not maintained by the generic code, but can be
1304         // used by language bindings to cache the result of the
1305         // summation. 
1306         
1307         int chainlen;
1308         
1309         Struct(const String *name) :
1310         Symbol(name),
1311         Def((const char *)&def, sizeof(def), CompiledDefHeader::Struct)
1312         {
1313                 memset(&def, 0, sizeof(def));
1314                 attrs_resolved = 0;
1315         }
1316         
1317         void init(StrList *SUPERNAME)
1318         {
1319                 supername = SUPERNAME;
1320         }
1321
1322         static Struct *declare(const String *name, NameSpace *parent,
1323                                StrList *SUPERNAME)
1324         {
1325                 assert(parent);
1326         
1327                 Struct *st = new Struct(name);
1328                 st->init(SUPERNAME);
1329
1330                 parent->add_user(st);
1331                 return st;
1332         }
1333         
1334         void set_virtual()
1335         {
1336                 def.flags.field.Virtual = 1;
1337         }
1338
1339         void set_inline()
1340         {
1341                 def.flags.field.Inline = 1;
1342         }
1343
1344         bool is_virtual()
1345         {
1346                 return def.flags.field.Virtual;
1347         }
1348
1349         bool is_inline()
1350         {
1351                 return def.flags.field.Inline;
1352         }
1353         
1354         // Only Datums and Types can be added.
1355
1356         void add(Symbol *sym, bool from_import);
1357
1358         virtual const char *description()
1359         {
1360                 return "struct";
1361         }
1362         
1363         Struct *get_super()
1364         {
1365                 assert(current_pass >= 4);
1366                 return super;
1367         }
1368
1369         virtual void lookup_chain()
1370         {
1371                 if (supername) {
1372                         supersym = lookup_sym(toplevel, supername, get_ns());
1373                         assert(supersym);
1374                 }
1375
1376                 NameSpace::lookup_chain();
1377         }
1378
1379 private:
1380         void lookup_super()
1381         {
1382                 if (supersym && !super) {
1383                         super = dynamic_cast<Struct *>(supersym->get_concrete_sym());
1384                 
1385                         if (!super) {
1386                                 const String *str = supername->back();
1387                                 yyerrorfl(str->file, str->line,
1388                                           "\"%s\" is not a struct.",
1389                                           supersym->get_fq_name()->flatten()->c_str());
1390                         }
1391                         
1392                         def.flags.field.Super = 1;
1393                         super->lookup_super();
1394                         
1395                         if (super->is_virtual())
1396                                 set_virtual();
1397                 }
1398                 
1399                 if (is_virtual() && !supersym && !super) {
1400                         assert(System_VStruct);
1401                         if (this != System_VStruct) {
1402                                 def.flags.field.Super = 1;
1403                                 super = System_VStruct;
1404                         }
1405                 }
1406         }
1407         
1408 public:
1409         virtual void lookup_misc()
1410         {
1411                 lookup_super();
1412
1413                 if (is_virtual() && def.guid[0] == 0 && def.guid[1] == 0)
1414                         yyerrorfl(name->file, name->line,
1415                                   "Virtual struct \"%s\" is missing a GUID.",
1416                                   get_fq_name()->flatten()->c_str());
1417
1418                 NameSpace::lookup_misc();
1419         }
1420         
1421         virtual void final_analysis()
1422         {
1423                 // FIXME: check for infinite loops in struct inheritance
1424
1425                 resolve_attrs();
1426                 NameSpace::final_analysis();
1427         }
1428
1429         virtual void output(const char *root);
1430         bool output_extra(FILE *f);
1431
1432         static Struct *import(ImportContext &ctx);
1433         virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
1434
1435         typedef list<DatumRef>::const_iterator entries_iterator;
1436
1437         entries_iterator entries_begin()
1438         {
1439                 return entries.begin();
1440         }
1441
1442         entries_iterator entries_end()
1443         {
1444                 return entries.end();
1445         }
1446
1447         void set_guid(uint64_t guid[2])
1448         {
1449                 if (def.guid[0] || def.guid[1])
1450                         yyerrorf("\"%s\" already has a GUID.",
1451                                  get_fq_name()->flatten()->c_str());
1452         
1453                 def.guid[0] = guid[0];
1454                 def.guid[1] = guid[1];
1455         }
1456
1457         // A struct is "plain data" if it contains no object references,
1458         // no non-inline arrays or structs, and no inline non-plain structs.
1459         bool is_plain_data();
1460 };
1461
1462 class Param : public Symbol, public Def {
1463         StrListRef type_name;
1464         StringRef type_fq_name;
1465
1466         bool basic;      // Datum is of a BasicType
1467         bool complete;
1468         
1469         ArrayRef array;
1470
1471         void use_named_type(BasicType *bt)
1472         {
1473                 assert(!bt || bt->def.flags.field.TypeDef);
1474                 
1475                 basic = false;
1476
1477                 type_fq_name = type->get_fq_name()->flatten();
1478                 def.type.length = type_fq_name->length();
1479         }
1480         
1481         void use_anon_type(const CompiledBasicType &cbt)
1482         {
1483                 def.basictype = cbt;
1484                 basic = true;
1485                 type = NULL;
1486         }
1487
1488         void set_array(Array *ARRAY)
1489         {
1490                 if (ARRAY)
1491                         array = ARRAY;
1492         }
1493
1494 public:
1495         CompiledParam def;
1496         TypeRef type;
1497
1498         Param(const String *name) :
1499         Symbol(name),
1500         Def((const char *)&def, sizeof(def), CompiledDefHeader::Param)
1501         {
1502                 memset(&def, 0, sizeof(def));
1503         }
1504
1505         void init(StrList *TYPE, CompiledParam::Flags flags, Array *ARRAY)
1506         {
1507                 type_name = TYPE;
1508                 def.flags = flags;
1509                 set_array(ARRAY);
1510         }
1511
1512         static Param *declare(const String *name, NameSpace *parent,
1513                               StrList *TYPE, CompiledParam::Flags flags,
1514                               Array *ARRAY);
1515
1516         virtual void lookup_misc()
1517         {
1518                 type = lookup_type(type_name, get_ns());
1519         }
1520         
1521         virtual void final_analysis()
1522         {
1523                 BasicType *bt = dynamic_cast<BasicType *>(type->get_concrete_sym());
1524
1525                 if (bt && !bt->def.flags.field.TypeDef) {
1526                         use_anon_type(bt->def);
1527                 } else {
1528                         use_named_type(bt);
1529
1530                         Struct *str = dynamic_cast<Struct *>(*type);
1531                         if (str && str->is_inline())
1532                                 set_inline();
1533                         
1534                         if (!str && is_inline()) {
1535                                 yyerrorfl(name->file, name->line,
1536                                           "\"%s\" is static but not a struct.",
1537                                           get_fq_name()->flatten()->c_str());
1538                         }
1539                 }
1540         
1541                 if (array) {
1542                         array->final_analysis();
1543                         def.basictype.array = array->ca;
1544                 } else {
1545                         def.basictype.array.bounds[0] = 0;
1546                         def.basictype.array.bounds[1] = 0;
1547                 }
1548         }
1549
1550         void set_inline()
1551         {
1552                 def.flags.field.Inline = 1;
1553         }
1554
1555         bool is_inline()
1556         {
1557                 return def.flags.field.Inline;
1558         }
1559         
1560         bool is_in()
1561         {
1562                 return def.flags.field.In;
1563         }
1564
1565         bool is_out()
1566         {
1567                 return def.flags.field.Out;
1568         }
1569
1570         virtual void output(const char *root);
1571         bool output_extra(FILE *f);
1572
1573         static Param *import(ImportContext &ctx);
1574         virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
1575         
1576         bool is_array()
1577         {
1578                 return ::is_array(def.basictype);
1579         }
1580 };
1581
1582 typedef Ref<Param> ParamRef;
1583
1584 class Method : public NameSpace, public Def {
1585         list<ParamRef> entries;
1586
1587         void add_elem(Param *p);
1588
1589 public:
1590         CompiledMethod def;
1591         
1592         Method(const String *name) :
1593         Symbol(name), 
1594         Def((const char *)&def, sizeof(def), CompiledDefHeader::Method)
1595         {
1596                 memset(&def, 0, sizeof(def));
1597         }
1598
1599         void set_async()
1600         {
1601                 def.flags.field.Async = 1;
1602         }
1603         
1604         bool is_async()
1605         {
1606                 return def.flags.field.Async;
1607         }
1608         
1609         static Method *declare(const String *name, NameSpace *parent);
1610
1611         void add(Symbol *sym, bool from_import);
1612
1613         virtual const char *description()
1614         {
1615                 return "method";
1616         }
1617
1618         virtual void output(const char *root);
1619         bool output_extra(FILE *f);
1620
1621         static Method *import(ImportContext &ctx);
1622         virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
1623
1624         typedef list<ParamRef>::const_iterator entries_iterator;
1625
1626         entries_iterator entries_begin()
1627         {
1628                 return entries.begin();
1629         }
1630
1631         entries_iterator entries_end()
1632         {
1633                 return entries.end();
1634         }
1635 };
1636
1637 typedef Ref<Method> MethodRef;
1638
1639 class Interface;
1640 typedef Ref<Interface> InterfaceRef;
1641
1642 extern InterfaceRef System_Object;
1643
1644 // FIXME: typedefed superinterfaces
1645 class Interface : public NameSpace, public Type, public Def {
1646         list<MethodRef> methods;
1647         list<InterfaceRef> supers;
1648         IDListRef supernames;
1649
1650         void add_elem(Method *m);
1651
1652         // This is like Symbol::traversed[], but used internally by the
1653         // for_each_super function to ensure that common ancestors are only
1654         // visited once.
1655         
1656         int traversed_all_supers;
1657         static int all_supers_traversal;
1658         
1659 public:
1660         typedef void (*callback)(Interface *i, void *arg);
1661         
1662 private:
1663         template<callback cb>
1664         void for_each_super_internal(void *arg)
1665         {
1666                 for (supers_iterator i = supers_begin(); i != supers_end(); ++i) {
1667                         Interface *iface = *i;
1668                         
1669                         if (iface->traversed_all_supers < all_supers_traversal) {
1670                                 iface->traversed_all_supers = all_supers_traversal;
1671                                 cb(iface, arg);
1672                                 iface->for_each_super_internal<cb>(arg);
1673                         }
1674                 }
1675         }
1676
1677         // All interfaces in the map and vector are supers of this
1678         // interface, and thus retained that way, so plain pointers
1679         // can be used here.
1680
1681         typedef map<Interface *, int> chain_map_type;
1682         typedef chain_map_type::value_type chain_valtype;
1683         typedef chain_map_type::const_iterator chain_iter;
1684
1685         chain_map_type super_to_chain_map;
1686
1687 private:
1688         int num_chains;
1689         vector<Interface *> chain_heads;
1690
1691 public: 
1692         int super_to_chain(Interface *iface, bool must_find_it = true)
1693         {
1694                 chain_iter ret = super_to_chain_map.find(iface);
1695                 
1696                 if (ret == super_to_chain_map.end()) {
1697                         assert(!must_find_it);
1698                         return -1;
1699                 }
1700
1701                 return (*ret).second;
1702         }
1703
1704         Interface *get_chain_head(int chain)
1705         {
1706                 return chain_heads[chain];
1707         }
1708
1709         int get_num_chains()
1710         {
1711                 return num_chains;
1712         }
1713         
1714 private:        
1715         void set_chain(Interface *iface, int chain)
1716         {
1717                 pair<chain_iter, bool> ret = 
1718                         super_to_chain_map.insert(chain_valtype(iface, chain));
1719                 assert(ret.second);
1720         }
1721         
1722         // This is the inner depth-first search, which terminates
1723         // at each level upon finding that the node it had previously
1724         // recursed into found an unchained node.
1725         
1726         void pick_chain(Interface *iface, int chain)
1727         {
1728                 assert(super_to_chain(iface, false) == -1);
1729                 chain_heads.push_back(iface);
1730         
1731                 do {
1732                         set_chain(iface, chain);
1733                         
1734                         if (iface->supers.empty())
1735                                 break;
1736                         
1737                         iface = iface->supers.front();
1738                 } while (super_to_chain(iface, false) == -1);
1739         }
1740
1741         // This is the outer breadth-first-search, making sure every
1742         // super is assigned to a chain.
1743
1744         void sort_chains()
1745         {
1746                 list<Interface *> bfs;
1747                 num_chains = 0;
1748
1749                 bfs.push_back(this);
1750                 
1751                 while (!bfs.empty()) {
1752                         Interface *iface = bfs.front();
1753                         bfs.pop_front();
1754                 
1755                         for (supers_iterator i = iface->supers_begin();
1756                              i != iface->supers_end(); ++i)
1757                                 bfs.push_back(*i);
1758                 
1759                         if (super_to_chain(iface, false) == -1)
1760                                 pick_chain(iface, num_chains++);
1761                 }
1762         }
1763
1764 public:
1765         // Do not call after lookup_misc
1766         void add_super(Interface *i)
1767         {
1768                 assert(current_pass != 1);
1769         
1770                 supers.push_back(i);
1771                 def.num_supers++;
1772         }
1773
1774         CompiledInterface def;
1775         
1776         Interface(const String *name) :
1777         Symbol(name),
1778         Def((const char *)&def, sizeof(def), CompiledDefHeader::Interface)
1779         {
1780                 memset(&def, 0, sizeof(def));
1781                 traversed_all_supers = 0;
1782         }
1783         
1784         void init(IDList *SUPERNAMES)
1785         {
1786                 supernames = SUPERNAMES;
1787         }
1788
1789         static Interface *declare(const String *name, NameSpace *parent, 
1790                                   IDList *SUPERNAMES)
1791         {
1792                 assert(parent);
1793
1794                 Interface *i = new Interface(name);
1795                 i->init(SUPERNAMES);
1796                 
1797                 parent->add_user(i);
1798                 return i;
1799         }
1800         
1801         // Only Methods, Types, and const BasicType Datums can be added.
1802
1803         void add(Symbol *sym, bool from_import);
1804
1805         virtual const char *description()
1806         {
1807                 return "interface";
1808         }
1809
1810 private:
1811         void add_object_super()
1812         {
1813                 assert(System_Object);
1814                 if (this != System_Object && supers.empty())
1815                         add_super(System_Object);
1816         }
1817
1818 public: 
1819         virtual void lookup_misc()
1820         {
1821                 if (def.guid[0] == 0 && def.guid[1] == 0)
1822                         yyerrorfl(name->file, name->line,
1823                                   "Interface \"%s\" is missing a GUID.",
1824                                   get_fq_name()->flatten()->c_str());
1825         
1826                 if (supernames) {
1827                         for (IDList::iterator i = supernames->begin(); 
1828                              i != supernames->end(); ++i)
1829                         {
1830                                 Symbol *sym = lookup_sym(toplevel, *i, get_ns());
1831                                 Interface *iface = 
1832                                         dynamic_cast<Interface *>(sym->get_concrete_sym());
1833                                 
1834                                 if (!iface) {
1835                                         const String *str = (*i)->back();
1836                                         yyerrorfl(str->file, str->line,
1837                                                   "\"%s\" is not an interface.\n",
1838                                                   sym->get_fq_name()->flatten()->c_str());
1839         
1840                                         throw UserError();
1841                                 }
1842                                 
1843                                 add_super(iface);
1844                         }
1845                 }
1846                 
1847                 add_object_super();
1848                 NameSpace::lookup_misc();
1849         }
1850         
1851         virtual void final_analysis()
1852         {
1853                 // FIXME: check for infinite loops in inheritance
1854         
1855                 sort_chains();
1856                 NameSpace::final_analysis();
1857         }
1858         
1859         virtual void output(const char *root);
1860         bool output_extra(FILE *f);
1861
1862         static Interface *import(ImportContext &ctx);
1863         virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
1864
1865         typedef list<MethodRef>::const_iterator methods_iterator;
1866         typedef list<InterfaceRef>::const_iterator supers_iterator;
1867
1868         supers_iterator supers_begin()
1869         {
1870                 assert(current_pass != 1);
1871                 return supers.begin();
1872         }
1873
1874         supers_iterator supers_end()
1875         {
1876                 return supers.end();
1877         }
1878         
1879         bool supers_empty()
1880         {
1881                 assert(current_pass != 1);
1882                 return supers.empty();
1883         }
1884
1885         methods_iterator methods_begin()
1886         {
1887                 return methods.begin();
1888         }
1889
1890         methods_iterator methods_end()
1891         {
1892                 return methods.end();
1893         }
1894         
1895         template<callback cb>
1896         void for_each_super(void *arg)
1897         {
1898                 assert(current_pass >= 4);
1899         
1900                 all_supers_traversal++;
1901                 for_each_super_internal<cb>(arg);
1902         }
1903
1904         void finalize_class_iface()
1905         {
1906                 add_object_super();
1907                 sort_chains();
1908         }
1909         
1910         void set_guid(uint64_t guid[2])
1911         {
1912                 if (def.guid[0] || def.guid[1])
1913                         yyerrorf("\"%s\" already has a GUID.",
1914                                  get_fq_name()->flatten()->c_str());
1915         
1916                 def.guid[0] = guid[0];
1917                 def.guid[1] = guid[1];
1918         }
1919 };
1920
1921 class IFaceList : public list<InterfaceRef>,
1922                   public RefCountable<IFaceList> {};
1923
1924 class Enum : public NameSpace, public Type, public Def {
1925         list<DatumRef> entries;
1926
1927         void add_elem(Datum *d);
1928
1929 public:
1930         unsigned int next_val;
1931         CompiledEnum def;
1932
1933         Enum(const String *name) :
1934         Symbol(name),
1935         Def((const char *)&def, sizeof(def), CompiledDefHeader::Enum),
1936         next_val(0)
1937         {
1938                 memset(&def, 0, sizeof(def));
1939         }
1940
1941         void init(int bits)
1942         {
1943                 if (bits < 0 || bits > 64) {
1944                         yyerrorf("\"%s\" has invalid enum size %d", 
1945                                  name->c_str(), bits);
1946
1947                         bits = bits < 0 ? 0 : 64;
1948                 }
1949         
1950                 def.bits = bits;
1951         }
1952
1953         static Enum *declare(const String *name, NameSpace *parent,
1954                              int bits)
1955         {
1956                 assert(parent);
1957                 
1958                 Enum *e = new Enum(name);
1959                 e->init(bits);
1960                 
1961                 parent->add_user(e);
1962                 return e;
1963         }
1964
1965         // Only const unsigned integer BasicType Datums are allowed.
1966
1967         void add(Symbol *sym, bool from_import);
1968
1969         virtual const char *description()
1970         {
1971                 return "enumeration";
1972         }
1973
1974         int get_default_bf_size()
1975         {
1976                 return def.bits;
1977         }
1978
1979         virtual void output(const char *root);
1980         bool output_extra(FILE *f);
1981
1982         static Enum *import(ImportContext &ctx);
1983         virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
1984
1985         typedef list<DatumRef>::const_iterator entries_iterator;
1986
1987         entries_iterator entries_begin()
1988         {
1989                 return entries.begin();
1990         }
1991
1992         entries_iterator entries_end()
1993         {
1994                 return entries.end();
1995         }
1996 };
1997
1998 class Alias : public Symbol, public Def {
1999         bool lookup_begun;
2000         
2001         struct Cycle {
2002                 Alias *end;
2003                 
2004                 Cycle(Alias *END) : end(END)
2005                 {
2006                 }
2007         };
2008
2009 public:
2010         CompiledAlias def;
2011         
2012         SymbolRef real_sym;
2013         StringRef sym_fq_name;
2014         StrListRef sym_name;
2015         
2016         Alias(const String *name) :
2017         Symbol(name),
2018         Def((const char *)&def, sizeof(def), CompiledDefHeader::Alias)
2019         {
2020                 memset(&def, 0, sizeof(def));
2021                 lookup_begun = false;
2022         }
2023         
2024         void init(StrList *symname, bool is_private)
2025         {
2026                 sym_name = symname;
2027                 priv = is_private;
2028         }
2029
2030         static Alias *declare(const String *name, NameSpace *parent,
2031                               StrList *symname, bool is_private = false)
2032         {
2033                 assert(parent);
2034                 Alias *a = new Alias(name);
2035                 a->init(symname, is_private);
2036
2037                 parent->add_user(a);
2038                 return a;
2039         }
2040         
2041         void resolve_chain()
2042         {       
2043                 if (!real_sym) {
2044                         if (lookup_begun) {
2045                                 yyerrorfl(name->file, name->line,
2046                                           "Alias loop defining \"%s\"",
2047                                           get_fq_name()->flatten()->c_str());
2048                         
2049                                 throw Cycle(this);
2050                         }
2051                         
2052                         lookup_begun = true;
2053                         
2054                         try {
2055                                 real_sym = lookup_sym(toplevel, sym_name, get_ns(), this);
2056                         }
2057                         
2058                         catch (Cycle &c) {
2059                                 yyerrorfl(name->file, name->line, "   ...referenced by \"%s\"",
2060                                           get_fq_name()->flatten()->c_str());
2061
2062                                 if (c.end == this)
2063                                         throw UserError();
2064
2065                                 throw c;
2066                         }
2067                 }
2068         }
2069
2070         virtual Symbol *get_concrete_sym(bool follow_typedefs = true)
2071         {
2072                 resolve_chain();
2073                 return real_sym->get_concrete_sym(follow_typedefs);
2074         }
2075
2076         virtual void lookup_chain()
2077         {
2078                 get_concrete_sym(true);
2079         }
2080
2081         virtual void lookup_misc()
2082         {
2083                 real_sym = real_sym->get_concrete_sym(false);
2084                 sym_fq_name = real_sym->get_fq_name()->flatten();
2085                 
2086                 def.length = sym_fq_name->length();
2087         }
2088
2089         virtual void output(const char *root);
2090         bool output_extra(FILE *f);
2091
2092         static Alias *import(ImportContext &ctx);
2093         virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
2094 };
2095
2096 class TypeDef : public Alias {
2097 public:
2098         TypeDef(const String *name) : Alias(name)
2099         {
2100                 memset(&def, 0, sizeof(def));
2101                 hdr.type = CompiledDefHeader::TypeDef;
2102         }
2103         
2104         static TypeDef *declare(const String *name, NameSpace *parent,
2105                                 StrList *symname)
2106         {
2107                 assert(parent);
2108                 TypeDef *td = new TypeDef(name);
2109                 td->init(symname, false);
2110                 
2111                 parent->add_user(td);
2112                 return td;
2113         }
2114
2115         virtual Symbol *get_concrete_sym(bool follow_typedefs = true)
2116         {
2117                 if (follow_typedefs) {
2118                         resolve_chain();
2119                         return real_sym->get_concrete_sym(follow_typedefs);
2120                 }
2121                 
2122                 return this;
2123         }
2124
2125         static TypeDef *import(ImportContext &ctx);
2126         virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
2127 };
2128
2129 NameSpace *add_nspace(StrList *name, bool push);
2130 void pop_nspace();
2131
2132 // Declare an instance of "type" in "ns" for each element of "ids".
2133 // This function will report any errors, but not throw UserError.
2134
2135 void declare_data(NameSpace *ns, StrList *ids, StrList *type,
2136                   Array *array, StrList *attr);
2137 void declare_aliases(NameSpace *ns, StrList *ids, StrList *type,
2138                      bool is_typedef);
2139 void declare_basictypes(NameSpace *ns, StrList *ids,
2140                         BasicType *type, bool is_typedef);
2141
2142 // You'd think they'd have standard functions to do this these days.
2143 // All I could find that come close are the network-byte-order
2144 // functions, and they're no-ops on big-endian machines.
2145
2146 static inline uint32_t swap32(uint32_t in, bool swap)
2147 {
2148         if (swap)
2149                 return ((in & 0x000000ff) << 24) |
2150                        ((in & 0x0000ff00) <<  8) |
2151                        ((in & 0x00ff0000) >>  8) |
2152                        ((in & 0xff000000) >> 24);
2153         
2154         return in;
2155 }
2156
2157 static inline uint64_t swap64(uint64_t in, bool swap)
2158 {
2159         if (swap)
2160                 return (((uint64_t)swap32((uint32_t)in, true)) << 32) |
2161                        swap32((uint32_t)(in >> 32), true);
2162
2163         return in;
2164 }
2165
2166 struct File {
2167         FILE *f;
2168         
2169         File()
2170         {
2171                 f = NULL;
2172         }
2173         
2174         File(FILE *F)
2175         {
2176                 f = F;
2177         }
2178         
2179         File *operator =(FILE *F)
2180         {
2181                 f = F;
2182                 return this;
2183         }
2184         
2185         ~File()
2186         {
2187                 if (f)
2188                         fclose(f);
2189         }
2190         
2191         operator FILE *()
2192         {
2193                 return f;
2194         }
2195 };
2196
2197 // Verify that a prospective new import (or output namespace)
2198 // does not overlap an existing import.  Returns the conflicting
2199 // import, or NULL if none found.
2200
2201 NameSpace *check_for_imports(NameSpace *ns);
2202
2203 #endif