1 // idlc.h -- Definitions used throughout idlc.
2 // A lot of this should probably be factored out into more specific headers.
4 // This software is copyright (c) 2006 Scott Wood <scott@buserror.net>.
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.
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.
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...
35 #include "compileddef.h"
46 #define cdl_lex idl_lex
47 void idl_error(const char *s);
49 #define cdl_error idl_error
51 void setup_idlparse();
52 void setup_cdlparse();
55 void yyerrorf(const char *s, ...) __attribute__((format(printf, 1, 2)));
56 void yyerrorfl(const char *file, int line, const char *s, ...)
57 __attribute__((format(printf, 3, 4)));
59 void yyerrorf(const char *s, ...);
60 void yyerrorfl(const char *file, int line, const char *s, ...);
67 extern int idl_debug, cdl_debug, curline, impl, num_err;
68 extern int current_pass;
70 extern unsigned int enum_pos;
71 extern const char *cur_input_file;
72 extern int compiling_idl, compiling_cdl;
77 // Location in the IDLC source of the BUG()
81 InternalError(const char *file, int line) :
82 file(file), line(line)
88 throw InternalError(__FILE__, __LINE__); \
93 #define assert(x) do { \
101 virtual ~Releasable()
105 Releasable(int COUNT) : count(COUNT)
112 fprintf(stderr, "Reference count is %d in release\n", count);
121 class AutoReleasePool {
122 list<const Releasable *> pool;
125 void add(const Releasable *obj)
132 for (list<const Releasable *>::iterator i = pool.begin();
133 i != pool.end(); ++i)
135 const Releasable *obj = *i;
143 extern AutoReleasePool autorelease_pool;
145 template <typename T>
146 class RefCountable : public Releasable {
148 // RefCountable objects should never be assigned to,
149 // as there could be references to the object remaining.
150 // The private assignment operator prevents this, unless
151 // a subclass defines its own assigment operator (don't
153 void operator =(const RefCountable &rc)
158 RefCountable(const RefCountable &rc) : Releasable(1)
164 RefCountable() : Releasable(1)
166 // Normally, this wouldn't be automatic, but this is what most
167 // things in IDLC are going to want, and it elimanates problems
168 // with needing to cast the return type of autorelease().
170 // The automatic autorelease() means that all refcountable objects
171 // must be allocated with "new", not on the stack, as global
172 // data, or as a class member.
177 virtual ~RefCountable()
181 const T *retain() const
184 fprintf(stderr, "Reference count is %d in retain\n", count);
189 return static_cast<const T *>(this);
195 fprintf(stderr, "Reference count is %d in retain\n", count);
200 return static_cast<T *>(this);
203 const T *autorelease() const
205 autorelease_pool.add(static_cast<Releasable *>(this));
206 return static_cast<T *>(this);
211 autorelease_pool.add(static_cast<Releasable *>(this));
212 return static_cast<T *>(this);
215 // This is only here because C++ obnoxiously requires it to
216 // be just because it's "called" from code excluded with an
217 // if (0) in a template. No code is ever generated that calls
218 // it, but it still must exist.
220 bool operator < (const RefCountable &rc)
226 // T must be RefCountable
227 template<typename T, bool compare_ptrs = true>
229 // STL containers like to use const on the items they
230 // contain; the mutable allows such containers to hold
231 // pointers to non-const data. For truly const Refs,
232 // make T const, as in StringRef. Unfortunately,
233 // it cannot be done in a more fine-grained manner,
245 Ref(T *data) : data(data)
251 Ref(Ref &le) : data(le.data)
257 Ref &operator =(const Ref &le)
259 // The retain must come first, in case both Refs are the same
270 Ref &operator =(T *new_data)
272 // The retain must come first, in case both Refs are the same
299 T *operator *() const
304 T *operator ->() const
309 bool operator == (const Ref &le) const
312 return data == le.data;
314 return *data == *le.data;
317 bool operator != (const Ref &le) const
320 return data != le.data;
322 return *data != *le.data;
325 bool operator < (const Ref &le) const
328 return reinterpret_cast<intptr_t>(data) <
329 reinterpret_cast<intptr_t>(le.data);
331 return *data < *le.data;
335 class String : public string, public RefCountable<String> {
337 // Origin of the string, if from the IDL file.
338 // Otherwise, fill both values with zero.
344 String(const char *s = "") : string(s)
351 String(const String &s) : string(s)
358 String(const char *s, const char *file, int line, int token) :
359 string(s), file(file), line(line), token(token)
363 extern String **yylval_string;
364 typedef Ref<const String, false> StringRef;
366 /* If a StrList is used for a namespace-qualified identifier, and
367 said identifier begins with ".." (i.e. starts from the root
368 namespace), the leading ".." is represented by a zero-length
371 Note that list doesn't have a virtual destructor, so all deletions
372 should happen through either RefCountable or the wrapper List
375 class StrList : public list<StringRef>, public RefCountable<StrList> {
381 // Parse a flat String into a StrList, using the specified delimeter.
382 StrList(const String *input, char delimiter = '.');
384 // Turn a StrList into a flat String, using the specified delimiter.
385 String *flatten(const char *delimiter = ".");
388 typedef Ref<StrList> StrListRef;
390 // ConList is like StrList, but with constant initializers
400 // FIXME: handle platforms with weird floating point endianness
406 // TOK_ICON, TOK_UCON, TOK_FCON, TOK_BOOL, TOK_DCON,
407 // TOK_INVALID, or TOK_NONE
408 // Constants are stored as signed (ICON) unless too
409 // large to fit in a signed 64-bit integer. Additional size and
410 // signedness checks are mode when down casting to a smaller size
411 // to fit into a particular datum; such constants will have a
414 // TOK_NONE is valid for maybeconst and size. TOK_INVALID
415 // indicates a previously detected error; don't emit any further
416 // errors due to this constant.
418 // TOK_DCON is used for symbolic constants, whose value may
424 extern Con *yylval_con;
430 ConInit(const String *str, Con &con) : str(str), con(con)
434 ConInit(const ConInit &coninit)
440 class ConList : public list<ConInit>, public RefCountable<ConList> {};
441 typedef Ref<ConList> ConListRef;
443 // Like StrList, but is a list of possibly namespace-qualified identifiers.
444 class IDList : public list<StrListRef>, public RefCountable<IDList> {};
445 typedef Ref<IDList> IDListRef;
451 typedef Ref<NameSpace> NameSpaceRef;
453 // This is incremented when a chain of symbols is traversed to reset
454 // detection of already-visited symbols. It is assumed that this
455 // will not have to happen billions of times.
457 extern int traversal;
459 class Symbol : public RefCountable<Symbol> {
473 // Symbol was loaded externally
476 // If set, the symbol is private, and will not be available
477 // for lookups except those made directly in the context of
478 // the containing namespace. Private symbols do not get
479 // outputted. They are used to implement imports of specific
480 // symbols (as aliases), rather than entire namespaces.
484 // Reserved for language binding use.
485 Releasable *lang_priv;
492 Symbol(const String *_name) : name(_name)
499 NameSpace *get_ns() const
504 const String *get_name() const
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.
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
523 StrList *get_fq_name(const char *append = NULL,
524 bool not_last = false) const;
526 virtual void lookup_imports()
530 virtual void lookup_chain()
534 virtual void lookup_misc()
538 virtual void final_analysis()
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).
545 virtual void output(const char *root)
549 virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL)
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.
558 Symbol *find_toplevel_type();
560 // Get the true type of the symbol, regardless of whether it is an
563 virtual Symbol *get_concrete_sym(bool follow_typedefs = true)
568 friend class NameSpace;
571 typedef Ref<Symbol> SymbolRef;
573 class SymList : public list<SymbolRef>, public RefCountable<SymList> {};
574 typedef Ref<SymList> SymListRef;
576 struct SymbolNotFound {
579 struct DuplicateSymbol {
582 struct InvalidArgument {
588 class NameSpace : public virtual Symbol {
590 // Filesystem path to the external symbol storage, or NULL
591 // if not an import namespace.
593 // Import namespaces are read-only namespaces which are created
594 // for the importation of externally-declared symbols. One is
595 // initially created for each "mount point" specified by the user;
596 // whenever such a namespace is searched, it checks the external
597 // storage, and if the lookup succeeds, the symbol is loaded and
598 // added to the namespace. Failed lookups could be cached with a
599 // special BadSymbol or some such, as the imported namespace is
600 // assumed to be constant, but I don't think such an optimization
601 // is worthwhile, at least at this point.
605 // Load a symbol from external storage, constructing the relevant type
606 // of object, and adding it to this namespace. Only called for
607 // import namespaces.
609 Symbol *load(const String *symname);
611 typedef map<StringRef, SymbolRef> tbl_type;
614 list<StrListRef> import_strs;
615 list<NameSpaceRef> imports;
618 // This is a counter for generating unique names for anonymous
619 // members of the namespace.
622 NameSpace() : anon(0)
626 virtual ~NameSpace();
628 // Return a description of the type of namespace, for
630 virtual const char *description()
635 virtual void output(const char *root);
637 typedef tbl_type::const_iterator const_iterator;
638 typedef tbl_type::value_type value_type;
640 // Derived classes can throw InvalidArgument if you give them
641 // a type of Symbol that they don't accept; see their comments
642 // for more details. Unfortunately, this cannot be done
643 // with static type-checking, as there are places that know
644 // they've been given a namespace that can accept a particular
645 // type of symbol, but they don't know exactly what kind of
646 // namespace it is. C++'s type system is not sufficient to
647 // express this (at least not while retaining any semblance
650 // DuplicateSymbol is thrown if sym already exists in this namespace.
651 virtual void add(Symbol *sym, bool from_import)
653 if (path && !from_import)
654 throw InvalidArgument();
657 sym->external = true;
662 pair<const_iterator, bool> ret = tbl.insert(value_type(sym->name, sym));
667 throw DuplicateSymbol();
671 // Add the symbol to this namespace, handling duplicate symbols by
672 // printing an error and throwing a UserError(). This should not be
673 // done in the symbol's constructor, as the parent may not accept
674 // the symbol until it is fully constructed (the RTTI information
675 // changes, and in general partially constructed objects shouldn't
676 // be exposed to the rest of the system).
678 void add_user(Symbol *sym);
680 // Like add_user, but used by the import code. Duplicate
681 // symbols result in internal errors, and the add is done with
682 // from_import set to true. InvalidArgument results in an error
683 // message and a reraise as UserError.
685 // All conditions checked by the parent namespace's add() method
686 // (such as constness of data) must be satisfied prior to calling
687 // add_import(). On the other hand, add_import() must be called
688 // before any recursive importation is done which could
689 // conceivably try to import the current symbol (thus causing
690 // infinite recursion).
692 void add_import(Symbol *sym, const char *filename);
694 // SymbolNotFound is thrown if sym is not in this namespace.
695 virtual void del(Symbol *sym)
698 throw SymbolNotFound();
701 int ret = tbl.erase(sym->name);
706 Symbol *lookup_noex_noimport(const String *symname)
708 const_iterator ret = tbl.find(symname);
710 if (ret != tbl.end())
711 return (*ret).second;
717 Symbol *lookup_noex(const String *symname, bool priv_ok = false)
719 Symbol *ret = NameSpace::lookup_noex_noimport(symname);
724 if (ret && !priv_ok && ret->priv)
730 Symbol *lookup(const String *symname, bool priv_ok = false)
732 Symbol *ret = lookup_noex(symname, priv_ok);
735 throw SymbolNotFound();
740 // Like lookup_noex, but also checks imported namespaces,
741 // and returns the namespace containing the match rather
742 // than the match itself.
744 NameSpace *search(const String *name, Symbol *exclude);
746 void add_search(StrList *ns)
748 import_strs.push_back(ns);
751 // Return a string containing case information manglement.
752 // See input.cc for more information.
754 static const String *mangle(const String *name);
756 const String *get_path()
761 // Import all members of this namespace. A no-op if not an import
765 // As import_all, but also recursively applies to any sub-namespaces.
766 void import_all_recursive();
768 const_iterator begin()
778 virtual void lookup_imports();
780 virtual void lookup_chain()
782 for (const_iterator i = begin(); i != end(); ++i) {
783 Symbol *sym = (*i).second;
788 virtual void lookup_misc()
790 for (const_iterator i = begin(); i != end(); ++i) {
791 Symbol *sym = (*i).second;
796 virtual void final_analysis()
798 for (const_iterator i = begin(); i != end(); ++i) {
799 Symbol *sym = (*i).second;
800 sym->final_analysis();
806 extern NameSpaceRef cur_nspace;
807 extern list<NameSpaceRef> nspace_stack;
809 typedef std::vector<StringRef> StringVec;
811 string *stringvec_to_path(StringVec &stringvec, const char *prepend);
813 // lookup_sym and lookup_type throw UserError on user error
814 // The context namespace is required for the proper
815 // set of namespaces to be searched.
817 Symbol *lookup_sym(NameSpace *topns, StrList *name, NameSpace *ctx,
818 Symbol *exclude = NULL);
821 const char *self; // Pointer to the type-specific struct
822 int self_len; // Length of the type-specific struct
825 CompiledDefHeader hdr;
827 // sym is the symbol from which to get the path/name, and
828 // is_dir is true if it should be "name/.self" rather than
830 void output_self(const char *dir, Symbol *sym, bool is_dir);
833 Def(const char *self, int self_len, CompiledDefHeader::Type type) :
834 self(self), self_len(self_len)
836 hdr.magic = CompiledDefHeader::magic_normal;
844 // Specific types may override this to output extra data
845 // to the .self file without having to reopen the file.
847 // Returns false on error.
849 virtual bool output_extra(FILE *f)
855 // Internal context struct used by input.cc to avoid passing
856 // lots of parameters around
857 struct ImportContext;
859 // This represents an actual IDL namespace {}, rather than
860 // a derived namespace such as a Struct or Interface.
862 class UserNameSpace : public NameSpace, public Def {
864 CompiledNameSpace def;
865 StringRef mountpoint_name;
867 UserNameSpace(const String *name = NULL) :
869 Def((const char *)&def, sizeof(def), CompiledDefHeader::NameSpace)
871 mountpoint_name = get_fq_name()->flatten();
872 def.length = mountpoint_name->length();
875 virtual void output(const char *root);
876 bool output_extra(FILE *f);
878 static void declare_import(const char *path);
880 static UserNameSpace *import(ImportContext &ctx);
881 virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
884 typedef Ref<UserNameSpace> UserNameSpaceRef;
885 extern UserNameSpaceRef toplevel, cdl_toplevel;
886 extern UserNameSpace *output_ns;
888 class Type : public virtual Symbol {
898 virtual int get_default_bf_size()
900 // Only allow types in bitfields that explicitly
907 typedef Ref<Type> TypeRef;
909 // ctx can be NULL if basic_types_only is true
910 Type *lookup_type(StrList *sl, NameSpace *ctx, bool basic_types_only = false);
912 class BasicType : public Type, public Def {
914 CompiledBasicType def;
917 BasicType(const String *name) :
919 Def((const char *)&def, sizeof(def), CompiledDefHeader::BasicType)
922 memset(&def, 0, sizeof(def));
925 void init(CompiledBasicType &DEF)
933 static BasicType *declare(const String *name, NameSpace *parent,
934 CompiledBasicType &DEF)
936 BasicType *bt = new BasicType(name);
940 parent->add_user(bt);
945 virtual void output(const char *root);
947 static BasicType *import(ImportContext &ctx);
948 virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
951 static inline bool is_array(CompiledBasicType &bt)
953 return bt.array.bounds[0] || bt.array.bounds[1];
956 static inline bool is_array(CompiledBasicType *bt)
958 return is_array(*bt);
961 typedef Ref<Datum> DatumRef;
963 class Array : public RefCountable<Array>
965 NameSpace *lookup_ctx;
968 // lower is [0], upper is [1]
971 // Strings for error reporting on each constant. If the constant
972 // is symbolic, then this is the fully qualified symbol name.
973 // Otherwise, it is the numerical value converted to a string. In
974 // each case, the file/line shall correspond to where the array
975 // bound was specified.
982 // ca is not valid until after final_analysis() is called.
985 Array(NameSpace *LOOKUP_CTX);
986 void set_bound(Con &con, int bound);
987 void final_analysis();
989 void set_unbounded();
992 typedef Ref<Array> ArrayRef;
994 class Datum : public Symbol, public Def {
995 StrListRef type_name;
997 StringRef type_fq_name;
999 StrListRef const_val_name;
1000 SymbolRef const_val_sym;
1003 bool basic; // Datum is of a BasicType
1005 bool const_init; // Datum's constant has been initialized; this is
1006 // true after a successful verify_const().
1007 CompiledBasicType *cbt;
1009 int chain_traversed;
1011 // Recursively retrieve the actual value of a const datum
1012 // initialized with another named const datum. Returns
1013 // the "end" of an infinite loop, if one is found. Once
1014 // the full infinite loop has been printed, UserError is
1017 Datum *resolve_constant_chain();
1019 void init_const_early(Con *con);
1021 void use_anon_type(const CompiledBasicType &CBT)
1023 def.basictype = CBT;
1024 cbt = &def.basictype;
1027 def.type.length = 0;
1030 void process_type();
1032 void set_array(Array *ARRAY)
1043 int con_type; // Used to store the TOK_[IUF]CON of the Con struct
1044 // for type checking once the type is known.
1046 Datum(const String *name) :
1048 Def((const char *)&def, sizeof(def), CompiledDefHeader::Datum)
1052 chain_traversed = 0;
1053 memset(&def, 0, sizeof(def));
1056 void init(StrList *type, Array *ARRAY, Con *con = NULL);
1057 void init(CompiledBasicType &cbt, Array *ARRAY, Con *con = NULL);
1059 static Datum *declare(const String *name, NameSpace *parent,
1060 StrList *type, Array *ARRAY,
1065 Datum *d = new Datum(name);
1066 d->init(type, ARRAY, con);
1068 parent->add_user(d);
1072 static Datum *declare(const String *name, NameSpace *parent,
1073 CompiledBasicType &type,
1074 Array *ARRAY, Con *con = NULL)
1078 Datum *d = new Datum(name);
1079 d->init(type, ARRAY, con);
1081 parent->add_user(d);
1087 def.flags.field.Inline = 1;
1092 return def.flags.field.Inline;
1095 void set_immutable()
1097 def.flags.field.Immutable = 1;
1102 return def.flags.field.Immutable;
1105 // Returns true if the constant was acceptable, false otherwise (an
1106 // error is also output to the user in this case).
1108 bool verify_const();
1110 virtual void lookup_chain()
1115 const_val_sym = lookup_sym(toplevel, const_val_name, get_ns());
1119 type_sym = lookup_type(type_name, get_ns(), true);
1121 type_sym = lookup_sym(toplevel, type_name, get_ns());
1127 virtual void lookup_misc()
1129 if (def.flags.field.Const) {
1131 assert(def.flags.field.Const);
1134 Datum *d = resolve_constant_chain();
1144 virtual void final_analysis();
1146 virtual void output(const char *root);
1147 bool output_extra(FILE *f);
1149 static Datum *import(ImportContext &ctx);
1150 virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
1152 uint64_t get_ucon(const String *err_str)
1154 if (!def.flags.field.Const) {
1155 yyerrorfl(err_str->file, err_str->line,
1156 "\"%s\" is not a const Datum.\n",
1157 get_fq_name()->flatten()->c_str());
1167 return ::is_array(def.basictype);
1171 template<typename T>
1172 bool output_list(T *sym, FILE *f);
1174 class BitField : public NameSpace, public Type, public Def {
1175 list<DatumRef> entries;
1177 void add_elem(Datum *d);
1180 CompiledBitField def;
1183 BitField(const String *name) :
1185 Def((const char *)&def, sizeof(def), CompiledDefHeader::BitField)
1187 memset(&def, 0, sizeof(def));
1190 void init(int bits, NameSpace *parent)
1192 if (bits < 0 || bits > 64) {
1193 yyerrorf("\"%s\" has invalid bitfield size %d",
1194 name->c_str(), bits);
1196 bits = bits < 0 ? 0 : 64;
1202 static BitField *declare(const String *name, NameSpace *parent,
1207 BitField *bf = new BitField(name);
1208 bf->init(bits, parent);
1210 parent->add_user(bf);
1214 // Only integral Datums, Enums, and BitFields can be added.
1216 void add(Symbol *sym, bool from_import);
1218 virtual const char *description()
1223 virtual void lookup_misc()
1225 NameSpace::lookup_misc();
1228 virtual void final_analysis()
1230 // FIXME: check total size of elements
1232 NameSpace::final_analysis();
1235 int get_default_bf_size()
1240 virtual void output(const char *root);
1241 bool output_extra(FILE *f);
1243 static BitField *import(ImportContext &ctx);
1244 virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
1246 typedef list<DatumRef>::const_iterator entries_iterator;
1247 typedef list<DatumRef>::const_reverse_iterator entries_reverse_iterator;
1249 entries_iterator entries_begin()
1251 return entries.begin();
1254 entries_iterator entries_end()
1256 return entries.end();
1259 entries_reverse_iterator entries_rbegin()
1261 return entries.rbegin();
1264 entries_reverse_iterator entries_rend()
1266 return entries.rend();
1271 typedef Ref<Struct> StructRef;
1272 extern StructRef System_VStruct;
1274 // FIXME: typedefed superstructs
1275 class Struct : public NameSpace, public Type, public Def {
1276 list<DatumRef> entries;
1279 StrListRef supername;
1280 bool attrs_resolved;
1282 // 0 = unknown, 1 = yes, 2 = no
1285 void add_elem(Datum *d);
1287 void resolve_attrs()
1292 if (super && !super->attrs_resolved)
1293 super->resolve_attrs();
1295 if (super && super->def.flags.field.Virtual)
1296 def.flags.field.Virtual = 1;
1298 attrs_resolved = true;
1304 // This is not maintained by the generic code, but can be
1305 // used by language bindings to cache the result of the
1310 Struct(const String *name) :
1312 Def((const char *)&def, sizeof(def), CompiledDefHeader::Struct)
1314 memset(&def, 0, sizeof(def));
1318 void init(StrList *SUPERNAME)
1320 supername = SUPERNAME;
1323 static Struct *declare(const String *name, NameSpace *parent,
1328 Struct *st = new Struct(name);
1329 st->init(SUPERNAME);
1331 parent->add_user(st);
1337 def.flags.field.Virtual = 1;
1342 def.flags.field.Inline = 1;
1347 return def.flags.field.Virtual;
1352 return def.flags.field.Inline;
1355 // Only Datums and Types can be added.
1357 void add(Symbol *sym, bool from_import);
1359 virtual const char *description()
1366 assert(current_pass >= 4);
1370 virtual void lookup_chain()
1373 supersym = lookup_sym(toplevel, supername, get_ns());
1377 NameSpace::lookup_chain();
1383 if (supersym && !super) {
1384 super = dynamic_cast<Struct *>(supersym->get_concrete_sym());
1387 const String *str = supername->back();
1388 yyerrorfl(str->file, str->line,
1389 "\"%s\" is not a struct.",
1390 supersym->get_fq_name()->flatten()->c_str());
1393 def.flags.field.Super = 1;
1394 super->lookup_super();
1396 if (super->is_virtual())
1400 if (is_virtual() && !supersym && !super) {
1401 assert(System_VStruct);
1402 if (this != System_VStruct) {
1403 def.flags.field.Super = 1;
1404 super = System_VStruct;
1410 virtual void lookup_misc()
1414 if (is_virtual() && def.guid[0] == 0 && def.guid[1] == 0)
1415 yyerrorfl(name->file, name->line,
1416 "Virtual struct \"%s\" is missing a GUID.",
1417 get_fq_name()->flatten()->c_str());
1419 NameSpace::lookup_misc();
1422 virtual void final_analysis()
1424 // FIXME: check for infinite loops in struct inheritance
1427 NameSpace::final_analysis();
1430 virtual void output(const char *root);
1431 bool output_extra(FILE *f);
1433 static Struct *import(ImportContext &ctx);
1434 virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
1436 typedef list<DatumRef>::const_iterator entries_iterator;
1438 entries_iterator entries_begin()
1440 return entries.begin();
1443 entries_iterator entries_end()
1445 return entries.end();
1448 void set_guid(uint64_t guid[2])
1450 if (def.guid[0] || def.guid[1])
1451 yyerrorf("\"%s\" already has a GUID.",
1452 get_fq_name()->flatten()->c_str());
1454 def.guid[0] = guid[0];
1455 def.guid[1] = guid[1];
1458 // A struct is "plain data" if it contains no object references,
1459 // no non-inline arrays or structs, and no inline non-plain structs.
1460 bool is_plain_data();
1463 class Param : public Symbol, public Def {
1464 StrListRef type_name;
1465 StringRef type_fq_name;
1467 bool basic; // Datum is of a BasicType
1472 void use_named_type(BasicType *bt)
1474 assert(!bt || bt->def.flags.field.TypeDef);
1478 type_fq_name = type->get_fq_name()->flatten();
1479 def.type.length = type_fq_name->length();
1482 void use_anon_type(const CompiledBasicType &cbt)
1484 def.basictype = cbt;
1489 void set_array(Array *ARRAY)
1499 Param(const String *name) :
1501 Def((const char *)&def, sizeof(def), CompiledDefHeader::Param)
1503 memset(&def, 0, sizeof(def));
1506 void init(StrList *TYPE, CompiledParam::Flags flags, Array *ARRAY)
1513 static Param *declare(const String *name, NameSpace *parent,
1514 StrList *TYPE, CompiledParam::Flags flags,
1517 virtual void lookup_misc()
1519 type = lookup_type(type_name, get_ns());
1522 virtual void final_analysis()
1524 BasicType *bt = dynamic_cast<BasicType *>(type->get_concrete_sym());
1526 if (bt && !bt->def.flags.field.TypeDef) {
1527 use_anon_type(bt->def);
1531 Struct *str = dynamic_cast<Struct *>(*type);
1532 if (str && str->is_inline())
1535 if (!str && is_inline()) {
1536 yyerrorfl(name->file, name->line,
1537 "\"%s\" is static but not a struct.",
1538 get_fq_name()->flatten()->c_str());
1543 array->final_analysis();
1544 def.basictype.array = array->ca;
1546 def.basictype.array.bounds[0] = 0;
1547 def.basictype.array.bounds[1] = 0;
1553 def.flags.field.Inline = 1;
1558 return def.flags.field.Inline;
1563 return def.flags.field.In;
1568 return def.flags.field.Out;
1571 virtual void output(const char *root);
1572 bool output_extra(FILE *f);
1574 static Param *import(ImportContext &ctx);
1575 virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
1579 return ::is_array(def.basictype);
1583 typedef Ref<Param> ParamRef;
1585 class Method : public NameSpace, public Def {
1586 list<ParamRef> entries;
1588 void add_elem(Param *p);
1593 Method(const String *name) :
1595 Def((const char *)&def, sizeof(def), CompiledDefHeader::Method)
1597 memset(&def, 0, sizeof(def));
1602 def.flags.field.Async = 1;
1607 return def.flags.field.Async;
1610 static Method *declare(const String *name, NameSpace *parent);
1612 void add(Symbol *sym, bool from_import);
1614 virtual const char *description()
1619 virtual void output(const char *root);
1620 bool output_extra(FILE *f);
1622 static Method *import(ImportContext &ctx);
1623 virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
1625 typedef list<ParamRef>::const_iterator entries_iterator;
1627 entries_iterator entries_begin()
1629 return entries.begin();
1632 entries_iterator entries_end()
1634 return entries.end();
1638 typedef Ref<Method> MethodRef;
1641 typedef Ref<Interface> InterfaceRef;
1643 extern InterfaceRef System_Object;
1645 // FIXME: typedefed superinterfaces
1646 class Interface : public NameSpace, public Type, public Def {
1647 list<MethodRef> methods;
1648 list<InterfaceRef> supers;
1649 IDListRef supernames;
1651 void add_elem(Method *m);
1653 // This is like Symbol::traversed[], but used internally by the
1654 // for_each_super function to ensure that common ancestors are only
1657 int traversed_all_supers;
1658 static int all_supers_traversal;
1661 typedef void (*callback)(Interface *i, void *arg);
1664 template<callback cb>
1665 void for_each_super_internal(void *arg)
1667 for (supers_iterator i = supers_begin(); i != supers_end(); ++i) {
1668 Interface *iface = *i;
1670 if (iface->traversed_all_supers < all_supers_traversal) {
1671 iface->traversed_all_supers = all_supers_traversal;
1673 iface->for_each_super_internal<cb>(arg);
1678 // All interfaces in the map and vector are supers of this
1679 // interface, and thus retained that way, so plain pointers
1680 // can be used here.
1682 typedef map<Interface *, int> chain_map_type;
1683 typedef chain_map_type::value_type chain_valtype;
1684 typedef chain_map_type::const_iterator chain_iter;
1686 chain_map_type super_to_chain_map;
1690 vector<Interface *> chain_heads;
1693 int super_to_chain(Interface *iface, bool must_find_it = true)
1695 chain_iter ret = super_to_chain_map.find(iface);
1697 if (ret == super_to_chain_map.end()) {
1698 assert(!must_find_it);
1702 return (*ret).second;
1705 Interface *get_chain_head(int chain)
1707 return chain_heads[chain];
1710 int get_num_chains()
1716 void set_chain(Interface *iface, int chain)
1718 pair<chain_iter, bool> ret =
1719 super_to_chain_map.insert(chain_valtype(iface, chain));
1723 // This is the inner depth-first search, which terminates
1724 // at each level upon finding that the node it had previously
1725 // recursed into found an unchained node.
1727 void pick_chain(Interface *iface, int chain)
1729 assert(super_to_chain(iface, false) == -1);
1730 chain_heads.push_back(iface);
1733 set_chain(iface, chain);
1735 if (iface->supers.empty())
1738 iface = iface->supers.front();
1739 } while (super_to_chain(iface, false) == -1);
1742 // This is the outer breadth-first-search, making sure every
1743 // super is assigned to a chain.
1747 list<Interface *> bfs;
1750 bfs.push_back(this);
1752 while (!bfs.empty()) {
1753 Interface *iface = bfs.front();
1756 for (supers_iterator i = iface->supers_begin();
1757 i != iface->supers_end(); ++i)
1760 if (super_to_chain(iface, false) == -1)
1761 pick_chain(iface, num_chains++);
1766 // Do not call after lookup_misc
1767 void add_super(Interface *i)
1769 assert(current_pass != 1);
1771 supers.push_back(i);
1775 CompiledInterface def;
1777 Interface(const String *name) :
1779 Def((const char *)&def, sizeof(def), CompiledDefHeader::Interface)
1781 memset(&def, 0, sizeof(def));
1782 traversed_all_supers = 0;
1785 void init(IDList *SUPERNAMES)
1787 supernames = SUPERNAMES;
1790 static Interface *declare(const String *name, NameSpace *parent,
1795 Interface *i = new Interface(name);
1796 i->init(SUPERNAMES);
1798 parent->add_user(i);
1802 // Only Methods, Types, and const BasicType Datums can be added.
1804 void add(Symbol *sym, bool from_import);
1806 virtual const char *description()
1812 void add_object_super()
1814 assert(System_Object);
1815 if (this != System_Object && supers.empty())
1816 add_super(System_Object);
1820 virtual void lookup_misc()
1822 if (def.guid[0] == 0 && def.guid[1] == 0)
1823 yyerrorfl(name->file, name->line,
1824 "Interface \"%s\" is missing a GUID.",
1825 get_fq_name()->flatten()->c_str());
1828 for (IDList::iterator i = supernames->begin();
1829 i != supernames->end(); ++i)
1831 Symbol *sym = lookup_sym(toplevel, *i, get_ns());
1833 dynamic_cast<Interface *>(sym->get_concrete_sym());
1836 const String *str = (*i)->back();
1837 yyerrorfl(str->file, str->line,
1838 "\"%s\" is not an interface.\n",
1839 sym->get_fq_name()->flatten()->c_str());
1849 NameSpace::lookup_misc();
1852 virtual void final_analysis()
1854 // FIXME: check for infinite loops in inheritance
1857 NameSpace::final_analysis();
1860 virtual void output(const char *root);
1861 bool output_extra(FILE *f);
1863 static Interface *import(ImportContext &ctx);
1864 virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
1866 typedef list<MethodRef>::const_iterator methods_iterator;
1867 typedef list<InterfaceRef>::const_iterator supers_iterator;
1869 supers_iterator supers_begin()
1871 assert(current_pass != 1);
1872 return supers.begin();
1875 supers_iterator supers_end()
1877 return supers.end();
1882 assert(current_pass != 1);
1883 return supers.empty();
1886 methods_iterator methods_begin()
1888 return methods.begin();
1891 methods_iterator methods_end()
1893 return methods.end();
1896 template<callback cb>
1897 void for_each_super(void *arg)
1899 assert(current_pass >= 4);
1901 all_supers_traversal++;
1902 for_each_super_internal<cb>(arg);
1905 void finalize_class_iface()
1911 void set_guid(uint64_t guid[2])
1913 if (def.guid[0] || def.guid[1])
1914 yyerrorf("\"%s\" already has a GUID.",
1915 get_fq_name()->flatten()->c_str());
1917 def.guid[0] = guid[0];
1918 def.guid[1] = guid[1];
1922 class IFaceList : public list<InterfaceRef>,
1923 public RefCountable<IFaceList> {};
1925 class Enum : public NameSpace, public Type, public Def {
1926 list<DatumRef> entries;
1928 void add_elem(Datum *d);
1931 unsigned int next_val;
1934 Enum(const String *name) :
1936 Def((const char *)&def, sizeof(def), CompiledDefHeader::Enum),
1939 memset(&def, 0, sizeof(def));
1944 if (bits < 0 || bits > 64) {
1945 yyerrorf("\"%s\" has invalid enum size %d",
1946 name->c_str(), bits);
1948 bits = bits < 0 ? 0 : 64;
1954 static Enum *declare(const String *name, NameSpace *parent,
1959 Enum *e = new Enum(name);
1962 parent->add_user(e);
1966 // Only const unsigned integer BasicType Datums are allowed.
1968 void add(Symbol *sym, bool from_import);
1970 virtual const char *description()
1972 return "enumeration";
1975 int get_default_bf_size()
1980 virtual void output(const char *root);
1981 bool output_extra(FILE *f);
1983 static Enum *import(ImportContext &ctx);
1984 virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
1986 typedef list<DatumRef>::const_iterator entries_iterator;
1988 entries_iterator entries_begin()
1990 return entries.begin();
1993 entries_iterator entries_end()
1995 return entries.end();
1999 class Alias : public Symbol, public Def {
2005 Cycle(Alias *END) : end(END)
2014 StringRef sym_fq_name;
2015 StrListRef sym_name;
2017 Alias(const String *name) :
2019 Def((const char *)&def, sizeof(def), CompiledDefHeader::Alias)
2021 memset(&def, 0, sizeof(def));
2022 lookup_begun = false;
2025 void init(StrList *symname, bool is_private)
2031 static Alias *declare(const String *name, NameSpace *parent,
2032 StrList *symname, bool is_private = false)
2035 Alias *a = new Alias(name);
2036 a->init(symname, is_private);
2038 parent->add_user(a);
2042 void resolve_chain()
2046 yyerrorfl(name->file, name->line,
2047 "Alias loop defining \"%s\"",
2048 get_fq_name()->flatten()->c_str());
2053 lookup_begun = true;
2056 real_sym = lookup_sym(toplevel, sym_name, get_ns(), this);
2060 yyerrorfl(name->file, name->line, " ...referenced by \"%s\"",
2061 get_fq_name()->flatten()->c_str());
2071 virtual Symbol *get_concrete_sym(bool follow_typedefs = true)
2074 return real_sym->get_concrete_sym(follow_typedefs);
2077 virtual void lookup_chain()
2079 get_concrete_sym(true);
2082 virtual void lookup_misc()
2084 real_sym = real_sym->get_concrete_sym(false);
2085 sym_fq_name = real_sym->get_fq_name()->flatten();
2087 def.length = sym_fq_name->length();
2090 virtual void output(const char *root);
2091 bool output_extra(FILE *f);
2093 static Alias *import(ImportContext &ctx);
2094 virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
2097 class TypeDef : public Alias {
2099 TypeDef(const String *name) : Alias(name)
2101 memset(&def, 0, sizeof(def));
2102 hdr.type = CompiledDefHeader::TypeDef;
2105 static TypeDef *declare(const String *name, NameSpace *parent,
2109 TypeDef *td = new TypeDef(name);
2110 td->init(symname, false);
2112 parent->add_user(td);
2116 virtual Symbol *get_concrete_sym(bool follow_typedefs = true)
2118 if (follow_typedefs) {
2120 return real_sym->get_concrete_sym(follow_typedefs);
2126 static TypeDef *import(ImportContext &ctx);
2127 virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
2130 NameSpace *add_nspace(StrList *name, bool push);
2133 // Declare an instance of "type" in "ns" for each element of "ids".
2134 // This function will report any errors, but not throw UserError.
2136 void declare_data(NameSpace *ns, StrList *ids, StrList *type,
2137 Array *array, StrList *attr);
2138 void declare_aliases(NameSpace *ns, StrList *ids, StrList *type,
2140 void declare_basictypes(NameSpace *ns, StrList *ids,
2141 BasicType *type, bool is_typedef);
2143 // You'd think they'd have standard functions to do this these days.
2144 // All I could find that come close are the network-byte-order
2145 // functions, and they're no-ops on big-endian machines.
2147 static inline uint32_t swap32(uint32_t in, bool swap)
2150 return ((in & 0x000000ff) << 24) |
2151 ((in & 0x0000ff00) << 8) |
2152 ((in & 0x00ff0000) >> 8) |
2153 ((in & 0xff000000) >> 24);
2158 static inline uint64_t swap64(uint64_t in, bool swap)
2161 return (((uint64_t)swap32((uint32_t)in, true)) << 32) |
2162 swap32((uint32_t)(in >> 32), true);
2180 File *operator =(FILE *F)
2198 // Verify that a prospective new import (or output namespace)
2199 // does not overlap an existing import. Returns the conflicting
2200 // import, or NULL if none found.
2202 NameSpace *check_for_imports(NameSpace *ns);