From 823026b58211a4166de06ac243d978dcb9930271 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Mon, 22 Jan 2024 15:58:08 +0300 Subject: Turn odb repository into muti-package repository Also remove the autoconf/make-based build system. --- odb/context.cxx | 3384 ------------------------------------------------------- 1 file changed, 3384 deletions(-) delete mode 100644 odb/context.cxx (limited to 'odb/context.cxx') diff --git a/odb/context.cxx b/odb/context.cxx deleted file mode 100644 index 13fc1b3..0000000 --- a/odb/context.cxx +++ /dev/null @@ -1,3384 +0,0 @@ -// file : odb/context.cxx -// license : GNU GPL v3; see accompanying LICENSE file - -#include - -#include // std::toupper -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -using namespace std; - -static inline void -add_space (string& s) -{ - string::size_type n (s.size ()); - if (n != 0 && s[n - 1] != ' ') - s += ' '; -} - -// -// custom_cxx_type -// -string custom_cxx_type:: -translate (string const& val, const cxx_tokens& expr) -{ - // Similar to member_access::translate() and a few other places. - // - string r; - - cxx_tokens_lexer l; - l.start (expr); - - string tl; - for (cpp_ttype tt (l.next (tl)), ptt (CPP_EOF); tt != CPP_EOF;) - { - // Try to format the expression to resemble the style of the - // generated code. - // - switch (tt) - { - case CPP_NOT: - { - add_space (r); - r += '!'; - break; - } - case CPP_COMMA: - { - r += ", "; - break; - } - case CPP_OPEN_PAREN: - { - if (ptt == CPP_NAME || - ptt == CPP_KEYWORD) - add_space (r); - - r += '('; - break; - } - case CPP_CLOSE_PAREN: - { - r += ')'; - break; - } - case CPP_OPEN_SQUARE: - { - r += '['; - break; - } - case CPP_CLOSE_SQUARE: - { - r += ']'; - break; - } - case CPP_OPEN_BRACE: - { - add_space (r); - r += "{ "; - break; - } - case CPP_CLOSE_BRACE: - { - add_space (r); - r += '}'; - break; - } - case CPP_SEMICOLON: - { - r += ';'; - break; - } - case CPP_ELLIPSIS: - { - add_space (r); - r += "..."; - break; - } - case CPP_PLUS: - case CPP_MINUS: - { - bool unary (ptt != CPP_NAME && - ptt != CPP_SCOPE && - ptt != CPP_NUMBER && - ptt != CPP_STRING && - ptt != CPP_CLOSE_PAREN && - ptt != CPP_PLUS_PLUS && - ptt != CPP_MINUS_MINUS); - - if (!unary) - add_space (r); - - r += cxx_lexer::token_spelling[tt]; - - if (!unary) - r += ' '; - break; - } - case CPP_PLUS_PLUS: - case CPP_MINUS_MINUS: - { - if (ptt != CPP_NAME && - ptt != CPP_CLOSE_PAREN && - ptt != CPP_CLOSE_SQUARE) - add_space (r); - - r += cxx_lexer::token_spelling[tt]; - break; - } - case CPP_DEREF: - case CPP_DEREF_STAR: - case CPP_DOT: - case CPP_DOT_STAR: - { - r += cxx_lexer::token_spelling[tt]; - break; - } - case CPP_STRING: - { - if (ptt == CPP_NAME || - ptt == CPP_KEYWORD || - ptt == CPP_STRING || - ptt == CPP_NUMBER) - add_space (r); - - r += context::strlit (tl); - break; - } - case CPP_NUMBER: - { - if (ptt == CPP_NAME || - ptt == CPP_KEYWORD || - ptt == CPP_STRING || - ptt == CPP_NUMBER) - add_space (r); - - r += tl; - break; - } - case CPP_SCOPE: - { - // Add space except for a few common cases. - // - if (ptt != CPP_NAME && - ptt != CPP_OPEN_PAREN && - ptt != CPP_OPEN_SQUARE) - add_space (r); - - r += cxx_lexer::token_spelling[tt]; - break; - } - case CPP_NAME: - { - // Start of a name. - // - if (ptt == CPP_NAME || - ptt == CPP_KEYWORD || - ptt == CPP_STRING || - ptt == CPP_NUMBER) - add_space (r); - - r += tl; - break; - } - case CPP_QUERY: - { - if (ptt == CPP_OPEN_PAREN) - { - // Get the next token and see if it is ')'. - // - ptt = tt; - tt = l.next (tl); - - if (tt == CPP_CLOSE_PAREN) - r += val; - else - { - add_space (r); - r += "? "; - } - continue; // We have already gotten the next token. - } - } - // Fall through. - default: - { - // Handle CPP_KEYWORD here to avoid a warning (it is not - // part of the cpp_ttype enumeration). - // - if (tt == CPP_KEYWORD) - { - if (ptt == CPP_NAME || - ptt == CPP_KEYWORD || - ptt == CPP_STRING || - ptt == CPP_NUMBER) - add_space (r); - - r += tl; - } - else - { - // All the other operators. - // - add_space (r); - r += cxx_lexer::token_spelling[tt]; - r += ' '; - } - break; - } - } - - // - // Watch out for the continue statements above if you add any - // logic here. - // - - ptt = tt; - tt = l.next (tl); - } - - return r; -} - - -// -// view_object -// - -string view_object:: -name () const -{ - if (!alias.empty ()) - return alias; - - return kind == object ? context::class_name (*obj) : tbl_name.string (); -} - -// -// member_access -// - -bool member_access:: -placeholder () const -{ - for (cxx_tokens::const_iterator i (expr.begin ()), e (expr.end ()); i != e;) - { - if (i->type == CPP_OPEN_PAREN) - { - if (++i != e && i->type == CPP_QUERY) - { - if (++i != e && i->type == CPP_CLOSE_PAREN) - return true; - } - } - else - ++i; - } - - return false; -} - -string member_access:: -translate (string const& obj, string const& val, string const& db) const -{ - if (empty ()) - { - error (loc) << "non-empty " << kind << " expression required" << endl; - throw operation_failed (); - } - - // This code is similar to translate_expression() from relations/source.cxx. - // - string r; - - cxx_tokens_lexer l; - l.start (expr); - - string tl; - for (cpp_ttype tt (l.next (tl)), ptt (CPP_EOF); tt != CPP_EOF;) - { - // Try to format the expression to resemble the style of the - // generated code. - // - switch (tt) - { - case CPP_COMMA: - { - r += ", "; - break; - } - case CPP_OPEN_PAREN: - { - if (ptt == CPP_NAME || - ptt == CPP_KEYWORD) - add_space (r); - - r += '('; - break; - } - case CPP_CLOSE_PAREN: - { - r += ')'; - break; - } - case CPP_OPEN_SQUARE: - { - r += '['; - break; - } - case CPP_CLOSE_SQUARE: - { - r += ']'; - break; - } - case CPP_OPEN_BRACE: - { - add_space (r); - r += "{ "; - break; - } - case CPP_CLOSE_BRACE: - { - add_space (r); - r += '}'; - break; - } - case CPP_SEMICOLON: - { - r += ';'; - break; - } - case CPP_ELLIPSIS: - { - add_space (r); - r += "..."; - break; - } - case CPP_PLUS: - case CPP_MINUS: - { - bool unary (ptt != CPP_NAME && - ptt != CPP_SCOPE && - ptt != CPP_NUMBER && - ptt != CPP_STRING && - ptt != CPP_CLOSE_PAREN && - ptt != CPP_PLUS_PLUS && - ptt != CPP_MINUS_MINUS); - - if (!unary) - add_space (r); - - r += cxx_lexer::token_spelling[tt]; - - if (!unary) - r += ' '; - break; - } - case CPP_PLUS_PLUS: - case CPP_MINUS_MINUS: - { - if (ptt != CPP_NAME && - ptt != CPP_CLOSE_PAREN && - ptt != CPP_CLOSE_SQUARE) - add_space (r); - - r += cxx_lexer::token_spelling[tt]; - break; - } - case CPP_DEREF: - case CPP_DEREF_STAR: - case CPP_DOT: - case CPP_DOT_STAR: - { - r += cxx_lexer::token_spelling[tt]; - break; - } - case CPP_STRING: - { - if (ptt == CPP_NAME || - ptt == CPP_KEYWORD || - ptt == CPP_STRING || - ptt == CPP_NUMBER) - add_space (r); - - r += context::strlit (tl); - break; - } - case CPP_NUMBER: - { - if (ptt == CPP_NAME || - ptt == CPP_KEYWORD || - ptt == CPP_STRING || - ptt == CPP_NUMBER) - add_space (r); - - r += tl; - break; - } - case CPP_SCOPE: - { - // Add space except for a few common cases. - // - if (ptt != CPP_NAME && - ptt != CPP_OPEN_PAREN && - ptt != CPP_OPEN_SQUARE) - add_space (r); - - r += cxx_lexer::token_spelling[tt]; - break; - } - case CPP_NAME: - { - // Start of a name. - // - if (ptt == CPP_NAME || - ptt == CPP_KEYWORD || - ptt == CPP_STRING || - ptt == CPP_NUMBER) - add_space (r); - - r += tl; - break; - } - case CPP_NOT: - case CPP_QUERY: - { - if (ptt == CPP_OPEN_PAREN) - { - // Get the next token and see if it is ')'. - // - ptt = tt; - tt = l.next (tl); - - if (tt == CPP_CLOSE_PAREN) - { - if (ptt == CPP_NOT) - { - if (db.empty ()) - { - error (loc) << "database instance (!) not available in this " - << "context" << endl; - throw operation_failed (); - } - - r += db; - } - else - r += val; - } - else - { - add_space (r); - r += (ptt == CPP_NOT ? "!" : "? "); - } - continue; // We have already gotten the next token. - } - } - // Fall through. - default: - { - // Handle CPP_KEYWORD here to avoid a warning (it is not - // part of the cpp_ttype enumeration). - // - if (tt == CPP_KEYWORD) - { - if (ptt == CPP_NAME || - ptt == CPP_KEYWORD || - ptt == CPP_STRING || - ptt == CPP_NUMBER) - add_space (r); - - // Translate 'this'. - // - r += (tl == "this" ? obj : tl); - } - else - { - // All the other operators. - // - add_space (r); - r += cxx_lexer::token_spelling[tt]; - r += ' '; - } - break; - } - } - - // - // Watch out for the continue statements above if you add any - // logic here. - // - - ptt = tt; - tt = l.next (tl); - } - - return r; -} - -// Sections. -// -main_section_type main_section; - -bool main_section_type:: -compare (object_section const& s) const -{ - main_section_type const* ms (dynamic_cast (&s)); - return ms != 0 && *this == *ms; -} - -bool user_section:: -compare (object_section const& s) const -{ - user_section const* us (dynamic_cast (&s)); - return us != 0 && *this == *us; -} - -user_section* user_section:: -total_base () const -{ - if (base != 0) - { - semantics::class_* poly_root (context::polymorphic (*object)); - if (poly_root != 0 && poly_root != *object) - return base; - } - - return 0; -} - -size_t user_sections:: -count (unsigned short f) const -{ - size_t r (0); - - semantics::class_* poly_root (context::polymorphic (*object)); - bool poly_derived (poly_root != 0 && poly_root != object); - - if (poly_derived && (f & count_total) != 0) - r = context::polymorphic_base (*object).get ( - "user-sections").count (f); - - for (const_iterator i (begin ()); i != end (); ++i) - { - // Skip special sections unless we were explicitly asked to count them. - // - if (i->special == user_section::special_version && - (f & count_special_version) == 0) - continue; - - // Skip non-versioned sections if we are only interested in the - // versioned ones. - // - if ((f & count_versioned_only) != 0 && - !context::added (*i->member) && !context::deleted (*i->member)) - continue; - - bool ovd (i->base != 0 && poly_derived); - - if (i->load != user_section::load_eager) - { - if (i->load_empty ()) - { - if ((f & count_load_empty) != 0) - { - if (ovd) - { - if ((f & count_override) != 0) - { - r++; - continue; // Count each section only once. - } - } - else - { - if ((f & count_new) != 0 || (f & count_total) != 0) - { - r++; - continue; - } - } - } - } - else - { - if ((f & count_load) != 0) - { - if (ovd) - { - if ((f & count_override) != 0) - { - r++; - continue; - } - } - else - { - if ((f & count_new) != 0 || (f & count_total) != 0) - { - r++; - continue; - } - } - } - } - } - - if (i->update_empty ()) - { - if ((f & count_update_empty) != 0) - { - if (ovd) - { - if ((f & count_override) != 0) - { - r++; - continue; - } - } - else - { - if ((f & count_new) != 0 || (f & count_total) != 0) - { - r++; - continue; - } - } - } - } - else - { - if ((f & count_update) != 0) - { - if (ovd) - { - if ((f & count_override) != 0) - { - r++; - continue; - } - } - else - { - if ((f & count_new) != 0 || (f & count_total) != 0) - { - r++; - continue; - } - } - } - } - - if (i->optimistic ()) - { - if ((f & count_optimistic) != 0) - { - if (ovd) - { - if ((f & count_override) != 0) - { - r++; - continue; - } - } - else - { - if ((f & count_new) != 0 || (f & count_total) != 0) - { - r++; - continue; - } - } - } - } - } - - return r; -} - -// -// context -// - -namespace -{ - char const* keywords[] = - { - "NULL", - "and", - "asm", - "auto", - "bitand", - "bitor", - "bool", - "break", - "case", - "catch", - "char", - "class", - "compl", - "const", - "const_cast", - "continue", - "default", - "delete", - "do", - "double", - "dynamic_cast", - "else", - "end_eq", - "enum", - "explicit", - "export", - "extern", - "false", - "float", - "for", - "friend", - "goto", - "if", - "inline", - "int", - "long", - "mutable", - "namespace", - "new", - "not", - "not_eq", - "operator", - "or", - "or_eq", - "private", - "protected", - "public", - "register", - "reinterpret_cast", - "return", - "short", - "signed", - "sizeof", - "static", - "static_cast", - "struct", - "switch", - "template", - "this", - "throw", - "true", - "try", - "typedef", - "typeid", - "typename", - "union", - "unsigned", - "using", - "virtual", - "void", - "volatile", - "wchar_t", - "while", - "xor", - "xor_eq" - }; -} - -unique_ptr -create_context (ostream& os, - semantics::unit& unit, - options const& ops, - features& f, - semantics::relational::model* m) -{ - unique_ptr r; - - switch (ops.database ()[0]) - { - case database::common: - { - r.reset (new context (os, unit, ops, f)); - break; - } - case database::mssql: - { - r.reset (new relational::mssql::context (os, unit, ops, f, m)); - break; - } - case database::mysql: - { - r.reset (new relational::mysql::context (os, unit, ops, f, m)); - break; - } - case database::oracle: - { - r.reset (new relational::oracle::context (os, unit, ops, f, m)); - break; - } - case database::pgsql: - { - r.reset (new relational::pgsql::context (os, unit, ops, f, m)); - break; - } - case database::sqlite: - { - r.reset (new relational::sqlite::context (os, unit, ops, f, m)); - break; - } - } - - return r; -} - -context:: -~context () -{ - if (current_ == this) - current_ = 0; -} - -context:: -context (ostream& os_, - semantics::unit& u, - options_type const& ops, - features_type& f, - data_ptr d) - : data_ (d ? d : data_ptr (new (shared) data (os_))), - extra (data_->extra_), - os (data_->os_), - unit (u), - options (ops), - features (f), - db (options.database ()[0]), - in_comment (data_->in_comment_), - exp (data_->exp_), - ext (data_->ext_), - keyword_set (data_->keyword_set_), - include_regex (data_->include_regex_), - accessor_regex (data_->accessor_regex_), - modifier_regex (data_->modifier_regex_), - embedded_schema ( - ops.generate_schema () && - ops.schema_format ()[db].count (schema_format::embedded)), - separate_schema ( - ops.generate_schema () && - ops.schema_format ()[db].count (schema_format::separate)), - multi_static (ops.multi_database () == multi_database::static_), - multi_dynamic (ops.multi_database () == multi_database::dynamic), - force_versioned (false), - top_object (data_->top_object_), - cur_object (data_->cur_object_) -{ - assert (current_ == 0); - current_ = this; - - // Write boolean values as true/false. - // - os.setf (ios_base::boolalpha); - - // Export control. - // - if (!ops.export_symbol ()[db].empty ()) - exp = ops.export_symbol ()[db] + " "; - - ext = ops.extern_symbol ()[db]; - - for (size_t i (0); i < sizeof (keywords) / sizeof (char*); ++i) - data_->keyword_set_.insert (keywords[i]); - - // SQL name regex. - // - if (ops.table_regex ().count (db) != 0) - { - strings const& s (ops.table_regex ()[db]); - data_->sql_name_regex_[sql_name_table].assign (s.begin (), s.end ()); - } - - if (ops.column_regex ().count (db) != 0) - { - strings const& s (ops.column_regex ()[db]); - data_->sql_name_regex_[sql_name_column].assign (s.begin (), s.end ()); - } - - if (ops.index_regex ().count (db) != 0) - { - strings const& s (ops.index_regex ()[db]); - data_->sql_name_regex_[sql_name_index].assign (s.begin (), s.end ()); - } - - if (ops.fkey_regex ().count (db) != 0) - { - strings const& s (ops.fkey_regex ()[db]); - data_->sql_name_regex_[sql_name_fkey].assign (s.begin (), s.end ()); - } - - if (ops.sequence_regex ().count (db) != 0) - { - strings const& s (ops.sequence_regex ()[db]); - data_->sql_name_regex_[sql_name_sequence].assign (s.begin (), s.end ()); - } - - if (ops.statement_regex ().count (db) != 0) - { - strings const& s (ops.statement_regex ()[db]); - data_->sql_name_regex_[sql_name_statement].assign (s.begin (), s.end ()); - } - - if (ops.sql_name_regex ().count (db) != 0) - { - strings const& s (ops.sql_name_regex ()[db]); - data_->sql_name_regex_[sql_name_all].assign (s.begin (), s.end ()); - } - - // Include regex. - // - for (strings::const_iterator i (ops.include_regex ().begin ()); - i != ops.include_regex ().end (); ++i) - data_->include_regex_.push_back (regexsub (*i)); - - // Common accessor/modifier naming variants. Try the user-supplied and - // more specific ones first. - // - for (strings::const_iterator i (ops.accessor_regex ().begin ()); - i != ops.accessor_regex ().end (); ++i) - data_->accessor_regex_.push_back (regexsub (*i)); - - data_->accessor_regex_.push_back (regexsub ("/(.+)/get_$1/")); // get_foo - data_->accessor_regex_.push_back (regexsub ("/(.+)/get\\u$1/")); // getFoo - data_->accessor_regex_.push_back (regexsub ("/(.+)/get$1/")); // getfoo - data_->accessor_regex_.push_back (regexsub ("/(.+)/$1/")); // foo - - for (strings::const_iterator i (ops.modifier_regex ().begin ()); - i != ops.modifier_regex ().end (); ++i) - data_->modifier_regex_.push_back (regexsub (*i)); - - data_->modifier_regex_.push_back (regexsub ("/(.+)/set_$1/")); // set_foo - data_->modifier_regex_.push_back (regexsub ("/(.+)/set\\u$1/")); // setFoo - data_->modifier_regex_.push_back (regexsub ("/(.+)/set$1/")); // setfoo - data_->modifier_regex_.push_back (regexsub ("/(.+)/$1/")); // foo -} - -context:: -context () - : data_ (current ().data_), - extra (current ().extra), - os (current ().os), - unit (current ().unit), - options (current ().options), - features (current ().features), - db (current ().db), - in_comment (current ().in_comment), - exp (current ().exp), - ext (current ().ext), - keyword_set (current ().keyword_set), - include_regex (current ().include_regex), - accessor_regex (current ().accessor_regex), - modifier_regex (current ().modifier_regex), - embedded_schema (current ().embedded_schema), - separate_schema (current ().separate_schema), - multi_static (current ().multi_static), - multi_dynamic (current ().multi_dynamic), - force_versioned (current ().force_versioned), - top_object (current ().top_object), - cur_object (current ().cur_object) -{ -} - -context* context::current_; - -semantics::data_member* context:: -id (data_member_path const& mp) -{ - semantics::data_member* idf (mp.front ()); - - if (!id (*idf)) - return 0; - - // This is for special ids, such as polymorphic-ref, which - // don't have "id-member" set (and we want to keep it that - // way since it is not really a full-fledged id). - // - if (idf->get ("id").empty ()) // Not a nested id. - return idf; - - const data_member_path& id ( - *id_member ( - dynamic_cast (idf->scope ()))); - - // Now we need to make sure id is a prefix of mp; - // - return mp.sub (id) ? idf : 0; -} - -semantics::data_member* context:: -object_pointer (data_member_path const& mp) -{ - for (data_member_path::const_reverse_iterator i (mp.rbegin ()); - i != mp.rend (); ++i) - { - if (object_pointer (utype (**i))) - return *i; - } - - return 0; -} - -bool context:: -readonly (data_member_path const& mp, data_member_scope const& ms) -{ - assert (mp.size () == ms.size ()); - - data_member_scope::const_reverse_iterator si (ms.rbegin ()); - - for (data_member_path::const_reverse_iterator pi (mp.rbegin ()); - pi != mp.rend (); - ++pi, ++si) - { - semantics::data_member& m (**pi); - - if (m.count ("readonly")) - return true; - - // Check if any of the classes in the inheritance chain for the - // class containing this member are readonly. - // - class_inheritance_chain const& ic (*si); - - assert (ic.back () == &m.scope ()); - - for (class_inheritance_chain::const_reverse_iterator ci (ic.rbegin ()); - ci != ic.rend (); - ++ci) - { - semantics::class_& c (**ci); - - if (c.count ("readonly")) - return true; - } - } - - return false; -} - -bool context:: -readonly (semantics::data_member& m) -{ - if (m.count ("readonly")) - return true; - - // Check if the whole class (object or composite value) is marked - // as readonly. - // - if (m.scope ().count ("readonly")) - return true; - - return false; -} - -bool context:: -null (data_member_path const& mp) const -{ - // Outer members can override the null-ability of the inner ones. So - // start from the most outer member. - // - for (data_member_path::const_iterator i (mp.begin ()); i != mp.end (); ++i) - { - if (null (**i)) - return true; - } - - return false; -} - -bool context:: -null (semantics::data_member& m) const -{ - semantics::names* hint; - semantics::type& t (utype (m, hint)); - - if (object_pointer (t)) - { - // By default pointers can be null. - // - if (m.count ("null")) - return true; - - if (!m.count ("not-null")) - { - if (t.count ("null")) - return true; - - if (!t.count ("not-null")) - return true; - } - - return false; - } - else - { - // Everything else by default is not null. - // - if (m.count ("null")) - return true; - - if (!m.count ("not-null")) - { - if (t.count ("null")) - return true; - - if (!t.count ("not-null")) - { - semantics::type* pt; - - // Check if this type is a wrapper. - // - if (t.get ("wrapper")) - { - // First see if it is null by default. - // - if (t.get ("wrapper-null-handler") && - t.get ("wrapper-null-default")) - return true; - - // Otherwise, check the wrapped type. - // - pt = t.get ("wrapper-type"); - hint = t.get ("wrapper-hint"); - pt = &utype (*pt, hint); - - if (pt->count ("null")) - return true; - - if (pt->count ("not-null")) - return false; - } - else - pt = &t; - } - } - - return false; - } -} - -bool context:: -null (semantics::data_member& m, string const& kp) const -{ - if (kp.empty ()) - return null (m); - - semantics::type& c (utype (m)); - semantics::type& t (utype (m, kp)); - - if (object_pointer (t)) - { - if (m.count (kp + "-null")) - return true; - - if (!m.count (kp + "-not-null")) - { - if (c.count (kp + "-null")) - return true; - - if (!c.count (kp + "-not-null")) - { - if (t.count ("null")) - return true; - - if (!t.count ("not-null")) - { - return true; - } - } - } - - return false; - } - else - { - if (m.count (kp + "-null")) - return true; - - if (!m.count (kp + "-not-null")) - { - if (c.count (kp + "-null")) - return true; - - if (!c.count (kp + "-not-null")) - { - if (t.count ("null")) - return true; - - if (!t.count ("not-null")) - { - semantics::type* pt; - - // Check if this type is a wrapper. - // - if (t.get ("wrapper")) - { - // First see if it is null by default. - // - if (t.get ("wrapper-null-handler") && - t.get ("wrapper-null-default")) - return true; - - // Otherwise, check the wrapped type. - // - pt = t.get ("wrapper-type"); - pt = &utype (*pt); - - if (pt->count ("null")) - return true; - - if (pt->count ("not-null")) - return false; - } - else - pt = &t; - } - } - } - - return false; - } -} - -size_t context:: -polymorphic_depth (semantics::class_& c) -{ - if (c.count ("polymorphic-depth")) - return c.get ("polymorphic-depth"); - - // Calculate our hierarchy depth (number of classes). - // - using semantics::class_; - - class_* root (polymorphic (c)); - assert (root != 0); - - size_t r (1); // One for the root. - - for (class_* b (&c); b != root; b = &polymorphic_base (*b)) - ++r; - - c.set ("polymorphic-depth", r); - return r; -} - -context::class_kind_type context:: -class_kind (semantics::class_& c) -{ - if (object (c)) - return class_object; - else if (view (c)) - return class_view; - else if (composite (c)) - return class_composite; - else - return class_other; -} - -string context:: -class_name (semantics::class_& c) -{ - return c.is_a () - ? c.get ("tree-hint")->name () - : c.name (); -} - -string context:: -class_fq_name (semantics::class_& c) -{ - return c.is_a () - ? c.fq_name (c.get ("tree-hint")) - : c.fq_name (); -} - -semantics::scope& context:: -class_scope (semantics::class_& c) -{ - return c.is_a () - ? c.get ("tree-hint")->scope () - : c.scope (); -} - -semantics::path context:: -class_file (semantics::class_& c) -{ - // If we have an explicit definition location, use that. - // - if (c.count ("definition")) - return semantics::path (LOCATION_FILE (c.get ("definition"))); - // - // Otherwise, if it is a template instantiation, use the location - // of the qualifier. - // - else if (c.is_a ()) - return semantics::path (LOCATION_FILE (c.get ("location"))); - else - return c.file (); -} - -location_t context:: -class_location (semantics::class_& c) -{ - return c.count ("definition") - ? c.get ("definition") - : class_real_location (c); -} - -location_t context:: -class_real_location (semantics::class_& c) -{ - return c.is_a () - ? c.get ("location") - : real_source_location (TYPE_NAME (c.tree_node ())); -} - -string context:: -upcase (string const& s) -{ - string r; - string::size_type n (s.size ()); - - r.reserve (n); - - for (string::size_type i (0); i < n; ++i) - r.push_back (toupper (s[i])); - - return r; -} - -void context:: -diverge (streambuf* sb) -{ - data_->os_stack_.push (data_->os_.rdbuf ()); - data_->os_.rdbuf (sb); -} - -void context:: -restore () -{ - data_->os_.rdbuf (data_->os_stack_.top ()); - data_->os_stack_.pop (); -} - -semantics::type& context:: -utype (semantics::type& t) -{ - if (semantics::qualifier* q = dynamic_cast (&t)) - return q->base_type (); - else - return t; -} - -semantics::type& context:: -utype (semantics::type& t, semantics::names*& hint) -{ - if (semantics::qualifier* q = dynamic_cast (&t)) - { - hint = q->qualifies ().hint (); - return q->base_type (); - } - else - return t; -} - -semantics::type& context:: -utype (semantics::data_member& m, - semantics::names*& hint, - string const& kp, - const custom_cxx_type** translation) -{ - semantics::type* t (0); - - if (kp.empty ()) - { - t = &m.type (); - - if (semantics::qualifier* q = dynamic_cast (t)) - { - hint = q->qualifies ().hint (); - t = &q->base_type (); - } - else - hint = m.belongs ().hint (); - } - else - { - if (m.count (kp + "-tree-type")) - t = indirect_type (m, kp, hint); - else - { - t = &utype (m); - - // "See through" wrappers. - // - if (semantics::type* wt = wrapper (*t)) - t = indirect_type (utype (*wt), kp, hint); - else - t = indirect_type (*t, kp, hint); - } - } - - // Do we need to map this type? - // - // @@ Need to cache the result on the member. - // - if (translation != 0) - *translation = 0; - - for (semantics::scope* s (&m.scope ());; s = &s->scope_ ()) - { - using semantics::namespace_; - - if (namespace_* ns = dynamic_cast (s)) - { - if (ns->extension ()) - s = &ns->original (); - } - - if (s->count ("custom-cxx-type-map")) - { - typedef custom_cxx_type_map map; - - map& m (s->get ("custom-cxx-type-map")); - map::const_iterator i (m.find (t)); - - if (i != m.end ()) - { - hint = i->second->as_hint; - t = i->second->as; - - if (translation != 0) - *translation = i->second; - - // Currently we only support one level of mapping, but I am - // sure someone will want multiple levels. - // - break; - } - } - - if (!s->named_p () || s->global_scope ()) - break; - } - - return *t; -} - -bool context:: -const_type (semantics::type& t) -{ - if (semantics::qualifier* q = dynamic_cast (&t)) - return q->const_ (); - - return false; -} - -string context:: -type_ref_type (semantics::type& t, - semantics::names* hint, - bool mc, - string const& var, - bool decay) -{ - using semantics::array; - string r; - - // Note that trailing const syntax is used for a reason (consider - // t == const foo*). We may also have to decay then top-level array. - // - array* a; - if (decay && (a = dynamic_cast (&utype (t))) != 0) - { - semantics::type& bt (a->base_type ()); - hint = a->contains ().hint (); - - if (bt.is_a ()) - { - // If we need to add/strip const or no name was used in the - // declaration, then create an array declaration (e.g., for - // char x[2][3] we will have char const (*x)[3]). - // - if (mc != const_type (t) || hint == 0) - return type_val_type (bt, 0, mc, "(*" + var + ")"); - } - - // Array base type is always cvr-unqualified. - // - if (mc) - r = bt.fq_name (hint) + " const"; - else - r = bt.fq_name (hint); - - r += '*'; - - if (!var.empty ()) - r += ' ' + var; - } - else - { - if (mc == const_type (t)) - r = t.fq_name (hint); - else if (mc) - r = t.fq_name (hint) + " const"; - else - { - semantics::type& ut (utype (t, hint)); - r = ut.fq_name (hint); - } - - r += '&'; - - if (!var.empty ()) - r += ' ' + var; - } - - return r; -} - -string context:: -type_val_type (semantics::type& t, - semantics::names* hint, - bool mc, - string const& var) -{ - using semantics::array; - string r; - - // Arrays are a complicated case. Firstly, we may need to add/strip const - // to/from the base type. Secondly, the array dimensions are written after - // the variable name. All this is further complicated by multiple dimensions. - // Thanks, Dennis! - // - if (array* a = dynamic_cast (&utype (t))) - { - semantics::type& bt (a->base_type ()); - - // If we don't need to add/strip const and a name was used in the - // declaration, then use that name. - // - if (mc == const_type (t) && hint != 0) - { - r = t.fq_name (hint); - - if (!var.empty ()) - r += ' ' + var; - } - else - { - // Otherwise, construct the array declaration. - // - string v (var); - v += '['; - ostringstream ostr; - ostr << a->size (); - v += ostr.str (); - - if (a->size () > 0xFFFFFFFF) - v += "ULL"; - else if (a->size () > 2147483647) - v += "U"; - - v += ']'; - - r = type_val_type (bt, a->contains ().hint (), mc, v); - } - } - else - { - if (mc == const_type (t)) - r = t.fq_name (hint); - else if (mc) - r = t.fq_name (hint) + " const"; - else - { - semantics::type& ut (utype (t, hint)); - r = ut.fq_name (hint); - } - - if (!var.empty ()) - r += ' ' + var; - } - - return r; -} - -void context:: -set_member (semantics::data_member& m, - const string& obj, - const string& val, - const string& db, - const string& type) -{ - member_access& ma (m.get ("set")); - - // If this is a custom expression, output the location of where - // it came from. - // - if (!ma.synthesized) - os << "// From " << location_string (ma.loc, true) << endl; - - if (ma.placeholder ()) - { - // Cast the database to the concrete type this code is generated - // for. This way the user is free to use either the concrete or - // the common. - // - string d; - if (!db.empty ()) - d = "static_cast<" + context::db.string () + "::database&> (" + db + ")"; - - os << ma.translate (obj, val, d) << ";"; - } - else - { - // If this member is const and we have a synthesized direct access, - // then cast away constness. Otherwise, we assume that the user- - // provided expression handles this. - // - bool cast (!type.empty () && ma.direct () && const_member (m)); - if (cast) - os << "const_cast< " << type << "& > (" << endl; - - os << ma.translate (obj); - - if (cast) - os << ")"; - - os << " = " << val << ";"; - } -} - -void context:: -inc_member (semantics::data_member& m, - const string& obj, - const string& gobj, - const string& type) -{ - member_access& ma (m.get ("set")); - - // If this is a custom expression, output the location of where - // it came from. - // - if (!ma.synthesized) - os << "// From " << location_string (ma.loc, true) << endl; - - if (ma.placeholder ()) - { - member_access& gma (m.get ("get")); - - if (!gma.synthesized) - os << "// From " << location_string (gma.loc, true) << endl; - - os << ma.translate (obj, gma.translate (gobj) + " + 1") << ";"; - } - else - { - // If this member is const and we have a synthesized direct access, - // then cast away constness. Otherwise, we assume that the user- - // provided expression handles this. - // - os << "++"; - - bool cast (ma.direct () && const_member (m)); - if (cast) - os << "const_cast< " << type << "& > (" << endl; - - os << ma.translate (obj); - - if (cast) - os << ")"; - - os << ";"; - } -} - -void context:: -resolve_data_members (data_member_path& r, - semantics::class_& c, - const string& name, - const location& l, - cxx_string_lexer& lex) -{ - using semantics::class_; - using semantics::data_member; - - // The name was already verified to be syntactically correct so - // we don't need to do any extra error checking in this area. - // - lex.start (name); - - try - { - string tl; - cpp_ttype tt (lex.next (tl)); - - data_member& m (c.lookup (tl, class_::include_hidden)); - - r.push_back (&m); - - if (container (m)) - return; - - // Resolve nested members if any. - // - for (tt = lex.next (tl); tt == CPP_DOT; tt = lex.next (tl)) - { - lex.next (tl); // Get CPP_NAME. - - data_member& om (*r.back ()); - - // Check that the outer member is composite and also unwrap it while - // at it. - // - class_* comp (composite_wrapper (utype (om))); - if (comp == 0) - { - error (l) << "data member '" << om.name () << "' is not composite" - << endl; - throw operation_failed (); - } - - data_member& nm ( - comp->lookup (tl, class_::include_hidden)); - - r.push_back (&nm); - - if (container (nm)) - return; - } - } - catch (semantics::unresolved const& e) - { - if (e.type_mismatch) - error (l) << "name '" << e.name << "' does not refer to a data member" - << endl; - else - error (l) << "unable to resolve data member '" << e.name << endl; - - throw operation_failed (); - } - catch (semantics::ambiguous const& e) - { - error (l) << "data member name '" << e.first.name () << "' is ambiguous" - << endl; - - info (e.first.named ().location ()) << "could resolve to " << - "this data member" << endl; - - info (e.second.named ().location ()) << "or could resolve " << - "to this data member" << endl; - - throw operation_failed (); - } -} - -bool context:: -composite_ (semantics::class_& c) -{ - bool r (c.count ("value") && !c.count ("simple") && !c.count ("container")); - c.set ("composite-value", r); - return r; -} - -// context::table_prefix -// -context::table_prefix:: -table_prefix (semantics::class_& c) - : level (1) -{ - context& ctx (context::current ()); - - ns_schema = ctx.schema (class_scope (c)); - ns_prefix = ctx.table_name_prefix (class_scope (c)); - prefix = ctx.table_name (c, &derived); - prefix += "_"; -} - -void context::table_prefix:: -append (semantics::data_member& m) -{ - assert (level > 0); - - context& ctx (context::current ()); - - // If a custom table prefix was specified, then ignore the top-level - // table prefix (this corresponds to a container directly inside an - // object) but keep the schema unless the alternative schema is fully - // qualified. - // - if (m.count ("table")) - { - qname p, n (m.get ("table")); - - if (n.fully_qualified ()) - p = n.qualifier (); - else - { - if (n.qualified ()) - { - p = ns_schema; - p.append (n.qualifier ()); - } - else - p = prefix.qualifier (); - } - - if (level == 1) - { - p.append (ns_prefix); - derived = false; - } - else - p.append (prefix.uname ()); - - p += n.uname (); - prefix.swap (p); - } - // Otherwise use the member name and add an underscore unless it is - // already there. - // - else - { - string name (ctx.public_name_db (m)); - size_t n (name.size ()); - - prefix += name; - - if (n != 0 && name[n - 1] != '_') - prefix += "_"; - - derived = true; - } - - level++; -} - -qname context:: -schema (semantics::scope& s) const -{ - if (s.count ("qualified-schema")) - return s.get ("qualified-schema"); - - qname r; - - for (semantics::scope* ps (&s);; ps = &ps->scope_ ()) - { - using semantics::namespace_; - - namespace_* ns (dynamic_cast (ps)); - - if (ns == 0) // Some other scope. - { - if (!ps->named_p ()) - break; - - continue; - } - - if (ns->extension ()) - ns = &ns->original (); - - bool sf (ns->count ("schema")); - bool tf (ns->count ("table")); - - if (tf) - { - qname n (ns->get ("table")); - tf = n.qualified (); - - // If we have both schema and qualified table prefix, see which - // takes precedence based on order. - // - - if (tf && sf) - { - if (ns->get ("table-location") > - ns->get ("schema-location")) - sf = false; - else - tf = false; - } - } - - if (sf || tf) - { - qname n ( - sf - ? ns->get ("schema") - : ns->get ("table").qualifier ()); - n.append (r); - n.swap (r); - } - - if (r.fully_qualified () || - ns->global_scope ()) // Note: namespaces always named. - break; - } - - // If we are still not fully qualified, add the schema that was - // specified on the command line. - // - if (!r.fully_qualified () && options.schema ().count (db) != 0) - { - qname n (options.schema ()[db]); - n.append (r); - n.swap (r); - } - - s.set ("qualified-schema", r); - return r; -} - -string context:: -table_name_prefix (semantics::scope& s) const -{ - if (s.count ("table-prefix")) - return s.get ("table-prefix"); - - string r; - - for (semantics::scope* ps (&s);; ps = &ps->scope_ ()) - { - using semantics::namespace_; - - namespace_* ns (dynamic_cast (ps)); - - if (ns == 0) // Some other scope. - { - if (!ps->named_p ()) - break; - - continue; - } - - if (ns->extension ()) - ns = &ns->original (); - - if (ns->count ("table")) - { - qname n (ns->get ("table")); - r = n.uname () + r; - } - - if (ns->global_scope ()) // Note: namespaces always named. - break; - } - - // Add the prefix that was specified on the command line. - // - if (options.table_prefix ().count (db) != 0) - r = options.table_prefix ()[db] + r; - - s.set ("table-prefix", r); - return r; -} - -qname context:: -table_name (semantics::class_& c, bool* pd) const -{ - if (c.count ("qualified-table")) - return c.get ("qualified-table"); - - qname r; - bool sf (c.count ("schema")); - bool derived; - - if (c.count ("table")) - { - r = c.get ("table"); - - if (sf) - { - // If we have both schema and qualified table, see which takes - // precedence based on order. If the table is unqualifed, then - // add the schema. - // - sf = !r.qualified () || - c.get ("table-location") < - c.get ("schema-location"); - } - - derived = false; - } - else - { - r = class_name (c); - derived = true; - } - - if (sf) - { - qname n (c.get ("schema")); - n.append (r.uname ()); - n.swap (r); - } - - // Unless we are fully qualified, add any schemas that were - // specified on the namespaces and/or with the command line - // option. - // - if (!r.fully_qualified ()) - { - qname n (schema (class_scope (c))); - n.append (r); - n.swap (r); - } - - // Add the table prefix if any. - // - r.uname () = table_name_prefix (class_scope (c)) + r.uname (); - - if (derived) - r.uname () = transform_name (r.uname (), sql_name_table); - - c.set ("qualified-table", r); - - if (pd != 0) - *pd = derived; - - return r; -} - -qname context:: -table_name (semantics::class_& obj, data_member_path const& mp) const -{ - table_prefix tp (obj); - - if (mp.size () == 1) - { - // Container directly in the object. - // - return table_name (*mp.back (), tp); - } - else - { - data_member_path::const_iterator i (mp.begin ()); - - // The last member is the container. - // - for (data_member_path::const_iterator e (mp.end () - 1); i != e; ++i) - tp.append (**i); - - return table_name (**i, tp); - } -} - -// The table prefix passed as the second argument must include the table -// prefix specified on namespaces and with the --table-prefix option. -// -qname context:: -table_name (semantics::data_member& m, table_prefix const& p) const -{ - assert (p.level > 0); - qname r; - string rn; - bool derived; // Any of the components in the table name is derived. - - // If a custom table name was specified, then ignore the top-level - // table prefix (this corresponds to a container directly inside an - // object). If the container table is unqualifed, then we use the - // object schema. If it is fully qualified, then we use that name. - // Finally, if it is qualified but not fully qualifed, then we - // append the object's namespace schema. - // - if (m.count ("table")) - { - qname n (m.get ("table")); - - if (n.fully_qualified ()) - r = n.qualifier (); - else - { - if (n.qualified ()) - { - r = p.ns_schema; - r.append (n.qualifier ()); - } - else - r = p.prefix.qualifier (); - } - - if (p.level == 1) - { - rn = p.ns_prefix; - derived = false; - } - else - { - rn = p.prefix.uname (); - derived = p.derived; - } - - rn += n.uname (); - } - else - { - r = p.prefix.qualifier (); - rn = p.prefix.uname () + public_name_db (m); - derived = true; - } - - if (derived) - r.append (transform_name (rn, sql_name_table)); - else - r.append (rn); - - return r; -} - -string context:: -table_options (semantics::class_& c) -{ - string r; - - // Accumulate options from class. - // - // @@ Should we also get them from bases? - // - // @@ Note for some databases (like SQLite), options are seperated with - // comma, not space. Likely the same issue in the column_options(). - // - if (c.count ("options")) - { - strings const& o (c.get ("options")); - - for (strings::const_iterator i (o.begin ()); i != o.end (); ++i) - { - if (i->empty ()) - r.clear (); - else - { - if (!r.empty ()) - r += ' '; - - r += *i; - } - } - } - - return r; -} - -string context:: -table_options (semantics::data_member& m, semantics::type& c) -{ - string r; - - // Accumulate options from container and member. - // - // @@ Currently there is no way to assign options to the container type. If - // we use the value specifier, then it ends up being treated as a value - // type. To support this we will probably need to invent the container - // specifier. - // - if (c.count ("options")) - { - strings const& o (c.get ("options")); - - for (strings::const_iterator i (o.begin ()); i != o.end (); ++i) - { - if (i->empty ()) - r.clear (); - else - { - if (!r.empty ()) - r += ' '; - - r += *i; - } - } - } - - if (m.count ("options")) - { - strings const& o (m.get ("options")); - - for (strings::const_iterator i (o.begin ()); i != o.end (); ++i) - { - if (i->empty ()) - r.clear (); - else - { - if (!r.empty ()) - r += ' '; - - r += *i; - } - } - } - - return r; -} - -// context::column_prefix -// -context::column_prefix:: -column_prefix (data_member_path const& mp, bool l) - : derived (false), underscore (false) -{ - if (mp.size () < (l ? 1 : 2)) - return; - - for (data_member_path::const_iterator i (mp.begin ()), - e (mp.end () - (l ? 0 : 1)); i != e; ++i) - append (**i); -} - -void context::column_prefix:: -append (semantics::data_member& m, string const& kp, string const& dn) -{ - bool d; - context& ctx (context::current ()); - - if (kp.empty ()) - prefix += ctx.column_name (m, d); - else - prefix += ctx.column_name (m, kp, dn, d); - - // If the user provided the column prefix, then use it verbatime. - // Otherwise, append the underscore, unless it is already there. - // - underscore = false; - if (d) - { - size_t n (prefix.size ()); - - if (n != 0 && prefix[n - 1] != '_') - { - prefix += '_'; - underscore = true; - } - } - - derived = derived || d; -} - -string context:: -column_name (semantics::data_member& m, bool& derived) const -{ - derived = !m.count ("column"); - return derived - ? public_name_db (m) - : m.get ("column").column; -} - -string context:: -column_name (semantics::data_member& m, column_prefix const& cp) const -{ - bool d; - const string& cn (column_name (m, d)); - string n (cp.prefix); - - if (cn.empty () && cp.underscore) - n.resize (n.size () - 1); // Strip underscore that was auto added. - - n += cn; - - // If any component is derived, then run it through the SQL name regex. - // - if (d || cp.derived) - n = transform_name (n, sql_name_column); - - return n; -} - -string context:: -column_name (semantics::data_member& m, - string const& p, - string const& d, - bool& derived) const -{ - if (p.empty () && d.empty ()) - return column_name (m, derived); - - // A container column name can be specified for the member or for the - // container type. - // - string key (p + "-column"); - derived = false; - - if (m.count (key)) - return m.get (key); - else - { - semantics::type& t (utype (m)); - - if (t.count (key)) - return t.get (key); - } - - derived = true; - return d; -} - -string context:: -column_name (semantics::data_member& m, - string const& kp, - string const& dn, - column_prefix const& cp) const -{ - bool d; - const string& cn (column_name (m, kp, dn, d)); - string n (cp.prefix); - - if (cn.empty () && cp.underscore) - n.resize (n.size () - 1); // Strip underscore that was auto-added. - - n += cn; - - // If any component is derived, the run it through the SQL name regex. - // - if (d || cp.derived) - n = transform_name (n, sql_name_column); - - return n; -} - -string context:: -column_name (data_member_path const& mp) const -{ - return column_name (*mp.back (), column_prefix (mp)); -} - -string context:: -column_type (const data_member_path& mp, string const& kp, bool id) -{ - if (kp.empty ()) - { - // Return the id type if this member is or is a part of an object id - // or pointer to object. - // - return mp.back ()->get ( - id || context::id (mp) || object_pointer (mp) - ? "column-id-type" - : "column-type"); - } - else - return indirect_value (*mp.back (), kp + "-column-type"); -} - -string context:: -column_type (semantics::data_member& m, string const& kp) -{ - return kp.empty () - ? m.get ("column-type") - : indirect_value (m, kp + "-column-type"); -} - -string context:: -column_options (semantics::data_member& m) -{ - // Accumulate options from both type and member. - // - semantics::type* t (&utype (m)); - - if (semantics::class_* p = object_pointer (*t)) - t = &utype (*id_member (*p)); - - if (semantics::type* w = wrapper (*t)) - t = w; - - string r; - - if (t->count ("options")) - { - strings const& o (t->get ("options")); - - for (strings::const_iterator i (o.begin ()); i != o.end (); ++i) - { - if (i->empty ()) - r.clear (); - else - { - if (!r.empty ()) - r += ' '; - - r += *i; - } - } - } - - if (m.count ("options")) - { - strings const& o (m.get ("options")); - - for (strings::const_iterator i (o.begin ()); i != o.end (); ++i) - { - if (i->empty ()) - r.clear (); - else - { - if (!r.empty ()) - r += ' '; - - r += *i; - } - } - } - - return r; -} - -string context:: -column_options (semantics::data_member& m, string const& kp) -{ - if (kp.empty ()) - return column_options (m); - - string k (kp + "-options"); - - // Accumulate options from type, container, and member. - // - semantics::type& c (utype (m)); - semantics::type* t (&utype (m, kp)); - - if (semantics::class_* p = object_pointer (*t)) - t = &utype (*id_member (*p)); - - if (semantics::type* w = wrapper (*t)) - t = w; - - string r; - - if (t->count ("options")) - { - strings const& o (t->get ("options")); - - for (strings::const_iterator i (o.begin ()); i != o.end (); ++i) - { - if (i->empty ()) - r.clear (); - else - { - if (!r.empty ()) - r += ' '; - - r += *i; - } - } - } - - if (c.count (k)) - { - strings const& o (c.get (k)); - - for (strings::const_iterator i (o.begin ()); i != o.end (); ++i) - { - if (i->empty ()) - r.clear (); - else - { - if (!r.empty ()) - r += ' '; - - r += *i; - } - } - } - - if (m.count (k)) - { - strings const& o (m.get (k)); - - for (strings::const_iterator i (o.begin ()); i != o.end (); ++i) - { - if (i->empty ()) - r.clear (); - else - { - if (!r.empty ()) - r += ' '; - - r += *i; - } - } - } - - return r; -} - -context::type_map_type::const_iterator context::type_map_type:: -find (semantics::type& t, semantics::names* hint) -{ - const_iterator e (end ()), i (e); - - // First check the hinted name. This allows us to handle things like - // size_t which is nice to map to the same type irrespective of the - // actual type. Since this type can be an alias for the one we are - // interested in, go into nested hints. - // - for (; hint != 0 && i == e; hint = hint->hint ()) - i = base::find (t.fq_name (hint)); - - // If the hinted name didn't work, try the primary name (e.g., - // ::std::string) instead of a user typedef (e.g., my_string). - // - if (i == e) - i = base::find (t.fq_name ()); - - return i; -} - -string context:: -database_type_impl (semantics::type& t, - semantics::names* hint, - bool id, - bool* null) -{ - 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; - } - - return string (); -} - -static string -public_name_impl (semantics::data_member& m) -{ - string s (m.name ()); - size_t n (s.size ()); - - // Do basic processing: remove trailing and leading underscores - // as well as the 'm_' prefix. - // - // @@ What if the resulting names conflict? - // - size_t b (0), e (n - 1); - - if (n > 2 && s[0] == 'm' && s[1] == '_') - b += 2; - - for (; b <= e && s[b] == '_'; b++) ; - for (; e >= b && s[e] == '_'; e--) ; - - return b > e ? s : string (s, b, e - b + 1); -} - -string context:: -public_name_db (semantics::data_member& m) const -{ - return public_name_impl (m); -} - -string context:: -compose_name (string const& prefix, string const& name) -{ - string r (prefix); - size_t n (r.size ()); - - // Add an underscore unless one is already in the prefix or - // the name is empty. Similarly, remove it if it is there but - // the name is empty. - // - if (n != 0) - { - if (r[n - 1] != '_') - { - if (!name.empty ()) - r += '_'; - } - else - { - if (name.empty ()) - r.resize (n - 1); - } - } - - r += name; - return r; -} - -string context:: -transform_name (string const& name, sql_name_type type) const -{ - string r; - - if (!data_->sql_name_regex_[type].empty () || - !data_->sql_name_regex_[sql_name_all].empty ()) - { - bool t (options.sql_name_regex_trace ()); - - if (t) - cerr << "name: '" << name << "'" << endl; - - bool found (false); - - // First try the type-specific transformations, if that didn't work, - // try common transformations. - // - for (unsigned short j (0); !found && j < 2; ++j) - { - regex_mapping const& rm = data_->sql_name_regex_[ - j == 0 ? type : sql_name_all]; - - for (regex_mapping::const_iterator i (rm.begin ()); i != rm.end (); ++i) - { - if (t) - cerr << "try: '" << i->regex () << "' : "; - - if (i->match (name)) - { - r = i->replace (name); - found = true; - - if (t) - cerr << "'" << r << "' : "; - } - - if (t) - cerr << (found ? '+' : '-') << endl; - - if (found) - break; - } - } - - if (!found) - r = name; - } - else - r = name; - - if (options.sql_name_case ().count (db) != 0) - { - switch (options.sql_name_case ()[db]) - { - case name_case::upper: - { - r = data_->sql_name_upper_.replace (r); - break; - } - case name_case::lower: - { - r = data_->sql_name_lower_.replace (r); - break; - } - } - } - - return r; -} - -string context:: -public_name (semantics::data_member& m, bool e) const -{ - return e ? escape (public_name_impl (m)) : public_name_impl (m); -} - -string context:: -flat_name (string const& fq) -{ - string r; - r.reserve (fq.size ()); - - for (string::size_type i (0), n (fq.size ()); i < n; ++i) - { - char c (fq[i]); - - if (c == ':') - { - if (!r.empty ()) - r += '_'; - ++i; // Skip the second ':'. - } - else - r += c; - } - - return r; -} - -string context:: -escape (string const& name) const -{ - typedef string::size_type size; - - string r; - size n (name.size ()); - - // In most common cases we will have that many characters. - // - r.reserve (n); - - for (size i (0); i < n; ++i) - { - char c (name[i]); - - if (i == 0) - { - if (!((c >= 'a' && c <= 'z') || - (c >= 'A' && c <= 'Z') || - c == '_')) - r = (c >= '0' && c <= '9') ? "cxx_" : "cxx"; - } - - if (!((c >= 'a' && c <= 'z') || - (c >= 'A' && c <= 'Z') || - (c >= '0' && c <= '9') || - c == '_')) - r += '_'; - else - r += c; - } - - if (r.empty ()) - r = "cxx"; - - // Custom reserved words. - // - /* - reserved_name_map_type::const_iterator i (reserved_name_map.find (r)); - - if (i != reserved_name_map.end ()) - { - if (!i->second.empty ()) - return i->second; - else - r += L'_'; - } - */ - - // Keywords - // - if (keyword_set.find (r) != keyword_set.end ()) - { - r += '_'; - - // Re-run custom words. - // - /* - i = reserved_name_map.find (r); - - if (i != reserved_name_map.end ()) - { - if (!i->second.empty ()) - return i->second; - else - r += L'_'; - } - */ - } - - return r; -} - -string context:: -make_guard (string const& s) const -{ - // Split words, e.g., "FooBar" to "Foo_Bar" and convert everything - // to upper case. - // - string r; - for (string::size_type i (0), n (s.size ()); i < n - 1; ++i) - { - char c1 (s[i]); - char c2 (s[i + 1]); - - r += toupper (c1); - - if (isalpha (c1) && isalpha (c2) && islower (c1) && isupper (c2)) - r += "_"; - } - r += toupper (s[s.size () - 1]); - - return escape (r); -} - -static string -charlit (unsigned int u) -{ - string r ("\\x"); - bool lead (true); - - for (short i (7); i >= 0; --i) - { - unsigned int x ((u >> (i * 4)) & 0x0F); - - if (lead) - { - if (x == 0) - continue; - - lead = false; - } - - r += static_cast (x < 10 ? ('0' + x) : ('A' + x - 10)); - } - - return r; -} - -static string -strlit_ascii (string const& str) -{ - string r; - string::size_type n (str.size ()); - - // In most common cases we will have that many chars. - // - r.reserve (n + 2); - - r += '"'; - - bool escape (false); - - for (string::size_type i (0); i < n; ++i) - { - unsigned int u (static_cast (str[i])); - - // [128 - ] - unrepresentable - // 127 - \x7F - // [32 - 126] - as is - // [0 - 31] - \X or \xXX - // - - if (u < 32 || u == 127) - { - switch (u) - { - case '\n': - { - r += "\\n"; - break; - } - case '\t': - { - r += "\\t"; - break; - } - case '\v': - { - r += "\\v"; - break; - } - case '\b': - { - r += "\\b"; - break; - } - case '\r': - { - r += "\\r"; - break; - } - case '\f': - { - r += "\\f"; - break; - } - case '\a': - { - r += "\\a"; - break; - } - default: - { - r += charlit (u); - escape = true; - break; - } - } - } - else if (u < 127) - { - if (escape) - { - // Close and open the string so there are no clashes. - // - r += '"'; - r += '"'; - - escape = false; - } - - switch (u) - { - case '"': - { - r += "\\\""; - break; - } - case '\\': - { - r += "\\\\"; - break; - } - default: - { - r += static_cast (u); - break; - } - } - } - else - { - // @@ Unrepresentable character. - // - r += '?'; - } - } - - r += '"'; - - return r; -} - -string context:: -strlit (string const& str) -{ - return strlit_ascii (str); -} - -void context:: -inst_header (bool decl, bool omit_exp) -{ - if (decl && !ext.empty ()) - os << ext << " "; - - os << "template struct"; - - if (!omit_exp && !exp.empty ()) - { - // If we are generating an explicit instantiation directive rather - // than the extern template declaration, then omit the export symbol - // if we already have it in the header (i.e., extern symbol specified - // and defined). If we don't do that, then we get GCC warnings saying - // that the second set of visibility attributes is ignored. - // - if (!decl && !ext.empty ()) - os << endl - << "#ifndef " << ext << endl - << options.export_symbol ()[db] << endl - << "#endif" << endl; - else - os << " " << exp; - } - else - os << " "; -} - -namespace -{ - struct column_count_impl: object_members_base - { - column_count_impl (object_section* section = 0) - : object_members_base (false, section) - { - } - - virtual void - traverse_pointer (semantics::data_member& m, semantics::class_& c) - { - // Object pointers in views require special treatment. - // - if (view_member (m)) - { - using semantics::class_; - - column_count_type cc; - - if (class_* root = polymorphic (c)) - { - // For a polymorphic class we are going to load all the members - // from all the bases (i.e., equivalent to the first statement - // in the list of SELECT statements generated for the object). - // So our count should be the same as the first value in the - // generated column_counts array. - // - for (class_* b (&c);; b = &polymorphic_base (*b)) - { - column_count_type const& ccb (column_count (*b, section_)); - - cc.total += ccb.total - (b != root ? ccb.id : 0); - cc.separate_load += ccb.separate_load; - cc.soft += ccb.soft; - - if (b == root) - break; - } - } - else - cc = column_count (c, section_); - - c_.total += cc.total - cc.separate_load; - - if (added (member_path_) != 0 || deleted (member_path_) != 0) - c_.soft += cc.total; - else - c_.soft += cc.soft; - } - else - { - size_t t (c_.total); - - object_members_base::traverse_pointer (m, c); - - if (context::inverse (m)) - { - size_t n (c_.total - t); - - c_.inverse += n; - - if (separate_update (member_path_)) - c_.separate_update -= n; - } - } - } - - virtual void - traverse_simple (semantics::data_member& m) - { - c_.total++; - - bool ro (context::readonly (member_path_, member_scope_)); - - if (id ()) - c_.id++; - else if (ro) - c_.readonly++; - else if (context::version (m)) - c_.optimistic_managed++; - - // For now discriminator can only be a simple value. - // - if (discriminator (m)) - c_.discriminator++; - - { - unsigned long long av (added (member_path_)); - unsigned long long dv (deleted (member_path_)); - - // If the addition/deletion version is the same as the section's, - // then don't count. - // - if (user_section* s = dynamic_cast (section_)) - { - if (av == added (*s->member)) - av = 0; - - if (dv == deleted (*s->member)) - dv = 0; - } - - if (av != 0) - c_.added++; - - if (dv != 0) - c_.deleted++; - - if (av != 0 || dv != 0) - c_.soft++; - } - - if (separate_load (member_path_)) - c_.separate_load++; - - if (separate_update (member_path_) && !ro) - c_.separate_update++; - } - - context::column_count_type c_; - }; -} - -context::column_count_type context:: -column_count (semantics::class_& c, object_section* s) -{ - if (s == 0) - { - // Whole class. - // - if (!c.count ("column-count")) - { - column_count_impl t; - t.traverse (c); - c.set ("column-count", t.c_); - } - - return c.get ("column-count"); - } - else - { - column_count_impl t (s); - t.traverse (c); - return t.c_; - } -} - -namespace -{ - struct has_a_impl: object_members_base - { - has_a_impl (unsigned short flags, object_section* s) - : object_members_base ((flags & context::include_base) != 0, s), - r_ (0), - flags_ (flags) - { - } - - size_t - result () const - { - return r_; - } - - virtual bool - section_test (data_member_path const& mp) - { - object_section& s (section (mp)); - - // Include eager loaded members into the main section if requested. - // - return section_ == 0 || - *section_ == s || - ((flags_ & include_eager_load) != 0 && - *section_ == main_section && - !s.separate_load ()); - } - - virtual void - traverse_pointer (semantics::data_member& m, semantics::class_&) - { - // Ignore polymorphic id references; they are represented as - // pointers but are normally handled in a special way. - // - if (m.count ("polymorphic-ref")) - return; - - // Ignore added/deleted members if so requested. - // - if (check_soft ()) - return; - - if (context::is_a (member_path_, member_scope_, flags_)) - r_++; - - // No need to go inside. - } - - virtual void - traverse_simple (semantics::data_member&) - { - // Ignore added/deleted members if so requested. - // - if (check_soft ()) - return; - - if (context::is_a (member_path_, member_scope_, flags_)) - r_++; - } - - virtual void - traverse_container (semantics::data_member& m, semantics::type&) - { - // Ignore added/deleted members if so requested. - // - if (check_soft ()) - return; - - // Ignore versioned containers if so requested. - // - if ((flags_ & exclude_versioned) != 0 && versioned (m)) - return; - - // We don't cross the container boundaries (separate table). - // - unsigned short f (flags_ & (context::test_container | - context::test_straight_container | - context::test_inverse_container | - context::test_readonly_container | - context::test_readwrite_container | - context::test_smart_container)); - - if (context::is_a (member_path_, - member_scope_, - f, - context::container_vt (m), - "value")) - r_++; - } - - virtual void - traverse_object (semantics::class_& c) - { - if ((flags_ & context::exclude_base) == 0) - inherits (c); - - names (c); - } - - private: - bool - check_soft () - { - if ((flags_ & exclude_added) != 0 || (flags_ & exclude_deleted) != 0) - { - unsigned long long av (added (member_path_)); - unsigned long long dv (deleted (member_path_)); - - // If the addition/deletion version is the same as the section's, - // then don't exclude. - // - if (user_section* s = dynamic_cast (section_)) - { - if (av == added (*s->member)) - av = 0; - - if (dv == deleted (*s->member)) - dv = 0; - } - - if ((av != 0 && (flags_ & exclude_added) != 0) || - (dv != 0 && (flags_ & exclude_deleted) != 0)) - return true; - } - - return false; - } - - private: - size_t r_; - unsigned short flags_; - }; -} - -bool context:: -is_a (data_member_path const& mp, - data_member_scope const& ms, - unsigned short f, - semantics::type& t, - string const& kp) -{ - bool r (false); - - semantics::data_member& m (*mp.back ()); - - if (f & test_pointer) - r = r || object_pointer (t); - - if (f & test_eager_pointer) - r = r || (object_pointer (t) && !lazy_pointer (t)); - - if (f & test_lazy_pointer) - r = r || (object_pointer (t) && lazy_pointer (t)); - - semantics::type* c; - if ((f & (test_container | - test_straight_container | - test_inverse_container | - test_readonly_container | - test_readwrite_container | - test_smart_container)) != 0 && - (c = container (m)) != 0) - { - if (f & test_container) - r = r || true; - - if (f & test_straight_container) - r = r || !inverse (m, kp); - - if (f & test_inverse_container) - r = r || inverse (m, kp); - - if (f & test_readonly_container) - r = r || readonly (mp, ms); - - if (f & test_readwrite_container) - r = r || (!inverse (m, kp) && !readonly (mp, ms)); - - if (f & test_smart_container) - r = r || (!inverse (m, kp) && !unordered (m) && container_smart (*c)); - } - - return r; -} - -size_t context:: -has_a (semantics::class_& c, unsigned short flags, object_section* s) -{ - has_a_impl impl (flags, s); - impl.dispatch (c); - return impl.result (); -} - -string context:: -process_include_path (string const& ip, bool prefix, char open) -{ - bool t (options.include_regex_trace ()); - string p (prefix ? options.include_prefix () : string ()); - - if (!p.empty () && p[p.size () - 1] != '/') - p.append ("/"); - - string path (p + ip), r; - - if (t) - cerr << "include: '" << path << "'" << endl; - - bool found (false); - - for (regex_mapping::const_iterator i (include_regex.begin ()); - i != include_regex.end (); ++i) - { - if (t) - cerr << "try: '" << i->regex () << "' : "; - - if (i->match (path)) - { - r = i->replace (path); - found = true; - - if (t) - cerr << "'" << r << "' : "; - } - - if (t) - cerr << (found ? '+' : '-') << endl; - - if (found) - break; - } - - if (!found) - r = path; - - // Add brackets or quotes unless the path already has them. - // - if (!r.empty () && r[0] != '"' && r[0] != '<') - { - bool b (open == '<' || (open == '\0' && options.include_with_brackets ())); - char op (b ? '<' : '"'), cl (b ? '>' : '"'); - r = op + r + cl; - } - - return r; -} -- cgit v1.1