From 4b1e037fb0f763cd3e3401d71b66269440d75dbf Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Sun, 27 Sep 2009 18:20:49 +0200 Subject: Generate parsing constructors and parsing code Also generate some runtime support code such exceptions, value parsers, etc. --- cli/source.cxx | 272 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 271 insertions(+), 1 deletion(-) (limited to 'cli/source.cxx') 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" << 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 " << endl + << "#include " << 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); } -- cgit v1.1