aboutsummaryrefslogtreecommitdiff
path: root/odb
diff options
context:
space:
mode:
Diffstat (limited to 'odb')
-rw-r--r--odb/context.cxx2
-rw-r--r--odb/context.hxx30
-rw-r--r--odb/plugin.cxx8
-rw-r--r--odb/pragma.cxx101
-rw-r--r--odb/processor.cxx273
-rw-r--r--odb/processor.hxx6
-rw-r--r--odb/relational/context.hxx20
-rw-r--r--odb/validator.hxx3
8 files changed, 287 insertions, 156 deletions
diff --git a/odb/context.cxx b/odb/context.cxx
index d6336d1..dc94abc 100644
--- a/odb/context.cxx
+++ b/odb/context.cxx
@@ -644,6 +644,7 @@ context (ostream& os_,
include_regex (data_->include_regex_),
accessor_regex (data_->accessor_regex_),
modifier_regex (data_->modifier_regex_),
+ custom_type_map (u.get<custom_cxx_type_map> ("custom-cxx-type-map")),
embedded_schema (
ops.generate_schema () &&
ops.schema_format ()[db].count (schema_format::embedded)),
@@ -761,6 +762,7 @@ context ()
include_regex (current ().include_regex),
accessor_regex (current ().accessor_regex),
modifier_regex (current ().modifier_regex),
+ custom_type_map (current ().custom_type_map),
embedded_schema (current ().embedded_schema),
separate_schema (current ().separate_schema),
multi_static (current ().multi_static),
diff --git a/odb/context.hxx b/odb/context.hxx
index 3b283ee..a98167f 100644
--- a/odb/context.hxx
+++ b/odb/context.hxx
@@ -112,6 +112,34 @@ typedef std::vector<class_inheritance_chain> data_member_scope;
// Semantic graph context types.
//
+// Custom C++ type mapping.
+//
+struct custom_cxx_type
+{
+ custom_cxx_type (): type_node (0), as_node (0) {}
+
+ tree type_node;
+ std::string type_name;
+ semantics::type* type;
+ semantics::names* type_hint;
+
+ tree as_node;
+ std::string as_name;
+ semantics::type* as;
+ semantics::names* as_hint;
+
+ // Empty expression means the values are implicitly convertible.
+ //
+ cxx_tokens to;
+ cxx_tokens from;
+
+ location_t loc;
+};
+
+typedef std::vector<custom_cxx_type> custom_cxx_types;
+typedef std::map<semantics::type*, custom_cxx_type*> custom_cxx_type_map;
+
+
// Object or view pointer.
//
struct class_pointer
@@ -1675,6 +1703,8 @@ public:
regex_mapping const& accessor_regex;
regex_mapping const& modifier_regex;
+ custom_cxx_type_map const& custom_type_map;
+
bool embedded_schema;
bool separate_schema;
diff --git a/odb/plugin.cxx b/odb/plugin.cxx
index 51f0cb1..ed7bd14 100644
--- a/odb/plugin.cxx
+++ b/odb/plugin.cxx
@@ -201,13 +201,17 @@ gate_callback (void*, void*)
features f;
+ // Process, pass 1.
+ //
+ process (*options_, f, *u, file_, 1);
+
// Validate, pass 1.
//
validate (*options_, f, *u, file_, 1);
- // Process.
+ // Process, pass 2.
//
- process (*options_, f, *u, file_);
+ process (*options_, f, *u, file_, 2);
// Validate, pass 2.
//
diff --git a/odb/pragma.cxx b/odb/pragma.cxx
index 01c31d2..733d19c 100644
--- a/odb/pragma.cxx
+++ b/odb/pragma.cxx
@@ -869,11 +869,56 @@ handle_pragma (cxx_lexer& l,
tt = l.next (tl, &tn);
- using relational::custom_db_type;
- using relational::custom_cxx_type;
+ if (qualifier_value.type_info () == typeid (custom_cxx_type))
+ {
+ // C++ type mapping.
+ //
+ custom_cxx_type& ct (qualifier_value.value<custom_cxx_type> ());
+
+ if (p == "type" || p == "as")
+ {
+ // Can be built-in type (e.g., bool).
+ //
+ if (tt == CPP_NAME || tt == CPP_KEYWORD || tt == CPP_SCOPE)
+ {
+ string name;
+ tree decl (
+ resolve_scoped_name (
+ l, tt, tl, tn, current_scope (), name, true, p));
+
+ if (decl == 0)
+ return; // Diagnostics has already been issued.
+
+ if (TREE_CODE (decl) != TYPE_DECL)
+ {
+ error (loc) << "name '" << name << "' in db pragma "
+ << p << " does not refer to a type" << endl;
+ return;
+ }
- if (qualifier_value.type_info () == typeid (custom_db_type))
+ (p == "type" ? ct.type_node : ct.as_node) = TREE_TYPE (decl);
+ (p == "type" ? ct.type_name : ct.as_name) = name;
+ }
+ else
+ {
+ error (l) << "type name expected in db pragma " << p << endl;
+ return;
+ }
+ }
+ else if (p == "to" || p == "from")
+ {
+ if (tt != CPP_CLOSE_PAREN) // Empty expression is ok.
+ {
+ if (!parse_expression (
+ l, tt, tl, tn, (p == "to" ? ct.to : ct.from), p))
+ return; // Diagnostics has already been issued.
+ }
+ }
+ }
+ else
{
+ using relational::custom_db_type;
+
// Database type mapping.
//
custom_db_type& ct (qualifier_value.value<custom_db_type> ());
@@ -932,54 +977,6 @@ handle_pragma (cxx_lexer& l,
tt = l.next (tl, &tn);
}
- else
- {
- // C++ type mapping.
- //
- custom_cxx_type& ct (qualifier_value.value<custom_cxx_type> ());
-
- if (p == "type" || p == "as")
- {
- // Can be built-in type (e.g., bool).
- //
- if (tt == CPP_NAME || tt == CPP_KEYWORD || tt == CPP_SCOPE)
- {
- string name;
- tree type (
- resolve_scoped_name (
- l, tt, tl, tn, current_scope (), name, true, p));
-
- if (type == 0)
- return; // Diagnostics has already been issued.
-
- if (TREE_CODE (type) != TYPE_DECL)
- {
- error (loc) << "name '" << name << "' in db pragma "
- << p << " does not refer to a type" << endl;
- return;
- }
-
- type = TREE_TYPE (type);
-
- (p == "type" ? ct.type_node : ct.as_node) = type;
- (p == "type" ? ct.type_name : ct.as_name) = name;
- }
- else
- {
- error (l) << "type name expected in db pragma " << p << endl;
- return;
- }
- }
- else if (p == "to" || p == "from")
- {
- if (tt != CPP_CLOSE_PAREN) // Empty expression is ok.
- {
- if (!parse_expression (
- l, tt, tl, tn, (p == "to" ? ct.to : ct.from), p))
- return; // Diagnostics has already been issued.
- }
- }
- }
if (tt != CPP_CLOSE_PAREN)
{
@@ -3118,8 +3115,6 @@ handle_pragma_qualifier (cxx_lexer& l, string p)
}
else
{
- using relational::custom_cxx_type;
-
custom_cxx_type ct;
ct.loc = loc;
val = ct;
diff --git a/odb/processor.cxx b/odb/processor.cxx
index f059d0b..f4cff89 100644
--- a/odb/processor.cxx
+++ b/odb/processor.cxx
@@ -20,6 +20,26 @@ using namespace std;
namespace
{
+ // Find name hint for this type decl.
+ //
+ static semantics::names*
+ find_hint (semantics::unit& u, tree decl)
+ {
+ semantics::names* r (0);
+
+ for (tree ot (DECL_ORIGINAL_TYPE (decl));
+ ot != 0;
+ ot = decl ? DECL_ORIGINAL_TYPE (decl) : 0)
+ {
+ if ((r = u.find_hint (ot)))
+ break;
+
+ decl = TYPE_NAME (ot);
+ }
+
+ return r;
+ }
+
// Indirect (dynamic) context values.
//
static semantics::type*
@@ -218,8 +238,8 @@ namespace
e.push_back (cxx_token (0, CPP_KEYWORD, "this"));
e.push_back (cxx_token (0, CPP_DOT));
e.push_back (cxx_token (0, CPP_NAME, n));
- e.push_back (cxx_token (0, CPP_OPEN_PAREN, n));
- e.push_back (cxx_token (0, CPP_CLOSE_PAREN, n));
+ e.push_back (cxx_token (0, CPP_OPEN_PAREN));
+ e.push_back (cxx_token (0, CPP_CLOSE_PAREN));
// See if it returns by value.
//
@@ -279,8 +299,8 @@ namespace
e.push_back (cxx_token (0, CPP_KEYWORD, "this"));
e.push_back (cxx_token (0, CPP_DOT));
e.push_back (cxx_token (0, CPP_NAME, n));
- e.push_back (cxx_token (0, CPP_OPEN_PAREN, n));
- e.push_back (cxx_token (0, CPP_CLOSE_PAREN, n));
+ e.push_back (cxx_token (0, CPP_OPEN_PAREN));
+ e.push_back (cxx_token (0, CPP_CLOSE_PAREN));
return found_best;
}
@@ -316,9 +336,9 @@ namespace
e.push_back (cxx_token (0, CPP_KEYWORD, "this"));
e.push_back (cxx_token (0, CPP_DOT));
e.push_back (cxx_token (0, CPP_NAME, n));
- e.push_back (cxx_token (0, CPP_OPEN_PAREN, n));
+ e.push_back (cxx_token (0, CPP_OPEN_PAREN));
e.push_back (cxx_token (0, CPP_QUERY));
- e.push_back (cxx_token (0, CPP_CLOSE_PAREN, n));
+ e.push_back (cxx_token (0, CPP_CLOSE_PAREN));
// Continue searching in case there is version that returns a
// non-const reference which we prefer for efficiency.
@@ -982,17 +1002,7 @@ namespace
// Find the hint.
//
- semantics::names* wh (0);
-
- for (tree ot (DECL_ORIGINAL_TYPE (decl));
- ot != 0;
- ot = decl ? DECL_ORIGINAL_TYPE (decl) : 0)
- {
- if ((wh = unit.find_hint (ot)))
- break;
-
- decl = TYPE_NAME (ot);
- }
+ semantics::names* wh (find_hint (unit, decl));
t.set ("wrapper-type", wt);
t.set ("wrapper-hint", wh);
@@ -1531,15 +1541,7 @@ namespace
// Find the hint.
//
- for (tree ot (DECL_ORIGINAL_TYPE (decl));
- ot != 0;
- ot = decl ? DECL_ORIGINAL_TYPE (decl) : 0)
- {
- if ((vh = unit.find_hint (ot)))
- break;
-
- decl = TYPE_NAME (ot);
- }
+ vh = find_hint (unit, decl);
}
catch (operation_failed const&)
{
@@ -1598,15 +1600,7 @@ namespace
// Find the hint.
//
- for (tree ot (DECL_ORIGINAL_TYPE (decl));
- ot != 0;
- ot = decl ? DECL_ORIGINAL_TYPE (decl) : 0)
- {
- if ((ih = unit.find_hint (ot)))
- break;
-
- decl = TYPE_NAME (ot);
- }
+ ih = find_hint (unit, decl);
}
catch (operation_failed const&)
{
@@ -1640,15 +1634,7 @@ namespace
// Find the hint.
//
- for (tree ot (DECL_ORIGINAL_TYPE (decl));
- ot != 0;
- ot = decl ? DECL_ORIGINAL_TYPE (decl) : 0)
- {
- if ((kh = unit.find_hint (ot)))
- break;
-
- decl = TYPE_NAME (ot);
- }
+ kh = find_hint (unit, decl);
}
catch (operation_failed const&)
{
@@ -3016,60 +3002,189 @@ namespace
tree access_; // odb::access node.
};
+
+ static void
+ check_to_from (const cxx_tokens& ex, const char* c, location_t l)
+ {
+ // Make sure we have one and only one placeholder (?).
+ //
+ bool r (false);
+
+ for (cxx_tokens::const_iterator i (ex.begin ()), e (ex.end ()); i != e;)
+ {
+ if (i->type == CPP_OPEN_PAREN)
+ {
+ if (++i != e && i->type == CPP_QUERY)
+ {
+ if (++i != e && i->type == CPP_CLOSE_PAREN)
+ {
+ if (r)
+ {
+ error (l) << "multiple '(?)' expressions in the '" << c << "' "
+ << "clause of db pragma map" << endl;
+ throw operation_failed ();
+ }
+ else
+ r = true;
+ }
+ }
+ }
+ else
+ ++i;
+ }
+
+ if (!r)
+ {
+ error (l) << "no '(?)' expression in the '" << c << "' clause "
+ << "of db pragma map" << endl;
+
+ throw operation_failed ();
+ }
+ }
}
-void
-process (options const& ops,
- features& f,
- semantics::unit& unit,
- semantics::path const&)
+static void
+process1 (semantics::unit& u)
{
- try
+ // Process custom C++ type mapping.
+ //
+
+ // Create an empty list if we don't have one. This makes the
+ // rest of the code simpler.
+ //
+ if (!u.count ("custom-cxx-types"))
+ u.set ("custom-cxx-types", custom_cxx_types ());
+
+ custom_cxx_types & cts (u.get<custom_cxx_types> ("custom-cxx-types"));
+ custom_cxx_type_map& ctm (u.set ("custom-cxx-type-map",
+ custom_cxx_type_map ()));
+
+ for (custom_cxx_types::iterator i (cts.begin ()); i != cts.end (); ++i)
{
- auto_ptr<context> ctx (create_context (cerr, unit, ops, f, 0));
+ custom_cxx_type& ct (*i);
- // Common processing.
+ // type
//
+ if (ct.type_node == 0)
{
- traversal::unit unit;
- traversal::defines unit_defines;
- typedefs unit_typedefs (true);
- traversal::namespace_ ns;
- class_ c;
-
- unit >> unit_defines >> ns;
- unit_defines >> c;
- unit >> unit_typedefs >> c;
-
- traversal::defines ns_defines;
- typedefs ns_typedefs (true);
+ error (ct.loc) << "'type' clause expected in db pragma map" << endl;
+ throw operation_failed ();
+ }
- ns >> ns_defines >> ns;
- ns_defines >> c;
- ns >> ns_typedefs >> c;
+ ct.type = dynamic_cast<semantics::type*> (
+ u.find (TYPE_MAIN_VARIANT (ct.type_node)));
+ ct.type_hint = u.find_hint (ct.type_node);
- unit.dispatch (ctx->unit);
+ // as
+ //
+ if (ct.as_node == 0)
+ {
+ error (ct.loc) << "'as' clause expected in db pragma map" << endl;
+ throw operation_failed ();
}
- // Database-specific processing.
+ ct.as = dynamic_cast<semantics::type*> (
+ u.find (TYPE_MAIN_VARIANT (ct.as_node)));
+ ct.as_hint = u.find_hint (ct.as_node);
+
+ // to
//
- switch (ops.database ()[0])
{
- case database::common:
+ cxx_tokens& e (ct.to);
+
+ if (e.empty ())
{
- break;
+ e.push_back (cxx_token (0, CPP_OPEN_PAREN));
+ e.push_back (cxx_token (0, CPP_QUERY));
+ e.push_back (cxx_token (0, CPP_CLOSE_PAREN));
}
- case database::mssql:
- case database::mysql:
- case database::oracle:
- case database::pgsql:
- case database::sqlite:
+ else
+ check_to_from (e, "to", ct.loc);
+ }
+
+ // to
+ //
+ {
+ cxx_tokens& e (ct.from);
+
+ if (e.empty ())
{
- relational::process ();
- break;
+ e.push_back (cxx_token (0, CPP_OPEN_PAREN));
+ e.push_back (cxx_token (0, CPP_QUERY));
+ e.push_back (cxx_token (0, CPP_CLOSE_PAREN));
}
+ else
+ check_to_from (e, "from", ct.loc);
+ }
+
+ // Enter into the map.
+ //
+ ctm[ct.type] = &ct;
+ }
+}
+
+static void
+process2 (options const& ops, features& f, semantics::unit& u)
+{
+ auto_ptr<context> ctx (create_context (cerr, u, ops, f, 0));
+
+ // Common processing.
+ //
+ {
+ traversal::unit unit;
+ traversal::defines unit_defines;
+ typedefs unit_typedefs (true);
+ traversal::namespace_ ns;
+ class_ c;
+
+ unit >> unit_defines >> ns;
+ unit_defines >> c;
+ unit >> unit_typedefs >> c;
+
+ traversal::defines ns_defines;
+ typedefs ns_typedefs (true);
+
+ ns >> ns_defines >> ns;
+ ns_defines >> c;
+ ns >> ns_typedefs >> c;
+
+ unit.dispatch (ctx->unit);
+ }
+
+ // Database-specific processing.
+ //
+ switch (ops.database ()[0])
+ {
+ case database::common:
+ {
+ break;
+ }
+ case database::mssql:
+ case database::mysql:
+ case database::oracle:
+ case database::pgsql:
+ case database::sqlite:
+ {
+ relational::process ();
+ break;
}
}
+}
+
+void
+process (options const& ops,
+ features& f,
+ semantics::unit& u,
+ semantics::path const&,
+ unsigned short pass)
+{
+ try
+ {
+ if (pass == 1)
+ process1 (u);
+ else if (pass == 2)
+ process2 (ops, f, u);
+ }
catch (operation_failed const&)
{
// Processing failed. Diagnostics has already been issued.
diff --git a/odb/processor.hxx b/odb/processor.hxx
index e62dd25..b010d6c 100644
--- a/odb/processor.hxx
+++ b/odb/processor.hxx
@@ -11,10 +11,14 @@
class processor_failed {};
+// Pass one is very early processing before any validation has been
+// done.
+//
void
process (options const&,
features&,
semantics::unit&,
- semantics::path const&);
+ semantics::path const&,
+ unsigned short pass);
#endif // ODB_PROCESSOR_HXX
diff --git a/odb/relational/context.hxx b/odb/relational/context.hxx
index 956f6c4..45dbba6 100644
--- a/odb/relational/context.hxx
+++ b/odb/relational/context.hxx
@@ -71,26 +71,6 @@ namespace relational
typedef std::vector<custom_db_type> custom_db_types;
- // Custom C++ type mapping.
- //
- struct custom_cxx_type
- {
- tree type_node;
- std::string type_name;
-
- tree as_node;
- std::string as_name;
-
- // Empty expression means the values are implicitly convertible.
- //
- cxx_tokens to;
- cxx_tokens from;
-
- location_t loc;
- };
-
- typedef std::vector<custom_cxx_type> custom_cxx_types;
-
class context: public virtual ::context
{
public:
diff --git a/odb/validator.hxx b/odb/validator.hxx
index 3ffa470..5159946 100644
--- a/odb/validator.hxx
+++ b/odb/validator.hxx
@@ -11,7 +11,8 @@
class validator_failed {};
-// The first pass is performed before processing. The second -- after.
+// The first pass is performed after processing pass 1 but before
+// processing pass 2. The second -- after pass 2.
//
void
validate (options const&,