1 // Semantic actions for types and namespaces
3 // This software is copyright (c) 2006 Scott Wood <scott@buserror.net>.
5 // Permission is hereby granted, free of charge, to any person obtaining a copy of
6 // this software and associated documentation files (the "Software"), to deal with
7 // the Software without restriction, including without limitation the rights to
8 // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9 // of the Software, and to permit persons to whom the Software is furnished to do
10 // so, subject to the following condition:
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
30 bool Datum::verify_const()
32 assert(def.flags.field.Const);
34 // TOK_INVALID should have caused an abort in an earlier pass, and
35 // TOK_DCON should have been replaced by the final constant by now.
37 assert(con_type == TOK_ICON || con_type == TOK_UCON ||
38 con_type == TOK_FCON || con_type == TOK_BOOL);
40 if (cbt->flags.field.Float) {
41 if (con_type == TOK_UCON)
42 def.fcon = static_cast<double>(def.ucon);
43 else if (con_type == TOK_ICON)
44 def.fcon = static_cast<double>(def.icon);
45 else if (con_type == TOK_BOOL) {
46 yyerrorfl(name->file, name->line,
47 "%s is of floating-point type, but is initialized with "
48 "a boolean constant.", name->c_str());
55 if (cbt->bits == 32) {
56 if (def.fcon > FLT_MAX || def.fcon < FLT_MIN) {
57 yyerrorfl(name->file, name->line,
58 "%s is out of range for a single-precision FP datum.",
69 if (con_type == TOK_FCON) {
70 yyerrorfl(name->file, name->line,
71 "%s is of %s type, but is initialized with "
72 "a floating-point constant.",
73 cbt->flags.field.Bool ? "boolean" : "integral",
79 if (cbt->flags.field.Bool) {
80 if (con_type != TOK_BOOL) {
81 yyerrorfl(name->file, name->line,
82 "%s is of boolean type, but is initialized with "
83 "a non-boolean constant.", name->c_str());
88 assert(def.ucon == 0 || def.ucon == 1);
94 if (con_type == TOK_BOOL) {
95 yyerrorfl(name->file, name->line,
96 "%s is of integral type, but is initialized with "
97 "a boolean constant.", name->c_str());
102 if (cbt->flags.field.Unsigned) {
103 if (con_type == TOK_ICON && def.icon < 0) {
104 yyerrorfl(name->file, name->line,
105 "Initializer for \"%s\" is out of range.",
110 if (cbt->bits < 64) {
111 uint64_t max = (1ULL << cbt->bits) - 1;
113 if (def.ucon > max) {
114 yyerrorfl(name->file, name->line,
115 "Initializer for \"%s\" is out of range.",
121 if (con_type == TOK_UCON && def.icon < 0) {
122 yyerrorfl(name->file, name->line,
123 "Initializer for \"%s\" is out of range.",
128 if (cbt->bits < 64) {
129 // Yes, the constant should be unsigned before conversion,
130 // as the temporary value could overflow a signed datum
131 // before the one is subtracted if bits == 63. It won't
132 // matter on most machines, but you never know...
134 int64_t max = (1ULL << (cbt->bits - 1)) - 1;
136 if (def.icon > max || def.icon < -max + 1) {
137 yyerrorfl(name->file, name->line,
138 "Initializer for \"%s\" is out of range.",
149 void Datum::init_const_early(Con *con)
152 if (con->type == TOK_DCON) {
153 assert(current_pass == 1);
154 const_val_name = con->con.dcon;
157 def.flags.field.Const = 1;
158 con_type = con->type;
159 def.ucon = con->con.ucon;
163 void Datum::init(StrList *type, Array *ARRAY, Con *con)
174 init_const_early(con);
177 void Datum::init(CompiledBasicType &CBT, Array *ARRAY, Con *con)
182 cbt = &def.basictype;
188 init_const_early(con);
191 void Datum::process_type()
193 assert(current_pass >= 4);
198 assert(!type_fq_name);
201 Symbol *sym = type_sym->get_concrete_sym(false);
202 type = dynamic_cast<Type *>(sym);
205 const String *str = type_name->back();
206 yyerrorfl(str->file, str->line, "\"%s\" is not a type.",
207 sym->get_fq_name()->flatten()->c_str());
212 BasicType *bt = dynamic_cast<BasicType *>(type->get_concrete_sym());
215 if (!bt->def.flags.field.TypeDef)
216 use_anon_type(bt->def);
219 } else if (const_val) {
220 const String *str = type_name->back();
221 yyerrorfl(str->file, str->line,
222 "\"%s\" is not a basic type (and thus \"%s\" cannot "
224 type->get_fq_name()->flatten()->c_str(),
230 type_fq_name = type->get_fq_name()->flatten();
231 def.type.length = type_fq_name->length();
235 Datum *Datum::resolve_constant_chain()
237 if (chain_traversed == traversal) {
238 yyerrorfl(name->file, name->line,
239 "Initialization of \"%s\" forms an infinite loop:",
240 get_fq_name()->flatten()->c_str());
244 chain_traversed = traversal;
252 const_val = dynamic_cast<Datum *>(const_val_sym->get_concrete_sym());
255 const String *str = const_val_name->back();
256 yyerrorfl(str->file, str->line, "\"%s\" is not a datum.",
257 const_val_sym->get_fq_name()->flatten()->c_str());
261 if (!const_val->def.flags.field.Const) {
262 const String *str = const_val_name->back();
263 yyerrorfl(str->file, str->line, "\"%s\" is not a constant.",
264 const_val->get_fq_name()->flatten()->c_str());
268 if (!const_val->const_init) {
269 Datum *d = const_val->resolve_constant_chain();
271 yyerrorfl(name->file, name->line, "...initializes \"%s\"",
272 get_fq_name()->flatten()->c_str());
281 assert(const_val->const_init);
283 con_type = const_val->con_type;
284 def.ucon = const_val->def.ucon;
294 // FIXME: Check for inline struct loops.
295 void Datum::final_analysis()
297 Struct *str = dynamic_cast<Struct *>(*type);
298 if (str && str->is_inline())
302 array->final_analysis();
303 def.basictype.array = array->ca;
305 def.basictype.array.bounds[0] = 0;
306 def.basictype.array.bounds[1] = 0;
309 BitField *bfparent = dynamic_cast<BitField *>(get_ns());
317 defsize = type->get_default_bf_size();
320 yyerrorfl(name->file, name->line,
321 "\"%s\" may not be the named type of bitfield entry "
322 "\"%s\", as it is not a bitfield or enumeration.",
323 type->get_fq_name()->flatten()->c_str(),
324 get_fq_name()->flatten()->c_str());
325 } else if (def.icon == -1) {
327 } else if (def.ucon < (unsigned int)defsize) {
328 yyerrorfl(name->file, name->line,
329 "Explicit size %llu on \"%s\" is too small for "
330 "type \"%s\", which has a minimum size of %u",
331 def.ucon, get_fq_name()->flatten()->c_str(),
332 type->get_fq_name()->flatten()->c_str(), defsize);
337 void Struct::add(Symbol *sym, bool from_import)
339 Datum *datum = dynamic_cast<Datum *>(sym);
341 if (!datum && !dynamic_cast<Alias *>(sym) &&
342 !dynamic_cast<Type *>(sym) &&
343 !dynamic_cast<Method *>(sym))
344 throw InvalidArgument();
346 NameSpace::add(sym, from_import);
348 if (!from_import && datum && !datum->def.flags.field.Const)
352 void Struct::add_elem(Datum *d)
354 entries.push_back(d);
358 Param *Param::declare(const String *name, NameSpace *parent,
359 StrList *TYPE, CompiledParam::Flags flags,
363 assert(dynamic_cast<Method *>(parent));
365 Param *p = new Param(name);
366 p->init(TYPE, flags, array);
372 Method *Method::declare(const String *name, NameSpace *parent)
375 assert(dynamic_cast<Interface *>(parent));
377 Method *m = new Method(name);
383 void Interface::add(Symbol *sym, bool from_import)
385 Datum *datum = dynamic_cast<Datum *>(sym);
386 Method *method = dynamic_cast<Method *>(sym);
388 if (!datum && !method &&
389 !dynamic_cast<Alias *>(sym) &&
390 !dynamic_cast<Type *>(sym))
391 throw InvalidArgument();
393 if (datum && !datum->def.flags.field.Const)
394 throw InvalidArgument();
396 NameSpace::add(sym, from_import);
398 if (!from_import && method)
402 // FIXME: check for duplicate and looping inheritance
403 void Interface::add_elem(Method *method)
405 methods.push_back(method);
409 void Enum::add(Symbol *sym, bool from_import)
411 Datum *datum = dynamic_cast<Datum *>(sym);
413 // It also must be const unsigned, but the const won't
414 // have been initialized yet.
417 throw InvalidArgument();
419 NameSpace::add(sym, from_import);
425 void Enum::add_elem(Datum *datum)
427 entries.push_back(datum);
431 void BitField::add(Symbol *sym, bool from_import)
433 Datum *datum = dynamic_cast<Datum *>(sym);
435 if (!datum && !dynamic_cast<Enum *>(sym) &&
436 !dynamic_cast<BitField *>(sym))
437 throw InvalidArgument();
439 NameSpace::add(sym, from_import);
441 if (!from_import && datum)
445 void BitField::add_elem(Datum *datum)
447 entries.push_back(datum);
451 void Method::add(Symbol *sym, bool from_import)
453 Param *param = dynamic_cast<Param *>(sym);
456 throw InvalidArgument();
458 NameSpace::add(sym, from_import);
463 void Method::add_elem(Param *param)
465 entries.push_back(param);
469 // Use this rather than lookup_sym if you want to check for built-in types.
470 // If only constructed types are valid, use lookup_sym. If basic_types_only
471 // is set, then NULL will be returned if sl does not describe a built-in
472 // basic type (such as int, flong, octet, etc). This option is used so that
473 // the first-pass code in idlparse.y can decide whether to create a BasicType
474 // or an Alias/TypeDef.
476 Type *lookup_type(StrList *sl, NameSpace *ctx, bool basic_types_only)
479 int token = sl->front()->token;
481 // These tokens aren't valid types, but the names can be
482 // used as identifiers.
490 // Treat it as a user-defined type if it's either not a reserved word,
491 // or if there are multiple components.
493 if (token == TOK_IDENT || sl->front() != sl->back()) {
494 if (basic_types_only)
497 Symbol *sym = lookup_sym(toplevel, sl, ctx);
498 type = dynamic_cast<Type *>(sym->get_concrete_sym(false));
501 const String *str = sl->back();
502 yyerrorfl(str->file, str->line, "\"%s\" is not a type.",
503 sym->get_fq_name()->flatten()->c_str());
508 CompiledBasicType cbt;
509 memset(&cbt, 0, sizeof(cbt));
514 cbt.flags.field.Bool = 1;
520 cbt.flags.field.Unsigned = 1;
537 cbt.flags.field.Unsigned = 1;
542 cbt.flags.field.Unsigned = 1;
547 cbt.flags.field.Unsigned = 1;
552 cbt.flags.field.Float = 1;
557 cbt.flags.field.Float = 1;
561 fprintf(stderr, "token %d\n", token);
565 type = BasicType::declare(sl->front(), NULL, cbt);
571 void declare_data(NameSpace *ns, StrList *ids, StrList *type,
572 Array *array, StrList *attr)
574 bool is_inline = false;
575 bool is_immutable = false;
578 for (StrList::iterator i = attr->begin(); i != attr->end(); ++i) {
579 const String *this_attr = *i;
581 switch (this_attr->token) {
591 yyerrorfl(this_attr->file, this_attr->line,
592 "Invalid attribute \"%s\"", (*i)->c_str());
597 for (StrList::iterator i = ids->begin(); i != ids->end(); ++i) {
599 Datum *d = Datum::declare(*i, ns, type, array);
609 // An error has already been displayed, but try to
610 // continue and find more errors.
615 void declare_aliases(NameSpace *ns, StrList *ids, StrList *type,
620 for (i = ids->begin(); i != ids->end(); ++i) {
623 TypeDef::declare(*i, ns, type);
625 Alias::declare(*i, ns, type);
629 // An error has already been displayed, but try to
630 // continue and find more errors.
635 void declare_basictypes(NameSpace *ns, StrList *ids,
636 BasicType *type, bool is_typedef)
638 assert(!type->def.flags.field.TypeDef);
641 for (i = ids->begin(); i != ids->end(); ++i) {
644 BasicType::declare(*i, ns, type->def);
646 bt->def.flags.field.TypeDef = is_typedef;
650 // An error has already been displayed, but try to
651 // continue and find more errors.
656 Array::Array(NameSpace *LOOKUP_CTX)
658 lookup_ctx = LOOKUP_CTX;
660 for (int i = 0; i < 2; i++) {
661 cons[i].con.ucon = 0;
662 cons[i].type = TOK_UCON;
666 void Array::set_unbounded()
668 for (int i = 0; i < 2; i++)
669 cons[i].type = TOK_NONE;
672 void Array::final_analysis()
674 for (int i = 0; i < 2; i++) {
675 if (cons[i].type == TOK_NONE) {
684 if (cons[i].type == TOK_DCON) {
685 Symbol *sym = lookup_sym(toplevel, dcons[i], lookup_ctx);
686 datums[i] = dynamic_cast<Datum *>(sym);
688 const String *str = dcons[i]->back();
689 yyerrorfl(str->file, str->line, "\"%s\" is not a Datum.",
690 sym->get_fq_name()->flatten()->c_str());
694 ca.bounds[i] = datums[i]->get_ucon(dcons[i]->back());
695 cons[i].type = datums[i]->con_type;
697 ca.bounds[i] = cons[i].con.ucon;
700 if (cons[i].type == TOK_FCON) {
701 yyerrorfl(strs[i]->file, strs[i]->line,
702 "\"%s\" is not an integral Datum.",
707 if (ca.bounds[i] < 0) {
708 yyerrorfl(strs[i]->file, strs[i]->line,
709 "\"%s\" %s.", strs[i]->c_str(),
710 cons[i].type == TOK_UCON ?
711 "does not fit in a signed 64-bit integer" :
717 if (ca.bounds[1] >= 0 && ca.bounds[0] > ca.bounds[1]) {
718 yyerrorfl(strs[0]->file, strs[0]->line,
719 "\"%s\" is larger than \"%s\".",
720 strs[0]->c_str(), strs[1]->c_str());
725 void Array::set_bound(Con &con, int bound)
727 assert(current_pass == 1);
729 if (con.type == TOK_FCON) {
730 yyerrorf("Array limits must be integers.");
734 if (con.type == TOK_ICON && con.con.icon <= 0) {
735 yyerrorf("Array limits must be positive");
739 if (con.type == TOK_UCON && con.con.icon <= 0) {
740 yyerrorf("Array limits must fit in a signed 64-bit integer");
746 if (con.type == TOK_DCON) {
747 assert(con.con.dcon);
748 dcons[bound] = con.con.dcon;
749 strs[bound] = con.con.dcon->flatten();
751 std::ostringstream ss(std::ostringstream::out);
776 strs[bound] = new String(ss.str().c_str(), cur_input_file,
782 void UserNameSpace::output_lang(LangCallback *lcb, int arg1, void *arg2)
784 lcb->output(this, arg1, arg2);
787 void BasicType::output_lang(LangCallback *lcb, int arg1, void *arg2)
789 lcb->output(this, arg1, arg2);
792 void Interface::output_lang(LangCallback *lcb, int arg1, void *arg2)
794 lcb->output(this, arg1, arg2);
797 void Struct::output_lang(LangCallback *lcb, int arg1, void *arg2)
799 lcb->output(this, arg1, arg2);
802 void BitField::output_lang(LangCallback *lcb, int arg1, void *arg2)
804 lcb->output(this, arg1, arg2);
807 void Enum::output_lang(LangCallback *lcb, int arg1, void *arg2)
809 lcb->output(this, arg1, arg2);
812 void Alias::output_lang(LangCallback *lcb, int arg1, void *arg2)
814 lcb->output(this, arg1, arg2);
817 void TypeDef::output_lang(LangCallback *lcb, int arg1, void *arg2)
819 lcb->output(this, arg1, arg2);
822 void Datum::output_lang(LangCallback *lcb, int arg1, void *arg2)
824 if (def.flags.field.Const)
825 lcb->output(this, arg1, arg2);
828 void Method::output_lang(LangCallback *lcb, int arg1, void *arg2)
832 void Param::output_lang(LangCallback *lcb, int arg1, void *arg2)
836 int Interface::all_supers_traversal;