From b8554760aa3a5c5697c77d11e507a2bb46dbf8e4 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 10 Jul 2012 15:17:16 +0200 Subject: Add support for custom database type mapping New pragma qualifier, map, and specifiers: as, to, from. New tests: /custom. --- odb/pragma.cxx | 338 ++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 241 insertions(+), 97 deletions(-) (limited to 'odb/pragma.cxx') diff --git a/odb/pragma.cxx b/odb/pragma.cxx index e2dc4cc..dcfab4e 100644 --- a/odb/pragma.cxx +++ b/odb/pragma.cxx @@ -13,7 +13,9 @@ #include #include #include + #include +#include using namespace std; using namespace cutl; @@ -342,77 +344,6 @@ resolve_scoped_name (tree& token, } static bool -check_qual_decl_type (tree d, - string const& name, - string const& p, - location_t l) -{ - int tc (TREE_CODE (d)); - - if (p == "namespace") - { - if (tc != NAMESPACE_DECL) - { - error (l) << "name '" << name << "' in db pragma " << p << " does " - << "not refer to a namespace" << endl; - return false; - } - } - else if (p == "object" || - p == "view") - { - if (tc != RECORD_TYPE) - { - error (l) << "name '" << name << "' in db pragma " << p << " does " - << "not refer to a class" << endl; - return false; - } - } - else if (p == "value") - { - if (!TYPE_P (d)) - { - error (l) << "name '" << name << "' in db pragma " << p << " does " - << "not refer to a type" << endl; - return false; - } - } - else if (p == "member") - { - if (tc != FIELD_DECL) - { - error (l) << "name '" << name << "' in db pragma " << p << " does " - << "not refer to a data member" << endl; - return false; - } - } - else - { - error () << "unknown db pragma " << p << endl; - return false; - } - - return true; -} - -static void -add_qual_entry (compiler::context& ctx, - string const& k, - any const& v, - location_t l) -{ - // Store the TYPE_DECL node that was referred to in the pragma. This - // can be used later as a name hint in case the type is a template - // instantiation. Also store the pragma location which is used as - // the "definition point" for this instantiation. - // - ctx.set ("tree-node", v); - ctx.set ("location", l); - - ctx.set (k, true); -} - -static bool check_spec_decl_type (tree d, string const& name, string const& p, @@ -632,6 +563,7 @@ static void handle_pragma (cpp_reader* reader, string const& p, string const& qualifier, + any& qualifier_value, tree decl, string const& decl_name, bool ns) // True if this is a position namespace pragma. @@ -1418,6 +1350,93 @@ handle_pragma (cpp_reader* reader, adder = &accumulate; tt = pragma_lex (&t); } + else if (qualifier == "map" && + (p == "type" || + p == "as" || + p == "to" || + p == "from")) + { + // type("") + // as("") + // to("") + // from("") + // + using relational::custom_db_type; + + // Make sure we've got the correct declaration type. + // + assert (decl == global_namespace); + custom_db_type& ct (qualifier_value.value ()); + + if (pragma_lex (&t) != CPP_OPEN_PAREN) + { + error () << "'(' expected after db pragma " << p << endl; + return; + } + + tt = pragma_lex (&t); + + if (p == "type") + { + if (tt != CPP_STRING) + { + error () << "type name regex expected in db pragma " << p << endl; + return; + } + + try + { + // Make it case-insensitive. + // + ct.type.assign (TREE_STRING_POINTER (t), true); + } + catch (regex_format const& e) + { + error () << "invalid regex: '" << e.regex () << "' in db pragma " << + p << ": " << e.description () << endl; + return; + } + } + else if (p == "as") + { + if (tt != CPP_STRING) + { + error () << "type name expected in db pragma " << p << endl; + return; + } + + ct.as = TREE_STRING_POINTER (t); + } + else if (p == "to") + { + if (tt != CPP_STRING) + { + error () << "expression expected in db pragma " << p << endl; + return; + } + + ct.to = TREE_STRING_POINTER (t); + } + else if (p == "from") + { + if (tt != CPP_STRING) + { + error () << "expression expected in db pragma " << p << endl; + return; + } + + ct.from = TREE_STRING_POINTER (t); + } + + if (pragma_lex (&t) != CPP_CLOSE_PAREN) + { + error () << "')' expected at the end of db pragma " << p << endl; + return; + } + + name.clear (); // We don't need to add anything for this pragma. + tt = pragma_lex (&t); + } else if (p == "type" || p == "id_type" || p == "value_type" || @@ -1691,35 +1710,124 @@ handle_pragma (cpp_reader* reader, return; } - // If the value is not specified and we don't use a custom adder, - // then make it bool (flag). + // Add the pragma unless was indicated otherwise. // - if (adder == 0 && val.empty ()) - val = true; + if (!name.empty ()) + { + // If the value is not specified and we don't use a custom adder, + // then make it bool (flag). + // + if (adder == 0 && val.empty ()) + val = true; - // Convert '_' to '-' in the context name so we get foo-bar instead - // of foo_bar (that's the convention used). - // - for (size_t i (0); i < name.size (); ++i) - if (name[i] == '_') - name[i] = '-'; + // Convert '_' to '-' in the context name so we get foo-bar instead + // of foo_bar (that's the convention used). + // + for (size_t i (0); i < name.size (); ++i) + if (name[i] == '_') + name[i] = '-'; - // Record this pragma. - // - add_pragma ( - pragma (p, name, val, loc, &check_spec_decl_type, adder), decl, ns); + // Record this pragma. + // + add_pragma ( + pragma (p, name, val, loc, &check_spec_decl_type, adder), decl, ns); + } // See if there are any more pragmas. // if (tt == CPP_NAME) { - handle_pragma ( - reader, IDENTIFIER_POINTER (t), qualifier, decl, decl_name, ns); + handle_pragma (reader, + IDENTIFIER_POINTER (t), + qualifier, + qualifier_value, + decl, + decl_name, + ns); } else if (tt != CPP_EOF) error () << "unexpected text after " << p << " in db pragma" << endl; } +// +// Qualifiers. +// + +static bool +check_qual_decl_type (tree d, + string const& name, + string const& p, + location_t l) +{ + int tc (TREE_CODE (d)); + + if (p == "map") + { + assert (d == global_namespace); + } + else if (p == "namespace") + { + if (tc != NAMESPACE_DECL) + { + error (l) << "name '" << name << "' in db pragma " << p << " does " + << "not refer to a namespace" << endl; + return false; + } + } + else if (p == "object" || + p == "view") + { + if (tc != RECORD_TYPE) + { + error (l) << "name '" << name << "' in db pragma " << p << " does " + << "not refer to a class" << endl; + return false; + } + } + else if (p == "value") + { + if (!TYPE_P (d)) + { + error (l) << "name '" << name << "' in db pragma " << p << " does " + << "not refer to a type" << endl; + return false; + } + } + else if (p == "member") + { + if (tc != FIELD_DECL) + { + error (l) << "name '" << name << "' in db pragma " << p << " does " + << "not refer to a data member" << endl; + return false; + } + } + else + { + error () << "unknown db pragma " << p << endl; + return false; + } + + return true; +} + +static void +add_qual_entry (compiler::context& ctx, + string const& k, + any const& v, + location_t l) +{ + // Store the TYPE_DECL node that was referred to in the pragma. This + // can be used later as a name hint in case the type is a template + // instantiation. Also store the pragma location which is used as + // the "definition point" for this instantiation. + // + ctx.set ("tree-node", v); + ctx.set ("location", l); + + ctx.set (k, true); +} + static void handle_pragma_qualifier (cpp_reader* reader, string const& p) { @@ -1728,12 +1836,30 @@ handle_pragma_qualifier (cpp_reader* reader, string const& p) tree decl (0), orig_decl (0); string decl_name; - location_t loc (input_location); - bool ns (false); // Namespace location pragma. + + string name (p); // Pragma name. + any val; // Pragma value. + location_t loc (input_location); // Pragma location. + pragma::add_func adder (0); // Custom context adder. + bool ns (false); // Namespace location pragma. // Pragma qualifiers. // - if (p == "namespace") + if (p == "map") + { + // map type("") as("") [to("")] [from("")] + // + using relational::custom_db_type; + + custom_db_type ct; + ct.loc = loc; + val = ct; + name = "custom-db-types"; + orig_decl = decl = global_namespace; + adder = &accumulate; + tt = pragma_lex (&t); + } + else if (p == "namespace") { // namespace [()] // namespace () (refers to global namespace) @@ -1917,7 +2043,7 @@ handle_pragma_qualifier (cpp_reader* reader, string const& p) p == "transient" || p == "version") { - handle_pragma (reader, p, "member", 0, "", false); + handle_pragma (reader, p, "member", val, 0, "", false); return; } else @@ -1926,17 +2052,22 @@ handle_pragma_qualifier (cpp_reader* reader, string const& p) return; } + if (adder == 0) + val = orig_decl; + // Record this pragma. // pragma prag (p, - p, // For now no need to translate '_' to '-'. - any (orig_decl), + name, // For now no need to translate '_' to '-'. + val, loc, &check_qual_decl_type, - &add_qual_entry); + adder != 0 ? adder : &add_qual_entry); + + any* pval; if (decl) - decl_pragmas_[decl].insert (prag); + pval = &decl_pragmas_[decl].insert (prag).value; else { tree scope (current_scope ()); @@ -1946,23 +2077,35 @@ handle_pragma_qualifier (cpp_reader* reader, string const& p) if (!CLASS_TYPE_P (scope)) scope = global_namespace; - loc_pragmas_[scope].push_back (prag); + pragma_list& pl (loc_pragmas_[scope]); + pl.push_back (prag); + pval = &pl.back ().value; } else + { ns_loc_pragmas_.push_back (ns_loc_pragma (scope, prag)); + pval = &ns_loc_pragmas_.back ().pragma.value; + } } // See if there are any more pragmas. // if (tt == CPP_NAME) { - handle_pragma (reader, IDENTIFIER_POINTER (t), p, decl, decl_name, ns); + handle_pragma ( + reader, IDENTIFIER_POINTER (t), p, *pval, decl, decl_name, ns); } else if (tt != CPP_EOF) error () << "unexpected text after " << p << " in db pragma" << endl; } extern "C" void +handle_pragma_db_map (cpp_reader* r) +{ + handle_pragma_qualifier (r, "map"); +} + +extern "C" void handle_pragma_db_namespace (cpp_reader* r) { handle_pragma_qualifier (r, "namespace"); @@ -2220,6 +2363,7 @@ register_odb_pragmas (void*, void*) c_register_pragma_with_expansion (0, "db", handle_pragma_db); /* + c_register_pragma_with_expansion ("db", "map", handle_pragma_db_map); c_register_pragma_with_expansion ("db", "namespace", handle_pragma_db_namespace); c_register_pragma_with_expansion ("db", "object", handle_pragma_db_object); c_register_pragma_with_expansion ("db", "view", handle_pragma_db_view); -- cgit v1.1