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