From 6e35807bd495c0001cba229fd082e45f0421100e Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 19 Jun 2015 19:57:35 +0200 Subject: Populate custom type map, make available in context --- odb/context.cxx | 2 + odb/context.hxx | 30 +++++ odb/plugin.cxx | 8 +- odb/pragma.cxx | 101 ++++++++--------- odb/processor.cxx | 273 ++++++++++++++++++++++++++++++++------------- odb/processor.hxx | 6 +- odb/relational/context.hxx | 20 ---- odb/validator.hxx | 3 +- 8 files changed, 287 insertions(+), 156 deletions(-) (limited to 'odb') 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")), 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 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_types; +typedef std::map 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 ()); + + 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 ()); @@ -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 ()); - - 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_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 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 ( + 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 ( + 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 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_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_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&, -- cgit v1.1