diff options
-rw-r--r-- | odb/context.cxx | 49 | ||||
-rw-r--r-- | odb/context.hxx | 79 | ||||
-rw-r--r-- | odb/generator.cxx | 156 | ||||
-rw-r--r-- | odb/generator.hxx | 29 | ||||
-rw-r--r-- | odb/makefile | 5 | ||||
-rw-r--r-- | odb/options.cli | 46 | ||||
-rw-r--r-- | odb/options.cxx | 84 | ||||
-rw-r--r-- | odb/options.hxx | 28 | ||||
-rw-r--r-- | odb/options.ixx | 42 | ||||
-rw-r--r-- | odb/plugin.cxx | 25 |
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 |