From bb76e9388009ed0bb2512034f8cd48a7d19aabb3 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 4 Jun 2010 16:29:02 +0200 Subject: Next chunk of functionality --- odb/common.hxx | 43 +++++++++++ odb/context.cxx | 47 +++++++++++ odb/context.hxx | 15 ++++ odb/database.cxx | 51 ++++++++++++ odb/database.hxx | 37 +++++++++ odb/generator.cxx | 130 +++++++++++++++++++++++++++++-- odb/header.cxx | 154 ++++++++++++++++++++++++++++++++++++ odb/header.hxx | 14 ++++ odb/inline.cxx | 72 +++++++++++++++++ odb/inline.hxx | 14 ++++ odb/makefile | 49 +++++++++--- odb/mysql-schema.cxx | 141 +++++++++++++++++++++++++++++++++ odb/mysql-schema.hxx | 14 ++++ odb/odb.cxx | 13 ++++ odb/options.cli | 73 +++++++++++++++--- odb/options.cxx | 214 +++++++++++++++++++++++++++++++++++++++++++++------ odb/options.hxx | 87 +++++++++++++++++++++ odb/options.ixx | 110 ++++++++++++++++++++++++++ odb/pragma.cxx | 183 +++++++++++++++++++++++++++++++++++++++---- odb/source.cxx | 126 +++++++++++++++--------------- odb/source.hxx | 2 +- 21 files changed, 1462 insertions(+), 127 deletions(-) create mode 100644 odb/common.hxx create mode 100644 odb/database.cxx create mode 100644 odb/database.hxx create mode 100644 odb/header.cxx create mode 100644 odb/header.hxx create mode 100644 odb/inline.cxx create mode 100644 odb/inline.hxx create mode 100644 odb/mysql-schema.cxx create mode 100644 odb/mysql-schema.hxx diff --git a/odb/common.hxx b/odb/common.hxx new file mode 100644 index 0000000..5588f00 --- /dev/null +++ b/odb/common.hxx @@ -0,0 +1,43 @@ +// file : odb/common.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_COMMON_HXX +#define ODB_COMMON_HXX + +#include + +// Find id member. +// +struct id_member: traversal::class_, + traversal::data_member, + context +{ + id_member (context& c) + : context (c), m_ (0) + { + *this >> names_ >> *this; + } + + semantics::data_member* + member () const + { + return m_; + } + + virtual void + traverse (semantics::data_member& m) + { + if (m.count ("id")) + m_ = &m; + } + + using class_::traverse; + +private: + traversal::names names_; + semantics::data_member* m_; +}; + +#endif // ODB_COMMON_HXX diff --git a/odb/context.cxx b/odb/context.cxx index c90086e..33aa73d 100644 --- a/odb/context.cxx +++ b/odb/context.cxx @@ -114,6 +114,53 @@ context (context& c) } string context:: +table_name (semantics::type& t) const +{ + if (t.count ("table")) + return t.get ("table"); + else + return t.name (); +} + +string context:: +column_name (semantics::data_member& m) const +{ + if (m.count ("column")) + return m.get ("column"); + else + { + 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:: +db_type (semantics::data_member& m) const +{ + if (m.count ("type")) + return m.get ("type"); + else + { + return "INT"; + } +} + +string context:: escape (string const& name) const { typedef string::size_type size; diff --git a/odb/context.hxx b/odb/context.hxx index 057b821..064b0d5 100644 --- a/odb/context.hxx +++ b/odb/context.hxx @@ -10,14 +10,17 @@ #include #include #include // std::size_t +#include #include +#include #include #include #include using std::endl; +using std::cerr; class generation_failed {}; @@ -28,6 +31,18 @@ public: typedef std::string string; typedef ::options options_type; + // Database names and types. + // +public: + string + table_name (semantics::type&) const; + + string + column_name (semantics::data_member&) const; + + string + db_type (semantics::data_member&) const; + public: // Escape C++ keywords, reserved names, and illegal characters. // diff --git a/odb/database.cxx b/odb/database.cxx new file mode 100644 index 0000000..d094397 --- /dev/null +++ b/odb/database.cxx @@ -0,0 +1,51 @@ +// file : odb/database.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include +#include +#include +#include // std::lower_bound + +#include + +using namespace std; + +static const char* str[] = +{ + "mysql", + "tracer" +}; + +const char* database:: +string () const +{ + return str[v_]; +} + +istream& +operator>> (istream& is, database& db) +{ + string s; + is >> s; + + if (!is.fail ()) + { + const char** e (str + sizeof (str) / sizeof (char*)); + const char** i (lower_bound (str, e, s)); + + if (i != e && *i == s) + db = database::value (i - str); + else + is.setstate (istream::failbit); + } + + return is; +} + +ostream& +operator<< (ostream& os, database db) +{ + return os << db.string (); +} diff --git a/odb/database.hxx b/odb/database.hxx new file mode 100644 index 0000000..c20e1c4 --- /dev/null +++ b/odb/database.hxx @@ -0,0 +1,37 @@ +// file : odb/database.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_DATABASE_HXX +#define ODB_DATABASE_HXX + +#include + +struct database +{ + enum value + { + // Keep in alphabetic order. + // + mysql, + tracer + }; + + database (value v = value (0)) : v_ (v) {} + operator value () const {return v_;} + + const char* + string () const; + +private: + value v_; +}; + +std::istream& +operator>> (std::istream&, database&); + +std::ostream& +operator<< (std::ostream&, database); + +#endif // ODB_DATABASE_HXX diff --git a/odb/generator.cxx b/odb/generator.cxx index 9e1da47..0d4e0c9 100644 --- a/odb/generator.cxx +++ b/odb/generator.cxx @@ -16,8 +16,12 @@ #include #include +#include +#include #include +#include + using namespace std; using namespace cutl; @@ -25,12 +29,11 @@ using semantics::path; namespace { - static char const cxx_header[] = + static char const file_header[] = "// This code was generated by CodeSynthesis ODB object persistence\n" "// compiler for C++.\n" "//\n\n"; - /* string make_guard (string const& file, context& ctx) { @@ -50,11 +53,10 @@ namespace if (isalpha (c1) && isalpha (c2) && islower (c1) && isupper (c2)) r += "_"; } - r += std::toupper (g[g.size () - 1]); + r += toupper (g[g.size () - 1]); return ctx.escape (r); } - */ void open (ifstream& ifs, string const& path) @@ -86,15 +88,51 @@ generate (options const& ops, semantics::unit& unit, path const& p) // C++ output. // + string hxx_name (base + ops.odb_file_suffix () + ops.hxx_suffix ()); + string ixx_name (base + ops.odb_file_suffix () + ops.ixx_suffix ()); string cxx_name (base + ops.odb_file_suffix () + ops.cxx_suffix ()); + string sql_name (base + ops.sql_suffix ()); + + path hxx_path (hxx_name); + path ixx_path (ixx_name); path cxx_path (cxx_name); + path sql_path (sql_name); if (!ops.output_dir ().empty ()) { path dir (ops.output_dir ()); + hxx_path = dir / hxx_path; + ixx_path = dir / ixx_path; cxx_path = dir / cxx_path; + sql_path = dir / sql_path; + } + + // + // + ofstream hxx (hxx_path.string ().c_str ()); + + if (!hxx.is_open ()) + { + cerr << "error: unable to open '" << hxx_path << "' in write mode" + << endl; + throw failed (); } + auto_rm.add (hxx_path); + + // + // + ofstream ixx (ixx_path.string ().c_str ()); + + if (!ixx.is_open ()) + { + cerr << "error: unable to open '" << ixx_path << "' in write mode" + << endl; + throw failed (); + } + + auto_rm.add (ixx_path); + // // ofstream cxx (cxx_path.string ().c_str ()); @@ -108,9 +146,29 @@ generate (options const& ops, semantics::unit& unit, path const& p) auto_rm.add (cxx_path); - // Print headers. // - cxx << cxx_header; + // + ofstream sql; + + if (ops.generate_schema ()) + { + sql.open (sql_path.string ().c_str (), ios_base::out); + + if (!sql.is_open ()) + { + cerr << "error: unable to open '" << sql_path << "' in write mode" + << endl; + throw failed (); + } + + auto_rm.add (sql_path); + } + + // Print C++ headers. + // + hxx << file_header; + ixx << file_header; + cxx << file_header; typedef compiler::ostream_filter cxx_filter; @@ -118,23 +176,81 @@ generate (options const& ops, semantics::unit& unit, path const& p) // bool br (ops.include_with_brackets ()); string ip (ops.include_prefix ()); + string gp (ops.guard_prefix ()); if (!ip.empty () && ip[ip.size () - 1] != '/') ip.append ("/"); + if (!gp.empty () && gp[gp.size () - 1] != '_') + gp.append ("_"); + + // HXX + // + { + cxx_filter filt (hxx); + context ctx (hxx, unit, ops); + + string guard (make_guard (gp + hxx_name, ctx)); + + hxx << "#ifndef " << guard << endl + << "#define " << guard << endl + << endl; + + hxx << "#include " << (br ? '<' : '"') << ip << file << + (br ? '>' : '"') << endl + << endl; + + generate_header (ctx); + + hxx << "#include " << (br ? '<' : '"') << ip << ixx_name << + (br ? '>' : '"') << endl + << endl; + + hxx << "#endif // " << guard << endl; + } + + // IXX + // + { + cxx_filter filt (ixx); + context ctx (ixx, unit, ops); + generate_inline (ctx); + } + // CXX // { cxx_filter filt (cxx); context ctx (cxx, unit, ops); - cxx << "#include " << (br ? '<' : '"') << ip << file << + cxx << "#include " << (br ? '<' : '"') << ip << hxx_name << (br ? '>' : '"') << endl << endl; generate_source (ctx); } + // SQL + // + if (ops.generate_schema ()) + { + context ctx (sql, unit, ops); + + switch (ops.database ()) + { + case database::mysql: + { + generate_mysql_schema (ctx); + break; + } + case database::tracer: + { + cerr << "error: the tracer database does not have schema" << endl; + throw failed (); + } + } + } + auto_rm.cancel (); } catch (const generation_failed&) diff --git a/odb/header.cxx b/odb/header.cxx new file mode 100644 index 0000000..5d87991 --- /dev/null +++ b/odb/header.cxx @@ -0,0 +1,154 @@ +// file : odb/header.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include +#include + +namespace +{ + struct class_: traversal::class_, context + { + class_ (context& c) + : context (c) + { + } + + virtual void + traverse (type& c) + { + if (c.file () != unit.file ()) + return; + + if (!c.count ("object")) + return; + + string const& type (c.fq_name ()); + + // Find the id member and type. + // + id_member t (*this); + t.traverse (c); + + if (t.member () == 0) + { + cerr << c.file () << ":" << c.line () << ":" << c.column () + << " error: no data member designated as object id" << endl; + + cerr << c.file () << ":" << c.line () << ":" << c.column () + << " info: use '#pragma odb id' to specify object id member" + << endl; + + throw generation_failed (); + } + + semantics::data_member& id (*t.member ()); + semantics::type& id_type (id.type ()); + + if (id_type.anonymous ()) + { + // Can be a template-id (which we should handle eventually) or an + // anonymous type in member declaration (e.g., struct {...} m_;). + // + cerr << id.file () << ":" << id.line () << ":" << id.column () + << " error: unnamed type in data member declaration" << endl; + + cerr << id.file () << ":" << id.line () << ":" << id.column () + << " info: use 'typedef' to name this type" + << endl; + + throw generation_failed (); + } + + os << "// " << c.name () << endl + << "//" << endl; + + os << "template <>" << endl + << "class access::object_traits< " << type << " >: " << endl + << " public access::object_memory< " << type << " >," << endl + << " public access::object_factory< " << type << " >" + << "{" + << "public:" << endl; + + // object_type & shared_ptr + // + os << "typedef " << type << " object_type;"; + + // id_type + // + os << "typedef " << id_type.fq_name () << " id_type;" + << endl; + + // id_source + // + os << "static const odb::id_source id_source = odb::ids_assigned;" + << endl; + + // type_name () + // + os << "static const char*" << endl + << "type_name ();" + << endl; + + // id () + // + os << "static id_type" << endl + << "id (const object_type&);" + << endl; + + // insert () + // + os << "static void" << endl + << "insert (database&, const object_type&);" + << endl; + + // update () + // + os << "static void" << endl + << "update (database&, const object_type&);" + << endl; + + // erase () + // + os << "static void" << endl + << "erase (database&, const id_type&);" + << endl; + + // find () + // + os << "static shared_ptr" << endl + << "find (database&, const id_type&);"; + + os << "};"; + } + }; +} + +void +generate_header (context& ctx) +{ + traversal::unit unit; + traversal::defines unit_defines; + traversal::namespace_ ns; + class_ c (ctx); + + unit >> unit_defines >> ns; + unit_defines >> c; + + traversal::defines ns_defines; + + ns >> ns_defines >> ns; + ns_defines >> c; + + ctx.os << "#include " << endl + << "#include " << endl + << endl; + + ctx.os << "namespace odb" + << "{"; + + unit.dispatch (ctx.unit); + + ctx.os << "}"; +} diff --git a/odb/header.hxx b/odb/header.hxx new file mode 100644 index 0000000..f7f3a34 --- /dev/null +++ b/odb/header.hxx @@ -0,0 +1,14 @@ +// file : odb/header.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_HEADER_HXX +#define ODB_HEADER_HXX + +#include + +void +generate_header (context&); + +#endif // ODB_HEADER_HXX diff --git a/odb/inline.cxx b/odb/inline.cxx new file mode 100644 index 0000000..ee3a8e6 --- /dev/null +++ b/odb/inline.cxx @@ -0,0 +1,72 @@ +// file : odb/inline.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include +#include + +namespace +{ + struct class_: traversal::class_, context + { + class_ (context& c) + : context (c) + { + } + + virtual void + traverse (type& c) + { + if (c.file () != unit.file ()) + return; + + if (!c.count ("object")) + return; + + string const& type (c.fq_name ()); + string traits ("access::object_traits< " + type + " >"); + + id_member t (*this); + t.traverse (c); + semantics::data_member& id (*t.member ()); + + os << "// " << c.name () << endl + << "//" << endl + << endl; + + // id () + // + os << "inline" << endl + << traits << "::id_type " << traits << "::" << endl + << "id (const object_type& obj)" + << "{" + << "return obj." << id.name () << ";" << endl + << "}"; + } + }; +} + +void +generate_inline (context& ctx) +{ + traversal::unit unit; + traversal::defines unit_defines; + traversal::namespace_ ns; + class_ c (ctx); + + unit >> unit_defines >> ns; + unit_defines >> c; + + traversal::defines ns_defines; + + ns >> ns_defines >> ns; + ns_defines >> c; + + ctx.os << "namespace odb" + << "{"; + + unit.dispatch (ctx.unit); + + ctx.os << "}"; +} diff --git a/odb/inline.hxx b/odb/inline.hxx new file mode 100644 index 0000000..77a2d56 --- /dev/null +++ b/odb/inline.hxx @@ -0,0 +1,14 @@ +// file : odb/inline.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_INLINE_HXX +#define ODB_INLINE_HXX + +#include + +void +generate_inline (context&); + +#endif // ODB_INLINE_HXX diff --git a/odb/makefile b/odb/makefile index 12c4a74..f6da371 100644 --- a/odb/makefile +++ b/odb/makefile @@ -13,7 +13,10 @@ generator.cxx \ parser.cxx \ plugin.cxx \ pragma.cxx \ -source.cxx +header.cxx \ +inline.cxx \ +source.cxx \ +mysql-schema.cxx cxx_ptun += \ semantics/class.cxx \ @@ -42,19 +45,32 @@ traversal/union-template.cxx # cxx_dtun := odb.cxx +# Common units. +# +cxx_ctun := database.cxx + # Options file. # cli_tun := options.cli # # -cxx_pobj := $(addprefix $(out_base)/,$(cxx_ptun:.cxx=.o) $(cli_tun:.cli=.o)) -cxx_dobj := $(addprefix $(out_base)/,$(cxx_dtun:.cxx=.o) $(cli_tun:.cli=.o)) +cxx_pobj := $(addprefix $(out_base)/,$(cxx_ptun:.cxx=.o)) +cxx_dobj := $(addprefix $(out_base)/,$(cxx_dtun:.cxx=.o)) +cxx_cobj := $(addprefix $(out_base)/,$(cxx_ctun:.cxx=.o) $(cli_tun:.cli=.o)) cxx_pod := $(cxx_pobj:.o=.o.d) cxx_dod := $(cxx_dobj:.o=.o.d) +cxx_cod := $(cxx_cobj:.o=.o.d) + odb := $(out_base)/odb odb_so := $(out_base)/odb.so + +# Dummy library to force driver timestamp update when the plugin DSO +# changes. +# +odb.l := $(out_base)/odb.l + clean := $(out_base)/.clean install := $(out_base)/.install @@ -70,17 +86,19 @@ $(call import,\ # Build. # -$(odb): $(cxx_dobj) $(cutl.l) | $(odb_so) -$(odb_so): $(cxx_pobj) $(cutl.l) +$(odb): $(cxx_dobj) $(cxx_cobj) $(odb.l) $(cutl.l) +$(odb_so): $(cxx_pobj) $(cxx_cobj) $(cutl.l) -$(cxx_dobj) $(cxx_dod): cpp_options := -I$(src_root) -$(cxx_pobj) $(cxx_dobj) $(cxx_pod) $(cxx_dod): $(cutl.l.cpp-options) +$(cxx_pobj) $(cxx_dobj) $(cxx_cobj) $(cxx_pod) $(cxx_dod) $(cxx_cod): \ +$(cutl.l.cpp-options) genf := $(cli_tun:.cli=.hxx) $(cli_tun:.cli=.ixx) $(cli_tun:.cli=.cxx) gen := $(addprefix $(out_base)/,$(genf)) +$(gen): $(cli) $(gen): cli := $(cli) -$(gen): cli_options := \ +$(gen): cli_options += \ +--generate-specifier \ --generate-file-scanner \ --include-with-brackets \ --include-prefix odb \ @@ -88,6 +106,7 @@ $(gen): cli_options := \ $(call include-dep,$(cxx_pod)) $(call include-dep,$(cxx_dod)) +$(call include-dep,$(cxx_cod)) # Alias for default target. # @@ -105,9 +124,12 @@ $(clean): \ $(odb).o.clean \ $(addsuffix .cxx.clean,$(cxx_pobj)) \ $(addsuffix .cxx.clean,$(cxx_dobj)) \ + $(addsuffix .cxx.clean,$(cxx_cobj)) \ $(addsuffix .cxx.clean,$(cxx_pod)) \ - $(addsuffix .cxx.clean,$(cxx_dod)) + $(addsuffix .cxx.clean,$(cxx_dod)) \ + $(addsuffix .cxx.clean,$(cxx_cod)) $(call message,rm $$1,rm -f $$1,$(out_base)/odb.so) + $(call message,,rm -f $(out_base)/odb.l) # Generated .gitignore. # @@ -128,12 +150,14 @@ $(call include,$(bld_root)/cxx/cxx-d.make) $(call include,$(bld_root)/cxx/cxx-o.make) $(call include,$(bld_root)/cxx/o-e.make) -# Custom rules for the plugin. +# Custom rules for the plugin and the driver. # ifdef cxx_gnu -$(cxx_pobj): cxx_pic_options := -fPIC +$(cxx_pobj) $(cxx_cobj): cxx_pic_options := -fPIC +$(cxx_cobj) $(cxx_cod): cpp_options := -I$(src_root) +$(cxx_dobj) $(cxx_dod): cpp_options := -I$(src_root) '-DGXX_NAME="$(cxx_gnu)"' $(cxx_pobj) $(cxx_pod): cpp_options := -I$(src_root) \ -I$(shell $(cxx_gnu) -print-file-name=plugin)/include @@ -142,4 +166,7 @@ $(odb_so): $(cxx_extra_options) $(ld_options) $(cxx_ld_extra_options) -shared -o $@ \ $(foreach f,$^,$(if $(patsubst %.l,,$f),$f,$(call expand-l,$f))) $(cxx_extra_libs)) +$(odb.l): $(odb_so) + $(call message,,touch $@) + endif diff --git a/odb/mysql-schema.cxx b/odb/mysql-schema.cxx new file mode 100644 index 0000000..ea3fece --- /dev/null +++ b/odb/mysql-schema.cxx @@ -0,0 +1,141 @@ +// file : odb/mysql-schema.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include + +namespace +{ + struct data_member: traversal::data_member, context + { + data_member (context& c) + : context (c), first_ (true) + { + } + + virtual void + traverse (type& m) + { + if (first_) + first_ = false; + else + os << "," << endl; + + os << " `" << column_name (m) << "` " << db_type (m) << + " NOT NULL"; + + if (m.count ("id")) + os << " PRIMARY KEY"; + } + + private: + bool first_; + }; + + struct class_create: traversal::class_, context + { + class_create (context& c) + : context (c) + { + } + + virtual void + traverse (type& c) + { + if (c.file () != unit.file ()) + return; + + if (!c.count ("object")) + return; + + os << "CREATE TABLE `" << table_name (c) << "` (" << endl; + + { + data_member m (*this); + traversal::names n (m); + names (c, n); + } + + os << ")"; + + string const& engine (options.mysql_engine ()); + + if (engine != "default") + os << endl + << " ENGINE=" << engine; + + os << ";" << endl + << endl; + } + }; + + struct class_drop: traversal::class_, context + { + class_drop (context& c) + : context (c) + { + } + + virtual void + traverse (type& c) + { + if (c.file () != unit.file ()) + return; + + if (!c.count ("object")) + return; + + os << "DROP TABLE IF EXISTS `" << table_name (c) << "`;" << endl; + } + }; +} + +static char const file_header[] = + "/* This file was generated by CodeSynthesis ODB object persistence\n" + " * compiler for C++.\n" + " */\n\n"; + +void +generate_mysql_schema (context& ctx) +{ + ctx.os << file_header; + + // Drop. + // + { + traversal::unit unit; + traversal::defines unit_defines; + traversal::namespace_ ns; + class_drop c (ctx); + + unit >> unit_defines >> ns; + unit_defines >> c; + + traversal::defines ns_defines; + + ns >> ns_defines >> ns; + ns_defines >> c; + unit.dispatch (ctx.unit); + } + + ctx.os << endl; + + // Create. + // + { + traversal::unit unit; + traversal::defines unit_defines; + traversal::namespace_ ns; + class_create c (ctx); + + unit >> unit_defines >> ns; + unit_defines >> c; + + traversal::defines ns_defines; + + ns >> ns_defines >> ns; + ns_defines >> c; + unit.dispatch (ctx.unit); + } +} diff --git a/odb/mysql-schema.hxx b/odb/mysql-schema.hxx new file mode 100644 index 0000000..f4a7996 --- /dev/null +++ b/odb/mysql-schema.hxx @@ -0,0 +1,14 @@ +// file : odb/mysql-schema.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_MYSQL_SCHEMA_HXX +#define ODB_MYSQL_SCHEMA_HXX + +#include + +void +generate_mysql_schema (context&); + +#endif // ODB_MYSQL_SCHEMA_HXX diff --git a/odb/odb.cxx b/odb/odb.cxx index b53b7ea..b6f76a0 100644 --- a/odb/odb.cxx +++ b/odb/odb.cxx @@ -49,7 +49,11 @@ main (int argc, char* argv[]) // The first argument points to the program name, which is // g++ by default. // +#ifdef GXX_NAME + args.push_back (GXX_NAME); +#else args.push_back ("g++"); +#endif // Default options. // @@ -202,6 +206,15 @@ main (int argc, char* argv[]) return 0; } + // Check that required options were specifed. + // + if (!ops.database_specified ()) + { + e << argv[0] << ": error: no database specified with the --database " + << "option" << endl; + return 1; + } + size_t end (scan.end () - 1); // We have one less in plugin_args. if (end == plugin_args.size ()) diff --git a/odb/options.cli b/odb/options.cli index 1454d9a..ebe65e5 100644 --- a/odb/options.cli +++ b/odb/options.cli @@ -6,6 +6,8 @@ include ; include ; +include ; + class options { // @@ -18,6 +20,21 @@ class options // // Plugin options. // + ::database --database | -d + { + "", + "Generate code for the database. Valid values are \cb{mysql} and + \cb{tracer}." + }; + + bool --generate-schema + { + "Generate database schema. The resulting SQL file creates database + tables required to store classes defined in the file being compiled. + Note that all the existing information stored in such tables will be + lost." + }; + std::string --output-dir | -o { "", @@ -28,28 +45,35 @@ class options { "", "Use instead of the default \cb{-odb} to construct the names - of the generated ODB files." + of the generated C++ files." }; std::string --hxx-suffix = ".hxx" { "", "Use instead of the default \cb{.hxx} to construct the name of - the generated header file." + the generated C++ header file." }; std::string --ixx-suffix = ".ixx" { "", "Use instead of the default \cb{.ixx} to construct the name of - the generated inline file." + the generated C++ inline file." }; std::string --cxx-suffix = ".cxx" { "", "Use instead of the default \cb{.cxx} to construct the name of - the generated source file." + the generated C++ source file." + }; + + std::string --sql-suffix = ".sql" + { + "", + "Use instead of the default \cb{.sql} to construct the name of + the generated database schema file." }; bool --include-with-brackets @@ -64,6 +88,14 @@ class options "Add to the generated \cb{#include} directive paths." }; + std::string --guard-prefix + { + "", + "Add to the generated header inclusion guards. The prefix is + transformed to upper case and characters that are illegal in a + preprocessor macro name are replaced with underscores." + }; + // This is a "fake" option in that it is actually handled by // argv_file_scanner. We have it here to get the documentation. // @@ -72,13 +104,34 @@ class options "", "Read additional options from with each option appearing on a separate line optionally followed by space and an option value. Empty - lines and lines starting with \cb{#} are ignored. The semantics of - providing options in a file is equivalent to providing the same set - of options in the same order on the command line at the point where the - \cb{--options-file} option is specified except that shell escaping and - quoting is not required. Repeat this option to specify more than one - options files." + lines and lines starting with \cb{#} are ignored. Option values can + be enclosed in double (\cb{\"}) or single (\cb{'}) quotes to preserve + leading and trailing whitespaces as well as to specify empty values. + If the value itself contains trailing or leading quotes, enclose it + with an extra pair of quotes, for example \cb{'\"x\"'}. Non-leading + and non-trailing quotes are interpreted as being part of the option + value. + + The semantics of providing options in a file is equivalent to providing + the same set of options in the same order on the command line at the + point where the \cb{--options-file} option is specified except that + the shell escaping and quoting is not required. Repeat this option + to specify more than one options files." }; bool --trace {"Trace the compilation process."}; + + // + // MySQL-specific options. + // + + std::string --mysql-engine = "InnoDB" + { + "", + "Use instead of the default \cb{InnoDB} in the generated + database schema file. For more information on the storage engine + options see the MySQL documentation. If you would like to use the + database-default engine, pass \cb{default} as the value for this + option." + }; }; diff --git a/odb/options.cxx b/odb/options.cxx index c5c2c0b..2af4e8e 100644 --- a/odb/options.cxx +++ b/odb/options.cxx @@ -125,6 +125,25 @@ namespace cli return "unable to open file or read failure"; } + // unmatched_quote + // + unmatched_quote:: + ~unmatched_quote () throw () + { + } + + void unmatched_quote:: + print (std::ostream& os) const + { + os << "unmatched quote in argument '" << argument () << "'"; + } + + const char* unmatched_quote:: + what () const throw () + { + return "unmatched quote"; + } + // scanner // scanner:: @@ -329,6 +348,19 @@ namespace cli string s2 (line, p); + // If the string is wrapped in quotes, remove them. + // + n = s2.size (); + char cf (s2[0]), cl (s2[n - 1]); + + if (cf == '"' || cf == '\'' || cl == '"' || cl == '\'') + { + if (n == 1 || cf != cl) + throw unmatched_quote (s2); + + s2 = string (s2, 1, n - 2); + } + if (!skip_ && s1 == option_) load (s2.c_str ()); else @@ -344,7 +376,7 @@ namespace cli struct parser { static void - parse (X& x, scanner& s) + parse (X& x, bool& xs, scanner& s) { const char* o (s.next ()); @@ -357,6 +389,8 @@ namespace cli } else throw missing_value (o); + + xs = true; } }; @@ -375,7 +409,7 @@ namespace cli struct parser { static void - parse (std::string& x, scanner& s) + parse (std::string& x, bool& xs, scanner& s) { const char* o (s.next ()); @@ -383,6 +417,8 @@ namespace cli x = s.next (); else throw missing_value (o); + + xs = true; } }; @@ -390,11 +426,12 @@ namespace cli struct parser > { static void - parse (std::vector& c, scanner& s) + parse (std::vector& c, bool& xs, scanner& s) { X x; parser::parse (x, s); c.push_back (x); + xs = true; } }; @@ -402,11 +439,12 @@ namespace cli struct parser > { static void - parse (std::set& c, scanner& s) + parse (std::set& c, bool& xs, scanner& s) { X x; parser::parse (x, s); c.insert (x); + xs = true; } }; @@ -414,7 +452,7 @@ namespace cli struct parser > { static void - parse (std::map& m, scanner& s) + parse (std::map& m, bool& xs, scanner& s) { const char* o (s.next ()); @@ -465,14 +503,23 @@ namespace cli } else throw missing_value (o); + + xs = true; } }; - template + template void thunk (X& x, scanner& s) { - parser::parse (x.*P, s); + parser::parse (x.*M, s); + } + + template + void + thunk (X& x, scanner& s) + { + parser::parse (x.*M, x.*S, s); } } @@ -490,15 +537,31 @@ options (int& argc, ::cli::unknown_mode arg) : help_ (), version_ (), + database_ (), + database_specified_ (false), + generate_schema_ (), output_dir_ (), + output_dir_specified_ (false), odb_file_suffix_ ("-odb"), + odb_file_suffix_specified_ (false), hxx_suffix_ (".hxx"), + hxx_suffix_specified_ (false), ixx_suffix_ (".ixx"), + ixx_suffix_specified_ (false), cxx_suffix_ (".cxx"), + cxx_suffix_specified_ (false), + sql_suffix_ (".sql"), + sql_suffix_specified_ (false), include_with_brackets_ (), include_prefix_ (), + include_prefix_specified_ (false), + guard_prefix_ (), + guard_prefix_specified_ (false), options_file_ (), - trace_ () + options_file_specified_ (false), + trace_ (), + mysql_engine_ ("InnoDB"), + mysql_engine_specified_ (false) { ::cli::argv_scanner s (argc, argv, erase); _parse (s, opt, arg); @@ -513,15 +576,31 @@ options (int start, ::cli::unknown_mode arg) : help_ (), version_ (), + database_ (), + database_specified_ (false), + generate_schema_ (), output_dir_ (), + output_dir_specified_ (false), odb_file_suffix_ ("-odb"), + odb_file_suffix_specified_ (false), hxx_suffix_ (".hxx"), + hxx_suffix_specified_ (false), ixx_suffix_ (".ixx"), + ixx_suffix_specified_ (false), cxx_suffix_ (".cxx"), + cxx_suffix_specified_ (false), + sql_suffix_ (".sql"), + sql_suffix_specified_ (false), include_with_brackets_ (), include_prefix_ (), + include_prefix_specified_ (false), + guard_prefix_ (), + guard_prefix_specified_ (false), options_file_ (), - trace_ () + options_file_specified_ (false), + trace_ (), + mysql_engine_ ("InnoDB"), + mysql_engine_specified_ (false) { ::cli::argv_scanner s (start, argc, argv, erase); _parse (s, opt, arg); @@ -536,15 +615,31 @@ options (int& argc, ::cli::unknown_mode arg) : help_ (), version_ (), + database_ (), + database_specified_ (false), + generate_schema_ (), output_dir_ (), + output_dir_specified_ (false), odb_file_suffix_ ("-odb"), + odb_file_suffix_specified_ (false), hxx_suffix_ (".hxx"), + hxx_suffix_specified_ (false), ixx_suffix_ (".ixx"), + ixx_suffix_specified_ (false), cxx_suffix_ (".cxx"), + cxx_suffix_specified_ (false), + sql_suffix_ (".sql"), + sql_suffix_specified_ (false), include_with_brackets_ (), include_prefix_ (), + include_prefix_specified_ (false), + guard_prefix_ (), + guard_prefix_specified_ (false), options_file_ (), - trace_ () + options_file_specified_ (false), + trace_ (), + mysql_engine_ ("InnoDB"), + mysql_engine_specified_ (false) { ::cli::argv_scanner s (argc, argv, erase); _parse (s, opt, arg); @@ -561,15 +656,31 @@ options (int start, ::cli::unknown_mode arg) : help_ (), version_ (), + database_ (), + database_specified_ (false), + generate_schema_ (), output_dir_ (), + output_dir_specified_ (false), odb_file_suffix_ ("-odb"), + odb_file_suffix_specified_ (false), hxx_suffix_ (".hxx"), + hxx_suffix_specified_ (false), ixx_suffix_ (".ixx"), + ixx_suffix_specified_ (false), cxx_suffix_ (".cxx"), + cxx_suffix_specified_ (false), + sql_suffix_ (".sql"), + sql_suffix_specified_ (false), include_with_brackets_ (), include_prefix_ (), + include_prefix_specified_ (false), + guard_prefix_ (), + guard_prefix_specified_ (false), options_file_ (), - trace_ () + options_file_specified_ (false), + trace_ (), + mysql_engine_ ("InnoDB"), + mysql_engine_specified_ (false) { ::cli::argv_scanner s (start, argc, argv, erase); _parse (s, opt, arg); @@ -582,15 +693,31 @@ options (::cli::scanner& s, ::cli::unknown_mode arg) : help_ (), version_ (), + database_ (), + database_specified_ (false), + generate_schema_ (), output_dir_ (), + output_dir_specified_ (false), odb_file_suffix_ ("-odb"), + odb_file_suffix_specified_ (false), hxx_suffix_ (".hxx"), + hxx_suffix_specified_ (false), ixx_suffix_ (".ixx"), + ixx_suffix_specified_ (false), cxx_suffix_ (".cxx"), + cxx_suffix_specified_ (false), + sql_suffix_ (".sql"), + sql_suffix_specified_ (false), include_with_brackets_ (), include_prefix_ (), + include_prefix_specified_ (false), + guard_prefix_ (), + guard_prefix_specified_ (false), options_file_ (), - trace_ () + options_file_specified_ (false), + trace_ (), + mysql_engine_ ("InnoDB"), + mysql_engine_specified_ (false) { _parse (s, opt, arg); } @@ -602,20 +729,28 @@ print_usage (::std::ostream& os) os << "--version Print version and exit." << ::std::endl; + os << "--database|-d Generate code for the database." << ::std::endl; + + os << "--generate-schema Generate database schema." << ::std::endl; + os << "--output-dir|-o Write the generated files to instead of the" << ::std::endl << " current directory." << ::std::endl; os << "--odb-file-suffix Use instead of the default '-odb' to" << ::std::endl - << " construct the names of the generated ODB files." << ::std::endl; + << " construct the names of the generated C++ files." << ::std::endl; os << "--hxx-suffix Use instead of the default '.hxx' to" << ::std::endl - << " construct the name of the generated header file." << ::std::endl; + << " construct the name of the generated C++ header file." << ::std::endl; os << "--ixx-suffix Use instead of the default '.ixx' to" << ::std::endl - << " construct the name of the generated inline file." << ::std::endl; + << " construct the name of the generated C++ inline file." << ::std::endl; os << "--cxx-suffix Use instead of the default '.cxx' to" << ::std::endl - << " construct the name of the generated source file." << ::std::endl; + << " construct the name of the generated C++ source file." << ::std::endl; + + os << "--sql-suffix Use instead of the default '.sql' to" << ::std::endl + << " construct the name of the generated database schema" << ::std::endl + << " file." << ::std::endl; os << "--include-with-brackets Use angle brackets (<>) instead of quotes (\"\") in the" << ::std::endl << " generated '#include' directives." << ::std::endl; @@ -623,11 +758,17 @@ print_usage (::std::ostream& os) os << "--include-prefix Add to the generated '#include' directive" << ::std::endl << " paths." << ::std::endl; + os << "--guard-prefix Add to the generated header inclusion" << ::std::endl + << " guards." << ::std::endl; + os << "--options-file Read additional options from with each option" << ::std::endl << " appearing on a separate line optionally followed by" << ::std::endl << " space and an option value." << ::std::endl; os << "--trace Trace the compilation process." << ::std::endl; + + os << "--mysql-engine Use instead of the default 'InnoDB' in the" << ::std::endl + << " generated database schema file." << ::std::endl; } typedef @@ -644,26 +785,51 @@ struct _cli_options_map_init &::cli::thunk< options, bool, &options::help_ >; _cli_options_map_["--version"] = &::cli::thunk< options, bool, &options::version_ >; + _cli_options_map_["--database"] = + &::cli::thunk< options, ::database, &options::database_, + &options::database_specified_ >; + _cli_options_map_["-d"] = + &::cli::thunk< options, ::database, &options::database_, + &options::database_specified_ >; + _cli_options_map_["--generate-schema"] = + &::cli::thunk< options, bool, &options::generate_schema_ >; _cli_options_map_["--output-dir"] = - &::cli::thunk< options, std::string, &options::output_dir_ >; + &::cli::thunk< options, std::string, &options::output_dir_, + &options::output_dir_specified_ >; _cli_options_map_["-o"] = - &::cli::thunk< options, std::string, &options::output_dir_ >; + &::cli::thunk< options, std::string, &options::output_dir_, + &options::output_dir_specified_ >; _cli_options_map_["--odb-file-suffix"] = - &::cli::thunk< options, std::string, &options::odb_file_suffix_ >; + &::cli::thunk< options, std::string, &options::odb_file_suffix_, + &options::odb_file_suffix_specified_ >; _cli_options_map_["--hxx-suffix"] = - &::cli::thunk< options, std::string, &options::hxx_suffix_ >; + &::cli::thunk< options, std::string, &options::hxx_suffix_, + &options::hxx_suffix_specified_ >; _cli_options_map_["--ixx-suffix"] = - &::cli::thunk< options, std::string, &options::ixx_suffix_ >; + &::cli::thunk< options, std::string, &options::ixx_suffix_, + &options::ixx_suffix_specified_ >; _cli_options_map_["--cxx-suffix"] = - &::cli::thunk< options, std::string, &options::cxx_suffix_ >; + &::cli::thunk< options, std::string, &options::cxx_suffix_, + &options::cxx_suffix_specified_ >; + _cli_options_map_["--sql-suffix"] = + &::cli::thunk< options, std::string, &options::sql_suffix_, + &options::sql_suffix_specified_ >; _cli_options_map_["--include-with-brackets"] = &::cli::thunk< options, bool, &options::include_with_brackets_ >; _cli_options_map_["--include-prefix"] = - &::cli::thunk< options, std::string, &options::include_prefix_ >; + &::cli::thunk< options, std::string, &options::include_prefix_, + &options::include_prefix_specified_ >; + _cli_options_map_["--guard-prefix"] = + &::cli::thunk< options, std::string, &options::guard_prefix_, + &options::guard_prefix_specified_ >; _cli_options_map_["--options-file"] = - &::cli::thunk< options, std::string, &options::options_file_ >; + &::cli::thunk< options, std::string, &options::options_file_, + &options::options_file_specified_ >; _cli_options_map_["--trace"] = &::cli::thunk< options, bool, &options::trace_ >; + _cli_options_map_["--mysql-engine"] = + &::cli::thunk< options, std::string, &options::mysql_engine_, + &options::mysql_engine_specified_ >; } } _cli_options_map_init_; diff --git a/odb/options.hxx b/odb/options.hxx index daf3d31..21cc496 100644 --- a/odb/options.hxx +++ b/odb/options.hxx @@ -166,6 +166,27 @@ namespace cli std::string file_; }; + class unmatched_quote: public exception + { + public: + virtual + ~unmatched_quote () throw (); + + unmatched_quote (const std::string& argument); + + const std::string& + argument () const; + + virtual void + print (std::ostream&) const; + + virtual const char* + what () const throw (); + + private: + std::string argument_; + }; + class scanner { public: @@ -256,6 +277,8 @@ namespace cli #include +#include + class options { public: @@ -301,33 +324,81 @@ class options const bool& version () const; + const ::database& + database () const; + + bool + database_specified () const; + + const bool& + generate_schema () const; + const std::string& output_dir () const; + bool + output_dir_specified () const; + const std::string& odb_file_suffix () const; + bool + odb_file_suffix_specified () const; + const std::string& hxx_suffix () const; + bool + hxx_suffix_specified () const; + const std::string& ixx_suffix () const; + bool + ixx_suffix_specified () const; + const std::string& cxx_suffix () const; + bool + cxx_suffix_specified () const; + + const std::string& + sql_suffix () const; + + bool + sql_suffix_specified () const; + const bool& include_with_brackets () const; const std::string& include_prefix () const; + bool + include_prefix_specified () const; + + const std::string& + guard_prefix () const; + + bool + guard_prefix_specified () const; + const std::string& options_file () const; + bool + options_file_specified () const; + const bool& trace () const; + const std::string& + mysql_engine () const; + + bool + mysql_engine_specified () const; + // Print usage information. // static void @@ -342,15 +413,31 @@ class options public: bool help_; bool version_; + ::database database_; + bool database_specified_; + bool generate_schema_; std::string output_dir_; + bool output_dir_specified_; std::string odb_file_suffix_; + bool odb_file_suffix_specified_; std::string hxx_suffix_; + bool hxx_suffix_specified_; std::string ixx_suffix_; + bool ixx_suffix_specified_; std::string cxx_suffix_; + bool cxx_suffix_specified_; + std::string sql_suffix_; + bool sql_suffix_specified_; bool include_with_brackets_; std::string include_prefix_; + bool include_prefix_specified_; + std::string guard_prefix_; + bool guard_prefix_specified_; std::string options_file_; + bool options_file_specified_; bool trace_; + std::string mysql_engine_; + bool mysql_engine_specified_; }; #include diff --git a/odb/options.ixx b/odb/options.ixx index dfe6995..9796a83 100644 --- a/odb/options.ixx +++ b/odb/options.ixx @@ -98,6 +98,20 @@ namespace cli return file_; } + // unmatched_quote + // + inline unmatched_quote:: + unmatched_quote (const std::string& argument) + : argument_ (argument) + { + } + + inline const std::string& unmatched_quote:: + argument () const + { + return argument_; + } + // argv_scanner // inline argv_scanner:: @@ -159,36 +173,96 @@ version () const return this->version_; } +inline const ::database& options:: +database () const +{ + return this->database_; +} + +inline bool options:: +database_specified () const +{ + return this->database_specified_; +} + +inline const bool& options:: +generate_schema () const +{ + return this->generate_schema_; +} + inline const std::string& options:: output_dir () const { return this->output_dir_; } +inline bool options:: +output_dir_specified () const +{ + return this->output_dir_specified_; +} + inline const std::string& options:: odb_file_suffix () const { return this->odb_file_suffix_; } +inline bool options:: +odb_file_suffix_specified () const +{ + return this->odb_file_suffix_specified_; +} + inline const std::string& options:: hxx_suffix () const { return this->hxx_suffix_; } +inline bool options:: +hxx_suffix_specified () const +{ + return this->hxx_suffix_specified_; +} + inline const std::string& options:: ixx_suffix () const { return this->ixx_suffix_; } +inline bool options:: +ixx_suffix_specified () const +{ + return this->ixx_suffix_specified_; +} + inline const std::string& options:: cxx_suffix () const { return this->cxx_suffix_; } +inline bool options:: +cxx_suffix_specified () const +{ + return this->cxx_suffix_specified_; +} + +inline const std::string& options:: +sql_suffix () const +{ + return this->sql_suffix_; +} + +inline bool options:: +sql_suffix_specified () const +{ + return this->sql_suffix_specified_; +} + inline const bool& options:: include_with_brackets () const { @@ -201,15 +275,51 @@ include_prefix () const return this->include_prefix_; } +inline bool options:: +include_prefix_specified () const +{ + return this->include_prefix_specified_; +} + +inline const std::string& options:: +guard_prefix () const +{ + return this->guard_prefix_; +} + +inline bool options:: +guard_prefix_specified () const +{ + return this->guard_prefix_specified_; +} + inline const std::string& options:: options_file () const { return this->options_file_; } +inline bool options:: +options_file_specified () const +{ + return this->options_file_specified_; +} + inline const bool& options:: trace () const { return this->trace_; } +inline const std::string& options:: +mysql_engine () const +{ + return this->mysql_engine_; +} + +inline bool options:: +mysql_engine_specified () const +{ + return this->mysql_engine_specified_; +} + diff --git a/odb/pragma.cxx b/odb/pragma.cxx index 33d69f0..eff1312 100644 --- a/odb/pragma.cxx +++ b/odb/pragma.cxx @@ -84,16 +84,19 @@ check_decl_type (tree d, string const& name, string const& p, location_t l) int tc (TREE_CODE (d)); char const* pc (p.c_str ()); - if (p == "column") + if (p == "id" || + p == "column" || + p == "type") { if (tc != FIELD_DECL) { error_at (l, "name %qs in odb pragma %qs does not refer to " - "a member variable", name.c_str (), pc); + "a data member", name.c_str (), pc); return false; } } - else if (p == "table") + else if (p == "object" || + p == "table") { if (tc != RECORD_TYPE) { @@ -122,7 +125,136 @@ handle_pragma (string const& p) tree decl (0); location_t loc (input_location); - if (p == "column") + if (p == "object") + { + // object [()] + // + + tt = pragma_lex (&t); + + if (tt == CPP_OPEN_PAREN) + { + tt = pragma_lex (&t); + + if (tt == CPP_NAME || tt == CPP_SCOPE) + { + string name; + decl = parse_scoped_name (t, tt, name, true, p); + + if (decl == 0) + return; + + // Make sure we've got the correct declaration type. + // + if (!check_decl_type (decl, name, p, loc)) + return; + + if (tt != CPP_CLOSE_PAREN) + { + error ("%qs expected at the end of odb pragma %qs", ")", pc); + return; + } + + tt = pragma_lex (&t); + } + else + { + error ("type name expected in odb pragma %qs", pc); + return; + } + } + } + else if (p == "table") + { + // table ([,] "") + // + + if (pragma_lex (&t) != CPP_OPEN_PAREN) + { + error ("%qs expected after odb pragma %qs", "(", pc); + return; + } + + tt = pragma_lex (&t); + + if (tt == CPP_NAME || tt == CPP_SCOPE) + { + string name; + decl = parse_scoped_name (t, tt, name, true, p); + + if (decl == 0) + return; + + // Make sure we've got the correct declaration type. + // + if (!check_decl_type (decl, name, p, loc)) + return; + + if (tt != CPP_COMMA) + { + error ("table name expected in odb pragma %qs", pc); + return; + } + + tt = pragma_lex (&t); + } + + if (tt != CPP_STRING) + { + error ("table name expected in odb pragma %qs", pc); + return; + } + + val = TREE_STRING_POINTER (t); + + if (pragma_lex (&t) != CPP_CLOSE_PAREN) + { + error ("%qs expected at the end of odb pragma %qs", ")", pc); + return; + } + + tt = pragma_lex (&t); + } + else if (p == "id") + { + // id [()] + // + + tt = pragma_lex (&t); + + if (tt == CPP_OPEN_PAREN) + { + tt = pragma_lex (&t); + + if (tt == CPP_NAME || tt == CPP_SCOPE) + { + string name; + decl = parse_scoped_name (t, tt, name, false, p); + + if (decl == 0) + return; + + // Make sure we've got the correct declaration type. + // + if (!check_decl_type (decl, name, p, loc)) + return; + + if (tt != CPP_CLOSE_PAREN) + { + error ("%qs expected at the end of odb pragma %qs", ")", pc); + return; + } + + tt = pragma_lex (&t); + } + else + { + error ("data member name expected in odb pragma %qs", pc); + return; + } + } + } + else if (p == "column") { // column ([,] "") // @@ -170,10 +302,12 @@ handle_pragma (string const& p) error ("%qs expected at the end of odb pragma %qs", ")", pc); return; } + + tt = pragma_lex (&t); } - else if (p == "table") + else if (p == "type") { - // table ([,] "") + // type ([,] "") // if (pragma_lex (&t) != CPP_OPEN_PAREN) @@ -187,7 +321,7 @@ handle_pragma (string const& p) if (tt == CPP_NAME || tt == CPP_SCOPE) { string name; - decl = parse_scoped_name (t, tt, name, true, p); + decl = parse_scoped_name (t, tt, name, false, p); if (decl == 0) return; @@ -199,7 +333,7 @@ handle_pragma (string const& p) if (tt != CPP_COMMA) { - error ("table name expected in odb pragma %qs", pc); + error ("type name expected in odb pragma %qs", pc); return; } @@ -208,7 +342,7 @@ handle_pragma (string const& p) if (tt != CPP_STRING) { - error ("table name expected in odb pragma %qs", pc); + error ("type name expected in odb pragma %qs", pc); return; } @@ -219,6 +353,8 @@ handle_pragma (string const& p) error ("%qs expected at the end of odb pragma %qs", ")", pc); return; } + + tt = pragma_lex (&t); } else { @@ -244,8 +380,6 @@ handle_pragma (string const& p) // See if there are any more pragmas. // - tt = pragma_lex (&t); - if (tt == CPP_NAME) { handle_pragma (IDENTIFIER_POINTER (t)); @@ -255,9 +389,9 @@ handle_pragma (string const& p) } extern "C" void -handle_pragma_odb_column (cpp_reader*) +handle_pragma_odb_object (cpp_reader*) { - handle_pragma ("column"); + handle_pragma ("object"); } extern "C" void @@ -267,8 +401,29 @@ handle_pragma_odb_table (cpp_reader*) } extern "C" void +handle_pragma_odb_id (cpp_reader*) +{ + handle_pragma ("id"); +} + +extern "C" void +handle_pragma_odb_column (cpp_reader*) +{ + handle_pragma ("column"); +} + +extern "C" void +handle_pragma_odb_type (cpp_reader*) +{ + handle_pragma ("type"); +} + +extern "C" void register_odb_pragmas (void*, void*) { - c_register_pragma_with_expansion ("odb", "column", handle_pragma_odb_column); + c_register_pragma_with_expansion ("odb", "object", handle_pragma_odb_object); c_register_pragma_with_expansion ("odb", "table", handle_pragma_odb_table); + c_register_pragma_with_expansion ("odb", "id", handle_pragma_odb_id); + c_register_pragma_with_expansion ("odb", "column", handle_pragma_odb_column); + c_register_pragma_with_expansion ("odb", "type", handle_pragma_odb_type); } diff --git a/odb/source.cxx b/odb/source.cxx index 02d26c4..0a14354 100644 --- a/odb/source.cxx +++ b/odb/source.cxx @@ -3,6 +3,7 @@ // copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file +#include #include namespace @@ -17,77 +18,71 @@ namespace virtual void traverse (type& c) { - if (c.file () != unit.file () || !odb_class (c)) + if (c.file () != unit.file ()) return; - string const& name (c.name ()); + if (!c.count ("object")) + return; + + string const& type (c.fq_name ()); + string traits ("access::object_traits< " + type + " >"); + + id_member t (*this); + t.traverse (c); + semantics::data_member& id (*t.member ()); os << "// " << c.name () << endl - << "//" << endl; + << "//" << endl + << endl; - os << name << "::" << endl - << name << " (::odb::image& i)" + // type_name () + // + os << "const char* " << traits << "::" << endl + << "type_name ()" << "{" + << "return \"" << type << "\";" << "}"; - } - private: - bool - odb_class (type& c) - { - // See if this class defines the ODB-specific c-tor. + // insert () // - tree t (c.tree_node ()); - - for (tree f (TYPE_METHODS (t)); f != 0; f = TREE_CHAIN (f)) - { - if (DECL_CONSTRUCTOR_P (f)) - { - // Get the argument list and skip the first (this) argument. - // - tree a (TREE_CHAIN (DECL_ARGUMENTS (f))); - - if (a == 0) - continue; - - tree at (TREE_TYPE (a)); - - // Check that it is ::odb::image&. - // - if (TREE_CODE (at) != REFERENCE_TYPE) - continue; - - tree rt (TREE_TYPE (at)); - tree mt (TYPE_MAIN_VARIANT (rt)); - - semantics::node* node (unit.find (mt)); - - if (node == 0) - continue; - - semantics::type* t_node (dynamic_cast (node)); - - if (t_node == 0) - continue; - - if (t_node->anonymous () || t_node->fq_name () != "::odb::image") - continue; - - // Make sure it is unqualified. - // - if (cp_type_quals (rt) != TYPE_UNQUALIFIED) - continue; // @@ Should probably be an error/warning. + os << "void " << traits << "::" << endl + << "insert (database&, const object_type& obj)" + << "{" + << "std::cout << \"insert \" << type_name () << \" id \" << " << + "id (obj) << std::endl;" + << "}"; - // Check that it is the only argument. - // - if (TREE_CHAIN (a) != 0) - continue; // @@ Should probably be an error/warning. + // update () + // + os << "void " << traits << "::" << endl + << "update (database&, const object_type& obj)" + << "{" + << "std::cout << \"update \" << type_name () << \" id \" << " << + "id (obj) << std::endl;" + << "}"; - return true; - } - } + // erase () + // + os << "void " << traits << "::" << endl + << "erase (database&, const id_type& id)" + << "{" + << "std::cout << \"delete \" << type_name () << \" id \" << " << + "id << std::endl;" + << "}"; - return false; + // find () + // + os << traits << "::shared_ptr " << endl + << traits << "::" << endl + << "find (database&, const id_type& id)" + << "{" + << "std::cout << \"select \" << type_name () << \" id \" << " << + "id << std::endl;" + << "shared_ptr r (access::object_factory< " << type << + " >::create ());" + << "r->" << id.name () << " = id;" + << "return r;" + << "}"; } }; } @@ -97,7 +92,7 @@ generate_source (context& ctx) { traversal::unit unit; traversal::defines unit_defines; - namespace_ ns (ctx); + traversal::namespace_ ns; class_ c (ctx); unit >> unit_defines >> ns; @@ -108,5 +103,16 @@ generate_source (context& ctx) ns >> ns_defines >> ns; ns_defines >> c; + ctx.os << "#include " << endl + << endl; + + //ctx.os << "#include " << endl + // << endl; + + ctx.os << "namespace odb" + << "{"; + unit.dispatch (ctx.unit); + + ctx.os << "}"; } diff --git a/odb/source.hxx b/odb/source.hxx index 9fac039..2db3fe2 100644 --- a/odb/source.hxx +++ b/odb/source.hxx @@ -6,7 +6,7 @@ #ifndef ODB_SOURCE_HXX #define ODB_SOURCE_HXX -#include "context.hxx" +#include void generate_source (context&); -- cgit v1.1