1 /* types.cc -- Semantic actions for types and namespaces.
3 * Written by Scott Wood <scott@buserror.net>
13 bool Datum::verify_const()
15 assert(def.flags.field.Const);
17 // TOK_INVALID should have caused an abort in an earlier pass, and
18 // TOK_DCON should have been replaced by the final constant by now.
20 assert(con_type == TOK_ICON || con_type == TOK_UCON ||
21 con_type == TOK_FCON || con_type == TOK_BOOL);
23 if (cbt->flags.field.Float) {
24 if (con_type == TOK_UCON)
25 def.fcon = static_cast<double>(def.ucon);
26 else if (con_type == TOK_ICON)
27 def.fcon = static_cast<double>(def.icon);
28 else if (con_type == TOK_BOOL) {
29 yyerrorfl(name->file, name->line,
30 "%s is of floating-point type, but is initialized with "
31 "a boolean constant.", name->c_str());
38 if (cbt->bits == 32) {
39 if (def.fcon > FLT_MAX || def.fcon < FLT_MIN) {
40 yyerrorfl(name->file, name->line,
41 "%s is out of range for a single-precision FP datum.",
52 if (con_type == TOK_FCON) {
53 yyerrorfl(name->file, name->line,
54 "%s is of %s type, but is initialized with "
55 "a floating-point constant.",
56 cbt->flags.field.Bool ? "boolean" : "integral",
62 if (cbt->flags.field.Bool) {
63 if (con_type != TOK_BOOL) {
64 yyerrorfl(name->file, name->line,
65 "%s is of boolean type, but is initialized with "
66 "a non-boolean constant.", name->c_str());
71 assert(def.ucon == 0 || def.ucon == 1);
77 if (con_type == TOK_BOOL) {
78 yyerrorfl(name->file, name->line,
79 "%s is of integral type, but is initialized with "
80 "a boolean constant.", name->c_str());
85 if (cbt->flags.field.Unsigned) {
86 if (con_type == TOK_ICON && def.icon < 0) {
87 yyerrorfl(name->file, name->line,
88 "Initializer for \"%s\" is out of range.",
94 uint64_t max = (1ULL << cbt->bits) - 1;
97 yyerrorfl(name->file, name->line,
98 "Initializer for \"%s\" is out of range.",
104 if (con_type == TOK_UCON && def.icon < 0) {
105 yyerrorfl(name->file, name->line,
106 "Initializer for \"%s\" is out of range.",
111 if (cbt->bits < 64) {
112 // Yes, the constant should be unsigned before conversion,
113 // as the temporary value could overflow a signed datum
114 // before the one is subtracted if bits == 63. It won't
115 // matter on most machines, but you never know...
117 int64_t max = (1ULL << (cbt->bits - 1)) - 1;
119 if (def.icon > max || def.icon < -max + 1) {
120 yyerrorfl(name->file, name->line,
121 "Initializer for \"%s\" is out of range.",
132 void Datum::init_const_early(Con *con)
135 if (con->type == TOK_DCON) {
136 assert(current_pass == 1);
137 const_val_name = con->con.dcon;
140 def.flags.field.Const = 1;
141 con_type = con->type;
142 def.ucon = con->con.ucon;
146 void Datum::init(StrList *type, Array *ARRAY, Con *con)
157 init_const_early(con);
160 void Datum::init(CompiledBasicType &CBT, Array *ARRAY, Con *con)
165 cbt = &def.basictype;
171 init_const_early(con);
174 void Datum::process_type()
176 assert(current_pass >= 4);
181 assert(!type_fq_name);
184 Symbol *sym = type_sym->get_concrete_sym(false);
185 type = dynamic_cast<Type *>(sym);
188 const String *str = type_name->back();
189 yyerrorfl(str->file, str->line, "\"%s\" is not a type.",
190 sym->get_fq_name()->flatten()->c_str());
195 BasicType *bt = dynamic_cast<BasicType *>(type->get_concrete_sym());
198 if (!bt->def.flags.field.TypeDef)
199 use_anon_type(bt->def);
202 } else if (const_val) {
203 const String *str = type_name->back();
204 yyerrorfl(str->file, str->line,
205 "\"%s\" is not a basic type (and thus \"%s\" cannot "
207 type->get_fq_name()->flatten()->c_str(),
213 type_fq_name = type->get_fq_name()->flatten();
214 def.type.length = type_fq_name->length();
218 Datum *Datum::resolve_constant_chain()
220 if (chain_traversed == traversal) {
221 yyerrorfl(name->file, name->line,
222 "Initialization of \"%s\" forms an infinite loop:",
223 get_fq_name()->flatten()->c_str());
227 chain_traversed = traversal;
235 const_val = dynamic_cast<Datum *>(const_val_sym->get_concrete_sym());
238 const String *str = const_val_name->back();
239 yyerrorfl(str->file, str->line, "\"%s\" is not a datum.",
240 const_val_sym->get_fq_name()->flatten()->c_str());
244 if (!const_val->def.flags.field.Const) {
245 const String *str = const_val_name->back();
246 yyerrorfl(str->file, str->line, "\"%s\" is not a constant.",
247 const_val->get_fq_name()->flatten()->c_str());
251 if (!const_val->const_init) {
252 Datum *d = const_val->resolve_constant_chain();
254 yyerrorfl(name->file, name->line, "...initializes \"%s\"",
255 get_fq_name()->flatten()->c_str());
264 assert(const_val->const_init);
266 con_type = const_val->con_type;
267 def.ucon = const_val->def.ucon;
277 // FIXME: Check for inline struct loops.
278 void Datum::final_analysis()
280 Struct *str = dynamic_cast<Struct *>(*type);
281 if (str && str->is_inline())
285 array->final_analysis();
286 def.basictype.array = array->ca;
288 def.basictype.array.bounds[0] = 0;
289 def.basictype.array.bounds[1] = 0;
292 BitField *bfparent = dynamic_cast<BitField *>(get_ns());
300 defsize = type->get_default_bf_size();
303 yyerrorfl(name->file, name->line,
304 "\"%s\" may not be the named type of bitfield entry "
305 "\"%s\", as it is not a bitfield or enumeration.",
306 type->get_fq_name()->flatten()->c_str(),
307 get_fq_name()->flatten()->c_str());
308 } else if (def.icon == -1) {
310 } else if (def.ucon < (unsigned int)defsize) {
311 yyerrorfl(name->file, name->line,
312 "Explicit size %llu on \"%s\" is too small for "
313 "type \"%s\", which has a minimum size of %u",
314 def.ucon, get_fq_name()->flatten()->c_str(),
315 type->get_fq_name()->flatten()->c_str(), defsize);
320 void Struct::add(Symbol *sym, bool from_import)
322 Datum *datum = dynamic_cast<Datum *>(sym);
324 if (!datum && !dynamic_cast<Alias *>(sym) &&
325 !dynamic_cast<Type *>(sym) &&
326 !dynamic_cast<Method *>(sym))
327 throw InvalidArgument();
329 NameSpace::add(sym, from_import);
331 if (!from_import && datum && !datum->def.flags.field.Const)
335 void Struct::add_elem(Datum *d)
337 entries.push_back(d);
341 Param *Param::declare(const String *name, NameSpace *parent,
342 StrList *TYPE, CompiledParam::Flags flags,
346 assert(dynamic_cast<Method *>(parent));
348 Param *p = new Param(name);
349 p->init(TYPE, flags, array);
355 Method *Method::declare(const String *name, NameSpace *parent)
358 assert(dynamic_cast<Interface *>(parent));
360 Method *m = new Method(name);
366 void Interface::add(Symbol *sym, bool from_import)
368 Datum *datum = dynamic_cast<Datum *>(sym);
369 Method *method = dynamic_cast<Method *>(sym);
371 if (!datum && !method &&
372 !dynamic_cast<Alias *>(sym) &&
373 !dynamic_cast<Type *>(sym))
374 throw InvalidArgument();
376 if (datum && !datum->def.flags.field.Const)
377 throw InvalidArgument();
379 NameSpace::add(sym, from_import);
381 if (!from_import && method)
385 // FIXME: check for duplicate and looping inheritance
386 void Interface::add_elem(Method *method)
388 methods.push_back(method);
392 void Enum::add(Symbol *sym, bool from_import)
394 Datum *datum = dynamic_cast<Datum *>(sym);
396 // It also must be const unsigned, but the const won't
397 // have been initialized yet.
400 throw InvalidArgument();
402 NameSpace::add(sym, from_import);
408 void Enum::add_elem(Datum *datum)
410 entries.push_back(datum);
414 void BitField::add(Symbol *sym, bool from_import)
416 Datum *datum = dynamic_cast<Datum *>(sym);
418 if (!datum && !dynamic_cast<Enum *>(sym) &&
419 !dynamic_cast<BitField *>(sym))
420 throw InvalidArgument();
422 NameSpace::add(sym, from_import);
424 if (!from_import && datum)
428 void BitField::add_elem(Datum *datum)
430 entries.push_back(datum);
434 void Method::add(Symbol *sym, bool from_import)
436 Param *param = dynamic_cast<Param *>(sym);
439 throw InvalidArgument();
441 NameSpace::add(sym, from_import);
446 void Method::add_elem(Param *param)
448 entries.push_back(param);
452 // Use this rather than lookup_sym if you want to check for built-in types.
453 // If only constructed types are valid, use lookup_sym. If basic_types_only
454 // is set, then NULL will be returned if sl does not describe a built-in
455 // basic type (such as int, flong, octet, etc). This option is used so that
456 // the first-pass code in idlparse.y can decide whether to create a BasicType
457 // or an Alias/TypeDef.
459 Type *lookup_type(StrList *sl, NameSpace *ctx, bool basic_types_only)
462 int token = sl->front()->token;
464 // These tokens aren't valid types, but the names can be
465 // used as identifiers.
473 // Treat it as a user-defined type if it's either not a reserved word,
474 // or if there are multiple components.
476 if (token == TOK_IDENT || sl->front() != sl->back()) {
477 if (basic_types_only)
480 Symbol *sym = lookup_sym(toplevel, sl, ctx);
481 type = dynamic_cast<Type *>(sym->get_concrete_sym(false));
484 const String *str = sl->back();
485 yyerrorfl(str->file, str->line, "\"%s\" is not a type.",
486 sym->get_fq_name()->flatten()->c_str());
491 CompiledBasicType cbt;
492 memset(&cbt, 0, sizeof(cbt));
497 cbt.flags.field.Bool = 1;
503 cbt.flags.field.Unsigned = 1;
520 cbt.flags.field.Unsigned = 1;
525 cbt.flags.field.Unsigned = 1;
530 cbt.flags.field.Unsigned = 1;
535 cbt.flags.field.Float = 1;
540 cbt.flags.field.Float = 1;
544 fprintf(stderr, "token %d\n", token);
548 type = BasicType::declare(sl->front(), NULL, cbt);
554 void declare_data(NameSpace *ns, StrList *ids, StrList *type,
555 Array *array, StrList *attr)
557 bool is_inline = false;
558 bool is_immutable = false;
561 for (StrList::iterator i = attr->begin(); i != attr->end(); ++i) {
562 const String *this_attr = *i;
564 switch (this_attr->token) {
574 yyerrorfl(this_attr->file, this_attr->line,
575 "Invalid attribute \"%s\"", (*i)->c_str());
580 for (StrList::iterator i = ids->begin(); i != ids->end(); ++i) {
582 Datum *d = Datum::declare(*i, ns, type, array);
592 // An error has already been displayed, but try to
593 // continue and find more errors.
598 void declare_aliases(NameSpace *ns, StrList *ids, StrList *type,
603 for (i = ids->begin(); i != ids->end(); ++i) {
606 TypeDef::declare(*i, ns, type);
608 Alias::declare(*i, ns, type);
612 // An error has already been displayed, but try to
613 // continue and find more errors.
618 void declare_basictypes(NameSpace *ns, StrList *ids,
619 BasicType *type, bool is_typedef)
621 assert(!type->def.flags.field.TypeDef);
624 for (i = ids->begin(); i != ids->end(); ++i) {
627 BasicType::declare(*i, ns, type->def);
629 bt->def.flags.field.TypeDef = is_typedef;
633 // An error has already been displayed, but try to
634 // continue and find more errors.
639 Array::Array(NameSpace *LOOKUP_CTX)
641 lookup_ctx = LOOKUP_CTX;
643 for (int i = 0; i < 2; i++) {
644 cons[i].con.ucon = 0;
645 cons[i].type = TOK_UCON;
649 void Array::set_unbounded()
651 for (int i = 0; i < 2; i++)
652 cons[i].type = TOK_NONE;
655 void Array::final_analysis()
657 for (int i = 0; i < 2; i++) {
658 if (cons[i].type == TOK_NONE) {
667 if (cons[i].type == TOK_DCON) {
668 Symbol *sym = lookup_sym(toplevel, dcons[i], lookup_ctx);
669 datums[i] = dynamic_cast<Datum *>(sym);
671 const String *str = dcons[i]->back();
672 yyerrorfl(str->file, str->line, "\"%s\" is not a Datum.",
673 sym->get_fq_name()->flatten()->c_str());
677 ca.bounds[i] = datums[i]->get_ucon(dcons[i]->back());
678 cons[i].type = datums[i]->con_type;
680 ca.bounds[i] = cons[i].con.ucon;
683 if (cons[i].type == TOK_FCON) {
684 yyerrorfl(strs[i]->file, strs[i]->line,
685 "\"%s\" is not an integral Datum.",
690 if (ca.bounds[i] < 0) {
691 yyerrorfl(strs[i]->file, strs[i]->line,
692 "\"%s\" %s.", strs[i]->c_str(),
693 cons[i].type == TOK_UCON ?
694 "does not fit in a signed 64-bit integer" :
700 if (ca.bounds[1] >= 0 && ca.bounds[0] > ca.bounds[1]) {
701 yyerrorfl(strs[0]->file, strs[0]->line,
702 "\"%s\" is larger than \"%s\".",
703 strs[0]->c_str(), strs[1]->c_str());
708 void Array::set_bound(Con &con, int bound)
710 assert(current_pass == 1);
712 if (con.type == TOK_FCON) {
713 yyerrorf("Array limits must be integers.");
717 if (con.type == TOK_ICON && con.con.icon <= 0) {
718 yyerrorf("Array limits must be positive");
722 if (con.type == TOK_UCON && con.con.icon <= 0) {
723 yyerrorf("Array limits must fit in a signed 64-bit integer");
729 if (con.type == TOK_DCON) {
730 assert(con.con.dcon);
731 dcons[bound] = con.con.dcon;
732 strs[bound] = con.con.dcon->flatten();
734 std::ostringstream ss(std::ostringstream::out);
759 strs[bound] = new String(ss.str().c_str(), cur_input_file,
765 void UserNameSpace::output_lang(LangCallback *lcb, int arg1, void *arg2)
767 lcb->output(this, arg1, arg2);
770 void BasicType::output_lang(LangCallback *lcb, int arg1, void *arg2)
772 lcb->output(this, arg1, arg2);
775 void Interface::output_lang(LangCallback *lcb, int arg1, void *arg2)
777 lcb->output(this, arg1, arg2);
780 void Struct::output_lang(LangCallback *lcb, int arg1, void *arg2)
782 lcb->output(this, arg1, arg2);
785 void BitField::output_lang(LangCallback *lcb, int arg1, void *arg2)
787 lcb->output(this, arg1, arg2);
790 void Enum::output_lang(LangCallback *lcb, int arg1, void *arg2)
792 lcb->output(this, arg1, arg2);
795 void Alias::output_lang(LangCallback *lcb, int arg1, void *arg2)
797 lcb->output(this, arg1, arg2);
800 void TypeDef::output_lang(LangCallback *lcb, int arg1, void *arg2)
802 lcb->output(this, arg1, arg2);
805 void Datum::output_lang(LangCallback *lcb, int arg1, void *arg2)
807 if (def.flags.field.Const)
808 lcb->output(this, arg1, arg2);
811 void Method::output_lang(LangCallback *lcb, int arg1, void *arg2)
815 void Param::output_lang(LangCallback *lcb, int arg1, void *arg2)
819 int Interface::all_supers_traversal;