summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--odb/context.cxx49
-rw-r--r--odb/context.hxx79
-rw-r--r--odb/generator.cxx156
-rw-r--r--odb/generator.hxx29
-rw-r--r--odb/makefile5
-rw-r--r--odb/options.cli46
-rw-r--r--odb/options.cxx84
-rw-r--r--odb/options.hxx28
-rw-r--r--odb/options.ixx42
-rw-r--r--odb/plugin.cxx25
10 files changed, 533 insertions, 10 deletions
diff --git a/odb/context.cxx b/odb/context.cxx
new file mode 100644
index 0000000..913aa5d
--- /dev/null
+++ b/odb/context.cxx
@@ -0,0 +1,49 @@
+// file : odb/context.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <stack>
+#include "context.hxx"
+
+using namespace std;
+
+context::
+context (ostream& os_,
+ semantics::unit& unit_,
+ options_type const& ops)
+ : data_ (new (shared) data),
+ os (os_),
+ unit (unit_),
+ options (ops)
+{
+}
+
+context::
+context (context& c)
+ : data_ (c.data_),
+ os (c.os),
+ unit (c.unit),
+ options (c.options)
+{
+}
+
+// namespace
+//
+
+void namespace_::
+traverse (type& ns)
+{
+ string name (ns.name ());
+
+ if (name.empty ())
+ os << "namespace";
+ else
+ os << "namespace " << name;
+
+ os << "{";
+
+ traversal::namespace_::traverse (ns);
+
+ os << "}";
+}
diff --git a/odb/context.hxx b/odb/context.hxx
new file mode 100644
index 0000000..efdf610
--- /dev/null
+++ b/odb/context.hxx
@@ -0,0 +1,79 @@
+// file : odb/context.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_CONTEXT_HXX
+#define ODB_CONTEXT_HXX
+
+#include <set>
+#include <map>
+#include <string>
+#include <ostream>
+#include <cstddef> // std::size_t
+
+#include <cutl/shared-ptr.hxx>
+
+#include <options.hxx>
+#include <semantics.hxx>
+#include <traversal.hxx>
+
+using std::endl;
+
+class generation_failed {};
+
+class context
+{
+public:
+ typedef std::size_t size_t;
+ typedef std::string string;
+ typedef ::options options_type;
+
+private:
+ struct data;
+ cutl::shared_ptr<data> data_;
+
+public:
+ std::ostream& os;
+ semantics::unit& unit;
+ options_type const& options;
+
+private:
+ struct data
+ {
+ };
+
+public:
+ context (std::ostream&, semantics::unit&, options_type const&);
+ context (context&);
+
+private:
+ context&
+ operator= (context const&);
+};
+
+// Checks if scope Y names any of X.
+//
+template <typename X, typename Y>
+bool
+has (Y& y)
+{
+ for (semantics::scope::names_iterator i (y.names_begin ()),
+ e (y.names_end ()); i != e; ++i)
+ if (i->named (). template is_a<X> ())
+ return true;
+
+ return false;
+}
+
+// Standard namespace traverser.
+//
+struct namespace_: traversal::namespace_, context
+{
+ namespace_ (context& c) : context (c) {}
+
+ virtual void
+ traverse (type&);
+};
+
+#endif // ODB_CONTEXT_HXX
diff --git a/odb/generator.cxx b/odb/generator.cxx
new file mode 100644
index 0000000..3548802
--- /dev/null
+++ b/odb/generator.cxx
@@ -0,0 +1,156 @@
+// file : cli/generator.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <cctype> // std::toupper, std::is{alpha,upper,lower}
+#include <string>
+#include <fstream>
+#include <iostream>
+
+#include <cutl/fs/auto-remove.hxx>
+
+#include <cutl/compiler/code-stream.hxx>
+#include <cutl/compiler/cxx-indenter.hxx>
+
+#include <context.hxx>
+#include <generator.hxx>
+
+using namespace std;
+using namespace cutl;
+
+using semantics::path;
+
+namespace
+{
+ static char const cxx_header[] =
+ "// This code was generated by ODB, an object persistence compiler\n"
+ "// for C++.\n"
+ "//\n\n";
+
+ /*
+ string
+ make_guard (string const& file, context& ctx)
+ {
+ string g (file);
+
+ // Split words, e.g., "FooBar" to "Foo_Bar" and convert everything
+ // to upper case.
+ //
+ string r;
+ for (string::size_type i (0), n (g.size ()); i < n - 1; ++i)
+ {
+ char c1 (g[i]);
+ char c2 (g[i + 1]);
+
+ r += toupper (c1);
+
+ if (isalpha (c1) && isalpha (c2) && islower (c1) && isupper (c2))
+ r += "_";
+ }
+ r += std::toupper (g[g.size () - 1]);
+
+ return ctx.escape (r);
+ }
+ */
+
+ void
+ open (ifstream& ifs, string const& path)
+ {
+ ifs.open (path.c_str (), ios_base::in | ios_base::binary);
+
+ if (!ifs.is_open ())
+ {
+ cerr << path << ": error: unable to open in read mode" << endl;
+ throw generator::failed ();
+ }
+ }
+}
+
+generator::
+generator ()
+{
+}
+
+void generator::
+generate (options const& ops, semantics::unit& unit, path const& p)
+{
+ try
+ {
+ path file (p.leaf ());
+ string base (file.base ().string ());
+
+ fs::auto_removes auto_rm;
+
+ // C++ output.
+ //
+ string cxx_name (base + ops.odb_file_suffix () + ops.cxx_suffix ());
+ path cxx_path (cxx_name);
+
+ if (!ops.output_dir ().empty ())
+ {
+ path dir (ops.output_dir ());
+ cxx_path = dir / cxx_path;
+ }
+
+ //
+ //
+ ofstream cxx (cxx_path.string ().c_str ());
+
+ if (!cxx.is_open ())
+ {
+ cerr << "error: unable to open '" << cxx_path << "' in write mode"
+ << endl;
+ throw failed ();
+ }
+
+ auto_rm.add (cxx_path);
+
+ // Print headers.
+ //
+ cxx << cxx_header;
+
+ typedef compiler::ostream_filter<compiler::cxx_indenter, char> cxx_filter;
+
+ // Include settings.
+ //
+ bool br (ops.include_with_brackets ());
+ string ip (ops.include_prefix ());
+
+ if (!ip.empty () && ip[ip.size () - 1] != '/')
+ ip.append ("/");
+
+ // CXX
+ //
+ {
+ cxx_filter filt (cxx);
+ context ctx (cxx, unit, ops);
+
+ cxx << "#include " << (br ? '<' : '"') << ip << file <<
+ (br ? '>' : '"') << endl
+ << endl;
+
+ // generate_source (ctx);
+ }
+
+ auto_rm.cancel ();
+ }
+ catch (const generation_failed&)
+ {
+ // Code generation failed. Diagnostics has already been issued.
+ //
+ throw failed ();
+ }
+ catch (semantics::invalid_path const& e)
+ {
+ cerr << "error: '" << e.path () << "' is not a valid filesystem path"
+ << endl;
+ throw failed ();
+ }
+ catch (fs::error const&)
+ {
+ // Auto-removal of generated files failed. Ignore it.
+ //
+ throw failed ();
+ }
+}
diff --git a/odb/generator.hxx b/odb/generator.hxx
new file mode 100644
index 0000000..42f7bed
--- /dev/null
+++ b/odb/generator.hxx
@@ -0,0 +1,29 @@
+// file : odb/generator.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_GENERATOR_HXX
+#define ODB_GENERATOR_HXX
+
+#include <options.hxx>
+#include <semantics/unit.hxx>
+
+class generator
+{
+public:
+ generator ();
+
+ class failed {};
+
+ void
+ generate (options const&, semantics::unit&, semantics::path const&);
+
+private:
+ generator (generator const&);
+
+ generator&
+ operator= (generator const&);
+};
+
+#endif // ODB_GENERATOR_HXX
diff --git a/odb/makefile b/odb/makefile
index 742b3a5..2789a47 100644
--- a/odb/makefile
+++ b/odb/makefile
@@ -7,7 +7,10 @@ include $(dir $(lastword $(MAKEFILE_LIST)))../build/bootstrap.make
# Plugin units.
#
-cxx_ptun := plugin.cxx
+cxx_ptun := \
+context.cxx \
+generator.cxx \
+plugin.cxx
cxx_ptun += \
semantics/class.cxx \
diff --git a/odb/options.cli b/odb/options.cli
index 3b15fb2..19c3b4c 100644
--- a/odb/options.cli
+++ b/odb/options.cli
@@ -18,6 +18,52 @@ class options
//
// Plugin options.
//
+ std::string --output-dir | -o
+ {
+ "<dir>",
+ "Write the generated files to <dir> instead of the current directory."
+ };
+
+ std::string --odb-file-suffix = "-odb"
+ {
+ "<suffix>",
+ "Use <suffix> instead of the default \cb{-odb} to construct the names
+ of the generated ODB files."
+ };
+
+ std::string --hxx-suffix = ".hxx"
+ {
+ "<suffix>",
+ "Use <suffix> instead of the default \cb{.hxx} to construct the name of
+ the generated header file."
+ };
+
+ std::string --ixx-suffix = ".ixx"
+ {
+ "<suffix>",
+ "Use <suffix> instead of the default \cb{.ixx} to construct the name of
+ the generated inline file."
+ };
+
+ std::string --cxx-suffix = ".cxx"
+ {
+ "<suffix>",
+ "Use <suffix> instead of the default \cb{.cxx} to construct the name of
+ the generated source file."
+ };
+
+ bool --include-with-brackets
+ {
+ "Use angle brackets (<>) instead of quotes (\"\") in the generated
+ \cb{#include} directives."
+ };
+
+ std::string --include-prefix
+ {
+ "<prefix>",
+ "Add <prefix> to the generated \cb{#include} directive paths."
+ };
+
bool --trace {"Trace the compilation process."};
// This is a "fake" option in that it is actually handled by
diff --git a/odb/options.cxx b/odb/options.cxx
index 8226e3f..b209119 100644
--- a/odb/options.cxx
+++ b/odb/options.cxx
@@ -490,6 +490,13 @@ options (int& argc,
::cli::unknown_mode arg)
: help_ (),
version_ (),
+ output_dir_ (),
+ odb_file_suffix_ ("-odb"),
+ hxx_suffix_ (".hxx"),
+ ixx_suffix_ (".ixx"),
+ cxx_suffix_ (".cxx"),
+ include_with_brackets_ (),
+ include_prefix_ (),
trace_ (),
options_file_ ()
{
@@ -506,6 +513,13 @@ options (int start,
::cli::unknown_mode arg)
: help_ (),
version_ (),
+ output_dir_ (),
+ odb_file_suffix_ ("-odb"),
+ hxx_suffix_ (".hxx"),
+ ixx_suffix_ (".ixx"),
+ cxx_suffix_ (".cxx"),
+ include_with_brackets_ (),
+ include_prefix_ (),
trace_ (),
options_file_ ()
{
@@ -522,6 +536,13 @@ options (int& argc,
::cli::unknown_mode arg)
: help_ (),
version_ (),
+ output_dir_ (),
+ odb_file_suffix_ ("-odb"),
+ hxx_suffix_ (".hxx"),
+ ixx_suffix_ (".ixx"),
+ cxx_suffix_ (".cxx"),
+ include_with_brackets_ (),
+ include_prefix_ (),
trace_ (),
options_file_ ()
{
@@ -540,6 +561,13 @@ options (int start,
::cli::unknown_mode arg)
: help_ (),
version_ (),
+ output_dir_ (),
+ odb_file_suffix_ ("-odb"),
+ hxx_suffix_ (".hxx"),
+ ixx_suffix_ (".ixx"),
+ cxx_suffix_ (".cxx"),
+ include_with_brackets_ (),
+ include_prefix_ (),
trace_ (),
options_file_ ()
{
@@ -554,6 +582,13 @@ options (::cli::scanner& s,
::cli::unknown_mode arg)
: help_ (),
version_ (),
+ output_dir_ (),
+ odb_file_suffix_ ("-odb"),
+ hxx_suffix_ (".hxx"),
+ ixx_suffix_ (".ixx"),
+ cxx_suffix_ (".cxx"),
+ include_with_brackets_ (),
+ include_prefix_ (),
trace_ (),
options_file_ ()
{
@@ -563,15 +598,36 @@ options (::cli::scanner& s,
void options::
print_usage (::std::ostream& os)
{
- os << "--help Print usage information and exit." << ::std::endl;
+ os << "--help Print usage information and exit." << ::std::endl;
- os << "--version Print version and exit." << ::std::endl;
+ os << "--version Print version and exit." << ::std::endl;
- os << "--trace Trace the compilation process." << ::std::endl;
+ os << "--output-dir|-o <dir> Write the generated files to <dir> instead of the" << ::std::endl
+ << " current directory." << ::std::endl;
- os << "--options-file <file> Read additional options from <file> with each option" << ::std::endl
- << " appearing on a separate line optionally followed by space" << ::std::endl
- << " and an option value." << ::std::endl;
+ os << "--odb-file-suffix <suffix> Use <suffix> instead of the default '-odb' to" << ::std::endl
+ << " construct the names of the generated ODB files." << ::std::endl;
+
+ os << "--hxx-suffix <suffix> Use <suffix> instead of the default '.hxx' to" << ::std::endl
+ << " construct the name of the generated header file." << ::std::endl;
+
+ os << "--ixx-suffix <suffix> Use <suffix> instead of the default '.ixx' to" << ::std::endl
+ << " construct the name of the generated inline file." << ::std::endl;
+
+ os << "--cxx-suffix <suffix> Use <suffix> instead of the default '.cxx' to" << ::std::endl
+ << " construct the name of the generated source file." << ::std::endl;
+
+ os << "--include-with-brackets Use angle brackets (<>) instead of quotes (\"\") in the" << ::std::endl
+ << " generated '#include' directives." << ::std::endl;
+
+ os << "--include-prefix <prefix> Add <prefix> to the generated '#include' directive" << ::std::endl
+ << " paths." << ::std::endl;
+
+ os << "--trace Trace the compilation process." << ::std::endl;
+
+ os << "--options-file <file> Read additional options from <file> with each option" << ::std::endl
+ << " appearing on a separate line optionally followed by" << ::std::endl
+ << " space and an option value." << ::std::endl;
}
typedef
@@ -588,6 +644,22 @@ struct _cli_options_map_init
&::cli::thunk< options, bool, &options::help_ >;
_cli_options_map_["--version"] =
&::cli::thunk< options, bool, &options::version_ >;
+ _cli_options_map_["--output-dir"] =
+ &::cli::thunk< options, std::string, &options::output_dir_ >;
+ _cli_options_map_["-o"] =
+ &::cli::thunk< options, std::string, &options::output_dir_ >;
+ _cli_options_map_["--odb-file-suffix"] =
+ &::cli::thunk< options, std::string, &options::odb_file_suffix_ >;
+ _cli_options_map_["--hxx-suffix"] =
+ &::cli::thunk< options, std::string, &options::hxx_suffix_ >;
+ _cli_options_map_["--ixx-suffix"] =
+ &::cli::thunk< options, std::string, &options::ixx_suffix_ >;
+ _cli_options_map_["--cxx-suffix"] =
+ &::cli::thunk< options, std::string, &options::cxx_suffix_ >;
+ _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_options_map_["--trace"] =
&::cli::thunk< options, bool, &options::trace_ >;
_cli_options_map_["--options-file"] =
diff --git a/odb/options.hxx b/odb/options.hxx
index 8fb43e2..b8a6488 100644
--- a/odb/options.hxx
+++ b/odb/options.hxx
@@ -301,6 +301,27 @@ class options
const bool&
version () const;
+ const std::string&
+ output_dir () const;
+
+ const std::string&
+ odb_file_suffix () const;
+
+ const std::string&
+ hxx_suffix () const;
+
+ const std::string&
+ ixx_suffix () const;
+
+ const std::string&
+ cxx_suffix () const;
+
+ const bool&
+ include_with_brackets () const;
+
+ const std::string&
+ include_prefix () const;
+
const bool&
trace () const;
@@ -321,6 +342,13 @@ class options
public:
bool help_;
bool version_;
+ std::string output_dir_;
+ std::string odb_file_suffix_;
+ std::string hxx_suffix_;
+ std::string ixx_suffix_;
+ std::string cxx_suffix_;
+ bool include_with_brackets_;
+ std::string include_prefix_;
bool trace_;
std::string options_file_;
};
diff --git a/odb/options.ixx b/odb/options.ixx
index 104556b..a511e0c 100644
--- a/odb/options.ixx
+++ b/odb/options.ixx
@@ -159,6 +159,48 @@ version () const
return this->version_;
}
+inline const std::string& options::
+output_dir () const
+{
+ return this->output_dir_;
+}
+
+inline const std::string& options::
+odb_file_suffix () const
+{
+ return this->odb_file_suffix_;
+}
+
+inline const std::string& options::
+hxx_suffix () const
+{
+ return this->hxx_suffix_;
+}
+
+inline const std::string& options::
+ixx_suffix () const
+{
+ return this->ixx_suffix_;
+}
+
+inline const std::string& options::
+cxx_suffix () const
+{
+ return this->cxx_suffix_;
+}
+
+inline const bool& options::
+include_with_brackets () const
+{
+ return this->include_with_brackets_;
+}
+
+inline const std::string& options::
+include_prefix () const
+{
+ return this->include_prefix_;
+}
+
inline const bool& options::
trace () const
{
diff --git a/odb/plugin.cxx b/odb/plugin.cxx
index 35e6ab6..f381251 100644
--- a/odb/plugin.cxx
+++ b/odb/plugin.cxx
@@ -15,6 +15,7 @@
#include <options.hxx>
#include <semantics.hxx>
+#include <generator.hxx>
#ifndef LOCATION_COLUMN
#define LOCATION_COLUMN(LOC) (expand_location (LOC).column)
@@ -1500,13 +1501,31 @@ auto_ptr<options const> options_;
extern "C" void
gate_callback (void* gcc_data, void*)
{
- if (!errorcount && !sorrycount)
+ // If there were errors during compilation, let GCC handle the
+ // exit.
+ //
+ if (errorcount || sorrycount)
+ return;
+
+ int r (0);
+
+ try
{
parser p (*options_);
- auto_ptr<unit> u (p.parse (global_namespace, path (main_input_filename)));
+ path file (main_input_filename);
+ auto_ptr<unit> u (p.parse (global_namespace, file));
+
+ generator g;
+ g.generate (*options_, *u, file);
+ }
+ catch (generator::failed const&)
+ {
+ // Diagnostics has aready been issued.
+ //
+ r = 1;
}
- exit (0);
+ exit (r);
}
extern "C" int