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