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 condition:
13 // The above copyright notice and this permission notice shall be
14 // included in all copies or substantial portions of the Software.
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
18 // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
27 // inttypes.h on OSX assumes it can use restrict, but C++ doesn't have it.
28 // Hopefully C++ will catch up to C soon...
42 #include "compileddef.h"
53 #define cdl_lex idl_lex
54 void idl_error(char *s);
56 #define cdl_error idl_error
58 void setup_idlparse();
59 void setup_cdlparse();
62 void yyerrorf(const char *s, ...) __attribute__((format(printf, 1, 2)));
63 void yyerrorfl(const char *file, int line, const char *s, ...)
64 __attribute__((format(printf, 3, 4)));
66 void yyerrorf(const char *s, ...);
67 void yyerrorfl(const char *file, int line, const char *s, ...);
74 extern int idl_debug, cdl_debug, curline, impl, num_err;
75 extern int current_pass;
77 extern unsigned int enum_pos;
78 extern const char *cur_input_file;
79 extern int compiling_idl, compiling_cdl;
84 // Location in the IDLC source of the BUG()
88 InternalError(const char *file, int line) :
89 file(file), line(line)
95 throw InternalError(__FILE__, __LINE__); \
100 #define assert(x) do { \
108 virtual ~Releasable()
112 Releasable(int COUNT) : count(COUNT)
119 fprintf(stderr, "Reference count is %d in release\n", count);
128 class AutoReleasePool {
129 list<const Releasable *> pool;
132 void add(const Releasable *obj)
139 for (list<const Releasable *>::iterator i = pool.begin();
140 i != pool.end(); ++i)
142 const Releasable *obj = *i;
150 extern AutoReleasePool autorelease_pool;
152 template <typename T>
153 class RefCountable : public Releasable {
155 // RefCountable objects should never be assigned to,
156 // as there could be references to the object remaining.
157 // The private assignment operator prevents this, unless
158 // a subclass defines its own assigment operator (don't
160 void operator =(const RefCountable &rc)
165 RefCountable(const RefCountable &rc) : Releasable(1)
171 RefCountable() : Releasable(1)
173 // Normally, this wouldn't be automatic, but this is what most
174 // things in IDLC are going to want, and it elimanates problems
175 // with needing to cast the return type of autorelease().
177 // The automatic autorelease() means that all refcountable objects
178 // must be allocated with "new", not on the stack, as global
179 // data, or as a class member.
184 virtual ~RefCountable()
188 const T *retain() const
191 fprintf(stderr, "Reference count is %d in retain\n", count);
196 return static_cast<const T *>(this);
202 fprintf(stderr, "Reference count is %d in retain\n", count);
207 return static_cast<T *>(this);
210 const T *autorelease() const
212 autorelease_pool.add(static_cast<Releasable *>(this));
213 return static_cast<T *>(this);
218 autorelease_pool.add(static_cast<Releasable *>(this));
219 return static_cast<T *>(this);
222 // This is only here because C++ obnoxiously requires it to
223 // be just because it's "called" from code excluded with an
224 // if (0) in a template. No code is ever generated that calls
225 // it, but it still must exist.
227 bool operator < (const RefCountable &rc)
233 // T must be RefCountable
234 template<typename T, bool compare_ptrs = true>
236 // STL containers like to use const on the items they
237 // contain; the mutable allows such containers to hold
238 // pointers to non-const data. For truly const Refs,
239 // make T const, as in StringRef. Unfortunately,
240 // it cannot be done in a more fine-grained manner,
252 Ref(T *data) : data(data)
258 Ref(Ref &le) : data(le.data)
264 Ref &operator =(const Ref &le)
266 // The retain must come first, in case both Refs are the same
277 Ref &operator =(T *new_data)
279 // The retain must come first, in case both Refs are the same
306 T *operator *() const
311 T *operator ->() const
316 bool operator == (const Ref &le) const
319 return data == le.data;
321 return *data == *le.data;
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 reinterpret_cast<intptr_t>(data) <
336 reinterpret_cast<intptr_t>(le.data);
338 return *data < *le.data;
342 class String : public string, public RefCountable<String> {
344 // Origin of the string, if from the IDL file.
345 // Otherwise, fill both values with zero.
351 String(const char *s = "") : string(s)
358 String(const String &s) : string(s)
365 String(const char *s, const char *file, int line, int token) :
366 string(s), file(file), line(line), token(token)
370 extern String **yylval_string;
371 typedef Ref<const String, false> StringRef;
373 /* If a StrList is used for a namespace-qualified identifier, and
374 said identifier begins with ".." (i.e. starts from the root
375 namespace), the leading ".." is represented by a zero-length
378 Note that list doesn't have a virtual destructor, so all deletions
379 should happen through either RefCountable or the wrapper List
382 class StrList : public list<StringRef>, public RefCountable<StrList> {
388 // Parse a flat String into a StrList, using the specified delimeter.
389 StrList(const String *input, char delimiter = '.');
391 // Turn a StrList into a flat String, using the specified delimiter.
392 String *flatten(const char *delimiter = ".");
395 typedef Ref<StrList> StrListRef;
397 // ConList is like StrList, but with constant initializers
407 // FIXME: handle platforms with weird floating point endianness
413 // TOK_ICON, TOK_UCON, TOK_FCON, TOK_BOOL, TOK_DCON,
414 // TOK_INVALID, or TOK_NONE
415 // Constants are stored as signed (ICON) unless too
416 // large to fit in a signed 64-bit integer. Additional size and
417 // signedness checks are mode when down casting to a smaller size
418 // to fit into a particular datum; such constants will have a
421 // TOK_NONE is valid for maybeconst and size. TOK_INVALID
422 // indicates a previously detected error; don't emit any further
423 // errors due to this constant.
425 // TOK_DCON is used for symbolic constants, whose value may
431 extern Con *yylval_con;
437 ConInit(const String *str, Con &con) : str(str), con(con)
441 ConInit(const ConInit &coninit)
447 class ConList : public list<ConInit>, public RefCountable<ConList> {};
448 typedef Ref<ConList> ConListRef;
450 // Like StrList, but is a list of possibly namespace-qualified identifiers.
451 class IDList : public list<StrListRef>, public RefCountable<IDList> {};
452 typedef Ref<IDList> IDListRef;
458 // This is incremented when a chain of symbols is traversed to reset
459 // detection of already-visited symbols. It is assumed that this
460 // will not have to happen billions of times.
462 extern int traversal;
464 class Symbol : public RefCountable<Symbol> {
470 // Symbol was loaded externally
473 // If set, the symbol is private, and will not be available
474 // for lookups except those made directly in the context of
475 // the containing namespace. Private symbols do not get
476 // outputted. They are used to implement imports of specific
477 // symbols (as aliases), rather than entire namespaces.
481 // This is set to ::traversal when this symbol is visited along a chain.
482 // If a target needs more than 8 simultaneous chains, increase the size
483 // of the array. These traversals are reserved for language binding use.
493 memset(traversed, 0, sizeof(traversed));
496 Symbol(const String *_name) : name(_name)
505 memset(traversed, 0, sizeof(traversed));
510 NameSpace *get_ns() const
515 const String *get_name() const
520 // If append is non-NULL, it is appended to non-user namespaces,
521 // to facilitate a language binding that cannot place nested types
522 // in the same language construct as the actual interface. The
523 // recommended suffix is "_ns", which is a reserved ending in the
524 // IDL. No suffix is placed on the final component of the name,
525 // even if it is a non-user namespace. The not_last field is used
526 // to detect whether it is the final component; it is only used
527 // internally, and should always be false when called externally.
529 // This function does *NOT* add a null first element to indicate
530 // that the name is fully qualified. If you need that, you have
531 // to add it yourself (call 'push_front(new String(""))' on the
534 StrList *get_fq_name(const char *append = NULL,
535 bool not_last = false) const;
537 virtual void lookup_imports()
541 virtual void lookup_chain()
545 virtual void lookup_misc()
549 virtual void final_analysis()
553 // These two methods must be implemented by all IDL symbols, but are
554 // not needed in CDL symbols (and therefore are not pure virtual).
556 virtual void output(const char *root)
560 virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL)
564 // Find and return the topmost symbol other than a user namespace
565 // containing this symbol. If this symbol's parent is a user
566 // namespace, it returns itself. May not be called on the
567 // toplevel namespace.
569 Symbol *find_toplevel_type();
571 // Get the true type of the symbol, regardless of whether it is an
574 virtual Symbol *get_concrete_sym(bool follow_typedefs = true)
579 friend class NameSpace;
582 typedef Ref<Symbol> SymbolRef;
584 class SymList : public list<SymbolRef>, public RefCountable<SymList> {};
585 typedef Ref<SymList> SymListRef;
587 struct SymbolNotFound {
590 struct DuplicateSymbol {
593 struct InvalidArgument {
599 typedef Ref<NameSpace> NameSpaceRef;
601 class NameSpace : public virtual Symbol {
603 // Filesystem path to the external symbol storage, or NULL
604 // if not an import namespace.
606 // Import namespaces are read-only namespaces which are created
607 // for the importation of externally-declared symbols. One is
608 // initially created for each "mount point" specified by the user;
609 // whenever such a namespace is searched, it checks the external
610 // storage, and if the lookup succeeds, the symbol is loaded and
611 // added to the namespace. Failed lookups could be cached with a
612 // special BadSymbol or some such, as the imported namespace is
613 // assumed to be constant, but I don't think such an optimization
614 // is worthwhile, at least at this point.
618 // Load a symbol from external storage, constructing the relevant type
619 // of object, and adding it to this namespace. Only called for
620 // import namespaces.
622 Symbol *load(const String *symname);
624 typedef map<StringRef, SymbolRef> tbl_type;
627 list<StrListRef> import_strs;
628 list<NameSpaceRef> imports;
631 // This is set in the destructor, so the contents of the namespace
632 // don't try to remove themselves from the namespace when destructed
633 // due to the destruction of map.
636 // This is a counter for generating unique names for anonymous
637 // members of the namespace.
640 NameSpace() : dying(0), anon(0)
649 // Return a description of the type of namespace, for
651 virtual const char *description()
656 virtual void output(const char *root);
658 typedef tbl_type::const_iterator const_iterator;
659 typedef tbl_type::value_type value_type;
661 // Derived classes can throw InvalidArgument if you give them
662 // a type of Symbol that they don't accept; see their comments
663 // for more details. Unfortunately, this cannot be done
664 // with static type-checking, as there are places that know
665 // they've been given a namespace that can accept a particular
666 // type of symbol, but they don't know exactly what kind of
667 // namespace it is. C++'s type system is not sufficient to
668 // express this (at least not while retaining any semblance
671 // DuplicateSymbol is thrown if sym already exists in this namespace.
672 virtual void add(Symbol *sym, bool from_import)
674 if (path && !from_import)
675 throw InvalidArgument();
678 sym->external = true;
683 pair<const_iterator, bool> ret = tbl.insert(value_type(sym->name, sym));
688 throw DuplicateSymbol();
692 // Add the symbol to this namespace, handling duplicate symbols by
693 // printing an error and throwing a UserError(). This should not be
694 // done in the symbol's constructor, as the parent may not accept
695 // the symbol until it is fully constructed (the RTTI information
696 // changes, and in general partially constructed objects shouldn't
697 // be exposed to the rest of the system).
699 void add_user(Symbol *sym);
701 // Like add_user, but used by the import code. Duplicate
702 // symbols result in internal errors, and the add is done with
703 // from_import set to true. InvalidArgument results in an error
704 // message and a reraise as UserError.
706 // All conditions checked by the parent namespace's add() method
707 // (such as constness of data) must be satisfied prior to calling
708 // add_import(). On the other hand, add_import() must be called
709 // before any recursive importation is done which could
710 // conceivably try to import the current symbol (thus causing
711 // infinite recursion).
713 void add_import(Symbol *sym, const char *filename);
715 // SymbolNotFound is thrown if sym is not in this namespace.
716 virtual void del(Symbol *sym)
718 fprintf(stderr, "Removing symbol %s\n",
719 sym->get_fq_name()->flatten()->c_str());
721 if (tbl.erase(sym->name) == 0)
722 throw SymbolNotFound();
728 Symbol *lookup_noex_noimport(const String *symname)
730 const_iterator ret = tbl.find(symname);
732 if (ret != tbl.end())
733 return (*ret).second;
739 Symbol *lookup_noex(const String *symname, bool priv_ok = false)
741 Symbol *ret = NameSpace::lookup_noex_noimport(symname);
746 if (ret && !priv_ok && ret->priv)
752 Symbol *lookup(const String *symname, bool priv_ok = false)
754 Symbol *ret = lookup_noex(symname, priv_ok);
757 throw SymbolNotFound();
762 // Like lookup_noex, but also checks imported namespaces,
763 // and returns the namespace containing the match rather
764 // than the match itself.
766 NameSpace *search(const String *name, Symbol *exclude);
768 void add_search(StrList *ns)
770 import_strs.push_back(ns);
773 // Return a string containing case information manglement.
774 // See input.cc for more information.
776 static const String *mangle(const String *name);
778 const String *get_path()
783 // Import all members of this namespace. A no-op if not an import
787 // As import_all, but also recursively applies to any sub-namespaces.
788 void import_all_recursive();
790 const_iterator begin()
800 virtual void lookup_imports();
802 virtual void lookup_chain()
804 for (const_iterator i = begin(); i != end(); ++i) {
805 Symbol *sym = (*i).second;
810 virtual void lookup_misc()
812 for (const_iterator i = begin(); i != end(); ++i) {
813 Symbol *sym = (*i).second;
818 virtual void final_analysis()
820 for (const_iterator i = begin(); i != end(); ++i) {
821 Symbol *sym = (*i).second;
822 sym->final_analysis();
828 extern NameSpaceRef cur_nspace;
829 extern list<NameSpaceRef> nspace_stack;
831 typedef std::vector<StringRef> StringVec;
833 string *stringvec_to_path(StringVec &stringvec, const char *prepend);
835 // lookup_sym and lookup_type throw UserError on user error
836 // The context namespace is required for the proper
837 // set of namespaces to be searched.
839 Symbol *lookup_sym(NameSpace *topns, StrList *name, NameSpace *ctx,
840 Symbol *exclude = NULL);
843 const char *self; // Pointer to the type-specific struct
844 int self_len; // Length of the type-specific struct
847 CompiledDefHeader hdr;
849 // sym is the symbol from which to get the path/name, and
850 // dir is true if it should be "name/.self" rather than
852 void output_self(const char *dir, Symbol *sym, bool dir);
855 Def(const char *self, int self_len, CompiledDefHeader::Type type) :
856 self(self), self_len(self_len)
858 hdr.magic = CompiledDefHeader::magic_normal;
866 // Specific types may override this to output extra data
867 // to the .self file without having to reopen the file.
869 // Returns false on error.
871 virtual bool output_extra(FILE *f)
877 // Internal context struct used by input.cc to avoid passing
878 // lots of parameters around
879 struct ImportContext;
881 // This represents an actual IDL namespace {}, rather than
882 // a derived namespace such as a Struct or Interface.
884 class UserNameSpace : public NameSpace, public Def {
886 CompiledNameSpace def;
887 StringRef mountpoint_name;
889 UserNameSpace(const String *name = NULL) :
891 Def((const char *)&def, sizeof(def), CompiledDefHeader::NameSpace)
893 mountpoint_name = get_fq_name()->flatten();
894 def.length = mountpoint_name->length();
897 virtual void output(const char *root);
898 bool output_extra(FILE *f);
900 static void declare_import(const char *path);
902 static UserNameSpace *import(ImportContext &ctx);
903 virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
906 typedef Ref<UserNameSpace> UserNameSpaceRef;
907 extern UserNameSpaceRef toplevel, cdl_toplevel;
908 extern UserNameSpace *output_ns;
910 class Type : public virtual Symbol {
920 virtual int get_default_bf_size()
922 // Only allow types in bitfields that explicitly
929 typedef Ref<Type> TypeRef;
931 // ctx can be NULL if basic_types_only is true
932 Type *lookup_type(StrList *sl, NameSpace *ctx, bool basic_types_only = false);
934 class BasicType : public Type, public Def {
936 CompiledBasicType def;
939 BasicType(const String *name) :
941 Def((const char *)&def, sizeof(def), CompiledDefHeader::BasicType)
944 memset(&def, 0, sizeof(def));
947 void init(CompiledBasicType &DEF)
955 static BasicType *declare(const String *name, NameSpace *parent,
956 CompiledBasicType &DEF)
958 BasicType *bt = new BasicType(name);
962 parent->add_user(bt);
967 virtual void output(const char *root);
969 static BasicType *import(ImportContext &ctx);
970 virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
973 static inline bool is_array(CompiledBasicType &bt)
975 return bt.array.bounds[0] || bt.array.bounds[1];
978 static inline bool is_array(CompiledBasicType *bt)
980 return is_array(*bt);
983 typedef Ref<Datum> DatumRef;
985 class Array : public RefCountable<Array>
987 NameSpace *lookup_ctx;
990 // lower is [0], upper is [1]
994 // Strings for error reporting on each constant. If the constant
995 // is symbolic, then this is the fully qualified symbol name.
996 // Otherwise, it is the numerical value converted to a string. In
997 // each case, the file/line shall correspond to where the array
998 // bound was specified.
1003 // ca is not valid until after final_analysis() is called.
1006 Array(NameSpace *LOOKUP_CTX);
1007 void set_bound(Con &con, int bound);
1008 void final_analysis();
1010 void set_unbounded();
1013 typedef Ref<Array> ArrayRef;
1015 class Datum : public Symbol, public Def {
1016 StrListRef type_name;
1018 StringRef type_fq_name;
1020 StrListRef const_val_name;
1021 SymbolRef const_val_sym;
1024 bool basic; // Datum is of a BasicType
1026 bool const_init; // Datum's constant has been initialized; this is
1027 // true after a successful verify_const().
1028 CompiledBasicType *cbt;
1032 int chain_traversed;
1034 // Recursively retrieve the actual value of a const datum
1035 // initialized with another named const datum. Returns
1036 // the "end" of an infinite loop, if one is found. Once
1037 // the full infinite loop has been printed, UserError is
1040 Datum *resolve_constant_chain();
1042 void init_const_early(Con *con);
1044 void use_anon_type(const CompiledBasicType &CBT)
1046 def.basictype = CBT;
1047 cbt = &def.basictype;
1050 def.type.length = 0;
1053 void process_type();
1055 void set_array(Array *ARRAY)
1065 int con_type; // Used to store the TOK_[IUF]CON of the Con struct
1066 // for type checking once the type is known.
1068 Datum(const String *name) :
1070 Def((const char *)&def, sizeof(def), CompiledDefHeader::Datum)
1074 chain_traversed = 0;
1075 memset(&def, 0, sizeof(def));
1078 void init(StrList *type, Array *ARRAY, Con *con = NULL);
1079 void init(CompiledBasicType &cbt, Array *ARRAY, Con *con = NULL);
1081 static Datum *declare(const String *name, NameSpace *parent,
1082 StrList *type, Array *ARRAY,
1087 Datum *d = new Datum(name);
1088 d->init(type, ARRAY, con);
1090 parent->add_user(d);
1094 static Datum *declare(const String *name, NameSpace *parent,
1095 CompiledBasicType &type,
1096 Array *ARRAY, Con *con = NULL)
1100 Datum *d = new Datum(name);
1101 d->init(type, ARRAY, con);
1103 parent->add_user(d);
1109 def.flags.field.Inline = 1;
1114 return def.flags.field.Inline;
1117 void set_immutable()
1119 def.flags.field.Immutable = 1;
1124 return def.flags.field.Immutable;
1127 // Returns true if the constant was acceptable, false otherwise (an
1128 // error is also output to the user in this case).
1130 bool verify_const();
1132 virtual void lookup_chain()
1137 const_val_sym = lookup_sym(toplevel, const_val_name, get_ns());
1141 type_sym = lookup_type(type_name, get_ns(), true);
1143 type_sym = lookup_sym(toplevel, type_name, get_ns());
1149 virtual void lookup_misc()
1151 if (def.flags.field.Const) {
1153 assert(def.flags.field.Const);
1156 Datum *d = resolve_constant_chain();
1166 virtual void final_analysis();
1168 virtual void output(const char *root);
1169 bool output_extra(FILE *f);
1171 static Datum *import(ImportContext &ctx);
1172 virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
1174 uint64_t get_ucon(const String *err_str)
1176 if (!def.flags.field.Const) {
1177 yyerrorfl(err_str->file, err_str->line,
1178 "\"%s\" is not a const Datum.\n",
1179 get_fq_name()->flatten()->c_str());
1189 return ::is_array(def.basictype);
1193 template<typename T>
1194 bool output_list(T *sym, FILE *f);
1196 class BitField : public NameSpace, public Type, public Def {
1197 list<DatumRef> entries;
1199 void add_elem(Datum *d);
1202 CompiledBitField def;
1205 BitField(const String *name) :
1207 Def((const char *)&def, sizeof(def), CompiledDefHeader::BitField)
1209 memset(&def, 0, sizeof(def));
1212 void init(int bits, NameSpace *parent)
1214 if (bits < 0 || bits > 64) {
1215 yyerrorf("\"%s\" has invalid bitfield size %d",
1216 name->c_str(), bits);
1218 bits = bits < 0 ? 0 : 64;
1224 static BitField *declare(const String *name, NameSpace *parent,
1229 BitField *bf = new BitField(name);
1230 bf->init(bits, parent);
1232 parent->add_user(bf);
1236 // Only integral Datums, Enums, and BitFields can be added.
1238 void add(Symbol *sym, bool from_import);
1240 virtual const char *description()
1245 virtual void lookup_misc()
1247 NameSpace::lookup_misc();
1250 virtual void final_analysis()
1252 // FIXME: check total size of elements
1254 NameSpace::final_analysis();
1257 int get_default_bf_size()
1262 virtual void output(const char *root);
1263 bool output_extra(FILE *f);
1265 static BitField *import(ImportContext &ctx);
1266 virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
1268 typedef list<DatumRef>::const_iterator entries_iterator;
1269 typedef list<DatumRef>::const_reverse_iterator entries_reverse_iterator;
1271 entries_iterator entries_begin()
1273 return entries.begin();
1276 entries_iterator entries_end()
1278 return entries.end();
1281 entries_reverse_iterator entries_rbegin()
1283 return entries.rbegin();
1286 entries_reverse_iterator entries_rend()
1288 return entries.rend();
1293 typedef Ref<Struct> StructRef;
1294 extern Struct *System_VStruct;
1296 // FIXME: typedefed superstructs
1297 class Struct : public NameSpace, public Type, public Def {
1298 list<DatumRef> entries;
1301 StrListRef supername;
1302 bool attrs_resolved;
1304 void add_elem(Datum *d);
1306 void resolve_attrs()
1311 if (super && !super->attrs_resolved)
1312 super->resolve_attrs();
1314 if (super && super->def.flags.field.Virtual)
1315 def.flags.field.Virtual = 1;
1317 attrs_resolved = true;
1323 // This is not maintained by the generic code, but can be
1324 // used by language bindings to cache the result of the
1329 Struct(const String *name) :
1331 Def((const char *)&def, sizeof(def), CompiledDefHeader::Struct)
1333 memset(&def, 0, sizeof(def));
1337 void init(StrList *SUPERNAME)
1339 supername = SUPERNAME;
1342 static Struct *declare(const String *name, NameSpace *parent,
1347 Struct *st = new Struct(name);
1348 st->init(SUPERNAME);
1350 parent->add_user(st);
1356 def.flags.field.Virtual = 1;
1361 def.flags.field.Inline = 1;
1366 return def.flags.field.Virtual;
1371 return def.flags.field.Inline;
1374 // Only Datums and Types can be added.
1376 void add(Symbol *sym, bool from_import);
1378 virtual const char *description()
1385 assert(current_pass >= 4);
1389 virtual void lookup_chain()
1392 supersym = lookup_sym(toplevel, supername, get_ns());
1396 NameSpace::lookup_chain();
1402 if (supersym && !super) {
1403 super = dynamic_cast<Struct *>(supersym->get_concrete_sym());
1406 const String *str = supername->back();
1407 yyerrorfl(str->file, str->line,
1408 "\"%s\" is not a struct.",
1409 supersym->get_fq_name()->flatten()->c_str());
1412 def.flags.field.Super = 1;
1413 super->lookup_super();
1415 if (super->is_virtual())
1419 if (is_virtual() && !supersym && !super) {
1420 assert(System_VStruct);
1421 if (this != System_VStruct) {
1422 def.flags.field.Super = 1;
1423 super = System_VStruct;
1429 virtual void lookup_misc()
1433 if (is_virtual() && def.guid[0] == 0 && def.guid[1] == 0)
1434 yyerrorfl(name->file, name->line,
1435 "Virtual struct \"%s\" is missing a GUID.",
1436 get_fq_name()->flatten()->c_str());
1438 NameSpace::lookup_misc();
1441 virtual void final_analysis()
1443 // FIXME: check for infinite loops in struct inheritance
1446 NameSpace::final_analysis();
1449 virtual void output(const char *root);
1450 bool output_extra(FILE *f);
1452 static Struct *import(ImportContext &ctx);
1453 virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
1455 typedef list<DatumRef>::const_iterator entries_iterator;
1457 entries_iterator entries_begin()
1459 return entries.begin();
1462 entries_iterator entries_end()
1464 return entries.end();
1467 void set_guid(uint64_t guid[2])
1469 if (def.guid[0] || def.guid[1])
1470 yyerrorf("\"%s\" already has a GUID.",
1471 get_fq_name()->flatten()->c_str());
1473 def.guid[0] = guid[0];
1474 def.guid[1] = guid[1];
1478 class Param : public Symbol, public Def {
1479 StrListRef type_name;
1480 StringRef type_fq_name;
1482 bool basic; // Datum is of a BasicType
1487 void use_named_type(BasicType *bt)
1489 assert(!bt || bt->def.flags.field.TypeDef);
1493 type_fq_name = type->get_fq_name()->flatten();
1494 def.type.length = type_fq_name->length();
1497 void use_anon_type(const CompiledBasicType &cbt)
1499 def.basictype = cbt;
1504 void set_array(Array *ARRAY)
1514 Param(const String *name) :
1516 Def((const char *)&def, sizeof(def), CompiledDefHeader::Param)
1518 memset(&def, 0, sizeof(def));
1521 void init(StrList *TYPE, CompiledParam::Flags flags, Array *ARRAY)
1528 static Param *declare(const String *name, NameSpace *parent,
1529 StrList *TYPE, CompiledParam::Flags flags,
1532 virtual void lookup_misc()
1534 type = lookup_type(type_name, get_ns());
1537 virtual void final_analysis()
1539 BasicType *bt = dynamic_cast<BasicType *>(type->get_concrete_sym());
1541 if (bt && !bt->def.flags.field.TypeDef) {
1542 use_anon_type(bt->def);
1546 Struct *str = dynamic_cast<Struct *>(*type);
1547 if (str && str->is_inline())
1550 if (!str && is_inline()) {
1551 yyerrorfl(name->file, name->line,
1552 "\"%s\" is static but not a struct.",
1553 get_fq_name()->flatten()->c_str());
1558 array->final_analysis();
1559 def.basictype.array = array->ca;
1561 def.basictype.array.bounds[0] = 0;
1562 def.basictype.array.bounds[1] = 0;
1568 def.flags.field.Inline = 1;
1573 return def.flags.field.Inline;
1578 return def.flags.field.In;
1583 return def.flags.field.Out;
1586 virtual void output(const char *root);
1587 bool output_extra(FILE *f);
1589 static Param *import(ImportContext &ctx);
1590 virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
1594 return ::is_array(def.basictype);
1598 typedef Ref<Param> ParamRef;
1600 class Method : public NameSpace, public Def {
1601 list<ParamRef> entries;
1603 void add_elem(Param *p);
1608 Method(const String *name) :
1610 Def((const char *)&def, sizeof(def), CompiledDefHeader::Method)
1612 memset(&def, 0, sizeof(def));
1617 def.flags.field.Async = 1;
1622 return def.flags.field.Async;
1625 static Method *declare(const String *name, NameSpace *parent);
1627 void add(Symbol *sym, bool from_import);
1629 virtual const char *description()
1634 virtual void output(const char *root);
1635 bool output_extra(FILE *f);
1637 static Method *import(ImportContext &ctx);
1638 virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
1640 typedef list<ParamRef>::const_iterator entries_iterator;
1642 entries_iterator entries_begin()
1644 return entries.begin();
1647 entries_iterator entries_end()
1649 return entries.end();
1653 typedef Ref<Method> MethodRef;
1656 typedef Ref<Interface> InterfaceRef;
1658 extern Interface *System_Object;
1660 // FIXME: typedefed superinterfaces
1661 class Interface : public NameSpace, public Type, public Def {
1662 list<MethodRef> methods;
1663 list<InterfaceRef> supers;
1664 IDListRef supernames;
1666 void add_elem(Method *m);
1668 // This is like Symbol::traversed[], but used internally by the
1669 // for_each_super function to ensure that common ancestors are only
1672 int traversed_all_supers;
1673 static int all_supers_traversal;
1676 typedef void (*callback)(Interface *i, void *arg);
1679 template<callback cb>
1680 void for_each_super_internal(void *arg)
1682 for (supers_iterator i = supers_begin(); i != supers_end(); ++i) {
1683 Interface *iface = *i;
1685 if (iface->traversed_all_supers < all_supers_traversal) {
1686 iface->traversed_all_supers = all_supers_traversal;
1688 iface->for_each_super_internal<cb>(arg);
1693 // All interfaces in the map and vector are supers of this
1694 // interface, and thus retained that way, so plain pointers
1695 // can be used here.
1697 typedef map<Interface *, int> chain_map_type;
1698 typedef chain_map_type::value_type chain_valtype;
1699 typedef chain_map_type::const_iterator chain_iter;
1701 chain_map_type super_to_chain_map;
1705 vector<Interface *> chain_heads;
1708 int super_to_chain(Interface *iface, bool must_find_it = true)
1710 chain_iter ret = super_to_chain_map.find(iface);
1712 if (ret == super_to_chain_map.end()) {
1713 assert(!must_find_it);
1717 return (*ret).second;
1720 Interface *get_chain_head(int chain)
1722 return chain_heads[chain];
1725 int get_num_chains()
1731 void set_chain(Interface *iface, int chain)
1733 pair<chain_iter, bool> ret =
1734 super_to_chain_map.insert(chain_valtype(iface, chain));
1738 // This is the inner depth-first search, which terminates
1739 // at each level upon finding that the node it had previously
1740 // recursed into found an unchained node.
1742 void pick_chain(Interface *iface, int chain)
1744 assert(super_to_chain(iface, false) == -1);
1745 chain_heads.push_back(iface);
1748 set_chain(iface, chain);
1750 if (iface->supers.empty())
1753 iface = iface->supers.front();
1754 } while (super_to_chain(iface, false) == -1);
1757 // This is the outer breadth-first-search, making sure every
1758 // super is assigned to a chain.
1762 list<Interface *> bfs;
1765 bfs.push_back(this);
1767 while (!bfs.empty()) {
1768 Interface *iface = bfs.front();
1771 for (supers_iterator i = iface->supers_begin();
1772 i != iface->supers_end(); ++i)
1775 if (super_to_chain(iface, false) == -1)
1776 pick_chain(iface, num_chains++);
1781 // Do not call after lookup_misc
1782 void add_super(Interface *i)
1784 assert(current_pass != 1);
1786 supers.push_back(i);
1790 CompiledInterface def;
1792 Interface(const String *name) :
1794 Def((const char *)&def, sizeof(def), CompiledDefHeader::Interface)
1796 memset(&def, 0, sizeof(def));
1797 traversed_all_supers = 0;
1800 void init(IDList *SUPERNAMES)
1802 supernames = SUPERNAMES;
1805 static Interface *declare(const String *name, NameSpace *parent,
1810 Interface *i = new Interface(name);
1811 i->init(SUPERNAMES);
1813 parent->add_user(i);
1817 // Only Methods, Types, and const BasicType Datums can be added.
1819 void add(Symbol *sym, bool from_import);
1821 virtual const char *description()
1827 void add_object_super()
1829 assert(System_Object);
1830 if (this != System_Object && supers.empty())
1831 add_super(System_Object);
1835 virtual void lookup_misc()
1837 if (def.guid[0] == 0 && def.guid[1] == 0)
1838 yyerrorfl(name->file, name->line,
1839 "Interface \"%s\" is missing a GUID.",
1840 get_fq_name()->flatten()->c_str());
1843 for (IDList::iterator i = supernames->begin();
1844 i != supernames->end(); ++i)
1846 Symbol *sym = lookup_sym(toplevel, *i, get_ns());
1848 dynamic_cast<Interface *>(sym->get_concrete_sym());
1851 const String *str = (*i)->back();
1852 yyerrorfl(str->file, str->line,
1853 "\"%s\" is not an interface.\n",
1854 sym->get_fq_name()->flatten()->c_str());
1864 NameSpace::lookup_misc();
1867 virtual void final_analysis()
1869 // FIXME: check for infinite loops in inheritance
1872 NameSpace::final_analysis();
1875 virtual void output(const char *root);
1876 bool output_extra(FILE *f);
1878 static Interface *import(ImportContext &ctx);
1879 virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
1881 typedef list<MethodRef>::const_iterator methods_iterator;
1882 typedef list<InterfaceRef>::const_iterator supers_iterator;
1884 supers_iterator supers_begin()
1886 assert(current_pass != 1);
1887 return supers.begin();
1890 supers_iterator supers_end()
1892 return supers.end();
1897 assert(current_pass != 1);
1898 return supers.empty();
1901 methods_iterator methods_begin()
1903 return methods.begin();
1906 methods_iterator methods_end()
1908 return methods.end();
1911 template<callback cb>
1912 void for_each_super(void *arg)
1914 assert(current_pass >= 4);
1916 all_supers_traversal++;
1917 for_each_super_internal<cb>(arg);
1920 void finalize_class_iface()
1926 void set_guid(uint64_t guid[2])
1928 if (def.guid[0] || def.guid[1])
1929 yyerrorf("\"%s\" already has a GUID.",
1930 get_fq_name()->flatten()->c_str());
1932 def.guid[0] = guid[0];
1933 def.guid[1] = guid[1];
1937 class IFaceList : public list<InterfaceRef>,
1938 public RefCountable<IFaceList> {};
1940 class Enum : public NameSpace, public Type, public Def {
1941 list<DatumRef> entries;
1943 void add_elem(Datum *d);
1946 unsigned int next_val;
1949 Enum(const String *name) :
1951 Def((const char *)&def, sizeof(def), CompiledDefHeader::Enum),
1954 memset(&def, 0, sizeof(def));
1959 if (bits < 0 || bits > 64) {
1960 yyerrorf("\"%s\" has invalid enum size %d",
1961 name->c_str(), bits);
1963 bits = bits < 0 ? 0 : 64;
1969 static Enum *declare(const String *name, NameSpace *parent,
1974 Enum *e = new Enum(name);
1977 parent->add_user(e);
1981 // Only const unsigned integer BasicType Datums are allowed.
1983 void add(Symbol *sym, bool from_import);
1985 virtual const char *description()
1987 return "enumeration";
1990 int get_default_bf_size()
1995 virtual void output(const char *root);
1996 bool output_extra(FILE *f);
1998 static Enum *import(ImportContext &ctx);
1999 virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
2001 typedef list<DatumRef>::const_iterator entries_iterator;
2003 entries_iterator entries_begin()
2005 return entries.begin();
2008 entries_iterator entries_end()
2010 return entries.end();
2014 class Alias : public Symbol, public Def {
2020 Cycle(Alias *END) : end(END)
2029 StringRef sym_fq_name;
2030 StrListRef sym_name;
2032 Alias(const String *name) :
2034 Def((const char *)&def, sizeof(def), CompiledDefHeader::Alias)
2036 memset(&def, 0, sizeof(def));
2037 lookup_begun = false;
2040 void init(StrList *symname, bool is_private)
2046 static Alias *declare(const String *name, NameSpace *parent,
2047 StrList *symname, bool is_private = false)
2050 Alias *a = new Alias(name);
2051 a->init(symname, is_private);
2053 parent->add_user(a);
2057 void resolve_chain()
2061 yyerrorfl(name->file, name->line,
2062 "Alias loop defining \"%s\"",
2063 get_fq_name()->flatten()->c_str());
2068 lookup_begun = true;
2071 real_sym = lookup_sym(toplevel, sym_name, get_ns(), this);
2075 yyerrorfl(name->file, name->line, " ...referenced by \"%s\"",
2076 get_fq_name()->flatten()->c_str());
2086 virtual Symbol *get_concrete_sym(bool follow_typedefs = true)
2089 return real_sym->get_concrete_sym(follow_typedefs);
2092 virtual void lookup_chain()
2094 get_concrete_sym(true);
2097 virtual void lookup_misc()
2099 real_sym = real_sym->get_concrete_sym(false);
2100 sym_fq_name = real_sym->get_fq_name()->flatten();
2102 def.length = sym_fq_name->length();
2105 virtual void output(const char *root);
2106 bool output_extra(FILE *f);
2108 static Alias *import(ImportContext &ctx);
2109 virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
2112 class TypeDef : public Alias {
2114 TypeDef(const String *name) : Alias(name)
2116 memset(&def, 0, sizeof(def));
2117 hdr.type = CompiledDefHeader::TypeDef;
2120 static TypeDef *declare(const String *name, NameSpace *parent,
2124 TypeDef *td = new TypeDef(name);
2125 td->init(symname, false);
2127 parent->add_user(td);
2131 virtual Symbol *get_concrete_sym(bool follow_typedefs = true)
2133 if (follow_typedefs) {
2135 return real_sym->get_concrete_sym(follow_typedefs);
2141 static TypeDef *import(ImportContext &ctx);
2142 virtual void output_lang(LangCallback *lcb, int arg = 0, void *arg2 = NULL);
2145 NameSpace *add_nspace(StrList *name, bool push);
2148 // Declare an instance of "type" in "ns" for each element of "ids".
2149 // This function will report any errors, but not throw UserError.
2151 void declare_data(NameSpace *ns, StrList *ids, StrList *type,
2152 Array *array, StrList *attr);
2153 void declare_aliases(NameSpace *ns, StrList *ids, StrList *type,
2155 void declare_basictypes(NameSpace *ns, StrList *ids,
2156 BasicType *type, bool is_typedef);
2158 // You'd think they'd have standard functions to do this these days.
2159 // All I could find that come close are the network-byte-order
2160 // functions, and they're no-ops on big-endian machines.
2162 static inline uint32_t swap32(uint32_t in, bool swap)
2165 return ((in & 0x000000ff) << 24) |
2166 ((in & 0x0000ff00) << 8) |
2167 ((in & 0x00ff0000) >> 8) |
2168 ((in & 0xff000000) >> 24);
2173 static inline uint64_t swap64(uint64_t in, bool swap)
2176 return (((uint64_t)swap32((uint32_t)in, true)) << 32) |
2177 swap32((uint32_t)(in >> 32), true);
2195 File *operator =(FILE *F)
2213 // Verify that a prospective new import (or output namespace)
2214 // does not overlap an existing import. Returns the conflicting
2215 // import, or NULL if none found.
2217 NameSpace *check_for_imports(NameSpace *ns);