summaryrefslogtreecommitdiff
path: root/cli/cli/runtime-source.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'cli/cli/runtime-source.cxx')
-rw-r--r--cli/cli/runtime-source.cxx382
1 files changed, 312 insertions, 70 deletions
diff --git a/cli/cli/runtime-source.cxx b/cli/cli/runtime-source.cxx
index 3864163..11cd746 100644
--- a/cli/cli/runtime-source.cxx
+++ b/cli/cli/runtime-source.cxx
@@ -15,12 +15,13 @@ generate_runtime_source (context& ctx, bool complete)
<< "#include <set>" << endl
<< "#include <string>" << endl
<< "#include <vector>" << endl
+ << "#include <utility>" << endl // pair
<< "#include <ostream>" << endl
- << "#include <sstream>" << endl;
+ << "#include <sstream>" << endl
+ << "#include <cstring>" << endl;
if (complete && ctx.options.generate_file_scanner ())
- os << "#include <cstring>" << endl
- << "#include <fstream>" << endl;
+ os << "#include <fstream>" << endl;
os << endl;
@@ -30,12 +31,16 @@ generate_runtime_source (context& ctx, bool complete)
{
string const& os_type (ctx.options.ostream_type ());
+ const char* nothrow (ctx.options.std () < cxx_version::cxx11
+ ? "throw ()"
+ : "noexcept");
+
// unknown_option
//
os << "// unknown_option" << endl
<< "//" << endl
<< "unknown_option::" << endl
- << "~unknown_option () throw ()"
+ << "~unknown_option () " << nothrow
<< "{"
<< "}"
@@ -46,7 +51,7 @@ generate_runtime_source (context& ctx, bool complete)
<< "}"
<< "const char* unknown_option::" << endl
- << "what () const throw ()"
+ << "what () const " << nothrow
<< "{"
<< "return \"unknown option\";"
<< "}";
@@ -56,7 +61,7 @@ generate_runtime_source (context& ctx, bool complete)
os << "// unknown_argument" << endl
<< "//" << endl
<< "unknown_argument::" << endl
- << "~unknown_argument () throw ()"
+ << "~unknown_argument () " << nothrow
<< "{"
<< "}"
@@ -67,7 +72,7 @@ generate_runtime_source (context& ctx, bool complete)
<< "}"
<< "const char* unknown_argument::" << endl
- << "what () const throw ()"
+ << "what () const " << nothrow
<< "{"
<< "return \"unknown argument\";"
<< "}";
@@ -77,7 +82,7 @@ generate_runtime_source (context& ctx, bool complete)
os << "// missing_value" << endl
<< "//" << endl
<< "missing_value::" << endl
- << "~missing_value () throw ()"
+ << "~missing_value () " << nothrow
<< "{"
<< "}"
@@ -88,7 +93,7 @@ generate_runtime_source (context& ctx, bool complete)
<< "}"
<< "const char* missing_value::" << endl
- << "what () const throw ()"
+ << "what () const " << nothrow
<< "{"
<< "return \"missing option value\";"
<< "}";
@@ -98,7 +103,7 @@ generate_runtime_source (context& ctx, bool complete)
os << "// invalid_value" << endl
<< "//" << endl
<< "invalid_value::" << endl
- << "~invalid_value () throw ()"
+ << "~invalid_value () " << nothrow
<< "{"
<< "}"
@@ -114,7 +119,7 @@ generate_runtime_source (context& ctx, bool complete)
<< "}"
<< "const char* invalid_value::" << endl
- << "what () const throw ()"
+ << "what () const " << nothrow
<< "{"
<< "return \"invalid option value\";"
<< "}";
@@ -130,7 +135,7 @@ generate_runtime_source (context& ctx, bool complete)
<< "}"
<< "const char* eos_reached::" << endl
- << "what () const throw ()"
+ << "what () const " << nothrow
<< "{"
<< "return \"end of argument stream reached\";"
<< "}";
@@ -142,7 +147,7 @@ generate_runtime_source (context& ctx, bool complete)
os << "// file_io_failure" << endl
<< "//" << endl
<< "file_io_failure::" << endl
- << "~file_io_failure () throw ()"
+ << "~file_io_failure () " << nothrow
<< "{"
<< "}"
@@ -154,7 +159,7 @@ generate_runtime_source (context& ctx, bool complete)
<< "}"
<< "const char* file_io_failure::" << endl
- << "what () const throw ()"
+ << "what () const " << nothrow
<< "{"
<< "return \"unable to open file or read failure\";"
<< "}";
@@ -164,7 +169,7 @@ generate_runtime_source (context& ctx, bool complete)
os << "// unmatched_quote" << endl
<< "//" << endl
<< "unmatched_quote::" << endl
- << "~unmatched_quote () throw ()"
+ << "~unmatched_quote () " << nothrow
<< "{"
<< "}"
@@ -176,7 +181,7 @@ generate_runtime_source (context& ctx, bool complete)
<< "}"
<< "const char* unmatched_quote::" << endl
- << "what () const throw ()"
+ << "what () const " << nothrow
<< "{"
<< "return \"unmatched quote\";"
<< "}";
@@ -190,7 +195,7 @@ generate_runtime_source (context& ctx, bool complete)
<< "//" << endl
<< "unexpected_group::" << endl
- << "~unexpected_group () throw ()"
+ << "~unexpected_group () " << nothrow
<< "{"
<< "}"
@@ -202,7 +207,7 @@ generate_runtime_source (context& ctx, bool complete)
<< "}"
<< "const char* unexpected_group::" << endl
- << "what () const throw ()"
+ << "what () const " << nothrow
<< "{"
<< "return \"unexpected grouped argument\";"
<< "}";
@@ -213,7 +218,7 @@ generate_runtime_source (context& ctx, bool complete)
<< "//" << endl
<< "group_separator::" << endl
- << "~group_separator () throw ()"
+ << "~group_separator () " << nothrow
<< "{"
<< "}"
@@ -237,7 +242,7 @@ generate_runtime_source (context& ctx, bool complete)
<< "}"
<< "const char* group_separator::" << endl
- << "what () const throw ()"
+ << "what () const " << nothrow
<< "{"
<< "bool ex (!expected_.empty ());"
<< "bool en (!encountered_.empty ());"
@@ -259,6 +264,10 @@ generate_runtime_source (context& ctx, bool complete)
// argv_scanner
//
+ // Note that due to the erase logic we cannot just add i_ to
+ // start_position and so have to increment it instead. See also
+ // argv_file_scanner that continues with this logic.
+ //
os << "// argv_scanner" << endl
<< "//" << endl
@@ -295,6 +304,7 @@ generate_runtime_source (context& ctx, bool complete)
<< "else" << endl
<< "++i_;"
<< endl
+ << "++start_position_;"
<< "return r;"
<< "}"
<< "else" << endl
@@ -304,10 +314,19 @@ generate_runtime_source (context& ctx, bool complete)
<< "void argv_scanner::" << endl
<< "skip ()"
<< "{"
- << "if (i_ < argc_)" << endl
+ << "if (i_ < argc_)"
+ << "{"
<< "++i_;"
+ << "++start_position_;"
+ << "}"
<< "else" << endl
<< "throw eos_reached ();"
+ << "}"
+
+ << "std::size_t argv_scanner::" << endl
+ << "position ()"
+ << "{"
+ << "return start_position_;"
<< "}";
// vector_scanner
@@ -348,11 +367,19 @@ generate_runtime_source (context& ctx, bool complete)
<< "++i_;"
<< "else" << endl
<< "throw eos_reached ();"
+ << "}"
+
+ << "std::size_t vector_scanner::" << endl
+ << "position ()"
+ << "{"
+ << "return start_position_ + i_;"
<< "}";
}
// argv_file_scanner
//
+ // Note that we continue incrementing start_position like argv_scanner.
+ //
if (ctx.options.generate_file_scanner ())
{
bool sep (!ctx.opt_sep.empty ());
@@ -486,6 +513,7 @@ generate_runtime_source (context& ctx, bool complete)
<< "{"
<< "hold_[i_ == 0 ? ++i_ : --i_].swap (args_.front ().value);"
<< "args_.pop_front ();"
+ << "++start_position_;"
<< "return hold_[i_].c_str ();"
<< "}"
<< "}"
@@ -498,8 +526,11 @@ generate_runtime_source (context& ctx, bool complete)
<< endl
<< "if (args_.empty ())" << endl
<< "return base::skip ();"
- << "else" << endl
+ << "else"
+ << "{"
<< "args_.pop_front ();"
+ << "++start_position_;"
+ << "}"
<< "}"
<< "const argv_file_scanner::option_info* argv_file_scanner::" << endl
@@ -512,6 +543,12 @@ generate_runtime_source (context& ctx, bool complete)
<< "return 0;"
<< "}"
+ << "std::size_t argv_file_scanner::" << endl
+ << "position ()"
+ << "{"
+ << "return start_position_;"
+ << "}"
+
<< "void argv_file_scanner::" << endl
<< "load (const std::string& file)"
<< "{"
@@ -699,43 +736,50 @@ generate_runtime_source (context& ctx, bool complete)
<< "if (state_ == scanned)"
<< "{"
<< "if (group_scan_.end () != group_.size ())" << endl
- << "throw unexpected_group (arg_[i_], group_scan_.next ());"
+ << "throw unexpected_group (arg_[i_][j_], group_scan_.next ());"
<< "}"
- << "return scan_.more ();"
+ << "return j_ != 0 || scan_.more ();"
<< "}"
<< "const char* group_scanner::" << endl
<< "peek ()"
<< "{"
- << "if (state_ != peeked)" << endl
- << "scan_group (peeked);"
- << "scan_.peek ();"
+ << "if (state_ != peeked)"
+ << "{"
+ << "scan_group ();"
+ << "state_ = peeked;"
+ << "}"
<< "// Return unescaped." << endl
- << "return arg_[i_].c_str ();"
+ << "return arg_[i_][j_ - 1].c_str ();"
<< "}"
<< "const char* group_scanner::" << endl
<< "next ()"
<< "{"
<< "if (state_ != peeked)" << endl
- << "scan_group (peeked);"
- << "scan_.next ();"
- << "scan_group (scanned);"
+ << "scan_group ();"
+ << "state_ = scanned;"
<< "// Return unescaped." << endl
- << "return arg_[i_].c_str ();"
+ << "return arg_[i_][--j_].c_str ();"
<< "}"
<< "void group_scanner::" << endl
<< "skip ()"
<< "{"
<< "if (state_ != peeked)" << endl
- << "scan_group (peeked);"
- << "scan_.skip ();"
- << "scan_group (skipped);"
+ << "scan_group ();"
+ << "state_ = skipped;"
+ << "--j_;"
+ << "}"
+
+ << "std::size_t group_scanner::" << endl
+ << "position ()"
+ << "{"
+ << "return j_ == 0 ? scan_.position () : pos_ + (arg_[i_].size () - j_);"
<< "}"
<< "void group_scanner::" << endl
- << "scan_group (state st)"
+ << "scan_group ()"
<< "{"
<< "// If the previous argument has been scanned, then make" << endl
<< "// sure the group has been scanned (handled) as well." << endl
@@ -743,53 +787,66 @@ generate_runtime_source (context& ctx, bool complete)
<< "if (state_ == scanned)"
<< "{"
<< "if (group_scan_.end () != group_.size ())" << endl
- << "throw unexpected_group (arg_[i_], group_scan_.next ());"
+ << "throw unexpected_group (arg_[i_][j_], group_scan_.next ());"
<< "}"
- << "if (state_ != peeked)"
+ << "// If we still have arguments in the pack, rewind the group." << endl
+ << "//" << endl
+ << "if (j_ != 0)"
<< "{"
- << "arg_[i_ == 0 ? ++i_ : --i_].clear ();"
- << "group_.clear ();"
<< "group_scan_.reset ();"
+ << "return;"
<< "}"
- << "// We recognize all group sequences both before and " << endl
- << "// after the argument and diagnose any misuse. We may" << endl
- << "// also have multiple groups:" << endl
- << "//" << endl
- << "// { -x }+ { -y }+ arg" << endl
- << "//" << endl
+ // Position must remain the same from before the first call to peek()
+ // (comes directly from the scanner) and until next().
+ //
+ // Note that while it may seem like a good idea to pass
+ // scan_.position() to reset() below, the trailing group positions
+ // will overlap with the argument's. So it seems best to start
+ // positions of each argument in a group from 0.
+ //
+ // Note also that we try hard not to throw away allocated memory in
+ // arg_[][0].
+ //
+ << "i_ += (i_ == 0 ? 1 : -1);"
+ << "group_.clear ();"
+ << "group_scan_.reset ();"
+ << "pos_ = scan_.position ();"
<< endl
- << "// Using group_ won't cover empty groups." << endl
+
+ << "// Note: using group_ won't cover empty groups and using" << endl
+ << "// j_ won't cover single-argument packs." << endl
<< "//" << endl
- << "bool g (false);"
+ << "bool group (false), pack (false);"
<< endl
- << "while (scan_.more ())"
+ << "do"
<< "{"
- << "const char* a (scan_.peek ());"
+ << "const char* a (scan_.next ());"
<< "size_t i (*a == '\\\\' ? 1 : 0);"
<< "separator s (sense (a + i));"
<< endl
<< "if (s == none || i != 0)"
<< "{"
- << "if (state_ != peeked)" << endl
- << "arg_[i_] = a + (s != none ? i : 0);"
+ << "if (arg_[i_].size () != 1)" << endl
+ << "arg_[i_].resize (1);"
+ << endl
+ << "arg_[i_][0] = a + (s != none ? i : 0);"
+ << "j_ = 1;"
<< "break;"
<< "}"
- << "// Start of a leading group for the next argument." << endl
+ << "// Start of a leading group for the next argument or" << endl
+ << "// argument pack. We will only know which once we see" << endl
+ << "// the closing separator." << endl
<< "//" << endl
- << "if (s == open && state_ == peeked)" << endl
- << "break;"
- << endl
- << "if (s != (state_ == peeked ? open_plus : open))" << endl
+ << "if (s != open)" << endl
<< "throw group_separator (a, \"\");"
<< endl
- << "g = true;"
+ << "size_t n (group_.size ());"
<< endl
<< "// Scan the group until the closing separator." << endl
<< "//" << endl
- << "scan_.next ();"
<< "s = none;"
<< "while (s == none && scan_.more ())"
<< "{"
@@ -804,20 +861,88 @@ generate_runtime_source (context& ctx, bool complete)
<< "}"
<< "}"
- << "if (s != (state_ == peeked ? close : close_plus))"
+ << "if (s == close)"
<< "{"
- << "throw group_separator ((s != none ? a : \"\")," << endl
- << "(state_ == peeked ? \"}\" : \"}+\"));"
+ << "size_t m (group_.size ());"
+ << endl
+ << "j_ = m - n;"
+ << "if (j_ == 0)" << endl
+ << "throw group_separator (\"{\", \"\");"
+ << endl
+ << "if (arg_[i_].size () != j_)" << endl
+ << "arg_[i_].resize (j_);"
+ << endl
+ << "// Move from group_ to arg_. Add in reverse for ease " << endl
+ << "// of iteration." << endl
+ << "//" << endl
+ << "for (size_t j (0); j != j_; ++j)" << endl
+ << "arg_[i_][j] = group_[m - j - 1];"
+ << "group_.resize (n);"
+ << endl
+ << "pack = true;"
+ << "break;"
<< "}"
+ << "else if (s == close_plus)" << endl
+ << "group = true;"
+ << "else" << endl
+ << "throw group_separator ((s != none ? a : \"\"), \"}+\");"
<< "}"
+ << "while (scan_.more ());"
+ << endl
<< "// Handle the case where we have seen the leading group" << endl
<< "// but there are no more arguments." << endl
<< "//" << endl
- << "if (g && state_ != peeked && !scan_.more ())" << endl
+ << "if (group && j_ == 0)" << endl
<< "throw group_separator (\"{\", \"\");"
<< endl
- << "state_ = st;"
+ << "// Handle trailing groups, if any." << endl
+ << "//" << endl
+
+ << "while (scan_.more ())"
+ << "{"
+ << "const char* a (scan_.peek ());"
+ << "size_t i (*a == '\\\\' ? 1 : 0);"
+ << "separator s (sense (a + i));"
+ << endl
+
+ << "// Next argument, argument pack, or leading group." << endl
+ << "//" << endl
+ << "if (s == none || s == open || i != 0)" << endl
+ << "break;"
+ << endl
+ << "if (s != open_plus)" << endl
+ << "throw group_separator (a, \"\");"
+ << endl
+ << "group = true;"
+ << endl
+ << "// Scan the group until the closing separator." << endl
+ << "//" << endl
+ << "scan_.next ();"
+ << "s = none;"
+ << "while (s == none && scan_.more ())"
+ << "{"
+ << "a = scan_.next ();"
+ << "i = (*a == '\\\\' ? 1 : 0);"
+ << "s = sense (a + i);"
+ << endl
+ << "if (s == none || i != 0)"
+ << "{"
+ << "group_.push_back (a + (s != none ? i : 0));"
+ << "s = none;"
+ << "}"
+ << "}"
+
+ << "if (s != close)" << endl
+ << "throw group_separator ((s != none ? a : \"\"), \"}\");"
+ << "}"
+
+ << "// Handle the case where we have seen the argument pack" << endl
+ << "// without leading or trailing group." << endl
+ << "//" << endl
+ << "if (pack && !group)" << endl
+ << "throw group_separator (\"{\", \"\");"
+
<< "}";
}
@@ -890,11 +1015,33 @@ generate_runtime_source (context& ctx, bool complete)
<< "{";
os << "static void" << endl
- << "parse (bool& x, scanner& s)"
+ << "parse (bool& x, " << (sp ? "bool& xs, " : "") << "scanner& s)"
<< "{"
- << "s.next ();"
- << "x = true;"
- << "}";
+ << "const char* o (s.next ());"
+ << endl
+ << "if (s.more ())"
+ << "{"
+ << "const char* v (s.next ());"
+ << endl
+ << "if (std::strcmp (v, \"1\") == 0 ||" << endl
+ << "std::strcmp (v, \"true\") == 0 ||" << endl
+ << "std::strcmp (v, \"TRUE\") == 0 ||" << endl
+ << "std::strcmp (v, \"True\") == 0)" << endl
+ << "x = true;"
+ << "else if (std::strcmp (v, \"0\") == 0 ||" << endl
+ << "std::strcmp (v, \"false\") == 0 ||" << endl
+ << "std::strcmp (v, \"FALSE\") == 0 ||" << endl
+ << "std::strcmp (v, \"False\") == 0)" << endl
+ << "x = false;"
+ << "else" << endl
+ << "throw invalid_value (o, v);"
+ << "}"
+ << "else" << endl
+ << "throw missing_value (o);";
+ if (sp)
+ os << endl
+ << "xs = true;";
+ os << "}";
if (gen_merge)
os << "static void" << endl
@@ -934,6 +1081,28 @@ generate_runtime_source (context& ctx, bool complete)
os << "};";
+ // parser<std::pair<X, std::size_t>>
+ //
+ os << "template <typename X>" << endl
+ << "struct parser<std::pair<X, std::size_t> >"
+ << "{";
+
+ os << "static void" << endl
+ << "parse (std::pair<X, std::size_t>& x, " << (sp ? "bool& xs, " : "") << "scanner& s)"
+ << "{"
+ << "x.second = s.position ();"
+ << "parser<X>::parse (x.first, " << (sp ? "xs, " : "") << "s);"
+ << "}";
+
+ if (gen_merge)
+ os << "static void" << endl
+ << "merge (std::pair<X, std::size_t>& b, const std::pair<X, std::size_t>& a)"
+ << "{"
+ << "b = a;"
+ << "}";
+
+ os << "};";
+
// parser<std::vector<X>>
//
os << "template <typename X>" << endl
@@ -1001,6 +1170,7 @@ generate_runtime_source (context& ctx, bool complete)
<< endl
<< "if (s.more ())"
<< "{"
+ << "std::size_t pos (s.position ());"
<< "std::string ov (s.next ());"
<< "std::string::size_type p = ov.find ('=');"
<< endl
@@ -1020,13 +1190,13 @@ generate_runtime_source (context& ctx, bool complete)
os << "if (!kstr.empty ())"
<< "{"
<< "av[1] = const_cast<char*> (kstr.c_str ());"
- << "argv_scanner s (0, ac, av);"
+ << "argv_scanner s (0, ac, av, false, pos);"
<< "parser<K>::parse (k, " << (sp ? "dummy, " : "") << "s);"
<< "}"
<< "if (!vstr.empty ())"
<< "{"
<< "av[1] = const_cast<char*> (vstr.c_str ());"
- << "argv_scanner s (0, ac, av);"
+ << "argv_scanner s (0, ac, av, false, pos);"
<< "parser<V>::parse (v, " << (sp ? "dummy, " : "") << "s);"
<< "}"
<< "m[k] = v;"
@@ -1050,6 +1220,70 @@ generate_runtime_source (context& ctx, bool complete)
os << "};";
+ // parser<std::multimap<K,V,C>>
+ //
+ os << "template <typename K, typename V, typename C>" << endl
+ << "struct parser<std::multimap<K, V, C> >"
+ << "{";
+
+ os << "static void" << endl
+ << "parse (std::multimap<K, V, C>& m, " << (sp ? "bool& xs, " : "") << "scanner& s)"
+ << "{"
+ << "const char* o (s.next ());"
+ << endl
+ << "if (s.more ())"
+ << "{"
+ << "std::size_t pos (s.position ());"
+ << "std::string ov (s.next ());"
+ << "std::string::size_type p = ov.find ('=');"
+ << endl
+ << "K k = K ();"
+ << "V v = V ();"
+ << "std::string kstr (ov, 0, p);"
+ << "std::string vstr (ov, (p != std::string::npos ? p + 1 : ov.size ()));"
+ << endl
+ << "int ac (2);"
+ << "char* av[] ="
+ << "{"
+ << "const_cast<char*> (o)," << endl
+ << "0"
+ << "};";
+ if (sp)
+ os << "bool dummy;";
+ os << "if (!kstr.empty ())"
+ << "{"
+ << "av[1] = const_cast<char*> (kstr.c_str ());"
+ << "argv_scanner s (0, ac, av, false, pos);"
+ << "parser<K>::parse (k, " << (sp ? "dummy, " : "") << "s);"
+ << "}"
+ << "if (!vstr.empty ())"
+ << "{"
+ << "av[1] = const_cast<char*> (vstr.c_str ());"
+ << "argv_scanner s (0, ac, av, false, pos);"
+ << "parser<V>::parse (v, " << (sp ? "dummy, " : "") << "s);"
+ << "}"
+ << "m.insert (typename std::multimap<K, V, C>::value_type (k, v));"
+ << "}"
+ << "else" << endl
+ << "throw missing_value (o);";
+ if (sp)
+ os << endl
+ << "xs = true;";
+ os << "}";
+
+ if (gen_merge)
+ os << "static void" << endl
+ << "merge (std::multimap<K, V, C>& b, const std::multimap<K, V, C>& a)"
+ << "{"
+ << "for (typename std::multimap<K, V, C>::const_iterator i (a.begin ()); " << endl
+ << "i != a.end (); " << endl
+ << "++i)" << endl
+ << "b.insert (typename std::multimap<K, V, C>::value_type (i->first," << endl
+ << "i->second));" << endl
+ << "}";
+
+ os << "};";
+
// Parser thunk.
//
os << "template <typename X, typename T, T X::*M>" << endl
@@ -1059,6 +1293,14 @@ generate_runtime_source (context& ctx, bool complete)
<< "parser<T>::parse (x.*M, s);"
<< "}";
+ os << "template <typename X, bool X::*M>" << endl
+ << "void" << endl
+ << "thunk (X& x, scanner& s)"
+ << "{"
+ << "s.next ();"
+ << "x.*M = true;"
+ << "}";
+
if (ctx.gen_specifier)
os << "template <typename X, typename T, T X::*M, bool X::*S>" << endl
<< "void" << endl