diff options
Diffstat (limited to 'cli/cli/runtime-source.cxx')
-rw-r--r-- | cli/cli/runtime-source.cxx | 382 |
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 |