summaryrefslogtreecommitdiff
path: root/odb/context.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'odb/context.cxx')
-rw-r--r--odb/context.cxx3289
1 files changed, 0 insertions, 3289 deletions
diff --git a/odb/context.cxx b/odb/context.cxx
deleted file mode 100644
index e220d0e..0000000
--- a/odb/context.cxx
+++ /dev/null
@@ -1,3289 +0,0 @@
-// file : odb/context.cxx
-// license : GNU GPL v3; see accompanying LICENSE file
-
-#include <odb/gcc.hxx>
-
-#include <cctype> // std::toupper
-#include <cassert>
-#include <sstream>
-
-#include <odb/context.hxx>
-#include <odb/common.hxx>
-#include <odb/pragma.hxx>
-#include <odb/cxx-lexer.hxx>
-#include <odb/diagnostics.hxx>
-
-#include <odb/relational/mssql/context.hxx>
-#include <odb/relational/mysql/context.hxx>
-#include <odb/relational/oracle/context.hxx>
-#include <odb/relational/pgsql/context.hxx>
-#include <odb/relational/sqlite/context.hxx>
-
-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<main_section_type const*> (&s));
- return ms != 0 && *this == *ms;
-}
-
-bool user_section::
-compare (object_section const& s) const
-{
- user_section const* us (dynamic_cast<user_section const*> (&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> (
- "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<context>
-create_context (ostream& os,
- semantics::unit& unit,
- options const& ops,
- features& f,
- semantics::relational::model* m)
-{
- unique_ptr<context> 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<string> ("id").empty ()) // Not a nested id.
- return idf;
-
- const data_member_path& id (
- *id_member (
- dynamic_cast<semantics::class_&> (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<bool> ("wrapper"))
- {
- // First see if it is null by default.
- //
- if (t.get<bool> ("wrapper-null-handler") &&
- t.get<bool> ("wrapper-null-default"))
- return true;
-
- // Otherwise, check the wrapped type.
- //
- pt = t.get<semantics::type*> ("wrapper-type");
- hint = t.get<semantics::names*> ("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<bool> ("wrapper"))
- {
- // First see if it is null by default.
- //
- if (t.get<bool> ("wrapper-null-handler") &&
- t.get<bool> ("wrapper-null-default"))
- return true;
-
- // Otherwise, check the wrapped type.
- //
- pt = t.get<semantics::type*> ("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<size_t> ("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<semantics::class_instantiation> ()
- ? c.get<semantics::names*> ("tree-hint")->name ()
- : c.name ();
-}
-
-string context::
-class_fq_name (semantics::class_& c)
-{
- return c.is_a<semantics::class_instantiation> ()
- ? c.fq_name (c.get<semantics::names*> ("tree-hint"))
- : c.fq_name ();
-}
-
-semantics::scope& context::
-class_scope (semantics::class_& c)
-{
- return c.is_a<semantics::class_instantiation> ()
- ? c.get<semantics::names*> ("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<location_t> ("definition")));
- //
- // Otherwise, if it is a template instantiation, use the location
- // of the qualifier.
- //
- else if (c.is_a<semantics::class_instantiation> ())
- return semantics::path (LOCATION_FILE (c.get<location_t> ("location")));
- else
- return c.file ();
-}
-
-location_t context::
-class_location (semantics::class_& c)
-{
- return c.count ("definition")
- ? c.get<location_t> ("definition")
- : class_real_location (c);
-}
-
-location_t context::
-class_real_location (semantics::class_& c)
-{
- return c.is_a<semantics::class_instantiation> ()
- ? c.get<location_t> ("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<semantics::qualifier*> (&t))
- return q->base_type ();
- else
- return t;
-}
-
-semantics::type& context::
-utype (semantics::type& t, semantics::names*& hint)
-{
- if (semantics::qualifier* q = dynamic_cast<semantics::qualifier*> (&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<semantics::qualifier*> (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<namespace_*> (s))
- {
- if (ns->extension ())
- s = &ns->original ();
- }
-
- if (s->count ("custom-cxx-type-map"))
- {
- typedef custom_cxx_type_map map;
-
- map& m (s->get<map> ("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->global_scope ())
- break;
- }
-
- return *t;
-}
-
-bool context::
-const_type (semantics::type& t)
-{
- if (semantics::qualifier* q = dynamic_cast<semantics::qualifier*> (&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<array*> (&utype (t))) != 0)
- {
- semantics::type& bt (a->base_type ());
- hint = a->contains ().hint ();
-
- if (bt.is_a<array> ())
- {
- // 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<array*> (&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<member_access> ("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<member_access> ("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<member_access> ("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<data_member> (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<data_member> (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<qname> ("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<qname> ("qualified-schema");
-
- qname r;
-
- for (semantics::scope* ps (&s);; ps = &ps->scope_ ())
- {
- using semantics::namespace_;
-
- namespace_* ns (dynamic_cast<namespace_*> (ps));
-
- if (ns == 0)
- continue; // Some other scope.
-
- if (ns->extension ())
- ns = &ns->original ();
-
- bool sf (ns->count ("schema"));
- bool tf (ns->count ("table"));
-
- if (tf)
- {
- qname n (ns->get<qname> ("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<location_t> ("table-location") >
- ns->get<location_t> ("schema-location"))
- sf = false;
- else
- tf = false;
- }
- }
-
- if (sf || tf)
- {
- qname n (
- sf
- ? ns->get<qname> ("schema")
- : ns->get<qname> ("table").qualifier ());
- n.append (r);
- n.swap (r);
- }
-
- if (r.fully_qualified () || ns->global_scope ())
- 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<string> ("table-prefix");
-
- string r;
-
- for (semantics::scope* ps (&s);; ps = &ps->scope_ ())
- {
- using semantics::namespace_;
-
- namespace_* ns (dynamic_cast<namespace_*> (ps));
-
- if (ns == 0)
- continue; // Some other scope.
-
- if (ns->extension ())
- ns = &ns->original ();
-
- if (ns->count ("table"))
- {
- qname n (ns->get<qname> ("table"));
- r = n.uname () + r;
- }
-
- if (ns->global_scope ())
- 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<qname> ("qualified-table");
-
- qname r;
- bool sf (c.count ("schema"));
- bool derived;
-
- if (c.count ("table"))
- {
- r = c.get<qname> ("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<location_t> ("table-location") <
- c.get<location_t> ("schema-location");
- }
-
- derived = false;
- }
- else
- {
- r = class_name (c);
- derived = true;
- }
-
- if (sf)
- {
- qname n (c.get<qname> ("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<qname> ("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;
-}
-
-// 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<table_column> ("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<string> (key);
- else
- {
- semantics::type& t (utype (m));
-
- if (t.count (key))
- return t.get<string> (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<string> (
- id || context::id (mp) || object_pointer (mp)
- ? "column-id-type"
- : "column-type");
- }
- else
- return indirect_value<string> (*mp.back (), kp + "-column-type");
-}
-
-string context::
-column_type (semantics::data_member& m, string const& kp)
-{
- return kp.empty ()
- ? m.get<string> ("column-type")
- : indirect_value<string> (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<strings> ("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<strings> ("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<strings> ("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<strings> (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<strings> (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<enum_*> (&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<char> (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<unsigned int> (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<char> (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<user_section*> (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_type> ("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<user_section*> (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;
-}