From a482f1c4dd4efab83d3b19309900f1cbf54383a5 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 15 Oct 2013 07:01:17 +0200 Subject: Automatically map C++11 enum classes (strong enums) --- odb/context.cxx | 15 +++++-- odb/parser.cxx | 39 ++++++++++++++--- odb/relational/mssql/context.cxx | 9 +--- odb/relational/mysql/context.cxx | 59 ++++++++++++------------- odb/relational/oracle/context.cxx | 9 +--- odb/relational/pgsql/context.cxx | 9 +--- odb/relational/sqlite/context.cxx | 9 +--- odb/semantics/elements.hxx | 7 +-- odb/semantics/enum.cxx | 21 +++++++-- odb/semantics/enum.hxx | 90 +++++++++++++++++++++++++++++++++++++-- odb/semantics/fundamental.cxx | 68 +++++++++++++++++++++++------ odb/semantics/fundamental.hxx | 61 +++++++++++++++++--------- odb/traversal/enum.cxx | 21 +++++++++ odb/traversal/enum.hxx | 23 ++++++++-- 14 files changed, 321 insertions(+), 119 deletions(-) (limited to 'odb') diff --git a/odb/context.cxx b/odb/context.cxx index 4db15a0..352cb51 100644 --- a/odb/context.cxx +++ b/odb/context.cxx @@ -1926,16 +1926,25 @@ database_type_impl (semantics::type& t, bool id, bool* null) { - type_map_type::const_iterator i (data_->type_map_.find (t, hint)); + using semantics::enum_; + + // By default map an enum as its underlying type. + // + if (enum_* e = dynamic_cast (&t)) + return database_type_impl ( + e->underlying_type (), e->underlying_type_hint (), id, null); + // Built-in type mapping. + // + type_map_type::const_iterator i (data_->type_map_.find (t, hint)); if (i != data_->type_map_.end ()) { if (null != 0) *null = i->second.null; return id ? i->second.id_type : i->second.type; } - else - return string (); + + return string (); } static string diff --git a/odb/parser.cxx b/odb/parser.cxx index 14dd81a..140e09e 100644 --- a/odb/parser.cxx +++ b/odb/parser.cxx @@ -746,7 +746,7 @@ parse (tree global_scope, path const& main_file) define_fund (char_type_node); define_fund (wchar_type_node); - if (ops_.std () == cxx_version::cxx11) + if (ops_.std () >= cxx_version::cxx11) { define_fund (char16_type_node); define_fund (char32_type_node); @@ -1422,8 +1422,29 @@ emit_enum (tree e, e_node = &dynamic_cast (*n); else { - e_node = &unit_->new_node ( - file, line, clmn, e, TYPE_UNSIGNED (e) != 0); + e_node = &unit_->new_node (file, line, clmn, e); + + // Set the underlying type even for incomplete (forward-declared) enums. + // + tree ut (ENUM_UNDERLYING_TYPE (e)); + names* hint (unit_->find_hint (ut)); + integral_type* un = dynamic_cast ( + unit_->find (TYPE_MAIN_VARIANT (ut))); + + // For "old" enums GCC creates a distinct type node and the only way to + // get to one of the known integrals is via its name. + // + if (un == 0) + { + ut = TREE_TYPE (TYPE_NAME (ut)); + un = dynamic_cast (unit_->find (TYPE_MAIN_VARIANT (ut))); + } + + underlies& edge (unit_->new_edge (*un, *e_node)); + + if (hint != 0) + edge.hint (*hint); + unit_->insert (e, *e_node); } @@ -1459,9 +1480,17 @@ emit_enum (tree e, unit_->new_edge (*e_node, er_node); unit_->insert (decl, er_node); - // Inject enumerators into the outer scope. + // In C++11 the enumerators are always available in the enum's + // scope, even for old enums. + // + if (ops_.std () >= cxx_version::cxx11) + unit_->new_edge (*e_node, er_node, name, access::public_); + + // Inject enumerators into the outer scope unless this is an + // enum class. // - unit_->new_edge (*scope_, er_node, name, access); + if (UNSCOPED_ENUM_P (e)) + unit_->new_edge (*scope_, er_node, name, access); if (trace) ts << "\tenumerator " << name << " at " << file << ":" << line << endl; diff --git a/odb/relational/mssql/context.cxx b/odb/relational/mssql/context.cxx index 1df235d..a0037eb 100644 --- a/odb/relational/mssql/context.cxx +++ b/odb/relational/mssql/context.cxx @@ -156,18 +156,11 @@ namespace relational if (!r.empty ()) return r; - using semantics::enum_; using semantics::array; - // Enum mapping. - // - if (t.is_a ()) - { - r = "INT"; - } // char[N] mapping. // - else if (array* a = dynamic_cast (&t)) + if (array* a = dynamic_cast (&t)) { semantics::type& bt (a->base_type ()); bool c (bt.is_a ()); diff --git a/odb/relational/mysql/context.cxx b/odb/relational/mysql/context.cxx index 75b71e9..55dd4f7 100644 --- a/odb/relational/mysql/context.cxx +++ b/odb/relational/mysql/context.cxx @@ -286,15 +286,12 @@ namespace relational bool id, bool* null) { - string r (base_context::database_type_impl (t, hint, id, null)); - - if (!r.empty ()) - return r; - using semantics::enum_; using semantics::enumerator; using semantics::array; + string r; + // Enum mapping. // if (enum_* e = dynamic_cast (&t)) @@ -302,43 +299,41 @@ namespace relational // We can only map to ENUM if the C++ enumeration is contiguous // and starts with 0. // - if (e->unsigned_ ()) + enum_::enumerates_iterator i (e->enumerates_begin ()), + end (e->enumerates_end ()); + + if (i != end) { - enum_::enumerates_iterator i (e->enumerates_begin ()), - end (e->enumerates_end ()); + r += "ENUM("; - if (i != end) + for (unsigned long long j (0); i != end; ++i, ++j) { - r += "ENUM("; - - for (unsigned long long j (0); i != end; ++i, ++j) - { - enumerator const& er (i->enumerator ()); + enumerator const& er (i->enumerator ()); - if (er.value () != j) - break; - - if (j != 0) - r += ", "; + if (er.value () != j) + break; - r += quote_string (er.name ()); - } + if (j != 0) + r += ", "; - if (i == end) - r += ")"; - else - r.clear (); + r += quote_string (er.name ()); } - } - - if (r.empty ()) - { - r = "INT"; - if (e->unsigned_ ()) - r += " UNSIGNED"; + if (i == end) + r += ")"; + else + r.clear (); } + + if (!r.empty ()) + return r; } + + r = base_context::database_type_impl (t, hint, id, null); + + if (!r.empty ()) + return r; + // char[N] mapping. // else if (array* a = dynamic_cast (&t)) diff --git a/odb/relational/oracle/context.cxx b/odb/relational/oracle/context.cxx index f885564..98cda52 100644 --- a/odb/relational/oracle/context.cxx +++ b/odb/relational/oracle/context.cxx @@ -152,18 +152,11 @@ namespace relational if (!r.empty ()) return r; - using semantics::enum_; using semantics::array; - // Enum mapping. - // - if (t.is_a ()) - { - r = "NUMBER(10)"; - } // char[N] mapping. // - else if (array* a = dynamic_cast (&t)) + if (array* a = dynamic_cast (&t)) { semantics::type& bt (a->base_type ()); if (bt.is_a ()) diff --git a/odb/relational/pgsql/context.cxx b/odb/relational/pgsql/context.cxx index 947c6bd..d09fa2c 100644 --- a/odb/relational/pgsql/context.cxx +++ b/odb/relational/pgsql/context.cxx @@ -252,18 +252,11 @@ namespace relational if (!r.empty ()) return r; - using semantics::enum_; using semantics::array; - // Enum mapping. - // - if (t.is_a ()) - { - r = "INTEGER"; - } // char[N] mapping. // - else if (array* a = dynamic_cast (&t)) + if (array* a = dynamic_cast (&t)) { semantics::type& bt (a->base_type ()); if (bt.is_a ()) diff --git a/odb/relational/sqlite/context.cxx b/odb/relational/sqlite/context.cxx index 664af35..f347d30 100644 --- a/odb/relational/sqlite/context.cxx +++ b/odb/relational/sqlite/context.cxx @@ -242,18 +242,11 @@ namespace relational if (!r.empty ()) return r; - using semantics::enum_; using semantics::array; - // Enum mapping. - // - if (t.is_a ()) - { - r = "INTEGER"; - } // char[N] mapping. // - else if (array* a = dynamic_cast (&t)) + if (array* a = dynamic_cast (&t)) { semantics::type& bt (a->base_type ()); if (bt.is_a () || diff --git a/odb/semantics/elements.hxx b/odb/semantics/elements.hxx index 1199c0c..059b639 100644 --- a/odb/semantics/elements.hxx +++ b/odb/semantics/elements.hxx @@ -178,9 +178,10 @@ namespace semantics // edges. // void - add_edge_right (edge&) - { - } + add_edge_left (edge&) {} + + void + add_edge_right (edge&) {} protected: // For virtual inheritance. Should never be actually called. diff --git a/odb/semantics/enum.cxx b/odb/semantics/enum.cxx index 7cffe30..dd8b905 100644 --- a/odb/semantics/enum.cxx +++ b/odb/semantics/enum.cxx @@ -22,13 +22,18 @@ namespace semantics { } + underlies:: + underlies () + : type_ (0), enum__ (0), hint_ (0) + { + } + enum_:: enum_ (path const& file, size_t line, size_t column, - tree tn, - bool unsigned_) - : node (file, line, column, tn), unsigned__ (unsigned_) + tree tn) + : node (file, line, column, tn) { } @@ -54,15 +59,25 @@ namespace semantics // { type_info ti (typeid (enumerator)); + ti.add_base (typeid (nameable)); ti.add_base (typeid (instance)); insert (ti); } + // underlies + // + { + type_info ti (typeid (underlies)); + ti.add_base (typeid (edge)); + insert (ti); + } + // enum_ // { type_info ti (typeid (enum_)); ti.add_base (typeid (type)); + ti.add_base (typeid (scope)); insert (ti); } } diff --git a/odb/semantics/enum.hxx b/odb/semantics/enum.hxx index de07885..02f2b27 100644 --- a/odb/semantics/enum.hxx +++ b/odb/semantics/enum.hxx @@ -7,6 +7,7 @@ #include #include +#include namespace semantics { @@ -101,7 +102,62 @@ namespace semantics // // - class enum_: public type + class underlies: public edge + { + public: + typedef semantics::enum_ enum_type; + + integral_type& + type () const + { + return *type_; + } + + enum_type& + enum_ () const + { + return *enum__; + } + + // Names edge in terms of which this edge was defined. Can be NULL. + // + public: + void + hint (names& hint) + { + hint_ = &hint; + } + + names* + hint () const + { + return hint_; + } + + public: + underlies (); + + void + set_left_node (integral_type& n) + { + type_ = &n; + } + + void + set_right_node (enum_type& n) + { + enum__ = &n; + } + + protected: + integral_type* type_; + enum_type* enum__; + names* hint_; + }; + + // + // + class enum_: public type, public scope { private: typedef std::vector enumerates_list; @@ -123,14 +179,38 @@ namespace semantics return enumerates_.end (); } + underlies& + underlied () const + { + return *underlied_; + } + + integral_type& + underlying_type () const + { + return underlied_->type (); + } + + names* + underlying_type_hint () const + { + return underlied_->hint (); + } + bool unsigned_ () const { - return unsigned__; + return underlying_type ().unsigned_ (); } public: - enum_ (path const&, size_t line, size_t column, tree, bool unsigned_); + enum_ (path const&, size_t line, size_t column, tree); + + void + add_edge_right (underlies& e) + { + underlied_ = &e; + } void add_edge_left (enumerates& e) @@ -138,9 +218,11 @@ namespace semantics enumerates_.push_back (&e); } + using scope::add_edge_left; + private: - bool unsigned__; enumerates_list enumerates_; + underlies* underlied_; }; } diff --git a/odb/semantics/fundamental.cxx b/odb/semantics/fundamental.cxx index 537a5cf..4a3bd69 100644 --- a/odb/semantics/fundamental.cxx +++ b/odb/semantics/fundamental.cxx @@ -2,6 +2,8 @@ // copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC // license : GNU GPL v3; see accompanying LICENSE file +#include + #include #include @@ -22,6 +24,22 @@ namespace semantics return type::fq_name (hint); } + // char + // + bool fund_char:: + unsigned_ () const + { + return TYPE_UNSIGNED (tree_node ()) != 0; + } + + // wchar_t + // + bool fund_wchar:: + unsigned_ () const + { + return TYPE_UNSIGNED (tree_node ()) != 0; + } + // type info // namespace @@ -48,11 +66,19 @@ namespace semantics insert (ti); } + // integral_type + // + { + type_info ti (typeid (integral_type)); + ti.add_base (typeid (fund_type)); + insert (ti); + } + // fund_bool // { type_info ti (typeid (fund_bool)); - ti.add_base (typeid (fund_type)); + ti.add_base (typeid (integral_type)); insert (ti); } @@ -60,7 +86,7 @@ namespace semantics // { type_info ti (typeid (fund_char)); - ti.add_base (typeid (fund_type)); + ti.add_base (typeid (integral_type)); insert (ti); } @@ -68,7 +94,23 @@ namespace semantics // { type_info ti (typeid (fund_wchar)); - ti.add_base (typeid (fund_type)); + ti.add_base (typeid (integral_type)); + insert (ti); + } + + // fund_char16 + // + { + type_info ti (typeid (fund_char16)); + ti.add_base (typeid (integral_type)); + insert (ti); + } + + // fund_char32 + // + { + type_info ti (typeid (fund_char32)); + ti.add_base (typeid (integral_type)); insert (ti); } @@ -76,7 +118,7 @@ namespace semantics // { type_info ti (typeid (fund_signed_char)); - ti.add_base (typeid (fund_type)); + ti.add_base (typeid (integral_type)); insert (ti); } @@ -84,7 +126,7 @@ namespace semantics // { type_info ti (typeid (fund_unsigned_char)); - ti.add_base (typeid (fund_type)); + ti.add_base (typeid (integral_type)); insert (ti); } @@ -92,7 +134,7 @@ namespace semantics // { type_info ti (typeid (fund_short)); - ti.add_base (typeid (fund_type)); + ti.add_base (typeid (integral_type)); insert (ti); } @@ -100,7 +142,7 @@ namespace semantics // { type_info ti (typeid (fund_unsigned_short)); - ti.add_base (typeid (fund_type)); + ti.add_base (typeid (integral_type)); insert (ti); } @@ -108,7 +150,7 @@ namespace semantics // { type_info ti (typeid (fund_int)); - ti.add_base (typeid (fund_type)); + ti.add_base (typeid (integral_type)); insert (ti); } @@ -116,7 +158,7 @@ namespace semantics // { type_info ti (typeid (fund_unsigned_int)); - ti.add_base (typeid (fund_type)); + ti.add_base (typeid (integral_type)); insert (ti); } @@ -124,7 +166,7 @@ namespace semantics // { type_info ti (typeid (fund_long)); - ti.add_base (typeid (fund_type)); + ti.add_base (typeid (integral_type)); insert (ti); } @@ -132,7 +174,7 @@ namespace semantics // { type_info ti (typeid (fund_unsigned_long)); - ti.add_base (typeid (fund_type)); + ti.add_base (typeid (integral_type)); insert (ti); } @@ -140,7 +182,7 @@ namespace semantics // { type_info ti (typeid (fund_long_long)); - ti.add_base (typeid (fund_type)); + ti.add_base (typeid (integral_type)); insert (ti); } @@ -148,7 +190,7 @@ namespace semantics // { type_info ti (typeid (fund_unsigned_long_long)); - ti.add_base (typeid (fund_type)); + ti.add_base (typeid (integral_type)); insert (ti); } diff --git a/odb/semantics/fundamental.hxx b/odb/semantics/fundamental.hxx index 55ce322..75cbbf5 100644 --- a/odb/semantics/fundamental.hxx +++ b/odb/semantics/fundamental.hxx @@ -13,7 +13,7 @@ namespace semantics // Fundamental C++ types. // - struct fund_type: public type + struct fund_type: type { virtual string fq_name () const; @@ -27,84 +27,105 @@ namespace semantics fund_void (tree tn): node (path (""), 0, 0, tn) {} }; - struct fund_bool: fund_type - { - fund_bool (tree tn): node (path (""), 0, 0, tn) {} - }; - // // Integral. // - struct fund_char: fund_type + struct integral_type: fund_type + { + virtual bool + unsigned_ () const = 0; + }; + + struct fund_bool: integral_type + { + fund_bool (tree tn): node (path (""), 0, 0, tn) {} + virtual bool unsigned_ () const {return true;} + }; + + struct fund_char: integral_type { fund_char (tree tn): node (path (""), 0, 0, tn) {} + virtual bool unsigned_ () const; }; - struct fund_wchar: fund_type + struct fund_wchar: integral_type { fund_wchar (tree tn): node (path (""), 0, 0, tn) {} + virtual bool unsigned_ () const; }; - struct fund_char16: fund_type + struct fund_char16: integral_type { fund_char16 (tree tn): node (path (""), 0, 0, tn) {} + virtual bool unsigned_ () const {return true;} }; - struct fund_char32: fund_type + struct fund_char32: integral_type { fund_char32 (tree tn): node (path (""), 0, 0, tn) {} + virtual bool unsigned_ () const {return true;} }; - struct fund_signed_char: fund_type + struct fund_signed_char: integral_type { fund_signed_char (tree tn): node (path (""), 0, 0, tn) {} + virtual bool unsigned_ () const {return false;} }; - struct fund_unsigned_char: fund_type + struct fund_unsigned_char: integral_type { fund_unsigned_char (tree tn): node (path (""), 0, 0, tn) {} + virtual bool unsigned_ () const {return true;} }; - struct fund_short: fund_type + struct fund_short: integral_type { fund_short (tree tn): node (path (""), 0, 0, tn) {} + virtual bool unsigned_ () const {return false;} }; - struct fund_unsigned_short: fund_type + struct fund_unsigned_short: integral_type { fund_unsigned_short (tree tn): node (path (""), 0, 0, tn) {} + virtual bool unsigned_ () const {return true;} }; - struct fund_int: fund_type + struct fund_int: integral_type { fund_int (tree tn): node (path (""), 0, 0, tn) {} + virtual bool unsigned_ () const {return false;} }; - struct fund_unsigned_int: fund_type + struct fund_unsigned_int: integral_type { fund_unsigned_int (tree tn): node (path (""), 0, 0, tn) {} + virtual bool unsigned_ () const {return true;} }; - struct fund_long: fund_type + struct fund_long: integral_type { fund_long (tree tn): node (path (""), 0, 0, tn) {} + virtual bool unsigned_ () const {return false;} }; - struct fund_unsigned_long: fund_type + struct fund_unsigned_long: integral_type { fund_unsigned_long (tree tn): node (path (""), 0, 0, tn) {} + virtual bool unsigned_ () const {return true;} }; - struct fund_long_long: fund_type + struct fund_long_long: integral_type { fund_long_long (tree tn): node (path (""), 0, 0, tn) {} + virtual bool unsigned_ () const {return false;} }; - struct fund_unsigned_long_long: fund_type + struct fund_unsigned_long_long: integral_type { fund_unsigned_long_long (tree tn) : node (path (""), 0, 0, tn) {} + virtual bool unsigned_ () const {return true;} }; // diff --git a/odb/traversal/enum.cxx b/odb/traversal/enum.cxx index 149f962..fd4ff89 100644 --- a/odb/traversal/enum.cxx +++ b/odb/traversal/enum.cxx @@ -14,13 +14,34 @@ namespace traversal // // + void underlies:: + traverse (type& u) + { + dispatch (u.type ()); + } + + // + // void enum_:: traverse (type& e) { + underlied (e); enumerates (e); } void enum_:: + underlied (type& e) + { + underlied (e, *this); + } + + void enum_:: + underlied (type& e, edge_dispatcher& d) + { + d.dispatch (e.underlied ()); + } + + void enum_:: enumerates (type& e) { enumerates (e, *this); diff --git a/odb/traversal/enum.hxx b/odb/traversal/enum.hxx index 1efccaa..c949934 100644 --- a/odb/traversal/enum.hxx +++ b/odb/traversal/enum.hxx @@ -12,10 +12,7 @@ namespace traversal { struct enumerates: edge { - enumerates () - { - } - + enumerates () {} enumerates (node_dispatcher& n) { node_traverser (n); @@ -27,12 +24,30 @@ namespace traversal struct enumerator: node {}; + struct underlies: edge + { + underlies () {} + underlies (node_dispatcher& n) + { + node_traverser (n); + } + + virtual void + traverse (type&); + }; + struct enum_: node { virtual void traverse (type&); virtual void + underlied (type&); + + virtual void + underlied (type&, edge_dispatcher&); + + virtual void enumerates (type&); virtual void -- cgit v1.1