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 // 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:
13 // * Redistributions of source code must retain the above copyright notice,
14 // this list of conditions and the following disclaimers.
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.
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.
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
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...
50 #include "compileddef.h"
61 #define cdl_lex idl_lex
62 void idl_error(char *s);
64 #define cdl_error idl_error
66 void setup_idlparse();
67 void setup_cdlparse();
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)));
74 void yyerrorf(const char *s, ...);
75 void yyerrorfl(const char *file, int line, const char *s, ...);
82 extern int idl_debug, cdl_debug, curline, impl, num_err;
83 extern int current_pass;
85 extern unsigned int enum_pos;
86 extern const char *cur_input_file;
87 extern int compiling_idl, compiling_cdl;
92 // Location in the IDLC source of the BUG()
96 InternalError(const char *file, int line) :
97 file(file), line(line)
103 throw InternalError(__FILE__, __LINE__); \
108 #define assert(x) do { \
116 virtual ~Releasable()
120 Releasable(int COUNT) : count(COUNT)
127 fprintf(stderr, "Reference count is %d in release\n", count);
136 class AutoReleasePool {
137 list<const Releasable *> pool;
140 void add(const Releasable *obj)
147 for (list<const Releasable *>::iterator i = pool.begin();
148 i != pool.end(); ++i)
150 const Releasable *obj = *i;
158 extern AutoReleasePool autorelease_pool;
160 template <typename T>
161 class RefCountable : public Releasable {
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
168 void operator =(const RefCountable &rc)
173 RefCountable(const RefCountable &rc) : Releasable(1)
179 RefCountable() : Releasable(1)
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().
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.
192 virtual ~RefCountable()
196 const T *retain() const
199 fprintf(stderr, "Reference count is %d in retain\n", count);
204 return static_cast<const T *>(this);
210 fprintf(stderr, "Reference count is %d in retain\n", count);
215 return static_cast<T *>(this);
218 const T *autorelease() const
220 autorelease_pool.add(static_cast<Releasable *>(this));
221 return static_cast<T *>(this);
226 autorelease_pool.add(static_cast<Releasable *>(this));
227 return static_cast<T *>(this);
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.
235 bool operator < (const RefCountable &rc)
241 // T must be RefCountable
242 template<typename T, bool compare_ptrs = true>
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,
260 Ref(T *data) : data(data)
266 Ref(Ref &le) : data(le.data)
272 Ref &operator =(const Ref &le)
274 // The retain must come first, in case both Refs are the same
285 Ref &operator =(T *new_data)
287 // The retain must come first, in case both Refs are the same
314 T *operator *() const
319 T *operator ->() const
324 bool operator == (const Ref &le) const
327 return data == le.data;
329 return *data == *le.data;
332 bool operator != (const Ref &le) const
335 return data != le.data;
337 return *data != *le.data;
340 bool operator < (const Ref &le) const
343 return reinterpret_cast<intptr_t>(data) <
344 reinterpret_cast<intptr_t>(le.data);
346 return *data < *le.data;
350 class String : public string, public RefCountable<String> {
352 // Origin of the string, if from the IDL file.
353 // Otherwise, fill both values with zero.
359 String(const char *s = "") : string(s)
366 String(const String &s) : string(s)
373 String(const char *s, const char *file, int line, int token) :
374 string(s), file(file), line(line), token(token)
378 extern String **yylval_string;
379 typedef Ref<const String, false> StringRef;
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
386 Note that list doesn't have a virtual destructor, so all deletions
387 should happen through either RefCountable or the wrapper List
390 class StrList : public list<StringRef>, public RefCountable<StrList> {
396 // Parse a flat String into a StrList, using the specified delimeter.
397 StrList(const String *input, char delimiter = '.');
399 // Turn a StrList into a flat String, using the specified delimiter.
400 String *flatten(const char *delimiter = ".");
403 typedef Ref<StrList> StrListRef;
405 // ConList is like StrList, but with constant initializers
415 // FIXME: handle platforms with weird floating point endianness
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
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.
433 // TOK_DCON is used for symbolic constants, whose value may
439 extern Con *yylval_con;
445 ConInit(const String *str, Con &con) : str(str), con(con)
449 ConInit(const ConInit &coninit)
455 class ConList : public list<ConInit>, public RefCountable<ConList> {};
456 typedef Ref<ConList> ConListRef;
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;
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.
470 extern int traversal;
472 class Symbol : public RefCountable<Symbol> {
478 // Symbol was loaded externally
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.
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.
501 memset(traversed, 0, sizeof(traversed));
504 Symbol(const String *_name) : name(_name)
513 memset(traversed, 0, sizeof(traversed));
518 NameSpace *get_ns() const
523 const String *get_name() const
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.
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
542 StrList *get_fq_name(const char *append = NULL,
543 bool not_last = false) const;
545 virtual void lookup_imports()
549 virtual void lookup_chain()
553 virtual void lookup_misc()
557 virtual void final_analysis()
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).
564 virtual void output(const char *root)
568 virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL)
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.
577 Symbol *find_toplevel_type();
579 // Get the true type of the symbol, regardless of whether it is an
582 virtual Symbol *get_concrete_sym(bool follow_typedefs = true)
587 friend class NameSpace;
590 typedef Ref<Symbol> SymbolRef;
592 class SymList : public list<SymbolRef>, public RefCountable<SymList> {};
593 typedef Ref<SymList> SymListRef;
595 struct SymbolNotFound {
598 struct DuplicateSymbol {
601 struct InvalidArgument {
607 typedef Ref<NameSpace> NameSpaceRef;
609 class NameSpace : public virtual Symbol {
611 // Filesystem path to the external symbol storage, or NULL
612 // if not an import namespace.
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.
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.
630 Symbol *load(const String *symname);
632 typedef map<StringRef, SymbolRef> tbl_type;
635 list<StrListRef> import_strs;
636 list<NameSpaceRef> imports;
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.
644 // This is a counter for generating unique names for anonymous
645 // members of the namespace.
648 NameSpace() : dying(0), anon(0)
657 // Return a description of the type of namespace, for
659 virtual const char *description()
664 virtual void output(const char *root);
666 typedef tbl_type::const_iterator const_iterator;
667 typedef tbl_type::value_type value_type;
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
679 // DuplicateSymbol is thrown if sym already exists in this namespace.
680 virtual void add(Symbol *sym, bool from_import)
682 if (path && !from_import)
683 throw InvalidArgument();
686 sym->external = true;
691 pair<const_iterator, bool> ret = tbl.insert(value_type(sym->name, sym));
696 throw DuplicateSymbol();
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).
707 void add_user(Symbol *sym);
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.
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).
721 void add_import(Symbol *sym, const char *filename);
723 // SymbolNotFound is thrown if sym is not in this namespace.
724 virtual void del(Symbol *sym)
726 fprintf(stderr, "Removing symbol %s\n",
727 sym->get_fq_name()->flatten()->c_str());
729 if (tbl.erase(sym->name) == 0)
730 throw SymbolNotFound();
736 Symbol *lookup_noex_noimport(const String *symname)
738 const_iterator ret = tbl.find(symname);
740 if (ret != tbl.end())
741 return (*ret).second;
747 Symbol *lookup_noex(const String *symname, bool priv_ok = false)
749 Symbol *ret = NameSpace::lookup_noex_noimport(symname);
754 if (ret && !priv_ok && ret->priv)
760 Symbol *lookup(const String *symname, bool priv_ok = false)
762 Symbol *ret = lookup_noex(symname, priv_ok);
765 throw SymbolNotFound();
770 // Like lookup_noex, but also checks imported namespaces,
771 // and returns the namespace containing the match rather
772 // than the match itself.
774 NameSpace *search(const String *name, Symbol *exclude);
776 void add_search(StrList *ns)
778 import_strs.push_back(ns);
781 // Return a string containing case information manglement.
782 // See input.cc for more information.
784 static const String *mangle(const String *name);
786 const String *get_path()
791 // Import all members of this namespace. A no-op if not an import
795 // As import_all, but also recursively applies to any sub-namespaces.
796 void import_all_recursive();
798 const_iterator begin()
808 virtual void lookup_imports();
810 virtual void lookup_chain()
812 for (const_iterator i = begin(); i != end(); ++i) {
813 Symbol *sym = (*i).second;
818 virtual void lookup_misc()
820 for (const_iterator i = begin(); i != end(); ++i) {
821 Symbol *sym = (*i).second;
826 virtual void final_analysis()
828 for (const_iterator i = begin(); i != end(); ++i) {
829 Symbol *sym = (*i).second;
830 sym->final_analysis();
836 extern NameSpaceRef cur_nspace;
837 extern list<NameSpaceRef> nspace_stack;
839 typedef std::vector<StringRef> StringVec;
841 string *stringvec_to_path(StringVec &stringvec, const char *prepend);
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.
847 Symbol *lookup_sym(NameSpace *topns, StrList *name, NameSpace *ctx,
848 Symbol *exclude = NULL);
851 const char *self; // Pointer to the type-specific struct
852 int self_len; // Length of the type-specific struct
855 CompiledDefHeader hdr;
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
860 void output_self(const char *dir, Symbol *sym, bool dir);
863 Def(const char *self, int self_len, CompiledDefHeader::Type type) :
864 self(self), self_len(self_len)
866 hdr.magic = CompiledDefHeader::magic_normal;
874 // Specific types may override this to output extra data
875 // to the .self file without having to reopen the file.
877 // Returns false on error.
879 virtual bool output_extra(FILE *f)
885 // Internal context struct used by input.cc to avoid passing
886 // lots of parameters around
887 struct ImportContext;
889 // This represents an actual IDL namespace {}, rather than
890 // a derived namespace such as a Struct or Interface.
892 class UserNameSpace : public NameSpace, public Def {
894 CompiledNameSpace def;
895 StringRef mountpoint_name;
897 UserNameSpace(const String *name = NULL) :
899 Def((const char *)&def, sizeof(def), CompiledDefHeader::NameSpace)
901 mountpoint_name = get_fq_name()->flatten();
902 def.length = mountpoint_name->length();
905 virtual void output(const char *root);
906 bool output_extra(FILE *f);
908 static void declare_import(const char *path);
910 static UserNameSpace *import(ImportContext &ctx);
911 virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
914 typedef Ref<UserNameSpace> UserNameSpaceRef;
915 extern UserNameSpaceRef toplevel, cdl_toplevel;
916 extern UserNameSpace *output_ns;
918 class Type : public virtual Symbol {
928 virtual int get_default_bf_size()
930 // Only allow types in bitfields that explicitly
937 typedef Ref<Type> TypeRef;
939 // ctx can be NULL if basic_types_only is true
940 Type *lookup_type(StrList *sl, NameSpace *ctx, bool basic_types_only = false);
942 class BasicType : public Type, public Def {
944 CompiledBasicType def;
947 BasicType(const String *name) :
949 Def((const char *)&def, sizeof(def), CompiledDefHeader::BasicType)
952 memset(&def, 0, sizeof(def));
955 void init(CompiledBasicType &DEF)
963 static BasicType *declare(const String *name, NameSpace *parent,
964 CompiledBasicType &DEF)
966 BasicType *bt = new BasicType(name);
970 parent->add_user(bt);
975 virtual void output(const char *root);
977 static BasicType *import(ImportContext &ctx);
978 virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
981 static inline bool is_array(CompiledBasicType &bt)
983 return bt.array.bounds[0] || bt.array.bounds[1];
986 static inline bool is_array(CompiledBasicType *bt)
988 return is_array(*bt);
991 typedef Ref<Datum> DatumRef;
993 class Array : public RefCountable<Array>
995 NameSpace *lookup_ctx;
998 // lower is [0], upper is [1]
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.
1011 // ca is not valid until after final_analysis() is called.
1014 Array(NameSpace *LOOKUP_CTX);
1015 void set_bound(Con &con, int bound);
1016 void final_analysis();
1018 void set_unbounded();
1021 typedef Ref<Array> ArrayRef;
1023 class Datum : public Symbol, public Def {
1024 StrListRef type_name;
1026 StringRef type_fq_name;
1028 StrListRef const_val_name;
1029 SymbolRef const_val_sym;
1032 bool basic; // Datum is of a BasicType
1034 bool const_init; // Datum's constant has been initialized; this is
1035 // true after a successful verify_const().
1036 CompiledBasicType *cbt;
1040 int chain_traversed;
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
1048 Datum *resolve_constant_chain();
1050 void init_const_early(Con *con);
1052 void use_anon_type(const CompiledBasicType &CBT)
1054 def.basictype = CBT;
1055 cbt = &def.basictype;
1058 def.type.length = 0;
1061 void process_type();
1063 void set_array(Array *ARRAY)
1073 int con_type; // Used to store the TOK_[IUF]CON of the Con struct
1074 // for type checking once the type is known.
1076 Datum(const String *name) :
1078 Def((const char *)&def, sizeof(def), CompiledDefHeader::Datum)
1082 chain_traversed = 0;
1083 memset(&def, 0, sizeof(def));
1086 void init(StrList *type, Array *ARRAY, Con *con = NULL);
1087 void init(CompiledBasicType &cbt, Array *ARRAY, Con *con = NULL);
1089 static Datum *declare(const String *name, NameSpace *parent,
1090 StrList *type, Array *ARRAY,
1095 Datum *d = new Datum(name);
1096 d->init(type, ARRAY, con);
1098 parent->add_user(d);
1102 static Datum *declare(const String *name, NameSpace *parent,
1103 CompiledBasicType &type,
1104 Array *ARRAY, Con *con = NULL)
1108 Datum *d = new Datum(name);
1109 d->init(type, ARRAY, con);
1111 parent->add_user(d);
1117 def.flags.field.Inline = 1;
1122 return def.flags.field.Inline;
1125 void set_immutable()
1127 def.flags.field.Immutable = 1;
1132 return def.flags.field.Immutable;
1135 // Returns true if the constant was acceptable, false otherwise (an
1136 // error is also output to the user in this case).
1138 bool verify_const();
1140 virtual void lookup_chain()
1145 const_val_sym = lookup_sym(toplevel, const_val_name, get_ns());
1149 type_sym = lookup_type(type_name, get_ns(), true);
1151 type_sym = lookup_sym(toplevel, type_name, get_ns());
1157 virtual void lookup_misc()
1159 if (def.flags.field.Const) {
1161 assert(def.flags.field.Const);
1164 Datum *d = resolve_constant_chain();
1174 virtual void final_analysis();
1176 virtual void output(const char *root);
1177 bool output_extra(FILE *f);
1179 static Datum *import(ImportContext &ctx);
1180 virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
1182 uint64_t get_ucon(const String *err_str)
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());
1197 return ::is_array(def.basictype);
1201 template<typename T>
1202 bool output_list(T *sym, FILE *f);
1204 class BitField : public NameSpace, public Type, public Def {
1205 list<DatumRef> entries;
1207 void add_elem(Datum *d);
1210 CompiledBitField def;
1213 BitField(const String *name) :
1215 Def((const char *)&def, sizeof(def), CompiledDefHeader::BitField)
1217 memset(&def, 0, sizeof(def));
1220 void init(int bits, NameSpace *parent)
1222 if (bits < 0 || bits > 64) {
1223 yyerrorf("\"%s\" has invalid bitfield size %d",
1224 name->c_str(), bits);
1226 bits = bits < 0 ? 0 : 64;
1232 static BitField *declare(const String *name, NameSpace *parent,
1237 BitField *bf = new BitField(name);
1238 bf->init(bits, parent);
1240 parent->add_user(bf);
1244 // Only integral Datums, Enums, and BitFields can be added.
1246 void add(Symbol *sym, bool from_import);
1248 virtual const char *description()
1253 virtual void lookup_misc()
1255 NameSpace::lookup_misc();
1258 virtual void final_analysis()
1260 // FIXME: check total size of elements
1262 NameSpace::final_analysis();
1265 int get_default_bf_size()
1270 virtual void output(const char *root);
1271 bool output_extra(FILE *f);
1273 static BitField *import(ImportContext &ctx);
1274 virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
1276 typedef list<DatumRef>::const_iterator entries_iterator;
1277 typedef list<DatumRef>::const_reverse_iterator entries_reverse_iterator;
1279 entries_iterator entries_begin()
1281 return entries.begin();
1284 entries_iterator entries_end()
1286 return entries.end();
1289 entries_reverse_iterator entries_rbegin()
1291 return entries.rbegin();
1294 entries_reverse_iterator entries_rend()
1296 return entries.rend();
1301 typedef Ref<Struct> StructRef;
1302 extern Struct *System_VStruct;
1304 // FIXME: typedefed superstructs
1305 class Struct : public NameSpace, public Type, public Def {
1306 list<DatumRef> entries;
1309 StrListRef supername;
1310 bool attrs_resolved;
1312 void add_elem(Datum *d);
1314 void resolve_attrs()
1319 if (super && !super->attrs_resolved)
1320 super->resolve_attrs();
1322 if (super && super->def.flags.field.Virtual)
1323 def.flags.field.Virtual = 1;
1325 attrs_resolved = true;
1331 // This is not maintained by the generic code, but can be
1332 // used by language bindings to cache the result of the
1337 Struct(const String *name) :
1339 Def((const char *)&def, sizeof(def), CompiledDefHeader::Struct)
1341 memset(&def, 0, sizeof(def));
1345 void init(StrList *SUPERNAME)
1347 supername = SUPERNAME;
1350 static Struct *declare(const String *name, NameSpace *parent,
1355 Struct *st = new Struct(name);
1356 st->init(SUPERNAME);
1358 parent->add_user(st);
1364 def.flags.field.Virtual = 1;
1369 def.flags.field.Inline = 1;
1374 return def.flags.field.Virtual;
1379 return def.flags.field.Inline;
1382 // Only Datums and Types can be added.
1384 void add(Symbol *sym, bool from_import);
1386 virtual const char *description()
1393 assert(current_pass >= 4);
1397 virtual void lookup_chain()
1400 supersym = lookup_sym(toplevel, supername, get_ns());
1404 NameSpace::lookup_chain();
1410 if (supersym && !super) {
1411 super = dynamic_cast<Struct *>(supersym->get_concrete_sym());
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());
1420 def.flags.field.Super = 1;
1421 super->lookup_super();
1423 if (super->is_virtual())
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;
1437 virtual void lookup_misc()
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());
1446 NameSpace::lookup_misc();
1449 virtual void final_analysis()
1451 // FIXME: check for infinite loops in struct inheritance
1454 NameSpace::final_analysis();
1457 virtual void output(const char *root);
1458 bool output_extra(FILE *f);
1460 static Struct *import(ImportContext &ctx);
1461 virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
1463 typedef list<DatumRef>::const_iterator entries_iterator;
1465 entries_iterator entries_begin()
1467 return entries.begin();
1470 entries_iterator entries_end()
1472 return entries.end();
1475 void set_guid(uint64_t guid[2])
1477 if (def.guid[0] || def.guid[1])
1478 yyerrorf("\"%s\" already has a GUID.",
1479 get_fq_name()->flatten()->c_str());
1481 def.guid[0] = guid[0];
1482 def.guid[1] = guid[1];
1486 class Param : public Symbol, public Def {
1487 StrListRef type_name;
1488 StringRef type_fq_name;
1490 bool basic; // Datum is of a BasicType
1495 void use_named_type(BasicType *bt)
1497 assert(!bt || bt->def.flags.field.TypeDef);
1501 type_fq_name = type->get_fq_name()->flatten();
1502 def.type.length = type_fq_name->length();
1505 void use_anon_type(const CompiledBasicType &cbt)
1507 def.basictype = cbt;
1512 void set_array(Array *ARRAY)
1522 Param(const String *name) :
1524 Def((const char *)&def, sizeof(def), CompiledDefHeader::Param)
1526 memset(&def, 0, sizeof(def));
1529 void init(StrList *TYPE, CompiledParam::Flags flags, Array *ARRAY)
1536 static Param *declare(const String *name, NameSpace *parent,
1537 StrList *TYPE, CompiledParam::Flags flags,
1540 virtual void lookup_misc()
1542 type = lookup_type(type_name, get_ns());
1545 virtual void final_analysis()
1547 BasicType *bt = dynamic_cast<BasicType *>(type->get_concrete_sym());
1549 if (bt && !bt->def.flags.field.TypeDef) {
1550 use_anon_type(bt->def);
1554 Struct *str = dynamic_cast<Struct *>(*type);
1555 if (str && str->is_inline())
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());
1566 array->final_analysis();
1567 def.basictype.array = array->ca;
1569 def.basictype.array.bounds[0] = 0;
1570 def.basictype.array.bounds[1] = 0;
1576 def.flags.field.Inline = 1;
1581 return def.flags.field.Inline;
1586 return def.flags.field.In;
1591 return def.flags.field.Out;
1594 virtual void output(const char *root);
1595 bool output_extra(FILE *f);
1597 static Param *import(ImportContext &ctx);
1598 virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
1602 return ::is_array(def.basictype);
1606 typedef Ref<Param> ParamRef;
1608 class Method : public NameSpace, public Def {
1609 list<ParamRef> entries;
1611 void add_elem(Param *p);
1616 Method(const String *name) :
1618 Def((const char *)&def, sizeof(def), CompiledDefHeader::Method)
1620 memset(&def, 0, sizeof(def));
1625 def.flags.field.Async = 1;
1630 return def.flags.field.Async;
1633 static Method *declare(const String *name, NameSpace *parent);
1635 void add(Symbol *sym, bool from_import);
1637 virtual const char *description()
1642 virtual void output(const char *root);
1643 bool output_extra(FILE *f);
1645 static Method *import(ImportContext &ctx);
1646 virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
1648 typedef list<ParamRef>::const_iterator entries_iterator;
1650 entries_iterator entries_begin()
1652 return entries.begin();
1655 entries_iterator entries_end()
1657 return entries.end();
1661 typedef Ref<Method> MethodRef;
1664 typedef Ref<Interface> InterfaceRef;
1666 extern Interface *System_Object;
1668 // FIXME: typedefed superinterfaces
1669 class Interface : public NameSpace, public Type, public Def {
1670 list<MethodRef> methods;
1671 list<InterfaceRef> supers;
1672 IDListRef supernames;
1674 void add_elem(Method *m);
1676 // This is like Symbol::traversed[], but used internally by the
1677 // for_each_super function to ensure that common ancestors are only
1680 int traversed_all_supers;
1681 static int all_supers_traversal;
1684 typedef void (*callback)(Interface *i, void *arg);
1687 template<callback cb>
1688 void for_each_super_internal(void *arg)
1690 for (supers_iterator i = supers_begin(); i != supers_end(); ++i) {
1691 Interface *iface = *i;
1693 if (iface->traversed_all_supers < all_supers_traversal) {
1694 iface->traversed_all_supers = all_supers_traversal;
1696 iface->for_each_super_internal<cb>(arg);
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.
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;
1709 chain_map_type super_to_chain_map;
1713 vector<Interface *> chain_heads;
1716 int super_to_chain(Interface *iface, bool must_find_it = true)
1718 chain_iter ret = super_to_chain_map.find(iface);
1720 if (ret == super_to_chain_map.end()) {
1721 assert(!must_find_it);
1725 return (*ret).second;
1728 Interface *get_chain_head(int chain)
1730 return chain_heads[chain];
1733 int get_num_chains()
1739 void set_chain(Interface *iface, int chain)
1741 pair<chain_iter, bool> ret =
1742 super_to_chain_map.insert(chain_valtype(iface, chain));
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.
1750 void pick_chain(Interface *iface, int chain)
1752 assert(super_to_chain(iface, false) == -1);
1753 chain_heads.push_back(iface);
1756 set_chain(iface, chain);
1758 if (iface->supers.empty())
1761 iface = iface->supers.front();
1762 } while (super_to_chain(iface, false) == -1);
1765 // This is the outer breadth-first-search, making sure every
1766 // super is assigned to a chain.
1770 list<Interface *> bfs;
1773 bfs.push_back(this);
1775 while (!bfs.empty()) {
1776 Interface *iface = bfs.front();
1779 for (supers_iterator i = iface->supers_begin();
1780 i != iface->supers_end(); ++i)
1783 if (super_to_chain(iface, false) == -1)
1784 pick_chain(iface, num_chains++);
1789 // Do not call after lookup_misc
1790 void add_super(Interface *i)
1792 assert(current_pass != 1);
1794 supers.push_back(i);
1798 CompiledInterface def;
1800 Interface(const String *name) :
1802 Def((const char *)&def, sizeof(def), CompiledDefHeader::Interface)
1804 memset(&def, 0, sizeof(def));
1805 traversed_all_supers = 0;
1808 void init(IDList *SUPERNAMES)
1810 supernames = SUPERNAMES;
1813 static Interface *declare(const String *name, NameSpace *parent,
1818 Interface *i = new Interface(name);
1819 i->init(SUPERNAMES);
1821 parent->add_user(i);
1825 // Only Methods, Types, and const BasicType Datums can be added.
1827 void add(Symbol *sym, bool from_import);
1829 virtual const char *description()
1835 void add_object_super()
1837 assert(System_Object);
1838 if (this != System_Object && supers.empty())
1839 add_super(System_Object);
1843 virtual void lookup_misc()
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());
1851 for (IDList::iterator i = supernames->begin();
1852 i != supernames->end(); ++i)
1854 Symbol *sym = lookup_sym(toplevel, *i, get_ns());
1856 dynamic_cast<Interface *>(sym->get_concrete_sym());
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());
1872 NameSpace::lookup_misc();
1875 virtual void final_analysis()
1877 // FIXME: check for infinite loops in inheritance
1880 NameSpace::final_analysis();
1883 virtual void output(const char *root);
1884 bool output_extra(FILE *f);
1886 static Interface *import(ImportContext &ctx);
1887 virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
1889 typedef list<MethodRef>::const_iterator methods_iterator;
1890 typedef list<InterfaceRef>::const_iterator supers_iterator;
1892 supers_iterator supers_begin()
1894 assert(current_pass != 1);
1895 return supers.begin();
1898 supers_iterator supers_end()
1900 return supers.end();
1905 assert(current_pass != 1);
1906 return supers.empty();
1909 methods_iterator methods_begin()
1911 return methods.begin();
1914 methods_iterator methods_end()
1916 return methods.end();
1919 template<callback cb>
1920 void for_each_super(void *arg)
1922 assert(current_pass >= 4);
1924 all_supers_traversal++;
1925 for_each_super_internal<cb>(arg);
1928 void finalize_class_iface()
1934 void set_guid(uint64_t guid[2])
1936 if (def.guid[0] || def.guid[1])
1937 yyerrorf("\"%s\" already has a GUID.",
1938 get_fq_name()->flatten()->c_str());
1940 def.guid[0] = guid[0];
1941 def.guid[1] = guid[1];
1945 class IFaceList : public list<InterfaceRef>,
1946 public RefCountable<IFaceList> {};
1948 class Enum : public NameSpace, public Type, public Def {
1949 list<DatumRef> entries;
1951 void add_elem(Datum *d);
1954 unsigned int next_val;
1957 Enum(const String *name) :
1959 Def((const char *)&def, sizeof(def), CompiledDefHeader::Enum),
1962 memset(&def, 0, sizeof(def));
1967 if (bits < 0 || bits > 64) {
1968 yyerrorf("\"%s\" has invalid enum size %d",
1969 name->c_str(), bits);
1971 bits = bits < 0 ? 0 : 64;
1977 static Enum *declare(const String *name, NameSpace *parent,
1982 Enum *e = new Enum(name);
1985 parent->add_user(e);
1989 // Only const unsigned integer BasicType Datums are allowed.
1991 void add(Symbol *sym, bool from_import);
1993 virtual const char *description()
1995 return "enumeration";
1998 int get_default_bf_size()
2003 virtual void output(const char *root);
2004 bool output_extra(FILE *f);
2006 static Enum *import(ImportContext &ctx);
2007 virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
2009 typedef list<DatumRef>::const_iterator entries_iterator;
2011 entries_iterator entries_begin()
2013 return entries.begin();
2016 entries_iterator entries_end()
2018 return entries.end();
2022 class Alias : public Symbol, public Def {
2028 Cycle(Alias *END) : end(END)
2037 StringRef sym_fq_name;
2038 StrListRef sym_name;
2040 Alias(const String *name) :
2042 Def((const char *)&def, sizeof(def), CompiledDefHeader::Alias)
2044 memset(&def, 0, sizeof(def));
2045 lookup_begun = false;
2048 void init(StrList *symname, bool is_private)
2054 static Alias *declare(const String *name, NameSpace *parent,
2055 StrList *symname, bool is_private = false)
2058 Alias *a = new Alias(name);
2059 a->init(symname, is_private);
2061 parent->add_user(a);
2065 void resolve_chain()
2069 yyerrorfl(name->file, name->line,
2070 "Alias loop defining \"%s\"",
2071 get_fq_name()->flatten()->c_str());
2076 lookup_begun = true;
2079 real_sym = lookup_sym(toplevel, sym_name, get_ns(), this);
2083 yyerrorfl(name->file, name->line, " ...referenced by \"%s\"",
2084 get_fq_name()->flatten()->c_str());
2094 virtual Symbol *get_concrete_sym(bool follow_typedefs = true)
2097 return real_sym->get_concrete_sym(follow_typedefs);
2100 virtual void lookup_chain()
2102 get_concrete_sym(true);
2105 virtual void lookup_misc()
2107 real_sym = real_sym->get_concrete_sym(false);
2108 sym_fq_name = real_sym->get_fq_name()->flatten();
2110 def.length = sym_fq_name->length();
2113 virtual void output(const char *root);
2114 bool output_extra(FILE *f);
2116 static Alias *import(ImportContext &ctx);
2117 virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
2120 class TypeDef : public Alias {
2122 TypeDef(const String *name) : Alias(name)
2124 memset(&def, 0, sizeof(def));
2125 hdr.type = CompiledDefHeader::TypeDef;
2128 static TypeDef *declare(const String *name, NameSpace *parent,
2132 TypeDef *td = new TypeDef(name);
2133 td->init(symname, false);
2135 parent->add_user(td);
2139 virtual Symbol *get_concrete_sym(bool follow_typedefs = true)
2141 if (follow_typedefs) {
2143 return real_sym->get_concrete_sym(follow_typedefs);
2149 static TypeDef *import(ImportContext &ctx);
2150 virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
2153 NameSpace *add_nspace(StrList *name, bool push);
2156 // Declare an instance of "type" in "ns" for each element of "ids".
2157 // This function will report any errors, but not throw UserError.
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,
2163 void declare_basictypes(NameSpace *ns, StrList *ids,
2164 BasicType *type, bool is_typedef);
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.
2170 static inline uint32_t swap32(uint32_t in, bool swap)
2173 return ((in & 0x000000ff) << 24) |
2174 ((in & 0x0000ff00) << 8) |
2175 ((in & 0x00ff0000) >> 8) |
2176 ((in & 0xff000000) >> 24);
2181 static inline uint64_t swap64(uint64_t in, bool swap)
2184 return (((uint64_t)swap32((uint32_t)in, true)) << 32) |
2185 swap32((uint32_t)(in >> 32), true);
2203 File *operator =(FILE *F)
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.
2225 NameSpace *check_for_imports(NameSpace *ns);