summaryrefslogtreecommitdiff
path: root/cli
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2009-09-27 18:20:49 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2009-09-27 18:20:49 +0200
commit4b1e037fb0f763cd3e3401d71b66269440d75dbf (patch)
tree68d16506b8c7410c0e0fd34358249ebf4929f395 /cli
parentb5e7ac58b0e44a7903808d622f5af97c07171281 (diff)
Generate parsing constructors and parsing code
Also generate some runtime support code such exceptions, value parsers, etc.
Diffstat (limited to 'cli')
-rw-r--r--cli/generator.cxx6
-rw-r--r--cli/header.cxx64
-rw-r--r--cli/makefile2
-rw-r--r--cli/runtime-header.cxx177
-rw-r--r--cli/runtime-header.hxx17
-rw-r--r--cli/runtime-source.cxx177
-rw-r--r--cli/runtime-source.hxx14
-rw-r--r--cli/source.cxx272
8 files changed, 725 insertions, 4 deletions
diff --git a/cli/generator.cxx b/cli/generator.cxx
index b864dfb..79401e0 100644
--- a/cli/generator.cxx
+++ b/cli/generator.cxx
@@ -17,6 +17,9 @@
#include "source.hxx"
#include "inline.hxx"
+#include "runtime-header.hxx"
+#include "runtime-source.hxx"
+
#include "context.hxx"
#include "generator.hxx"
#include "name-processor.hxx"
@@ -174,7 +177,9 @@ generate (semantics::cli_unit& unit, path const& p)
<< "#define " << guard << endl
<< endl;
+ generate_runtime_header_decl (ctx);
generate_header (ctx);
+ generate_runtime_header_impl (ctx);
if (inl)
{
@@ -206,6 +211,7 @@ generate (semantics::cli_unit& unit, path const& p)
if (!inl)
generate_inline (ctx);
+ generate_runtime_source (ctx);
generate_source (ctx);
}
diff --git a/cli/header.cxx b/cli/header.cxx
index c248690..8033b7f 100644
--- a/cli/header.cxx
+++ b/cli/header.cxx
@@ -25,6 +25,8 @@ namespace
}
};
+ //
+ //
struct option_data: traversal::option, context
{
option_data (context& c) : context (c) {}
@@ -62,9 +64,61 @@ namespace
<< "public:" << endl
<< endl;
+ // c-tors
+ //
+ string um ("::cli::unknown_mode");
+
+ os << name << " (int argc," << endl
+ << "char** argv," << endl
+ << um << " option = " << um << "::fail," << endl
+ << um << " argument = " << um << "::stop);"
+ << endl;
+
+ os << name << " (int start," << endl
+ << "int argc," << endl
+ << "char** argv," << endl
+ << um << " option = " << um << "::fail," << endl
+ << um << " argument = " << um << "::stop);"
+ << endl;
+
+ os << name << " (int argc," << endl
+ << "char** argv," << endl
+ << "int& end," << endl
+ << um << " option = " << um << "::fail," << endl
+ << um << " argument = " << um << "::stop);"
+ << endl;
+
+ os << name << " (int start," << endl
+ << "int argc," << endl
+ << "char** argv," << endl
+ << "int& end," << endl
+ << um << " option = " << um << "::fail," << endl
+ << um << " argument = " << um << "::stop);"
+ << endl;
+
+ //
+ //
+ os << "// Option accessors." << endl
+ << "//" << endl
+ << "public:" << endl
+ << endl;
+
names (c, names_option_);
- os << "private:" << endl;
+ // _parse()
+ //
+ os << "private:" << endl
+ << "int" << endl
+ << "_parse (int start," << endl
+ << "int argc," << endl
+ << "char** argv," << endl
+ << um << " option," << endl
+ << um << " argument);"
+ << endl;
+
+ // Data members.
+ //
+ os << "public:" << endl; //@@ tmp
names (c, names_option_data_);
@@ -101,11 +155,15 @@ generate_header (context& ctx)
includes includes (ctx);
traversal::names unit_names;
namespace_ ns (ctx);
- traversal::names ns_names;
class_ cl (ctx);
unit >> includes;
- unit >> unit_names >> ns >> ns_names >> ns;
+ unit >> unit_names >> ns;
+ unit_names >> cl;
+
+ traversal::names ns_names;
+
+ ns >> ns_names >> ns;
ns_names >> cl;
unit.dispatch (ctx.unit);
diff --git a/cli/makefile b/cli/makefile
index 488d758..f281167 100644
--- a/cli/makefile
+++ b/cli/makefile
@@ -12,6 +12,8 @@ context.cxx \
header.cxx \
inline.cxx \
source.cxx \
+runtime-header.cxx \
+runtime-source.cxx \
generator.cxx \
name-processor.cxx
diff --git a/cli/runtime-header.cxx b/cli/runtime-header.cxx
new file mode 100644
index 0000000..87cdf11
--- /dev/null
+++ b/cli/runtime-header.cxx
@@ -0,0 +1,177 @@
+// file : cli/runtime-header.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009 Code Synthesis Tools CC
+// license : MIT; see accompanying LICENSE file
+
+#include "runtime-header.hxx"
+
+using namespace std;
+
+void
+generate_runtime_header_decl (context& ctx)
+{
+ ostream& os (ctx.os);
+
+ os << "#include <iosfwd>" << endl
+ << "#include <string>" << endl
+ << "#include <exception>" << endl
+ << endl;
+
+ os << "namespace cli"
+ << "{";
+
+ // unknown_mode
+ //
+ os << "class unknown_mode"
+ << "{"
+ << "public:"
+ << "enum value"
+ << "{"
+ << "skip," << endl
+ << "stop," << endl
+ << "fail" << endl
+ << "};"
+ << "unknown_mode (value v)" << endl
+ << ": v_ (v) {}"
+ << "operator value () const {return v_;}"
+ << "private:" << endl
+ << "value v_;"
+ << "};";
+
+ // Exceptions.
+ //
+
+ os << "// Exceptions." << endl
+ << "//" << endl
+ << endl;
+
+ os << "class exception: public std::exception"
+ << "{"
+ << "public:" << endl
+ << "virtual void" << endl
+ << "print (std::ostream&) const = 0;"
+ << "};";
+
+ os << "inline std::ostream&" << endl
+ << "operator<< (std::ostream& os, const exception& e)"
+ << "{"
+ << "e.print (os);"
+ << "return os;"
+ << "}";
+
+ os << "class unknown_option: public exception"
+ << "{"
+ << "public:" << endl
+ << "virtual" << endl
+ << "~unknown_option () throw ();"
+ << endl
+ << "unknown_option (const std::string& option)" << endl
+ << ": option_ (option)"
+ << "{"
+ << "}"
+ << "const std::string&" << endl
+ << "option () const"
+ << "{"
+ << "return option_;"
+ << "}"
+ << "virtual void" << endl
+ << "print (std::ostream&) const;"
+ << endl
+ << "virtual const char*" << endl
+ << "what () const throw ();"
+ << endl
+ << "private:" << endl
+ << "std::string option_;"
+ << "};";
+
+ os << "class unknown_argument: public exception"
+ << "{"
+ << "public:" << endl
+ << "virtual" << endl
+ << "~unknown_argument () throw ();"
+ << endl
+ << "unknown_argument (const std::string& argument)" << endl
+ << ": argument_ (argument)"
+ << "{"
+ << "}"
+ << "const std::string&" << endl
+ << "argument () const"
+ << "{"
+ << "return argument_;"
+ << "}"
+ << "virtual void" << endl
+ << "print (std::ostream&) const;"
+ << endl
+ << "virtual const char*" << endl
+ << "what () const throw ();"
+ << endl
+ << "private:" << endl
+ << "std::string argument_;"
+ << "};";
+
+ os << "class missing_value: public exception"
+ << "{"
+ << "public:" << endl
+ << "virtual" << endl
+ << "~missing_value () throw ();"
+ << endl
+ << "missing_value (const std::string& option)" << endl
+ << ": option_ (option)"
+ << "{"
+ << "}"
+ << "const std::string&" << endl
+ << "option () const"
+ << "{"
+ << "return option_;"
+ << "}"
+ << "virtual void" << endl
+ << "print (std::ostream&) const;"
+ << endl
+ << "virtual const char*" << endl
+ << "what () const throw ();"
+ << endl
+ << "private:" << endl
+ << "std::string option_;"
+ << "};";
+
+ os << "class invalid_value: public exception"
+ << "{"
+ << "public:" << endl
+ << "virtual" << endl
+ << "~invalid_value () throw ();"
+ << endl
+ << "invalid_value (const std::string& option," << endl
+ << "const std::string& value)" << endl
+ << ": option_ (option),"
+ << " value_ (value)"
+ << "{"
+ << "}"
+ << "const std::string&" << endl
+ << "option () const"
+ << "{"
+ << "return option_;"
+ << "}"
+ << "const std::string&" << endl
+ << "value () const"
+ << "{"
+ << "return value_;"
+ << "}"
+ << "virtual void" << endl
+ << "print (std::ostream&) const;"
+ << endl
+ << "virtual const char*" << endl
+ << "what () const throw ();"
+ << endl
+ << "private:" << endl
+ << "std::string option_;"
+ << "std::string value_;"
+ << "};";
+
+ os << "}"; // namespace cli
+}
+
+void
+generate_runtime_header_impl (context& ctx)
+{
+ ostream& os (ctx.os);
+}
diff --git a/cli/runtime-header.hxx b/cli/runtime-header.hxx
new file mode 100644
index 0000000..5f78e9d
--- /dev/null
+++ b/cli/runtime-header.hxx
@@ -0,0 +1,17 @@
+// file : cli/runtime-header.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009 Code Synthesis Tools CC
+// license : MIT; see accompanying LICENSE file
+
+#ifndef CLI_RUNTIME_HEADER_HXX
+#define CLI_RUNTIME_HEADER_HXX
+
+#include "context.hxx"
+
+void
+generate_runtime_header_decl (context&);
+
+void
+generate_runtime_header_impl (context&);
+
+#endif // CLI_RUNTIME_HEADER_HXX
diff --git a/cli/runtime-source.cxx b/cli/runtime-source.cxx
new file mode 100644
index 0000000..3cb5f2e
--- /dev/null
+++ b/cli/runtime-source.cxx
@@ -0,0 +1,177 @@
+// file : cli/runtime-source.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009 Code Synthesis Tools CC
+// license : MIT; see accompanying LICENSE file
+
+#include "runtime-source.hxx"
+
+using namespace std;
+
+void
+generate_runtime_source (context& ctx)
+{
+ ostream& os (ctx.os);
+
+ os << "#include <string>" << endl
+ << "#include <vector>" << endl
+ << "#include <ostream>" << endl
+ << "#include <sstream>" << endl
+ << endl;
+
+ os << "namespace cli"
+ << "{";
+
+ // unknown_option
+ //
+ os << "// unknown_option" << endl
+ << "//" << endl
+ << "unknown_option::" << endl
+ << "~unknown_option () throw ()"
+ << "{"
+ << "}"
+ << "void unknown_option::" << endl
+ << "print (std::ostream& os) const"
+ << "{"
+ << "os << \"unknown option '\" << option () << \"'\";"
+ << "}"
+ << "const char* unknown_option::" << endl
+ << "what () const throw ()"
+ << "{"
+ << "return \"unknown option\";"
+ << "}";
+
+ // unknown_argument
+ //
+ os << "// unknown_argument" << endl
+ << "//" << endl
+ << "unknown_argument::" << endl
+ << "~unknown_argument () throw ()"
+ << "{"
+ << "}"
+ << "void unknown_argument::" << endl
+ << "print (std::ostream& os) const"
+ << "{"
+ << "os << \"unknown argument '\" << argument () << \"'\";"
+ << "}"
+ << "const char* unknown_argument::" << endl
+ << "what () const throw ()"
+ << "{"
+ << "return \"unknown argument\";"
+ << "}";
+
+ // missing_value
+ //
+ os << "// missing_value" << endl
+ << "//" << endl
+ << "missing_value::" << endl
+ << "~missing_value () throw ()"
+ << "{"
+ << "}"
+ << "void missing_value::" << endl
+ << "print (std::ostream& os) const"
+ << "{"
+ << "os << \"missing value for option '\" << option () << \"'\";"
+ << "}"
+ << "const char* missing_value::" << endl
+ << "what () const throw ()"
+ << "{"
+ << "return \"missing option value\";"
+ << "}";
+
+ // invalid_value
+ //
+ os << "// invalid_value" << endl
+ << "//" << endl
+ << "invalid_value::" << endl
+ << "~invalid_value () throw ()"
+ << "{"
+ << "}"
+ << "void invalid_value::" << endl
+ << "print (std::ostream& os) const"
+ << "{"
+ << "os << \"invalid value '\" << value () << \"' for option '\"" << endl
+ << " << option () << \"'\";"
+ << "}"
+ << "const char* invalid_value::" << endl
+ << "what () const throw ()"
+ << "{"
+ << "return \"invalid option value\";"
+ << "}";
+
+ // parser class template & its specializations
+ //
+ os << "template <typename X>" << endl
+ << "struct parser"
+ << "{"
+ << "static int" << endl
+ << "parse (X& x, char** argv, int n)"
+ << "{"
+ << "if (n > 1)"
+ << "{"
+ << "std::istringstream is (argv[1]);"
+ << "if (!(is >> x && is.eof ()))" << endl
+ << "throw invalid_value (argv[0], argv[1]);"
+ << "return 2;"
+ << "}"
+ << "else" << endl
+ << "throw missing_value (argv[0]);"
+ << "}"
+ << "};";
+
+ // parser<bool>
+ //
+ os << "template <>" << endl
+ << "struct parser<bool>"
+ << "{"
+ << "static int" << endl
+ << "parse (bool& x, char**, int)"
+ << "{"
+ << "x = true;"
+ << "return 1;"
+ << "}"
+ << "};";
+
+ // parser<string>
+ //
+ os << "template <>" << endl
+ << "struct parser<std::string>"
+ << "{"
+ << "static int" << endl
+ << "parse (std::string& x, char** argv, int n)"
+ << "{"
+ << "if (n > 1)"
+ << "{"
+ << "x = argv[1];"
+ << "return 2;"
+ << "}"
+ << "else" << endl
+ << "throw missing_value (argv[0]);"
+ << "}"
+ << "};";
+
+ // parser<std::vector<X>>
+ //
+ os << "template <typename X>" << endl
+ << "struct parser<std::vector<X> >"
+ << "{"
+ << "static int" << endl
+ << "parse (std::vector<X>& v, char** argv, int n)"
+ << "{"
+ << "X x;"
+ << "int i (parser<X>::parse (x, argv, n));"
+ << "v.push_back (x);"
+ << "return i;"
+ << "}"
+ << "};";
+
+ // Parser thunk.
+ //
+ os << "template <typename X, typename T, T X::*P>" << endl
+ << "int" << endl
+ << "thunk (X& x, char** argv, int n)"
+ << "{"
+ << "return parser<T>::parse (x.*P, argv, n);"
+ << "}";
+
+ os << "}"; // namespace cli
+}
diff --git a/cli/runtime-source.hxx b/cli/runtime-source.hxx
new file mode 100644
index 0000000..efcba29
--- /dev/null
+++ b/cli/runtime-source.hxx
@@ -0,0 +1,14 @@
+// file : cli/runtime-source.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009 Code Synthesis Tools CC
+// license : MIT; see accompanying LICENSE file
+
+#ifndef CLI_RUNTIME_SOURCE_HXX
+#define CLI_RUNTIME_SOURCE_HXX
+
+#include "context.hxx"
+
+void
+generate_runtime_source (context&);
+
+#endif // CLI_RUNTIME_SOURCE_HXX
diff --git a/cli/source.cxx b/cli/source.cxx
index 75be8a3..e9e4365 100644
--- a/cli/source.cxx
+++ b/cli/source.cxx
@@ -7,18 +7,288 @@
namespace
{
+ //
+ //
+ struct option_init: traversal::option, context
+ {
+ option_init (context& c) : context (c), comma_ (false) {}
+ virtual void
+ traverse (type& o)
+ {
+ if (comma_)
+ os << "," << endl
+ << " ";
+ else
+ comma_ = true;
+
+ os << emember (o);
+
+ if (o.initialized_p ())
+ {
+ using semantics::expression;
+ expression const& i (o.initializer ());
+
+ switch (i.type ())
+ {
+ case expression::string_lit:
+ case expression::char_lit:
+ case expression::bool_lit:
+ case expression::int_lit:
+ case expression::float_lit:
+ case expression::identifier:
+ {
+ os << " (" << i.value () << ")";
+ break;
+ }
+ case expression::call_expr:
+ {
+ os << " " << i.value ();
+ break;
+ }
+ }
+ }
+ else
+ os << " ()";
+ }
+
+ private:
+ bool comma_;
+ };
+
+ //
+ //
+ struct option_map: traversal::option, context
+ {
+ option_map (context& c) : context (c) {}
+
+ virtual void
+ traverse (type& o)
+ {
+ string name (ename (o));
+ string type (o.type ().name ());
+ string scope (escape (o.scope ().name ()));
+ string map ("_cli_" + scope + "_map_");
+
+ os << "_cli_" << scope << "_map_[\"" << o.name () << "\"] = " << endl
+ << "&::cli::thunk<" << scope << ", " << type << ", " <<
+ "&" << scope << "::" << emember (o) << ">;";
+ }
+ };
+
+ //
+ //
+ struct class_: traversal::class_, context
+ {
+ class_ (context& c)
+ : context (c), option_map_ (c)
+ {
+ names_option_map_ >> option_map_;
+ }
+
+ virtual void
+ traverse (type& c)
+ {
+ string name (escape (c.name ()));
+
+ os << "// " << name << endl
+ << "//" << endl
+ << endl;
+
+ // c-tors
+ //
+ string um ("::cli::unknown_mode");
+
+ os << name << "::" << endl
+ << name << " (int argc," << endl
+ << "char** argv," << endl
+ << um << " opt," << endl
+ << um << " arg)" << endl
+ << ": ";
+ {
+ option_init init (*this);
+ traversal::names names_init (init);
+ names (c, names_init);
+ }
+ os << "{"
+ << "_parse (1, argc, argv, opt, arg);"
+ << "}";
+
+ os << name << "::" << endl
+ << name << " (int start," << endl
+ << "int argc," << endl
+ << "char** argv," << endl
+ << um << " opt," << endl
+ << um << " arg)" << endl
+ << ": ";
+ {
+ option_init init (*this);
+ traversal::names names_init (init);
+ names (c, names_init);
+ }
+ os << "{"
+ << "_parse (start, argc, argv, opt, arg);"
+ << "}";
+
+ os << name << "::" << endl
+ << name << " (int argc," << endl
+ << "char** argv," << endl
+ << "int& end," << endl
+ << um << " opt," << endl
+ << um << " arg)" << endl
+ << ": ";
+ {
+ option_init init (*this);
+ traversal::names names_init (init);
+ names (c, names_init);
+ }
+ os << "{"
+ << "end = _parse (1, argc, argv, opt, arg);"
+ << "}";
+
+ os << name << "::" << endl
+ << name << " (int start," << endl
+ << "int argc," << endl
+ << "char** argv," << endl
+ << "int& end," << endl
+ << um << " opt," << endl
+ << um << " arg)" << endl
+ << ": ";
+ {
+ option_init init (*this);
+ traversal::names names_init (init);
+ names (c, names_init);
+ }
+ os << "{"
+ << "end = _parse (start, argc, argv, opt, arg);"
+ << "}";
+
+ // _parse()
+ //
+ string map ("_cli_" + name + "_map");
+
+ os << "typedef" << endl
+ << "std::map<std::string, int (*) (" <<
+ name << "&, char**, int)>" << endl
+ << map << ";"
+ << endl
+ << "static " << map << " " << map << "_;"
+ << endl;
+
+ os << "struct " << map << "_init"
+ << "{"
+ << map << "_init ()"
+ << "{";
+
+ names (c, names_option_map_);
+
+ os << "}"
+ << "} " << map << "_init_;"
+ << endl;
+
+ os << "int " << name << "::" << endl
+ << "_parse (int start," << endl
+ << "int argc," << endl
+ << "char** argv," << endl
+ << um << " opt_mode," << endl
+ << um << " arg_mode)"
+ << "{"
+ << "bool opt (true);" // Still recognizing options.
+ << endl
+ << "for (; start < argc;)"
+ << "{"
+ << "const char* s (argv[start]);"
+ << endl
+ << "if (std::strcmp (s, \"--\") == 0)"
+ << "{"
+ << "start++;"
+ << "opt = false;"
+ << "continue;"
+ << "}"
+ << map << "::const_iterator i (" << endl
+ << "opt ? " << map << "_.find (s) : " << map << "_.end ());"
+ << endl
+ << "if (i != " << map << "_.end ())"
+ << "{"
+ << "start += (*(i->second)) (*this, argv + start, argc - start);"
+ << "}"
+ << "else if (opt && s[0] == '-' && s[1] != '\\0')"
+ << "{"
+
+ // Unknown option.
+ //
+ << "switch (opt_mode)"
+ << "{"
+ << "case ::cli::unknown_mode::skip:" << endl
+ << "{"
+ << "start++;"
+ << "continue;"
+ << "}"
+ << "case ::cli::unknown_mode::stop:" << endl
+ << "{"
+ << "break;"
+ << "}"
+ << "case ::cli::unknown_mode::fail:" << endl
+ << "{"
+ << "throw ::cli::unknown_option (s);"
+ << "}"
+ << "}" // switch
+ << "break;" // The stop case.
+ << "}"
+ << "else"
+ << "{"
+
+ // Unknown argument.
+ //
+ << "switch (arg_mode)"
+ << "{"
+ << "case ::cli::unknown_mode::skip:" << endl
+ << "{"
+ << "start++;"
+ << "continue;"
+ << "}"
+ << "case ::cli::unknown_mode::stop:" << endl
+ << "{"
+ << "break;"
+ << "}"
+ << "case ::cli::unknown_mode::fail:" << endl
+ << "{"
+ << "throw ::cli::unknown_argument (s);"
+ << "}"
+ << "}" // switch
+ << "break;" // The stop case.
+ << "}"
+
+ << "}" // for
+ << "return start;"
+ << "}";
+ }
+
+ private:
+ option_map option_map_;
+ traversal::names names_option_map_;
+ };
}
void
generate_source (context& ctx)
{
+ ctx.os << "#include <map>" << endl
+ << "#include <cstring>" << endl
+ << endl;
+
traversal::cli_unit unit;
traversal::names unit_names;
namespace_ ns (ctx);
+ class_ cl (ctx);
+
+ unit >> unit_names >> ns;
+ unit_names >> cl;
+
traversal::names ns_names;
- unit >> unit_names >> ns >> ns_names >> ns;
+ ns >> ns_names >> ns;
+ ns_names >> cl;
unit.dispatch (ctx.unit);
}