summaryrefslogtreecommitdiff
path: root/cli/source.cxx
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/source.cxx
parentb5e7ac58b0e44a7903808d622f5af97c07171281 (diff)
Generate parsing constructors and parsing code
Also generate some runtime support code such exceptions, value parsers, etc.
Diffstat (limited to 'cli/source.cxx')
-rw-r--r--cli/source.cxx272
1 files changed, 271 insertions, 1 deletions
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);
}