From 720c5a33b6a49cf328fdd7611f49153cf8f60247 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Wed, 8 Apr 2020 14:51:57 +0300 Subject: Separate tests and examples into individual packages Also make cli module to be explicitly enabled via the config.cli configuration variable. --- cli/cli/header.cxx | 383 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 383 insertions(+) create mode 100644 cli/cli/header.cxx (limited to 'cli/cli/header.cxx') diff --git a/cli/cli/header.cxx b/cli/cli/header.cxx new file mode 100644 index 0000000..a2a3ccd --- /dev/null +++ b/cli/cli/header.cxx @@ -0,0 +1,383 @@ +// file : cli/header.cxx +// author : Boris Kolpackov +// license : MIT; see accompanying LICENSE file + +#include + +using namespace std; + +namespace +{ + // + // + struct option: traversal::option, context + { + option (context& c) : context (c) {} + + virtual void + traverse (type& o) + { + string name (ename (o)); + string type (o.type ().name ()); + + os << "const " << type << "&" << endl + << name << " () const;" + << endl; + + if (gen_modifier) + { + os << type << "&" << endl + << name << " ();" + << endl; + + os << "void" << endl + << name << " (const " << type << "&);" + << endl; + } + + if (gen_specifier && type != "bool") + { + string spec (especifier (o)); + + os << "bool" << endl + << spec << " () const;" + << endl; + + if (gen_modifier) + os << "void" << endl + << spec << " (bool);" + << endl; + } + } + }; + + // + // + struct option_data: traversal::option, context + { + option_data (context& c) : context (c) {} + + virtual void + traverse (type& o) + { + string member (emember (o)); + string type (o.type ().name ()); + + os << type << " " << member << ";"; + + if (gen_specifier && type != "bool") + os << "bool " << especifier_member (o) << ";"; + } + }; + + // + // + struct base: traversal::class_, context + { + base (context& c): context (c), first_ (true) {} + + virtual void + traverse (type& c) + { + if (first_) + { + os << ": "; + first_ = false; + } + else + os << "," << endl + << " "; + + os << "public " << fq_name (c); + } + + private: + bool first_; + }; + + // + // + struct class_: traversal::class_, context + { + class_ (context& c) + : context (c), + option_ (c), + option_data_ (c) + { + names_option_ >> option_; + names_option_data_ >> option_data_; + } + + virtual void + traverse (type& c) + { + bool abst (c.abstract ()); + string name (escape (c.name ())); + string um (cli + "::unknown_mode"); + + os << "class " << name; + + { + base b (*this); + traversal::inherits i (b); + inherits (c, i); + } + + os << "{" + << "public:" << endl; + + // c-tors + // + if (!abst) + { + os << name << " ();" + << endl; + + // Are we generating parsing constructors or parse() functions? + // + string n; + if (gen_parse) + { + os << "// Return true if anything has been parsed." << endl + << "//" << endl; + + n = string ("bool\n") + (name != "parse" ? "parse" : "parse_"); + } + else + n = name; + + os << n << " (int& argc," << endl + << "char** argv," << endl + << "bool erase = false," << endl + << um << " option = " << um << "::fail," << endl + << um << " argument = " << um << "::stop);" + << endl; + + os << n << " (int start," << endl + << "int& argc," << endl + << "char** argv," << endl + << "bool erase = false," << endl + << um << " option = " << um << "::fail," << endl + << um << " argument = " << um << "::stop);" + << endl; + + os << n << " (int& argc," << endl + << "char** argv," << endl + << "int& end," << endl + << "bool erase = false," << endl + << um << " option = " << um << "::fail," << endl + << um << " argument = " << um << "::stop);" + << endl; + + os << n << " (int start," << endl + << "int& argc," << endl + << "char** argv," << endl + << "int& end," << endl + << "bool erase = false," << endl + << um << " option = " << um << "::fail," << endl + << um << " argument = " << um << "::stop);" + << endl; + + os << n << " (" << cli << "::scanner&," << endl + << um << " option = " << um << "::fail," << endl + << um << " argument = " << um << "::stop);" + << endl; + } + + + // Note that we are generating public merge() function even for abstract + // classes; theoretically, one may want to merge options only starting + // form a specific point in the inheritance hierarchy (e.g., only common + // options or some such). + // + if (gen_merge) + os << "// Merge options from the specified instance appending/overriding" << endl + << "// them as if they appeared after options in this instance." << endl + << "//" << endl + << "void" << endl + << "merge (const " << name << "&);" + << endl; + + // + // + os << "// Option accessors" << (gen_modifier ? " and modifiers." : ".") << endl + << "//" << endl; + + names (c, names_option_); + + // Usage. + // + if (gen_usage != ut_none) + { + string up (cli + "::usage_para"); + string const& ost (options.ostream_type ()); + + os << "// Print usage information." << endl + << "//" << endl; + + os << "static " << up << endl + << "print_usage (" << ost << "&," << endl + << up << " = " << up << "::none);" + << endl; + + if (gen_usage == ut_both) + os << "static " << up << endl + << "print_long_usage (" << ost << "&," << endl + << up << " = " << up << "::none);" + << endl; + } + + // Description. + // + if (options.generate_description ()) + { + os << "// Option description." << endl + << "//" << endl + << "static const " << cli << "::options&" << endl + << "description ();" + << endl; + } + + os << "// Implementation details." << endl + << "//" << endl + << "protected:" << endl; + + // default c-tor (abstract) + // + if (abst) + os << name << " ();" + << endl; + + // fill () + // + if (options.generate_description ()) + os << "friend struct _cli_" + name + "_desc_type;" + << endl + << "static void" << endl + << "fill (" << cli << "::options&);" + << endl; + + // _parse () + // + os << "bool" << endl + << "_parse (const char*, " << cli << "::scanner&);" + << endl; + + // _parse () + // + if (!abst) + os << "private:" << endl + << "bool" << endl + << "_parse (" << cli << "::scanner&," << endl + << um << " option," << endl + << um << " argument);" + << endl; + + // Data members. + // + os << "public:" << endl; //@@ tmp + + names (c, names_option_data_); + + os << "};"; + } + + private: + option option_; + traversal::names names_option_; + + option_data option_data_; + traversal::names names_option_data_; + }; + + // + // + struct includes_: traversal::cxx_includes, + traversal::cli_includes, + context + { + includes_ (context& c) : context (c) {} + + virtual void + traverse (semantics::cxx_includes& i) + { + generate (i.kind (), i.file ().string ()); + } + + virtual void + traverse (semantics::cli_includes& i) + { + generate (i.kind (), + (options.output_prefix () + + i.file ().base ().string () + + options.output_suffix () + + options.hxx_suffix ())); + } + + void + generate (semantics::includes::kind_type k, string const& f) + { + char b, e; + if (k == semantics::includes::quote) + b = e = '"'; + else + { + b = '<'; + e = '>'; + } + + os << "#include " << b << f << e << endl + << endl; + } + }; +} + +void +generate_header (context& ctx) +{ + ostream& os (ctx.os); + + traversal::cli_unit unit; + includes_ includes (ctx); + traversal::names unit_names; + namespace_ ns (ctx); + class_ cl (ctx); + + unit >> includes; + unit >> unit_names >> ns; + unit_names >> cl; + + traversal::names ns_names; + + ns >> ns_names >> ns; + ns_names >> cl; + + unit.dispatch (ctx.unit); + + // Entire page usage. + // + if (ctx.gen_usage != ut_none && ctx.options.page_usage_specified ()) + { + os << "// Print page usage information." << endl + << "//" << endl; + + const string& qn (ctx.options.page_usage ()); + string n (ctx.escape (ctx.substitute (ctx.ns_open (qn, false)))); + + string up (ctx.cli + "::usage_para"); + string const& ost (ctx.options.ostream_type ()); + + os << up << endl + << n << "usage (" << ost << "&," << endl + << up << " = " << up << "::none);" + << endl; + + if (ctx.gen_usage == ut_both) + os << up << endl + << n << "long_usage (" << ost << "&," << endl + << up << " = " << up << "::none);" + << endl; + + ctx.ns_close (qn, false); + } +} -- cgit v1.1