feat add lyra
All checks were successful
rpcrypto-build / build (Debug, himix200.toolchain.cmake) (push) Successful in 1m9s
rpcrypto-build / build (Debug, hisiv510.toolchain.cmake) (push) Successful in 1m19s
rpcrypto-build / build (Release, himix200.toolchain.cmake) (push) Successful in 1m27s
rpcrypto-build / build (Release, hisiv510.toolchain.cmake) (push) Successful in 1m31s
linux-mips64-gcc / linux-gcc-mips64el (push) Successful in 1m34s
linux-hisiv500-gcc / linux-gcc-hisiv500 (push) Successful in 1m40s
linux-x64-gcc / linux-gcc (push) Successful in 1m40s
All checks were successful
rpcrypto-build / build (Debug, himix200.toolchain.cmake) (push) Successful in 1m9s
rpcrypto-build / build (Debug, hisiv510.toolchain.cmake) (push) Successful in 1m19s
rpcrypto-build / build (Release, himix200.toolchain.cmake) (push) Successful in 1m27s
rpcrypto-build / build (Release, hisiv510.toolchain.cmake) (push) Successful in 1m31s
linux-mips64-gcc / linux-gcc-mips64el (push) Successful in 1m34s
linux-hisiv500-gcc / linux-gcc-hisiv500 (push) Successful in 1m40s
linux-x64-gcc / linux-gcc (push) Successful in 1m40s
This commit is contained in:
parent
6483c28e26
commit
55b28fb58b
113
3party/lyra/lyra/arg.hpp
Normal file
113
3party/lyra/lyra/arg.hpp
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
// Copyright 2018-2022 René Ferdinand Rivera Morell
|
||||||
|
// Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
#ifndef LYRA_ARG_HPP
|
||||||
|
#define LYRA_ARG_HPP
|
||||||
|
|
||||||
|
#include "lyra/detail/print.hpp"
|
||||||
|
#include "lyra/parser.hpp"
|
||||||
|
|
||||||
|
namespace lyra {
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_arg]
|
||||||
|
= `lyra::arg`
|
||||||
|
|
||||||
|
A parser for regular arguments, i.e. not `--` or `-` prefixed. This is simply
|
||||||
|
a way to get values of arguments directly specified in the cli.
|
||||||
|
|
||||||
|
Is-a <<lyra_bound_parser>>.
|
||||||
|
|
||||||
|
*/ // end::reference[]
|
||||||
|
class arg : public bound_parser<arg>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using bound_parser::bound_parser;
|
||||||
|
|
||||||
|
virtual std::string get_usage_text(const option_style &) const override
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
if (!m_hint.empty())
|
||||||
|
{
|
||||||
|
auto c = cardinality();
|
||||||
|
if (c.is_required())
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < c.minimum; ++i)
|
||||||
|
oss << (i > 0 ? " " : "") << "<" << m_hint << ">";
|
||||||
|
if (c.is_unbounded())
|
||||||
|
oss << (c.is_required() ? " " : "") << "[<" << m_hint
|
||||||
|
<< ">...]";
|
||||||
|
}
|
||||||
|
else if (c.is_unbounded())
|
||||||
|
{
|
||||||
|
oss << "[<" << m_hint << ">...]";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
oss << "<" << m_hint << ">";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual help_text get_help_text(const option_style & style) const override
|
||||||
|
{
|
||||||
|
return { { get_usage_text(style), m_description } };
|
||||||
|
}
|
||||||
|
|
||||||
|
using parser::parse;
|
||||||
|
|
||||||
|
parse_result parse(detail::token_iterator const & tokens,
|
||||||
|
const option_style & style) const override
|
||||||
|
{
|
||||||
|
(void)style;
|
||||||
|
LYRA_PRINT_SCOPE("arg::parse");
|
||||||
|
auto validationResult = validate();
|
||||||
|
if (!validationResult) return parse_result(validationResult);
|
||||||
|
|
||||||
|
if (!tokens)
|
||||||
|
{
|
||||||
|
// Nothing to match against.
|
||||||
|
return parse_result::ok(
|
||||||
|
detail::parse_state(parser_result_type::no_match, tokens));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto const & token = tokens.argument();
|
||||||
|
|
||||||
|
auto valueRef = static_cast<detail::BoundValueRefBase *>(m_ref.get());
|
||||||
|
|
||||||
|
if (value_choices)
|
||||||
|
{
|
||||||
|
auto choice_result = value_choices->contains_value(token.name);
|
||||||
|
if (!choice_result)
|
||||||
|
{
|
||||||
|
LYRA_PRINT_DEBUG(
|
||||||
|
"(!)", get_usage_text(style), "!=", token.name);
|
||||||
|
return parse_result(choice_result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto set_result = valueRef->setValue(token.name);
|
||||||
|
if (!set_result)
|
||||||
|
{
|
||||||
|
LYRA_PRINT_DEBUG("(!)", get_usage_text(style), "!=", token.name);
|
||||||
|
return parse_result(set_result);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LYRA_PRINT_DEBUG("(=)", get_usage_text(style), "==", token.name);
|
||||||
|
auto remainingTokens = tokens;
|
||||||
|
remainingTokens.pop(token);
|
||||||
|
return parse_result::ok(detail::parse_state(
|
||||||
|
parser_result_type::matched, remainingTokens));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace lyra
|
||||||
|
|
||||||
|
#endif
|
68
3party/lyra/lyra/args.hpp
Normal file
68
3party/lyra/lyra/args.hpp
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
// Copyright 2018-2022 René Ferdinand Rivera Morell
|
||||||
|
// Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
#ifndef LYRA_ARGS_HPP
|
||||||
|
#define LYRA_ARGS_HPP
|
||||||
|
|
||||||
|
#include <initializer_list>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace lyra {
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_args]
|
||||||
|
= `lyra::args`
|
||||||
|
|
||||||
|
Transport for raw args (copied from main args, supplied via init list, or from
|
||||||
|
a pair of iterators).
|
||||||
|
|
||||||
|
*/ // end::reference[]
|
||||||
|
class args
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Construct from usual main() function arguments.
|
||||||
|
args(int argc, char const * const * argv)
|
||||||
|
: m_exeName(argv[0])
|
||||||
|
, m_args(argv + 1, argv + argc)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// Construct directly from an initializer '{}'.
|
||||||
|
args(std::initializer_list<std::string> args_list)
|
||||||
|
: m_exeName(*args_list.begin())
|
||||||
|
, m_args(args_list.begin() + 1, args_list.end())
|
||||||
|
{}
|
||||||
|
|
||||||
|
// Construct from iterators.
|
||||||
|
template <typename It>
|
||||||
|
args(const It & start, const It & end)
|
||||||
|
: m_exeName(*start)
|
||||||
|
, m_args(start + 1, end)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// The executable name taken from argument zero.
|
||||||
|
std::string exe_name() const { return m_exeName; }
|
||||||
|
|
||||||
|
// Arguments, excluding the exe name.
|
||||||
|
std::vector<std::string>::const_iterator begin() const
|
||||||
|
{
|
||||||
|
return m_args.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string>::const_iterator end() const
|
||||||
|
{
|
||||||
|
return m_args.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_exeName;
|
||||||
|
std::vector<std::string> m_args;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace lyra
|
||||||
|
|
||||||
|
#endif
|
527
3party/lyra/lyra/arguments.hpp
Normal file
527
3party/lyra/lyra/arguments.hpp
Normal file
@ -0,0 +1,527 @@
|
|||||||
|
// Copyright 2018-2022 René Ferdinand Rivera Morell
|
||||||
|
// Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
#ifndef LYRA_ARGUMENTS_HPP
|
||||||
|
#define LYRA_ARGUMENTS_HPP
|
||||||
|
|
||||||
|
#include "lyra/detail/print.hpp"
|
||||||
|
#include "lyra/exe_name.hpp"
|
||||||
|
#include "lyra/parser.hpp"
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
namespace lyra {
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_arguments]
|
||||||
|
= `lyra::arguments`
|
||||||
|
|
||||||
|
A Combined parser made up of any number of parsers. Creating and using
|
||||||
|
one of these as a basis one can incrementally compose other parsers into this
|
||||||
|
one. For example:
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
auto p = lyra::arguments();
|
||||||
|
std::string what;
|
||||||
|
float when = 0;
|
||||||
|
std::string where;
|
||||||
|
p |= lyra::opt(what, "what")["--make-it-so"]("Make it so.").required();
|
||||||
|
p |= lyra::opt(when. "when")["--time"]("When to do <what>.").optional();
|
||||||
|
p.add_argument(lyra::opt(where, "where").name("--where")
|
||||||
|
.help("There you are.").optional());
|
||||||
|
----
|
||||||
|
|
||||||
|
*/ // end::reference[]
|
||||||
|
class arguments : public parser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// How to evaluate the collection of arguments within the limits of the
|
||||||
|
// cardinality.
|
||||||
|
enum evaluation
|
||||||
|
{
|
||||||
|
// Any of the arguments, in any order, are valid. I.e. an inclusive-or.
|
||||||
|
any = 0,
|
||||||
|
// All arguments, in sequence, matched. I.e. conjunctive-and.
|
||||||
|
sequence = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
arguments() = default;
|
||||||
|
|
||||||
|
arguments(evaluation e)
|
||||||
|
: eval_mode(e)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// Copy construction, needs to copy the the composed parsers.
|
||||||
|
arguments(const arguments & other);
|
||||||
|
|
||||||
|
// Compose a regular parser.
|
||||||
|
arguments & add_argument(parser const & p);
|
||||||
|
arguments & operator|=(parser const & p);
|
||||||
|
|
||||||
|
// Compose the parsers from another `arguments`.
|
||||||
|
arguments & add_argument(arguments const & other);
|
||||||
|
arguments & operator|=(arguments const & other);
|
||||||
|
|
||||||
|
// Concat composition.
|
||||||
|
template <typename T>
|
||||||
|
arguments operator|(T const & other) const
|
||||||
|
{
|
||||||
|
return arguments(*this) |= other;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parsing mode.
|
||||||
|
arguments & sequential();
|
||||||
|
arguments & inclusive();
|
||||||
|
|
||||||
|
// Access.
|
||||||
|
template <typename T>
|
||||||
|
T & get(size_t i);
|
||||||
|
|
||||||
|
// Internal..
|
||||||
|
|
||||||
|
virtual std::string get_usage_text(
|
||||||
|
const option_style & style) const override
|
||||||
|
{
|
||||||
|
std::ostringstream os;
|
||||||
|
for (auto const & p : parsers)
|
||||||
|
{
|
||||||
|
std::string usage_text = p->get_usage_text(style);
|
||||||
|
if (usage_text.size() > 0)
|
||||||
|
{
|
||||||
|
if (os.tellp() != std::ostringstream::pos_type(0)) os << " ";
|
||||||
|
if (p->is_group() && p->is_optional())
|
||||||
|
os << "[ " << usage_text << " ]";
|
||||||
|
else if (p->is_group())
|
||||||
|
os << "{ " << usage_text << " }";
|
||||||
|
else if (p->is_optional())
|
||||||
|
os << "[" << usage_text << "]";
|
||||||
|
else
|
||||||
|
os << usage_text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return os.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::string get_description_text(
|
||||||
|
const option_style & style) const override
|
||||||
|
{
|
||||||
|
std::ostringstream os;
|
||||||
|
for (auto const & p : parsers)
|
||||||
|
{
|
||||||
|
if (p->is_group()) continue;
|
||||||
|
auto child_description = p->get_description_text(style);
|
||||||
|
if (!child_description.empty()) os << child_description << "\n";
|
||||||
|
}
|
||||||
|
return os.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a container of the individual help text for the composed parsers.
|
||||||
|
virtual help_text get_help_text(const option_style & style) const override
|
||||||
|
{
|
||||||
|
help_text text;
|
||||||
|
for (auto const & p : parsers)
|
||||||
|
{
|
||||||
|
if (p->is_group()) text.push_back({ "", "" });
|
||||||
|
auto child_help = p->get_help_text(style);
|
||||||
|
text.insert(text.end(), child_help.begin(), child_help.end());
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual detail::parser_cardinality cardinality() const override
|
||||||
|
{
|
||||||
|
return { 0, 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual result validate() const override
|
||||||
|
{
|
||||||
|
for (auto const & p : parsers)
|
||||||
|
{
|
||||||
|
auto parse_valid = p->validate();
|
||||||
|
if (!parse_valid) return parse_valid;
|
||||||
|
}
|
||||||
|
return result::ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_result parse(detail::token_iterator const & tokens,
|
||||||
|
const option_style & style) const override
|
||||||
|
{
|
||||||
|
switch (eval_mode)
|
||||||
|
{
|
||||||
|
case any: return parse_any(tokens, style);
|
||||||
|
case sequence: return parse_sequence(tokens, style);
|
||||||
|
}
|
||||||
|
return parse_result::error(
|
||||||
|
detail::parse_state(parser_result_type::no_match, tokens),
|
||||||
|
"Unknown evaluation mode; not one of 'any', or 'sequence'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Match in any order, any number of times. Returns an error if nothing
|
||||||
|
// matched.
|
||||||
|
parse_result parse_any(
|
||||||
|
detail::token_iterator const & tokens, const option_style & style) const
|
||||||
|
{
|
||||||
|
LYRA_PRINT_SCOPE("arguments::parse_any");
|
||||||
|
LYRA_PRINT_DEBUG("(?)", get_usage_text(style),
|
||||||
|
"?=", tokens ? tokens.argument().name : "", "..");
|
||||||
|
|
||||||
|
struct ParserInfo
|
||||||
|
{
|
||||||
|
parser const * parser_p = nullptr;
|
||||||
|
size_t count = 0;
|
||||||
|
};
|
||||||
|
std::vector<ParserInfo> parser_info(parsers.size());
|
||||||
|
{
|
||||||
|
size_t i = 0;
|
||||||
|
for (auto const & p : parsers) parser_info[i++].parser_p = p.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto p_result = parse_result::ok(
|
||||||
|
detail::parse_state(parser_result_type::matched, tokens));
|
||||||
|
auto error_result = parse_result::ok(
|
||||||
|
detail::parse_state(parser_result_type::no_match, tokens));
|
||||||
|
while (p_result.value().remainingTokens())
|
||||||
|
{
|
||||||
|
bool token_parsed = false;
|
||||||
|
|
||||||
|
for (auto & parse_info : parser_info)
|
||||||
|
{
|
||||||
|
auto parser_cardinality = parse_info.parser_p->cardinality();
|
||||||
|
if (parser_cardinality.is_unbounded()
|
||||||
|
|| parse_info.count < parser_cardinality.maximum)
|
||||||
|
{
|
||||||
|
auto subparse_result = parse_info.parser_p->parse(
|
||||||
|
p_result.value().remainingTokens(), style);
|
||||||
|
if (!subparse_result)
|
||||||
|
{
|
||||||
|
LYRA_PRINT_DEBUG("(!)", get_usage_text(style), "!=",
|
||||||
|
p_result.value().remainingTokens().argument().name);
|
||||||
|
// Is the subparse error bad enough to trigger an
|
||||||
|
// immediate return? For example for an option syntax
|
||||||
|
// error.
|
||||||
|
if (subparse_result.has_value()
|
||||||
|
&& subparse_result.value().type()
|
||||||
|
== parser_result_type::short_circuit_all)
|
||||||
|
return subparse_result;
|
||||||
|
// For not severe errors, we save the error if it's
|
||||||
|
// the first so that in case no other parsers match
|
||||||
|
// we can report the earliest problem, as that's
|
||||||
|
// the likeliest issue.
|
||||||
|
if (error_result)
|
||||||
|
error_result = parse_result(subparse_result);
|
||||||
|
}
|
||||||
|
else if (subparse_result
|
||||||
|
&& subparse_result.value().type()
|
||||||
|
!= parser_result_type::no_match)
|
||||||
|
{
|
||||||
|
LYRA_PRINT_DEBUG("(=)", get_usage_text(style), "==",
|
||||||
|
p_result.value().remainingTokens().argument().name,
|
||||||
|
"==>", subparse_result.value().type());
|
||||||
|
p_result = parse_result(subparse_result);
|
||||||
|
token_parsed = true;
|
||||||
|
parse_info.count += 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p_result.value().type() == parser_result_type::short_circuit_all)
|
||||||
|
return p_result;
|
||||||
|
// If something signaled and error, and hence we didn't match/parse
|
||||||
|
// anything, we indicate the error.
|
||||||
|
if (!token_parsed && !error_result) return error_result;
|
||||||
|
if (!token_parsed) break;
|
||||||
|
}
|
||||||
|
// Check missing required options. For bounded arguments we check
|
||||||
|
// bound min and max bounds against what we parsed. For the loosest
|
||||||
|
// required arguments we check for only the minimum. As the upper
|
||||||
|
// bound could be infinite.
|
||||||
|
for (auto & parseInfo : parser_info)
|
||||||
|
{
|
||||||
|
auto parser_cardinality = parseInfo.parser_p->cardinality();
|
||||||
|
if ((parser_cardinality.is_bounded()
|
||||||
|
&& (parseInfo.count < parser_cardinality.minimum
|
||||||
|
|| parser_cardinality.maximum < parseInfo.count))
|
||||||
|
|| (parser_cardinality.is_required()
|
||||||
|
&& (parseInfo.count < parser_cardinality.minimum)))
|
||||||
|
{
|
||||||
|
return parse_result::error(p_result.value(),
|
||||||
|
"Expected: " + parseInfo.parser_p->get_usage_text(style));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return p_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_result parse_sequence(
|
||||||
|
detail::token_iterator const & tokens, const option_style & style) const
|
||||||
|
{
|
||||||
|
LYRA_PRINT_SCOPE("arguments::parse_sequence");
|
||||||
|
LYRA_PRINT_DEBUG("(?)", get_usage_text(style),
|
||||||
|
"?=", tokens ? tokens.argument().name : "", "..");
|
||||||
|
|
||||||
|
struct ParserInfo
|
||||||
|
{
|
||||||
|
parser const * parser_p = nullptr;
|
||||||
|
size_t count = 0;
|
||||||
|
};
|
||||||
|
std::vector<ParserInfo> parser_info(parsers.size());
|
||||||
|
{
|
||||||
|
size_t i = 0;
|
||||||
|
for (auto const & p : parsers) parser_info[i++].parser_p = p.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto p_result = parse_result::ok(
|
||||||
|
detail::parse_state(parser_result_type::matched, tokens));
|
||||||
|
|
||||||
|
// Sequential parsing means we walk through the given parsers in order
|
||||||
|
// and exhaust the tokens as we match persers.
|
||||||
|
for (std::size_t parser_i = 0; parser_i < parsers.size(); ++parser_i)
|
||||||
|
{
|
||||||
|
auto & parse_info = parser_info[parser_i];
|
||||||
|
auto parser_cardinality = parse_info.parser_p->cardinality();
|
||||||
|
// This is a greedy sequential parsing algo. As it parsers the
|
||||||
|
// current argument as much as possible.
|
||||||
|
do
|
||||||
|
{
|
||||||
|
auto subresult = parse_info.parser_p->parse(
|
||||||
|
p_result.value().remainingTokens(), style);
|
||||||
|
if (!subresult)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (subresult.value().type()
|
||||||
|
== parser_result_type::short_circuit_all)
|
||||||
|
{
|
||||||
|
return subresult;
|
||||||
|
}
|
||||||
|
if (subresult.value().type() != parser_result_type::no_match)
|
||||||
|
{
|
||||||
|
LYRA_PRINT_DEBUG("(=)", get_usage_text(style), "==",
|
||||||
|
p_result.value().remainingTokens()
|
||||||
|
? p_result.value().remainingTokens().argument().name
|
||||||
|
: "",
|
||||||
|
"==>", subresult.value().type());
|
||||||
|
p_result = subresult;
|
||||||
|
parse_info.count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (p_result.value().have_tokens()
|
||||||
|
&& (parser_cardinality.is_unbounded()
|
||||||
|
|| parse_info.count < parser_cardinality.maximum));
|
||||||
|
// Check missing required options immediately as for sequential the
|
||||||
|
// argument is greedy and will fully match here. For bounded
|
||||||
|
// arguments we check bound min and max bounds against what we
|
||||||
|
// parsed. For the loosest required arguments we check for only the
|
||||||
|
// minimum. As the upper bound could be infinite.
|
||||||
|
if ((parser_cardinality.is_bounded()
|
||||||
|
&& (parse_info.count < parser_cardinality.minimum
|
||||||
|
|| parser_cardinality.maximum < parse_info.count))
|
||||||
|
|| (parser_cardinality.is_required()
|
||||||
|
&& (parse_info.count < parser_cardinality.minimum)))
|
||||||
|
{
|
||||||
|
return parse_result::error(p_result.value(),
|
||||||
|
"Expected: " + parse_info.parser_p->get_usage_text(style));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// The return is just the last state as it contains any remaining tokens
|
||||||
|
// to parse.
|
||||||
|
return p_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::unique_ptr<parser> clone() const override
|
||||||
|
{
|
||||||
|
return make_clone<arguments>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend std::ostream & operator<<(
|
||||||
|
std::ostream & os, arguments const & parser)
|
||||||
|
{
|
||||||
|
const option_style & s
|
||||||
|
= parser.opt_style ? *parser.opt_style : option_style::posix();
|
||||||
|
parser.print_help_text(os, s);
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual const parser * get_named(const std::string & n) const override
|
||||||
|
{
|
||||||
|
for (auto & p : parsers)
|
||||||
|
{
|
||||||
|
const parser * p_result = p->get_named(n);
|
||||||
|
if (p_result) return p_result;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::shared_ptr<option_style> opt_style;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::unique_ptr<parser>> parsers;
|
||||||
|
evaluation eval_mode = any;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_arguments_ctor]
|
||||||
|
== Construction
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_arguments_ctor_default]
|
||||||
|
=== Default
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
arguments() = default;
|
||||||
|
----
|
||||||
|
|
||||||
|
Default constructing a `arguments` is the starting point to adding arguments
|
||||||
|
and options for parsing a arguments line.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_arguments_ctor_copy]
|
||||||
|
=== Copy
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
arguments::arguments(const arguments& other);
|
||||||
|
----
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
inline arguments::arguments(const arguments & other)
|
||||||
|
: parser(other)
|
||||||
|
, opt_style(other.opt_style)
|
||||||
|
, eval_mode(other.eval_mode)
|
||||||
|
{
|
||||||
|
for (auto & other_parser : other.parsers)
|
||||||
|
{
|
||||||
|
parsers.push_back(other_parser->clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_arguments_specification]
|
||||||
|
== Specification
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
|
||||||
|
// ==
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
[#lyra_arguments_add_argument]
|
||||||
|
=== `lyra::arguments::add_argument`
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
arguments& arguments::add_argument(parser const& p);
|
||||||
|
arguments& arguments::operator|=(parser const& p);
|
||||||
|
arguments& arguments::add_argument(arguments const& other);
|
||||||
|
arguments& arguments::operator|=(arguments const& other);
|
||||||
|
----
|
||||||
|
|
||||||
|
Adds the given argument parser to the considered arguments for this
|
||||||
|
`arguments`. Depending on the parser given it will be: directly added as an
|
||||||
|
argument (for `parser`), or add the parsers from another `arguments` to
|
||||||
|
this one.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
inline arguments & arguments::add_argument(parser const & p)
|
||||||
|
{
|
||||||
|
parsers.push_back(p.clone());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
inline arguments & arguments::operator|=(parser const & p)
|
||||||
|
{
|
||||||
|
return this->add_argument(p);
|
||||||
|
}
|
||||||
|
inline arguments & arguments::add_argument(arguments const & other)
|
||||||
|
{
|
||||||
|
if (other.is_group())
|
||||||
|
{
|
||||||
|
parsers.push_back(other.clone());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (auto & p : other.parsers)
|
||||||
|
{
|
||||||
|
parsers.push_back(p->clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
inline arguments & arguments::operator|=(arguments const & other)
|
||||||
|
{
|
||||||
|
return this->add_argument(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
=== `lyra::arguments::sequential`
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
arguments & arguments::sequential();
|
||||||
|
----
|
||||||
|
|
||||||
|
Sets the parsing mode for the arguments to "sequential". When parsing the
|
||||||
|
arguments they will be, greedily, consumed in the order they where added.
|
||||||
|
This is useful for sub-commands and structured command lines.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
inline arguments & arguments::sequential()
|
||||||
|
{
|
||||||
|
eval_mode = sequence;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
=== `lyra::arguments::inclusive`
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
arguments & arguments::inclusive();
|
||||||
|
----
|
||||||
|
|
||||||
|
Sets the parsing mode for the arguments to "inclusively any". This is the
|
||||||
|
default that attempts to match each parsed argument with all the available
|
||||||
|
parsers. This means that there is no ordering enforced.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
inline arguments & arguments::inclusive()
|
||||||
|
{
|
||||||
|
eval_mode = any;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
=== `lyra::arguments::get`
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
template <typename T>
|
||||||
|
T & arguments::get(size_t i);
|
||||||
|
----
|
||||||
|
|
||||||
|
Get a modifyable reference to one of the parsers specified.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
template <typename T>
|
||||||
|
T & arguments::get(size_t i)
|
||||||
|
{
|
||||||
|
return static_cast<T &>(*parsers.at(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace lyra
|
||||||
|
|
||||||
|
#endif
|
376
3party/lyra/lyra/cli.hpp
Normal file
376
3party/lyra/lyra/cli.hpp
Normal file
@ -0,0 +1,376 @@
|
|||||||
|
// Copyright 2018-2022 René Ferdinand Rivera Morell
|
||||||
|
// Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
#ifndef LYRA_CLI_HPP
|
||||||
|
#define LYRA_CLI_HPP
|
||||||
|
|
||||||
|
#include "lyra/arguments.hpp"
|
||||||
|
#include "lyra/detail/deprecated_parser_customization.hpp"
|
||||||
|
#include "lyra/detail/from_string.hpp"
|
||||||
|
#include "lyra/detail/print.hpp"
|
||||||
|
#include "lyra/exe_name.hpp"
|
||||||
|
#include "lyra/group.hpp"
|
||||||
|
#include "lyra/option_style.hpp"
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace lyra {
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_cli]
|
||||||
|
= `lyra::cli`
|
||||||
|
|
||||||
|
A Combined parser made up of any two or more other parsers. Creating and using
|
||||||
|
one of these as a basis one can incrementally compose other parsers into this
|
||||||
|
one. For example:
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
auto cli = lyra::cli();
|
||||||
|
std::string what;
|
||||||
|
float when = 0;
|
||||||
|
std::string where;
|
||||||
|
cli |= lyra::opt(what, "what")["--make-it-so"]("Make it so.").required();
|
||||||
|
cli |= lyra::opt(when. "when")["--time"]("When to do <what>.").optional();
|
||||||
|
cli.add_argument(lyra::opt(where, "where").name("--where")
|
||||||
|
.help("There you are.").optional());
|
||||||
|
----
|
||||||
|
|
||||||
|
*/ // end::reference[]
|
||||||
|
class cli : protected arguments
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cli() = default;
|
||||||
|
|
||||||
|
// Copy construction, needs to copy the exe name and the composed parsers.
|
||||||
|
cli(const cli & other);
|
||||||
|
|
||||||
|
// Compose the `exe_name` parser.
|
||||||
|
cli & add_argument(exe_name const & exe_name);
|
||||||
|
cli & operator|=(exe_name const & exe_name);
|
||||||
|
|
||||||
|
// Compose a regular parser.
|
||||||
|
cli & add_argument(parser const & p);
|
||||||
|
cli & operator|=(parser const & p);
|
||||||
|
|
||||||
|
// Compose a group, by adding it as a single argument.
|
||||||
|
cli & add_argument(group const & p);
|
||||||
|
cli & operator|=(group const & p);
|
||||||
|
|
||||||
|
// Compose the parsers from another `cli`.
|
||||||
|
cli & add_argument(cli const & other);
|
||||||
|
cli & operator|=(cli const & other);
|
||||||
|
|
||||||
|
// Concat composition.
|
||||||
|
template <typename T>
|
||||||
|
cli operator|(T const & other) const;
|
||||||
|
|
||||||
|
// Result reference wrapper to fetch and convert argument.
|
||||||
|
struct value_result
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit value_result(const parser * p)
|
||||||
|
: parser_ref(p)
|
||||||
|
{}
|
||||||
|
|
||||||
|
template <typename T,
|
||||||
|
typename std::enable_if<detail::is_convertible_from_string<
|
||||||
|
typename detail::remove_cvref<T>::type>::value>::
|
||||||
|
type * = nullptr>
|
||||||
|
operator T() const
|
||||||
|
{
|
||||||
|
typename detail::remove_cvref<T>::type converted_value {};
|
||||||
|
if (parser_ref)
|
||||||
|
detail::from_string<std::string,
|
||||||
|
typename detail::remove_cvref<T>::type>(
|
||||||
|
parser_ref->get_value(0), converted_value);
|
||||||
|
return converted_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
operator std::vector<T>() const
|
||||||
|
{
|
||||||
|
std::vector<T> converted_value;
|
||||||
|
if (parser_ref)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < parser_ref->get_value_count(); ++i)
|
||||||
|
{
|
||||||
|
T v;
|
||||||
|
if (detail::from_string(parser_ref->get_value(i), v))
|
||||||
|
converted_value.push_back(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return converted_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
operator std::string() const
|
||||||
|
{
|
||||||
|
if (parser_ref) return parser_ref->get_value(0);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const parser * parser_ref = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
value_result operator[](const std::string & n);
|
||||||
|
|
||||||
|
cli & style(const option_style & style);
|
||||||
|
cli & style(option_style && style);
|
||||||
|
|
||||||
|
// Stream out generates the help output.
|
||||||
|
friend std::ostream & operator<<(std::ostream & os, cli const & parser)
|
||||||
|
{
|
||||||
|
return os << static_cast<const arguments &>(parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse from arguments.
|
||||||
|
parse_result parse(args const & args) const
|
||||||
|
{
|
||||||
|
if (opt_style)
|
||||||
|
return parse(args, *opt_style);
|
||||||
|
else
|
||||||
|
return parse(args, option_style::posix());
|
||||||
|
}
|
||||||
|
parse_result parse(args const & args, const option_style & style) const;
|
||||||
|
|
||||||
|
// Backward compatability parse() that takes `parser_customization` and
|
||||||
|
// converts to `option_style`.
|
||||||
|
[[deprecated]] parse_result parse(
|
||||||
|
args const & args, const parser_customization & customize) const
|
||||||
|
{
|
||||||
|
return this->parse(args,
|
||||||
|
option_style(customize.token_delimiters(),
|
||||||
|
customize.option_prefix(), 2, customize.option_prefix(), 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal..
|
||||||
|
|
||||||
|
using arguments::parse;
|
||||||
|
using arguments::get_named;
|
||||||
|
|
||||||
|
virtual std::unique_ptr<parser> clone() const override
|
||||||
|
{
|
||||||
|
return std::unique_ptr<parser>(new cli(*this));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
mutable exe_name m_exeName;
|
||||||
|
|
||||||
|
virtual std::string get_usage_text(
|
||||||
|
const option_style & style) const override
|
||||||
|
{
|
||||||
|
if (!m_exeName.name().empty())
|
||||||
|
return m_exeName.name() + " " + arguments::get_usage_text(style);
|
||||||
|
else
|
||||||
|
// We use an empty exe name as an indicator to remove USAGE text.
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_cli_ctor]
|
||||||
|
== Construction
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_cli_ctor_default]
|
||||||
|
=== Default
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
cli() = default;
|
||||||
|
----
|
||||||
|
|
||||||
|
Default constructing a `cli` is the starting point to adding arguments
|
||||||
|
and options for parsing a command line.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_cli_ctor_copy]
|
||||||
|
=== Copy
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
cli::cli(const cli& other);
|
||||||
|
----
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
inline cli::cli(const cli & other)
|
||||||
|
: arguments(other)
|
||||||
|
, m_exeName(other.m_exeName)
|
||||||
|
{}
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_cli_specification]
|
||||||
|
== Specification
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
|
||||||
|
// ==
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
[#lyra_cli_add_argument]
|
||||||
|
=== `lyra::cli::add_argument`
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
cli& cli::add_argument(exe_name const& exe_name);
|
||||||
|
cli& cli::operator|=(exe_name const& exe_name);
|
||||||
|
cli& cli::add_argument(parser const& p);
|
||||||
|
cli& cli::operator|=(parser const& p);
|
||||||
|
cli& cli::add_argument(group const& p);
|
||||||
|
cli& cli::operator|=(group const& p);
|
||||||
|
cli& cli::add_argument(cli const& other);
|
||||||
|
cli& cli::operator|=(cli const& other);
|
||||||
|
----
|
||||||
|
|
||||||
|
Adds the given argument parser to the considered arguments for this
|
||||||
|
`cli`. Depending on the parser given it will be: recorded as the exe
|
||||||
|
name (for `exe_name` parser), directly added as an argument (for
|
||||||
|
`parser`), or add the parsers from another `cli` to this one.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
inline cli & cli::add_argument(exe_name const & exe_name)
|
||||||
|
{
|
||||||
|
m_exeName = exe_name;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
inline cli & cli::operator|=(exe_name const & exe_name)
|
||||||
|
{
|
||||||
|
return this->add_argument(exe_name);
|
||||||
|
}
|
||||||
|
inline cli & cli::add_argument(parser const & p)
|
||||||
|
{
|
||||||
|
arguments::add_argument(p);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
inline cli & cli::operator|=(parser const & p)
|
||||||
|
{
|
||||||
|
arguments::add_argument(p);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
inline cli & cli::add_argument(group const & other)
|
||||||
|
{
|
||||||
|
arguments::add_argument(static_cast<parser const &>(other));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
inline cli & cli::operator|=(group const & other)
|
||||||
|
{
|
||||||
|
return this->add_argument(other);
|
||||||
|
}
|
||||||
|
inline cli & cli::add_argument(cli const & other)
|
||||||
|
{
|
||||||
|
arguments::add_argument(static_cast<arguments const &>(other));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
inline cli & cli::operator|=(cli const & other)
|
||||||
|
{
|
||||||
|
return this->add_argument(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline cli cli::operator|(T const & other) const
|
||||||
|
{
|
||||||
|
return cli(*this).add_argument(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename DerivedT, typename T>
|
||||||
|
cli operator|(composable_parser<DerivedT> const & thing, T const & other)
|
||||||
|
{
|
||||||
|
return cli() | static_cast<DerivedT const &>(thing) | other;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
[#lyra_cli_array_ref]
|
||||||
|
=== `lyra::cli::operator[]`
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
cli::value_result cli::operator[](const std::string & n)
|
||||||
|
----
|
||||||
|
|
||||||
|
Finds the given argument by either option name or hint name and returns a
|
||||||
|
convertible reference to the value, either the one provided by the user or the
|
||||||
|
default.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
inline cli::value_result cli::operator[](const std::string & n)
|
||||||
|
{
|
||||||
|
return value_result(this->get_named(n));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
[#lyra_cli_parse]
|
||||||
|
=== `lyra::cli::parse`
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
parse_result cli::parse(
|
||||||
|
args const& args, const option_style& customize) const;
|
||||||
|
----
|
||||||
|
|
||||||
|
Parses given arguments `args` and optional option style.
|
||||||
|
The result indicates success or failure, and if failure what kind of failure
|
||||||
|
it was. The state of variables bound to options is unspecified and any bound
|
||||||
|
callbacks may have been called.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
inline parse_result cli::parse(
|
||||||
|
args const & args, const option_style & style) const
|
||||||
|
{
|
||||||
|
LYRA_PRINT_SCOPE("cli::parse");
|
||||||
|
m_exeName.set(args.exe_name());
|
||||||
|
detail::token_iterator args_tokens(args, style);
|
||||||
|
parse_result p_result = parse(args_tokens, style);
|
||||||
|
if (p_result
|
||||||
|
&& (p_result.value().type() == parser_result_type::no_match
|
||||||
|
|| p_result.value().type() == parser_result_type::matched))
|
||||||
|
{
|
||||||
|
if (p_result.value().have_tokens())
|
||||||
|
{
|
||||||
|
return parse_result::error(p_result.value(),
|
||||||
|
"Unrecognized token: "
|
||||||
|
+ p_result.value().remainingTokens().argument().name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return p_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
[#lyra_cli_style]
|
||||||
|
=== `lyra::cli::style`
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
lyra::cli & lyra::cli::style(const lyra::option_style & style)
|
||||||
|
lyra::cli & lyra::cli::style(lyra::option_style && style)
|
||||||
|
----
|
||||||
|
|
||||||
|
Specifies the <<lyra_option_style>> to accept for this instance.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
inline cli & cli::style(const option_style & style)
|
||||||
|
{
|
||||||
|
opt_style = std::make_shared<option_style>(style);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
inline cli & cli::style(option_style && style)
|
||||||
|
{
|
||||||
|
opt_style = std::make_shared<option_style>(std::move(style));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace lyra
|
||||||
|
|
||||||
|
#endif
|
17
3party/lyra/lyra/cli_parser.hpp
Normal file
17
3party/lyra/lyra/cli_parser.hpp
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2018-2022 René Ferdinand Rivera Morell
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
#ifndef LYRA_CLI_PARSER_HPP
|
||||||
|
#define LYRA_CLI_PARSER_HPP
|
||||||
|
|
||||||
|
#include "lyra/cli.hpp"
|
||||||
|
|
||||||
|
namespace lyra {
|
||||||
|
|
||||||
|
using cli_parser = cli;
|
||||||
|
|
||||||
|
} // namespace lyra
|
||||||
|
|
||||||
|
#endif
|
166
3party/lyra/lyra/command.hpp
Normal file
166
3party/lyra/lyra/command.hpp
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
// Copyright 2020-2022 René Ferdinand Rivera Morell
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
#ifndef LYRA_COMMAND_HPP
|
||||||
|
#define LYRA_COMMAND_HPP
|
||||||
|
|
||||||
|
#include "lyra/group.hpp"
|
||||||
|
#include "lyra/literal.hpp"
|
||||||
|
#include <functional>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace lyra {
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_command]
|
||||||
|
= `lyra::command`
|
||||||
|
|
||||||
|
A parser that encapsulates the pattern of parsing sub-commands. It provides a
|
||||||
|
quick wrapper for the equivalent arrangement of `group` and `literal` parsers.
|
||||||
|
For example:
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
lyra::command c = lyra::command("sub");
|
||||||
|
----
|
||||||
|
|
||||||
|
Is equivalent to:
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
lyra::command c = lyra::group()
|
||||||
|
.sequential()
|
||||||
|
.add_argument(literal("sub"))
|
||||||
|
.add_argument(group());
|
||||||
|
lyra::group & g = c.get<lyra::group>(1);
|
||||||
|
----
|
||||||
|
|
||||||
|
I.e. it's conposed of a `literal` followed by the rest of the command arguments.
|
||||||
|
|
||||||
|
Is-a <<lyra_group>>.
|
||||||
|
|
||||||
|
*/ // end::reference[]
|
||||||
|
class command : public group
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Construction, with and without, callback.
|
||||||
|
explicit command(const std::string & n);
|
||||||
|
command(
|
||||||
|
const std::string & n, const std::function<void(const group &)> & f);
|
||||||
|
|
||||||
|
// Help description.
|
||||||
|
command & help(const std::string & text);
|
||||||
|
command & operator()(std::string const & description);
|
||||||
|
|
||||||
|
// Add arguments.
|
||||||
|
template <typename P>
|
||||||
|
command & add_argument(P const & p);
|
||||||
|
template <typename P>
|
||||||
|
command & operator|=(P const & p);
|
||||||
|
|
||||||
|
// Internal.
|
||||||
|
virtual std::unique_ptr<parser> clone() const override
|
||||||
|
{
|
||||||
|
return make_clone<command>(this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_command_ctor]
|
||||||
|
== Construction
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
command::command(const std::string & n);
|
||||||
|
command::command(
|
||||||
|
const std::string & n, const std::function<void(const group &)>& f);
|
||||||
|
----
|
||||||
|
|
||||||
|
To construct an `command` we need a name (`n`) that matches, and triggers, that
|
||||||
|
command.
|
||||||
|
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
inline command::command(const std::string & n)
|
||||||
|
{
|
||||||
|
this->sequential()
|
||||||
|
.add_argument(literal(n))
|
||||||
|
.add_argument(group().required());
|
||||||
|
}
|
||||||
|
inline command::command(
|
||||||
|
const std::string & n, const std::function<void(const group &)> & f)
|
||||||
|
: group(f)
|
||||||
|
{
|
||||||
|
this->sequential()
|
||||||
|
.add_argument(literal(n))
|
||||||
|
.add_argument(group().required());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_command_specification]
|
||||||
|
== Specification
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_command_help]
|
||||||
|
=== `lyra:command::help`
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
command & command::help(const std::string& text)
|
||||||
|
command & command::operator()(std::string const& description)
|
||||||
|
----
|
||||||
|
|
||||||
|
Specify a help description for the command. This sets the help for the
|
||||||
|
underlying literal of the command.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
inline command & command::help(const std::string & text)
|
||||||
|
{
|
||||||
|
this->get<literal>(0).help(text);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
inline command & command::operator()(std::string const & description)
|
||||||
|
{
|
||||||
|
return this->help(description);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
[#lyra_command_add_argument]
|
||||||
|
=== `lyra::command::add_argument`
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
template <typename P>
|
||||||
|
command & command::add_argument(P const & p);
|
||||||
|
template <typename P>
|
||||||
|
command & command::operator|=(P const & p);
|
||||||
|
----
|
||||||
|
|
||||||
|
Adds the given argument parser to the considered arguments for this `comand`.
|
||||||
|
The argument is added to the sub-group argument instead of this one. Hence it
|
||||||
|
has the effect of adding arguments *after* the command name.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
template <typename P>
|
||||||
|
command & command::add_argument(P const & p)
|
||||||
|
{
|
||||||
|
this->get<group>(1).add_argument(p);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
template <typename P>
|
||||||
|
command & command::operator|=(P const & p)
|
||||||
|
{
|
||||||
|
return this->add_argument(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace lyra
|
||||||
|
|
||||||
|
#endif
|
193
3party/lyra/lyra/detail/bound.hpp
Normal file
193
3party/lyra/lyra/detail/bound.hpp
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
// Copyright 2018-2022 René Ferdinand Rivera Morell
|
||||||
|
// Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
#ifndef LYRA_DETAIL_BOUND_HPP
|
||||||
|
#define LYRA_DETAIL_BOUND_HPP
|
||||||
|
|
||||||
|
#include "lyra/detail/from_string.hpp"
|
||||||
|
#include "lyra/detail/invoke_lambda.hpp"
|
||||||
|
#include "lyra/detail/parse.hpp"
|
||||||
|
#include "lyra/detail/unary_lambda_traits.hpp"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace lyra { namespace detail {
|
||||||
|
|
||||||
|
struct NonCopyable
|
||||||
|
{
|
||||||
|
NonCopyable() = default;
|
||||||
|
NonCopyable(NonCopyable const &) = delete;
|
||||||
|
NonCopyable(NonCopyable &&) = delete;
|
||||||
|
NonCopyable & operator=(NonCopyable const &) = delete;
|
||||||
|
NonCopyable & operator=(NonCopyable &&) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BoundRef : NonCopyable
|
||||||
|
{
|
||||||
|
virtual ~BoundRef() = default;
|
||||||
|
virtual auto isContainer() const -> bool { return false; }
|
||||||
|
virtual auto isFlag() const -> bool { return false; }
|
||||||
|
|
||||||
|
virtual size_t get_value_count() const { return 0; }
|
||||||
|
virtual std::string get_value(size_t) const { return ""; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BoundValueRefBase : BoundRef
|
||||||
|
{
|
||||||
|
virtual auto setValue(std::string const & arg) -> parser_result = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BoundFlagRefBase : BoundRef
|
||||||
|
{
|
||||||
|
virtual auto setFlag(bool flag) -> parser_result = 0;
|
||||||
|
virtual auto isFlag() const -> bool { return true; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct BoundValueRef : BoundValueRefBase
|
||||||
|
{
|
||||||
|
T & m_ref;
|
||||||
|
|
||||||
|
explicit BoundValueRef(T & ref)
|
||||||
|
: m_ref(ref)
|
||||||
|
{}
|
||||||
|
|
||||||
|
auto setValue(std::string const & arg) -> parser_result override
|
||||||
|
{
|
||||||
|
return parse_string(arg, m_ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual size_t get_value_count() const override { return 1; }
|
||||||
|
virtual std::string get_value(size_t i) const override
|
||||||
|
{
|
||||||
|
if (i == 0)
|
||||||
|
{
|
||||||
|
std::string result;
|
||||||
|
detail::to_string(m_ref, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct BoundValueRef<std::vector<T>> : BoundValueRefBase
|
||||||
|
{
|
||||||
|
std::vector<T> & m_ref;
|
||||||
|
|
||||||
|
explicit BoundValueRef(std::vector<T> & ref)
|
||||||
|
: m_ref(ref)
|
||||||
|
{}
|
||||||
|
|
||||||
|
auto isContainer() const -> bool override { return true; }
|
||||||
|
|
||||||
|
auto setValue(std::string const & arg) -> parser_result override
|
||||||
|
{
|
||||||
|
T temp;
|
||||||
|
auto str_result = parse_string(arg, temp);
|
||||||
|
if (str_result) m_ref.push_back(temp);
|
||||||
|
return str_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual size_t get_value_count() const override { return m_ref.size(); }
|
||||||
|
virtual std::string get_value(size_t i) const override
|
||||||
|
{
|
||||||
|
if (i < m_ref.size())
|
||||||
|
{
|
||||||
|
std::string str_result;
|
||||||
|
detail::to_string(m_ref[i], str_result);
|
||||||
|
return str_result;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BoundFlagRef : BoundFlagRefBase
|
||||||
|
{
|
||||||
|
bool & m_ref;
|
||||||
|
|
||||||
|
explicit BoundFlagRef(bool & ref)
|
||||||
|
: m_ref(ref)
|
||||||
|
{}
|
||||||
|
|
||||||
|
auto setFlag(bool flag) -> parser_result override
|
||||||
|
{
|
||||||
|
m_ref = flag;
|
||||||
|
return parser_result::ok(parser_result_type::matched);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual size_t get_value_count() const override { return 1; }
|
||||||
|
virtual std::string get_value(size_t i) const override
|
||||||
|
{
|
||||||
|
if (i == 0) return m_ref ? "true" : "false";
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename L>
|
||||||
|
struct BoundLambda : BoundValueRefBase
|
||||||
|
{
|
||||||
|
L m_lambda;
|
||||||
|
|
||||||
|
static_assert(unary_lambda_traits<L>::isValid,
|
||||||
|
"Supplied lambda must take exactly one argument");
|
||||||
|
explicit BoundLambda(L const & lambda)
|
||||||
|
: m_lambda(lambda)
|
||||||
|
{}
|
||||||
|
|
||||||
|
auto setValue(std::string const & arg) -> parser_result override
|
||||||
|
{
|
||||||
|
return invokeLambda<typename unary_lambda_traits<L>::ArgType>(
|
||||||
|
m_lambda, arg);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename L>
|
||||||
|
struct BoundFlagLambda : BoundFlagRefBase
|
||||||
|
{
|
||||||
|
L m_lambda;
|
||||||
|
|
||||||
|
static_assert(unary_lambda_traits<L>::isValid,
|
||||||
|
"Supplied lambda must take exactly one argument");
|
||||||
|
static_assert(
|
||||||
|
std::is_same<typename unary_lambda_traits<L>::ArgType, bool>::value,
|
||||||
|
"flags must be boolean");
|
||||||
|
|
||||||
|
explicit BoundFlagLambda(L const & lambda)
|
||||||
|
: m_lambda(lambda)
|
||||||
|
{}
|
||||||
|
|
||||||
|
auto setFlag(bool flag) -> parser_result override
|
||||||
|
{
|
||||||
|
return LambdaInvoker<
|
||||||
|
typename unary_lambda_traits<L>::ReturnType>::invoke(m_lambda,
|
||||||
|
flag);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct BoundVal : BoundValueRef<T>
|
||||||
|
{
|
||||||
|
T value;
|
||||||
|
|
||||||
|
BoundVal(T && v)
|
||||||
|
: BoundValueRef<T>(value)
|
||||||
|
, value(v)
|
||||||
|
{}
|
||||||
|
|
||||||
|
BoundVal(BoundVal && other)
|
||||||
|
: BoundValueRef<T>(value)
|
||||||
|
, value(std::move(other.value))
|
||||||
|
{}
|
||||||
|
|
||||||
|
std::shared_ptr<BoundRef> move_to_shared()
|
||||||
|
{
|
||||||
|
return std::shared_ptr<BoundRef>(new BoundVal<T>(std::move(*this)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}} // namespace lyra::detail
|
||||||
|
|
||||||
|
#endif
|
149
3party/lyra/lyra/detail/choices.hpp
Normal file
149
3party/lyra/lyra/detail/choices.hpp
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
// Copyright 2018-2022 René Ferdinand Rivera Morell
|
||||||
|
// Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
#ifndef LYRA_DETAIL_CHOICES_HPP
|
||||||
|
#define LYRA_DETAIL_CHOICES_HPP
|
||||||
|
|
||||||
|
#include "lyra/detail/from_string.hpp"
|
||||||
|
#include "lyra/detail/result.hpp"
|
||||||
|
#include "lyra/detail/unary_lambda_traits.hpp"
|
||||||
|
#include "lyra/parser_result.hpp"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <initializer_list>
|
||||||
|
#include <string>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace lyra { namespace detail {
|
||||||
|
|
||||||
|
/*
|
||||||
|
Type erased base for set of choices. I.e. it's an "interface".
|
||||||
|
*/
|
||||||
|
struct choices_base
|
||||||
|
{
|
||||||
|
virtual ~choices_base() = default;
|
||||||
|
virtual parser_result contains_value(std::string const & val) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Stores a set of choice values and provides checking if a given parsed
|
||||||
|
string value is one of the choices.
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
struct choices_set : choices_base
|
||||||
|
{
|
||||||
|
// The allowed values.
|
||||||
|
std::vector<T> values;
|
||||||
|
|
||||||
|
template <typename... Vals>
|
||||||
|
explicit choices_set(Vals... vals)
|
||||||
|
: choices_set({ vals... })
|
||||||
|
{}
|
||||||
|
|
||||||
|
explicit choices_set(const std::vector<T> & vals)
|
||||||
|
: values(vals)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// Checks if the given string val exists in the set of
|
||||||
|
// values. Returns a parsing error if the value is not present.
|
||||||
|
parser_result contains_value(std::string const & val) const override
|
||||||
|
{
|
||||||
|
T value;
|
||||||
|
auto parse = parse_string(val, value);
|
||||||
|
if (!parse)
|
||||||
|
{
|
||||||
|
return parser_result::error(
|
||||||
|
parser_result_type::no_match, parse.message());
|
||||||
|
}
|
||||||
|
bool result = std::count(values.begin(), values.end(), value) > 0;
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
return parser_result::ok(parser_result_type::matched);
|
||||||
|
}
|
||||||
|
// We consider not finding a choice a parse error.
|
||||||
|
return parser_result::error(parser_result_type::no_match,
|
||||||
|
"Value '" + val
|
||||||
|
+ "' not expected. Allowed values are: " + this->to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a comma separated list of the allowed values.
|
||||||
|
std::string to_string() const
|
||||||
|
{
|
||||||
|
std::string result;
|
||||||
|
for (const T & val : values)
|
||||||
|
{
|
||||||
|
if (!result.empty()) result += ", ";
|
||||||
|
std::string val_string;
|
||||||
|
if (detail::to_string(val, val_string))
|
||||||
|
{
|
||||||
|
result += val_string;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result += "<value error>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
explicit choices_set(std::initializer_list<T> const & vals)
|
||||||
|
: values(vals)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct choices_set<const char *> : choices_set<std::string>
|
||||||
|
{
|
||||||
|
template <typename... Vals>
|
||||||
|
explicit choices_set(Vals... vals)
|
||||||
|
: choices_set<std::string>(vals...)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Calls a designated function to check if the choice is valid.
|
||||||
|
*/
|
||||||
|
template <typename Lambda>
|
||||||
|
struct choices_check : choices_base
|
||||||
|
{
|
||||||
|
static_assert(unary_lambda_traits<Lambda>::isValid,
|
||||||
|
"Supplied lambda must take exactly one argument");
|
||||||
|
static_assert(std::is_same<bool,
|
||||||
|
typename unary_lambda_traits<Lambda>::ReturnType>::value,
|
||||||
|
"Supplied lambda must return bool");
|
||||||
|
|
||||||
|
Lambda checker;
|
||||||
|
using value_type = typename unary_lambda_traits<Lambda>::ArgType;
|
||||||
|
|
||||||
|
explicit choices_check(Lambda const & checker_function)
|
||||||
|
: checker(checker_function)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// Checks if the given string val exists in the set of
|
||||||
|
// values. Returns a parsing error if the value is not present.
|
||||||
|
parser_result contains_value(std::string const & val) const override
|
||||||
|
{
|
||||||
|
value_type value;
|
||||||
|
auto parse = parse_string(val, value);
|
||||||
|
if (!parse)
|
||||||
|
{
|
||||||
|
return parser_result::error(
|
||||||
|
parser_result_type::no_match, parse.message());
|
||||||
|
}
|
||||||
|
if (checker(value))
|
||||||
|
{
|
||||||
|
return parser_result::ok(parser_result_type::matched);
|
||||||
|
}
|
||||||
|
// We consider not finding a choice a parse error.
|
||||||
|
return parser_result::error(
|
||||||
|
parser_result_type::no_match, "Value '" + val + "' not expected.");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}} // namespace lyra::detail
|
||||||
|
|
||||||
|
#endif
|
63
3party/lyra/lyra/detail/deprecated_parser_customization.hpp
Normal file
63
3party/lyra/lyra/detail/deprecated_parser_customization.hpp
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
// Copyright 2018-2022 René Ferdinand Rivera Morell
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
#ifndef LYRA_DETAIL_DEPRECATED_PARSER_CUSTOMIZATION_HPP
|
||||||
|
#define LYRA_DETAIL_DEPRECATED_PARSER_CUSTOMIZATION_HPP
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace lyra {
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_parser_customization]
|
||||||
|
= `lyra::parser_customization`
|
||||||
|
|
||||||
|
Customization interface for parsing of options.
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
virtual std::string token_delimiters() const = 0;
|
||||||
|
----
|
||||||
|
|
||||||
|
Specifies the characters to use for splitting a cli argument into the option
|
||||||
|
and its value (if any).
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
virtual std::string option_prefix() const = 0;
|
||||||
|
----
|
||||||
|
|
||||||
|
Specifies the characters to use as possible prefix, either single or double,
|
||||||
|
for all options.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
struct parser_customization
|
||||||
|
{
|
||||||
|
virtual std::string token_delimiters() const = 0;
|
||||||
|
virtual std::string option_prefix() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_default_parser_customization]
|
||||||
|
= `lyra::default_parser_customization`
|
||||||
|
|
||||||
|
Is-a `lyra::parser_customization` that defines token delimiters as space (" ")
|
||||||
|
or equal (`=`). And specifies the option prefix character as dash (`-`)
|
||||||
|
resulting in long options with `--` and short options with `-`.
|
||||||
|
|
||||||
|
This customization is used as the default if none is given.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
struct default_parser_customization : parser_customization
|
||||||
|
{
|
||||||
|
std::string token_delimiters() const override { return " ="; }
|
||||||
|
std::string option_prefix() const override { return "-"; }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace lyra
|
||||||
|
|
||||||
|
#endif
|
196
3party/lyra/lyra/detail/from_string.hpp
Normal file
196
3party/lyra/lyra/detail/from_string.hpp
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
// Copyright 2018-2022 René Ferdinand Rivera Morell
|
||||||
|
// Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
#ifndef LYRA_DETAIL_FROM_STRING_HPP
|
||||||
|
#define LYRA_DETAIL_FROM_STRING_HPP
|
||||||
|
|
||||||
|
#include "lyra/detail/trait_utils.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#ifndef LYRA_CONFIG_OPTIONAL_TYPE
|
||||||
|
# ifdef __has_include
|
||||||
|
# if __has_include(<optional>) && __cplusplus >= 201703L
|
||||||
|
# include <optional>
|
||||||
|
# define LYRA_CONFIG_OPTIONAL_TYPE std::optional
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace lyra { namespace detail {
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool to_string(const T & source, std::string & target)
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << source;
|
||||||
|
ss >> target;
|
||||||
|
return !ss.fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool to_string(const std::string & source, std::string & target)
|
||||||
|
{
|
||||||
|
target = source;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool to_string(const char * source, std::string & target)
|
||||||
|
{
|
||||||
|
target = source;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool to_string(bool source, std::string & target)
|
||||||
|
{
|
||||||
|
target = source ? "true" : "false";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef LYRA_CONFIG_OPTIONAL_TYPE
|
||||||
|
template <typename T>
|
||||||
|
inline bool to_string(
|
||||||
|
LYRA_CONFIG_OPTIONAL_TYPE<T> & source, std::string & target)
|
||||||
|
{
|
||||||
|
if (source)
|
||||||
|
return to_string(*source, target);
|
||||||
|
else
|
||||||
|
target = "<nullopt>";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif // LYRA_CONFIG_OPTIONAL_TYPE
|
||||||
|
|
||||||
|
template <typename, typename = void>
|
||||||
|
struct is_convertible_from_string : std::false_type
|
||||||
|
{};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct is_convertible_from_string<T,
|
||||||
|
typename std::enable_if<std::is_arithmetic<T>::value>::type>
|
||||||
|
: std::true_type
|
||||||
|
{};
|
||||||
|
|
||||||
|
// Validates format of given value strings before conversion. This default
|
||||||
|
// template return true always.
|
||||||
|
template <typename, typename = void>
|
||||||
|
struct validate_from_string
|
||||||
|
{
|
||||||
|
static bool validate(const std::string &) { return true; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Validates that a to be parsed unsigned integer only contains number
|
||||||
|
// digits.
|
||||||
|
template <typename T>
|
||||||
|
struct validate_from_string<T,
|
||||||
|
typename std::enable_if<
|
||||||
|
std::is_unsigned<typename detail::remove_cvref<T>::type>::value>::type>
|
||||||
|
{
|
||||||
|
static bool validate(const std::string & s)
|
||||||
|
{
|
||||||
|
return s.find_first_not_of("0123456789") == std::string::npos;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Validates that a to be parsed signed integer only contains a sign and
|
||||||
|
// number digits.
|
||||||
|
template <typename T>
|
||||||
|
struct validate_from_string<T,
|
||||||
|
typename std::enable_if<
|
||||||
|
std::is_integral<typename detail::remove_cvref<T>::type>::value
|
||||||
|
&& std::is_signed<typename detail::remove_cvref<T>::type>::value>::type>
|
||||||
|
{
|
||||||
|
static bool validate(const std::string & s)
|
||||||
|
{
|
||||||
|
return s.find_first_not_of("-0123456789") == std::string::npos;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename S, typename T>
|
||||||
|
inline bool from_string(S const & source, T & target)
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
// Feed what we want to convert into the stream so that we can convert it
|
||||||
|
// on extraction to the target type.
|
||||||
|
ss << source;
|
||||||
|
// Check that the source string data is valid. This check depends on the
|
||||||
|
// target type.
|
||||||
|
if (!validate_from_string<T>::validate(ss.str())) return false;
|
||||||
|
T temp {};
|
||||||
|
ss >> temp;
|
||||||
|
if (!ss.fail() && ss.eof())
|
||||||
|
{
|
||||||
|
target = temp;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename S, typename... C>
|
||||||
|
inline bool from_string(S const & source, std::basic_string<C...> & target)
|
||||||
|
{
|
||||||
|
to_string(source, target);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct is_convertible_from_string<T,
|
||||||
|
typename std::enable_if<std::is_same<T, bool>::value>::type>
|
||||||
|
: std::true_type
|
||||||
|
{};
|
||||||
|
|
||||||
|
template <typename S>
|
||||||
|
inline bool from_string(S const & source, bool & target)
|
||||||
|
{
|
||||||
|
std::string srcLC;
|
||||||
|
to_string(source, srcLC);
|
||||||
|
std::transform(srcLC.begin(), srcLC.end(), srcLC.begin(),
|
||||||
|
[](char c) { return static_cast<char>(::tolower(c)); });
|
||||||
|
if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes"
|
||||||
|
|| srcLC == "on")
|
||||||
|
target = true;
|
||||||
|
else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no"
|
||||||
|
|| srcLC == "off")
|
||||||
|
target = false;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef LYRA_CONFIG_OPTIONAL_TYPE
|
||||||
|
template <typename T>
|
||||||
|
struct is_convertible_from_string<T,
|
||||||
|
typename std::enable_if<
|
||||||
|
is_specialization_of<T, LYRA_CONFIG_OPTIONAL_TYPE>::value>::type>
|
||||||
|
: std::true_type
|
||||||
|
{};
|
||||||
|
|
||||||
|
template <typename S, typename T>
|
||||||
|
inline bool from_string(S const & source, LYRA_CONFIG_OPTIONAL_TYPE<T> & target)
|
||||||
|
{
|
||||||
|
std::string srcLC;
|
||||||
|
to_string(source, srcLC);
|
||||||
|
std::transform(srcLC.begin(), srcLC.end(), srcLC.begin(),
|
||||||
|
[](char c) { return static_cast<char>(::tolower(c)); });
|
||||||
|
if (srcLC == "<nullopt>")
|
||||||
|
{
|
||||||
|
target.reset();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
T temp;
|
||||||
|
auto str_result = from_string(source, temp);
|
||||||
|
if (str_result) target = std::move(temp);
|
||||||
|
return str_result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // LYRA_CONFIG_OPTIONAL_TYPE
|
||||||
|
|
||||||
|
}} // namespace lyra::detail
|
||||||
|
|
||||||
|
#endif
|
51
3party/lyra/lyra/detail/invoke_lambda.hpp
Normal file
51
3party/lyra/lyra/detail/invoke_lambda.hpp
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
// Copyright 2018-2022 René Ferdinand Rivera Morell
|
||||||
|
// Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
#ifndef LYRA_DETAIL_INVOKE_LAMBDA_HPP
|
||||||
|
#define LYRA_DETAIL_INVOKE_LAMBDA_HPP
|
||||||
|
|
||||||
|
#include "lyra/detail/parse.hpp"
|
||||||
|
#include "lyra/detail/result.hpp"
|
||||||
|
#include "lyra/detail/unary_lambda_traits.hpp"
|
||||||
|
#include "lyra/parser_result.hpp"
|
||||||
|
|
||||||
|
namespace lyra { namespace detail {
|
||||||
|
|
||||||
|
template <typename ReturnType>
|
||||||
|
struct LambdaInvoker
|
||||||
|
{
|
||||||
|
template <typename L, typename ArgType>
|
||||||
|
static parser_result invoke(L const & lambda, ArgType const & arg)
|
||||||
|
{
|
||||||
|
return lambda(arg);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct LambdaInvoker<void>
|
||||||
|
{
|
||||||
|
template <typename L, typename ArgType>
|
||||||
|
static parser_result invoke(L const & lambda, ArgType const & arg)
|
||||||
|
{
|
||||||
|
lambda(arg);
|
||||||
|
return parser_result::ok(parser_result_type::matched);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename ArgType, typename L>
|
||||||
|
inline parser_result invokeLambda(L const & lambda, std::string const & arg)
|
||||||
|
{
|
||||||
|
ArgType temp {};
|
||||||
|
auto p_result = parse_string(arg, temp);
|
||||||
|
return !p_result
|
||||||
|
? p_result
|
||||||
|
: LambdaInvoker<typename unary_lambda_traits<L>::ReturnType>::invoke(
|
||||||
|
lambda, temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
}} // namespace lyra::detail
|
||||||
|
|
||||||
|
#endif
|
29
3party/lyra/lyra/detail/parse.hpp
Normal file
29
3party/lyra/lyra/detail/parse.hpp
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// Copyright 2018-2022 René Ferdinand Rivera Morell
|
||||||
|
// Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
#ifndef LYRA_DETAIL_PARSE_HPP
|
||||||
|
#define LYRA_DETAIL_PARSE_HPP
|
||||||
|
|
||||||
|
#include "lyra/detail/from_string.hpp"
|
||||||
|
#include "lyra/parser_result.hpp"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace lyra { namespace detail {
|
||||||
|
|
||||||
|
template <typename S, typename T>
|
||||||
|
parser_result parse_string(S const & source, T & target)
|
||||||
|
{
|
||||||
|
if (from_string(source, target))
|
||||||
|
return parser_result::ok(parser_result_type::matched);
|
||||||
|
else
|
||||||
|
return parser_result::error(parser_result_type::no_match,
|
||||||
|
"Unable to convert '" + source + "' to destination type");
|
||||||
|
}
|
||||||
|
|
||||||
|
}} // namespace lyra::detail
|
||||||
|
|
||||||
|
#endif
|
79
3party/lyra/lyra/detail/print.hpp
Normal file
79
3party/lyra/lyra/detail/print.hpp
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
// Copyright 2021-2022 René Ferdinand Rivera Morell
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
#ifndef LYRA_DETAIL_PRINT_HPP
|
||||||
|
#define LYRA_DETAIL_PRINT_HPP
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#ifndef LYRA_DEBUG
|
||||||
|
# define LYRA_DEBUG 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace lyra { namespace detail {
|
||||||
|
|
||||||
|
constexpr bool is_debug = LYRA_DEBUG;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::string to_string(T && t)
|
||||||
|
{
|
||||||
|
return std::string(std::move(t));
|
||||||
|
}
|
||||||
|
|
||||||
|
using std::to_string;
|
||||||
|
|
||||||
|
struct print
|
||||||
|
{
|
||||||
|
print(const char * scope_name = nullptr)
|
||||||
|
: scope(scope_name)
|
||||||
|
{
|
||||||
|
if (is_debug) print::depth() += 1;
|
||||||
|
if (scope) debug(scope, "...");
|
||||||
|
}
|
||||||
|
|
||||||
|
~print()
|
||||||
|
{
|
||||||
|
if (scope) debug("...", scope);
|
||||||
|
if (is_debug) print::depth() -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... A>
|
||||||
|
void debug(A... arg)
|
||||||
|
{
|
||||||
|
if (is_debug)
|
||||||
|
{
|
||||||
|
std::cerr << "[DEBUG]"
|
||||||
|
<< std::string((print::depth() - 1) * 2, ' ');
|
||||||
|
std::string args[] = { to_string(arg)... };
|
||||||
|
for (auto & arg_string : args)
|
||||||
|
{
|
||||||
|
std::cerr << " " << arg_string;
|
||||||
|
}
|
||||||
|
std::cerr << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const char * scope;
|
||||||
|
|
||||||
|
static std::size_t & depth()
|
||||||
|
{
|
||||||
|
static std::size_t d = 0;
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}} // namespace lyra::detail
|
||||||
|
|
||||||
|
#if LYRA_DEBUG
|
||||||
|
# define LYRA_PRINT_SCOPE ::lyra::detail::print lyra_print_scope
|
||||||
|
# define LYRA_PRINT_DEBUG lyra_print_scope.debug
|
||||||
|
#else
|
||||||
|
# define LYRA_PRINT_SCOPE(...) while (false)
|
||||||
|
# define LYRA_PRINT_DEBUG(...) while (false)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
165
3party/lyra/lyra/detail/result.hpp
Normal file
165
3party/lyra/lyra/detail/result.hpp
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
// Copyright 2018-2022 René Ferdinand Rivera Morell
|
||||||
|
// Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
#ifndef LYRA_DETAIL_RESULT_HPP
|
||||||
|
#define LYRA_DETAIL_RESULT_HPP
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace lyra { namespace detail {
|
||||||
|
|
||||||
|
class result_base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
result_base const & base() const { return *this; }
|
||||||
|
explicit operator bool() const { return is_ok(); }
|
||||||
|
bool is_ok() const { return kind_ == result_kind::ok; }
|
||||||
|
std::string message() const { return message_; }
|
||||||
|
[[deprecated]] std::string errorMessage() const { return message(); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
enum class result_kind
|
||||||
|
{
|
||||||
|
ok,
|
||||||
|
error
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit result_base(result_kind kind, const std::string & message = "")
|
||||||
|
: kind_(kind)
|
||||||
|
, message_(message)
|
||||||
|
{}
|
||||||
|
|
||||||
|
explicit result_base(const result_base & other)
|
||||||
|
: kind_(other.kind_)
|
||||||
|
, message_(other.message_)
|
||||||
|
{}
|
||||||
|
|
||||||
|
virtual ~result_base() = default;
|
||||||
|
|
||||||
|
result_base & operator=(const result_base &) = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
result_kind kind_;
|
||||||
|
std::string message_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class result_value_base : public result_base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using value_type = T;
|
||||||
|
|
||||||
|
value_type const & value() const { return *value_; }
|
||||||
|
bool has_value() const { return bool(value_); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::unique_ptr<value_type> value_;
|
||||||
|
|
||||||
|
explicit result_value_base(
|
||||||
|
result_kind kind, const std::string & message = "")
|
||||||
|
: result_base(kind, message)
|
||||||
|
{}
|
||||||
|
|
||||||
|
explicit result_value_base(result_kind kind,
|
||||||
|
const value_type & val,
|
||||||
|
const std::string & message = "")
|
||||||
|
: result_base(kind, message)
|
||||||
|
{
|
||||||
|
value_.reset(new value_type(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit result_value_base(result_value_base const & other)
|
||||||
|
: result_base(other)
|
||||||
|
{
|
||||||
|
if (other.value_) value_.reset(new value_type(*other.value_));
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit result_value_base(const result_base & other)
|
||||||
|
: result_base(other)
|
||||||
|
{}
|
||||||
|
|
||||||
|
result_value_base & operator=(result_value_base const & other)
|
||||||
|
{
|
||||||
|
result_base::operator=(other);
|
||||||
|
if (other.value_) value_.reset(new T(*other.value_));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
class result_value_base<void> : public result_base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using value_type = void;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// using result_base::result_base;
|
||||||
|
explicit result_value_base(const result_base & other)
|
||||||
|
: result_base(other)
|
||||||
|
{}
|
||||||
|
explicit result_value_base(
|
||||||
|
result_kind kind, const std::string & message = "")
|
||||||
|
: result_base(kind, message)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class basic_result : public result_value_base<T>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using value_type = typename result_value_base<T>::value_type;
|
||||||
|
|
||||||
|
explicit basic_result(result_base const & other)
|
||||||
|
: result_value_base<T>(other)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// With-value results..
|
||||||
|
|
||||||
|
static basic_result ok(value_type const & val)
|
||||||
|
{
|
||||||
|
return basic_result(result_base::result_kind::ok, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static basic_result error(
|
||||||
|
value_type const & val, std::string const & message)
|
||||||
|
{
|
||||||
|
return basic_result(result_base::result_kind::error, val, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
using result_value_base<T>::result_value_base;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
class basic_result<void> : public result_value_base<void>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using value_type = typename result_value_base<void>::value_type;
|
||||||
|
|
||||||
|
explicit basic_result(result_base const & other)
|
||||||
|
: result_value_base<void>(other)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// Value-less results.. (only kind as void is a value-less kind)
|
||||||
|
|
||||||
|
static basic_result ok()
|
||||||
|
{
|
||||||
|
return basic_result(result_base::result_kind::ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
static basic_result error(std::string const & message)
|
||||||
|
{
|
||||||
|
return basic_result(result_base::result_kind::error, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
using result_value_base<void>::result_value_base;
|
||||||
|
};
|
||||||
|
|
||||||
|
}} // namespace lyra::detail
|
||||||
|
|
||||||
|
#endif
|
295
3party/lyra/lyra/detail/tokens.hpp
Normal file
295
3party/lyra/lyra/detail/tokens.hpp
Normal file
@ -0,0 +1,295 @@
|
|||||||
|
// Copyright 2018-2022 René Ferdinand Rivera Morell
|
||||||
|
// Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
#ifndef LYRA_DETAIL_TOKENS_HPP
|
||||||
|
#define LYRA_DETAIL_TOKENS_HPP
|
||||||
|
|
||||||
|
#include "lyra/option_style.hpp"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace lyra { namespace detail {
|
||||||
|
|
||||||
|
// Wraps a token coming from a token stream. These may not directly
|
||||||
|
// correspond to strings as a single string may encode an option + its
|
||||||
|
// argument if the : or = form is used
|
||||||
|
enum class token_type
|
||||||
|
{
|
||||||
|
unknown,
|
||||||
|
option,
|
||||||
|
argument
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Char, class Traits = std::char_traits<Char>>
|
||||||
|
class basic_token_name
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using traits_type = Traits;
|
||||||
|
using value_type = Char;
|
||||||
|
using pointer = value_type *;
|
||||||
|
using const_pointer = const value_type *;
|
||||||
|
using reference = value_type &;
|
||||||
|
using const_reference = const value_type &;
|
||||||
|
using size_type = std::size_t;
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
using const_iterator = const_pointer;
|
||||||
|
using iterator = const_iterator;
|
||||||
|
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||||
|
using reverse_iterator = const_reverse_iterator;
|
||||||
|
using string_type = std::basic_string<value_type, traits_type>;
|
||||||
|
|
||||||
|
basic_token_name() noexcept
|
||||||
|
: str { nullptr }
|
||||||
|
, len { 0 }
|
||||||
|
{}
|
||||||
|
|
||||||
|
basic_token_name(const basic_token_name &) noexcept = default;
|
||||||
|
|
||||||
|
basic_token_name(const_pointer s) noexcept
|
||||||
|
: str { s }
|
||||||
|
, len { traits_type::length(s) }
|
||||||
|
{}
|
||||||
|
|
||||||
|
basic_token_name(const_pointer s, size_type count) noexcept
|
||||||
|
: str { s }
|
||||||
|
, len { count }
|
||||||
|
{}
|
||||||
|
|
||||||
|
basic_token_name & operator=(const basic_token_name &) noexcept = default;
|
||||||
|
|
||||||
|
void swap(basic_token_name & other) noexcept
|
||||||
|
{
|
||||||
|
auto tmp = *this;
|
||||||
|
*this = other;
|
||||||
|
other = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator begin() const noexcept { return this->str; }
|
||||||
|
const_iterator end() const noexcept { return this->str + this->len; }
|
||||||
|
const_iterator cbegin() const noexcept { return this->str; }
|
||||||
|
const_iterator cend() const noexcept { return this->str + this->len; }
|
||||||
|
|
||||||
|
size_type size() const noexcept { return this->len; }
|
||||||
|
size_type length() const noexcept { return this->len; }
|
||||||
|
bool empty() const noexcept { return this->len == 0; }
|
||||||
|
|
||||||
|
friend string_type to_string(const basic_token_name & t)
|
||||||
|
{
|
||||||
|
return { t.str, t.len };
|
||||||
|
}
|
||||||
|
|
||||||
|
friend string_type operator+(
|
||||||
|
const_pointer lhs, const basic_token_name & rhs)
|
||||||
|
{
|
||||||
|
return lhs + to_string(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const_pointer str;
|
||||||
|
size_type len;
|
||||||
|
};
|
||||||
|
|
||||||
|
// using token_name = basic_token_name<std::string::value_type>;
|
||||||
|
using token_name = std::string;
|
||||||
|
|
||||||
|
struct token
|
||||||
|
{
|
||||||
|
token_type type;
|
||||||
|
token_name name;
|
||||||
|
|
||||||
|
token()
|
||||||
|
: type(token_type::unknown)
|
||||||
|
{}
|
||||||
|
token(const token & other) = default;
|
||||||
|
token(token_type t, const token_name & n)
|
||||||
|
: type(t)
|
||||||
|
, name(n)
|
||||||
|
{}
|
||||||
|
|
||||||
|
explicit operator bool() const { return type != token_type::unknown; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Abstracts iterators into args with option arguments uniformly handled
|
||||||
|
class token_iterator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template <typename Span>
|
||||||
|
explicit token_iterator(Span const & args, const option_style & opt_style)
|
||||||
|
: style(opt_style)
|
||||||
|
, args_i(args.begin())
|
||||||
|
, args_e(args.end())
|
||||||
|
, args_i_sub(opt_style.short_option_size)
|
||||||
|
{}
|
||||||
|
|
||||||
|
explicit operator bool() const noexcept { return args_i != args_e; }
|
||||||
|
|
||||||
|
token_iterator & pop(const token & arg_or_opt)
|
||||||
|
{
|
||||||
|
if (arg_or_opt.type == token_type::option && has_short_option_prefix())
|
||||||
|
{
|
||||||
|
// Multiple short options argument (-abc). Advance to the next
|
||||||
|
// short option possible, or the next arg entirely.
|
||||||
|
if (++args_i_sub >= args_i->size())
|
||||||
|
{
|
||||||
|
++args_i;
|
||||||
|
args_i_sub = style.short_option_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Regular arg or long option, just advance to the next arg.
|
||||||
|
++args_i;
|
||||||
|
args_i_sub = style.short_option_size;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
token_iterator & pop(const token & /* opt */, const token & /* val */)
|
||||||
|
{
|
||||||
|
if (has_short_option_prefix() && args_i->size() > 2)
|
||||||
|
++args_i;
|
||||||
|
else if (!has_value_delimiter())
|
||||||
|
args_i += 2;
|
||||||
|
else
|
||||||
|
++args_i;
|
||||||
|
args_i_sub = style.short_option_size;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Current arg looks like an option, short or long.
|
||||||
|
bool has_option_prefix() const noexcept
|
||||||
|
{
|
||||||
|
return has_long_option_prefix() || has_short_option_prefix();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Current arg looks like a short option (-o).
|
||||||
|
bool has_short_option_prefix() const noexcept
|
||||||
|
{
|
||||||
|
return (args_i != args_e)
|
||||||
|
&& is_prefixed(
|
||||||
|
style.short_option_prefix, style.short_option_size, *args_i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Current arg looks like a long option (--option).
|
||||||
|
bool has_long_option_prefix() const noexcept
|
||||||
|
{
|
||||||
|
return (args_i != args_e)
|
||||||
|
&& is_prefixed(
|
||||||
|
style.long_option_prefix, style.long_option_size, *args_i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Current arg looks like a delimited option+value (--option=x, -o=x)
|
||||||
|
bool has_value_delimiter() const noexcept
|
||||||
|
{
|
||||||
|
return (args_i != args_e)
|
||||||
|
&& (args_i->find_first_of(style.value_delimiters)
|
||||||
|
!= std::string::npos);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract the current option token.
|
||||||
|
token option() const
|
||||||
|
{
|
||||||
|
if (has_long_option_prefix())
|
||||||
|
{
|
||||||
|
if (has_value_delimiter())
|
||||||
|
// --option=x
|
||||||
|
return token(token_type::option,
|
||||||
|
args_i->substr(
|
||||||
|
0, args_i->find_first_of(style.value_delimiters)));
|
||||||
|
else
|
||||||
|
// --option
|
||||||
|
return token(token_type::option, *args_i);
|
||||||
|
}
|
||||||
|
else if (has_short_option_prefix())
|
||||||
|
{
|
||||||
|
// -o (or possibly -abco)
|
||||||
|
return { token_type::option,
|
||||||
|
prefix_value(style.short_option_prefix, style.short_option_size)
|
||||||
|
+ (*args_i)[args_i_sub] };
|
||||||
|
}
|
||||||
|
return token();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extracts the option value if available. This will do any needed
|
||||||
|
// lookahead through the args for the value.
|
||||||
|
token value() const
|
||||||
|
{
|
||||||
|
if (has_option_prefix() && has_value_delimiter())
|
||||||
|
// --option=x, -o=x
|
||||||
|
return token(token_type::argument,
|
||||||
|
args_i->substr(
|
||||||
|
args_i->find_first_of(style.value_delimiters) + 1));
|
||||||
|
else if (has_long_option_prefix())
|
||||||
|
{
|
||||||
|
if (args_i + 1 != args_e)
|
||||||
|
// --option x
|
||||||
|
return token(token_type::argument, *(args_i + 1));
|
||||||
|
}
|
||||||
|
else if (has_short_option_prefix())
|
||||||
|
{
|
||||||
|
if (args_i_sub + 1 < args_i->size())
|
||||||
|
// -ox
|
||||||
|
return token(
|
||||||
|
token_type::argument, args_i->substr(args_i_sub + 1));
|
||||||
|
else if (args_i + 1 != args_e)
|
||||||
|
// -o x
|
||||||
|
return token(token_type::argument, *(args_i + 1));
|
||||||
|
}
|
||||||
|
return token();
|
||||||
|
}
|
||||||
|
|
||||||
|
token argument() const { return token(token_type::argument, *args_i); }
|
||||||
|
|
||||||
|
static bool is_prefixed(
|
||||||
|
const std::string & prefix, std::size_t size, const std::string & s)
|
||||||
|
{
|
||||||
|
if (!prefix.empty() && size > 0 && s.size() > size)
|
||||||
|
{
|
||||||
|
for (auto c : prefix)
|
||||||
|
{
|
||||||
|
// Checks that the option looks like "[<c>]{size}[^<c>]".
|
||||||
|
if (s[size] != c
|
||||||
|
&& s.find_last_not_of(c, size - 1) == std::string::npos)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const option_style & style;
|
||||||
|
std::vector<std::string>::const_iterator args_i;
|
||||||
|
std::vector<std::string>::const_iterator args_e;
|
||||||
|
std::string::size_type args_i_sub;
|
||||||
|
|
||||||
|
inline bool is_opt_prefix(char c) const noexcept
|
||||||
|
{
|
||||||
|
return is_prefix_char(
|
||||||
|
style.long_option_prefix, style.long_option_size, c)
|
||||||
|
|| is_prefix_char(
|
||||||
|
style.short_option_prefix, style.short_option_size, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool is_prefix_char(const std::string & prefix,
|
||||||
|
std::size_t size,
|
||||||
|
std::string::value_type c) const noexcept
|
||||||
|
{
|
||||||
|
return !prefix.empty() && size > 0
|
||||||
|
&& prefix.find(c) != std::string::npos;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string prefix_value(
|
||||||
|
const std::string & prefix, std::size_t size) const
|
||||||
|
{
|
||||||
|
return std::string(
|
||||||
|
static_cast<typename std::string::size_type>(size), prefix[0]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}} // namespace lyra::detail
|
||||||
|
|
||||||
|
#endif
|
74
3party/lyra/lyra/detail/trait_utils.hpp
Normal file
74
3party/lyra/lyra/detail/trait_utils.hpp
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
// Copyright 2020-2022 René Ferdinand Rivera Morell
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
#ifndef LYRA_DETAIL_TRAIT_UTILS_HPP
|
||||||
|
#define LYRA_DETAIL_TRAIT_UTILS_HPP
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace lyra { namespace detail {
|
||||||
|
|
||||||
|
// Checks that F can be called with arguments of type Args.
|
||||||
|
// Credit for the technique goes to Richard Hodges (in SO post).
|
||||||
|
template <class F, class... Args>
|
||||||
|
struct is_callable
|
||||||
|
{
|
||||||
|
template <class U>
|
||||||
|
static auto test(U * p)
|
||||||
|
-> decltype((*p)(std::declval<Args>()...), void(), std::true_type());
|
||||||
|
|
||||||
|
template <class U>
|
||||||
|
static auto test(...) -> decltype(std::false_type());
|
||||||
|
|
||||||
|
static constexpr bool value = decltype(test<F>(0))::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct remove_cvref
|
||||||
|
{
|
||||||
|
typedef
|
||||||
|
typename std::remove_cv<typename std::remove_reference<T>::type>::type
|
||||||
|
type;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Checks that F can be called, with an unspecified set of arguments.
|
||||||
|
//
|
||||||
|
// Currently this only detects function objects, like lambdas.
|
||||||
|
// Where the operator() is not templated.
|
||||||
|
template <class F>
|
||||||
|
struct is_invocable
|
||||||
|
{
|
||||||
|
template <class U>
|
||||||
|
static auto test(U * p)
|
||||||
|
-> decltype((&U::operator()), void(), std::true_type());
|
||||||
|
|
||||||
|
template <class U>
|
||||||
|
static auto test(...) -> decltype(std::false_type());
|
||||||
|
|
||||||
|
static constexpr bool value
|
||||||
|
= decltype(test<typename remove_cvref<F>::type>(0))::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
// C++11 compatible void_t equivalent.
|
||||||
|
template <typename... Ts>
|
||||||
|
struct make_void
|
||||||
|
{
|
||||||
|
typedef void type;
|
||||||
|
};
|
||||||
|
template <typename... Ts>
|
||||||
|
using valid_t = typename make_void<Ts...>::type;
|
||||||
|
|
||||||
|
// Borrowed from https://wg21.link/p2098r1
|
||||||
|
template <class T, template <class...> class Primary>
|
||||||
|
struct is_specialization_of : std::false_type
|
||||||
|
{};
|
||||||
|
template <template <class...> class Primary, class... Args>
|
||||||
|
struct is_specialization_of<Primary<Args...>, Primary> : std::true_type
|
||||||
|
{};
|
||||||
|
|
||||||
|
}} // namespace lyra::detail
|
||||||
|
|
||||||
|
#endif
|
37
3party/lyra/lyra/detail/unary_lambda_traits.hpp
Normal file
37
3party/lyra/lyra/detail/unary_lambda_traits.hpp
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
// Copyright 2018-2022 René Ferdinand Rivera Morell
|
||||||
|
// Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
#ifndef LYRA_DETAIL_UNARY_LAMBDA_TRAITS_HPP
|
||||||
|
#define LYRA_DETAIL_UNARY_LAMBDA_TRAITS_HPP
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace lyra { namespace detail {
|
||||||
|
|
||||||
|
// Traits for extracting arg and return type of lambdas (for single argument
|
||||||
|
// lambdas)
|
||||||
|
template <typename L>
|
||||||
|
struct unary_lambda_traits : unary_lambda_traits<decltype(&L::operator())>
|
||||||
|
{};
|
||||||
|
|
||||||
|
template <typename ClassT, typename ReturnT, typename... Args>
|
||||||
|
struct unary_lambda_traits<ReturnT (ClassT::*)(Args...) const>
|
||||||
|
{
|
||||||
|
static const bool isValid = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename ClassT, typename ReturnT, typename ArgT>
|
||||||
|
struct unary_lambda_traits<ReturnT (ClassT::*)(ArgT) const>
|
||||||
|
{
|
||||||
|
static const bool isValid = true;
|
||||||
|
using ArgType = typename std::remove_const<
|
||||||
|
typename std::remove_reference<ArgT>::type>::type;
|
||||||
|
using ReturnType = ReturnT;
|
||||||
|
};
|
||||||
|
|
||||||
|
}} // namespace lyra::detail
|
||||||
|
|
||||||
|
#endif
|
155
3party/lyra/lyra/exe_name.hpp
Normal file
155
3party/lyra/lyra/exe_name.hpp
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
// Copyright 2018-2022 René Ferdinand Rivera Morell
|
||||||
|
// Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
#ifndef LYRA_EXE_NAME_HPP
|
||||||
|
#define LYRA_EXE_NAME_HPP
|
||||||
|
|
||||||
|
#include "lyra/detail/bound.hpp"
|
||||||
|
#include "lyra/detail/tokens.hpp"
|
||||||
|
#include "lyra/parser.hpp"
|
||||||
|
#include "lyra/parser_result.hpp"
|
||||||
|
|
||||||
|
namespace lyra {
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_exe_name]
|
||||||
|
= `lyra::exe_name`
|
||||||
|
|
||||||
|
Specifies the name of the executable.
|
||||||
|
|
||||||
|
Is-a <<lyra_composable_parser>>.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
class exe_name : public composable_parser<exe_name>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
exe_name()
|
||||||
|
: m_name(std::make_shared<std::string>("<executable>"))
|
||||||
|
{}
|
||||||
|
|
||||||
|
explicit exe_name(std::string & ref);
|
||||||
|
|
||||||
|
template <typename LambdaT>
|
||||||
|
explicit exe_name(LambdaT const & lambda);
|
||||||
|
|
||||||
|
std::string name() const;
|
||||||
|
parser_result set(std::string const & newName);
|
||||||
|
|
||||||
|
// The exe name is not parsed out of the normal tokens, but is handled
|
||||||
|
// specially
|
||||||
|
virtual parse_result parse(detail::token_iterator const & tokens,
|
||||||
|
const option_style &) const override
|
||||||
|
{
|
||||||
|
return parse_result::ok(
|
||||||
|
detail::parse_state(parser_result_type::no_match, tokens));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::unique_ptr<parser> clone() const override
|
||||||
|
{
|
||||||
|
return make_clone<exe_name>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<std::string> m_name;
|
||||||
|
std::shared_ptr<detail::BoundValueRefBase> m_ref;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_exe_name_ctor]
|
||||||
|
== Construction
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
exe_name::exe_name(std::string& ref)
|
||||||
|
----
|
||||||
|
|
||||||
|
Constructs with a target string to receive the name of the executable. When
|
||||||
|
the `cli` is run the target string will contain the exec name.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
inline exe_name::exe_name(std::string & ref)
|
||||||
|
: exe_name()
|
||||||
|
{
|
||||||
|
m_ref = std::make_shared<detail::BoundValueRef<std::string>>(ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
template <typename LambdaT>
|
||||||
|
exe_name::exe_name(LambdaT const& lambda)
|
||||||
|
----
|
||||||
|
|
||||||
|
Construct with a callback that is called with the value of the executable name
|
||||||
|
when the `cli` runs.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
template <typename LambdaT>
|
||||||
|
exe_name::exe_name(LambdaT const & lambda)
|
||||||
|
: exe_name()
|
||||||
|
{
|
||||||
|
m_ref = std::make_shared<detail::BoundLambda<LambdaT>>(lambda);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_exe_name_accessors]
|
||||||
|
== Accessors
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_exe_name_name]
|
||||||
|
=== `lyra::exe_name::name`
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
std::string exe_name::name() const
|
||||||
|
----
|
||||||
|
|
||||||
|
Returns the executable name when available. Otherwise it returns a default
|
||||||
|
value.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
inline std::string exe_name::name() const { return *m_name; }
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_exe_name_set]
|
||||||
|
=== `lyra::exe_name::set`
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
parser_result exe_name::set(std::string const& newName)
|
||||||
|
----
|
||||||
|
|
||||||
|
Sets the executable name with the `newName` value. The new value is reflected
|
||||||
|
in the bound string reference or callback.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
inline parser_result exe_name::set(std::string const & newName)
|
||||||
|
{
|
||||||
|
auto lastSlash = newName.find_last_of("\\/");
|
||||||
|
auto filename = (lastSlash == std::string::npos)
|
||||||
|
? newName
|
||||||
|
: newName.substr(lastSlash + 1);
|
||||||
|
|
||||||
|
*m_name = filename;
|
||||||
|
if (m_ref)
|
||||||
|
return m_ref->setValue(filename);
|
||||||
|
else
|
||||||
|
return parser_result::ok(parser_result_type::matched);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace lyra
|
||||||
|
|
||||||
|
#endif
|
214
3party/lyra/lyra/group.hpp
Normal file
214
3party/lyra/lyra/group.hpp
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
// Copyright 2020-2022 René Ferdinand Rivera Morell
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
#ifndef LYRA_GROUP_HPP
|
||||||
|
#define LYRA_GROUP_HPP
|
||||||
|
|
||||||
|
#include "lyra/arguments.hpp"
|
||||||
|
#include "lyra/detail/print.hpp"
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
namespace lyra {
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_group]
|
||||||
|
= `lyra::group`
|
||||||
|
|
||||||
|
A group of arguments provides for parsing, optionally, a set of arguments
|
||||||
|
together. The group itself is considered successfully parsed only when the
|
||||||
|
arguments in the group are parsed without errors. A common use case for this
|
||||||
|
are sub-commands. This implementation is recursive. And hence allows groups
|
||||||
|
within groups for describing branching argument parsing.
|
||||||
|
|
||||||
|
Is-a <<lyra_arguments>>.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
class group : public arguments
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
group();
|
||||||
|
group(const group & other);
|
||||||
|
explicit group(const std::function<void(const group &)> & f);
|
||||||
|
|
||||||
|
virtual bool is_group() const override { return true; }
|
||||||
|
|
||||||
|
parse_result parse(detail::token_iterator const & tokens,
|
||||||
|
const option_style & style) const override
|
||||||
|
{
|
||||||
|
LYRA_PRINT_SCOPE("group::parse");
|
||||||
|
LYRA_PRINT_DEBUG("(?)", get_usage_text(style),
|
||||||
|
"?=", tokens ? tokens.argument().name : "");
|
||||||
|
parse_result p_result = arguments::parse(tokens, style);
|
||||||
|
if (p_result && p_result.value().type() != parser_result_type::no_match
|
||||||
|
&& success_signal)
|
||||||
|
{
|
||||||
|
// Trigger any success signal for parsing the argument as the group.
|
||||||
|
// This allows for executing handlers for commands.
|
||||||
|
this->success_signal(*this);
|
||||||
|
}
|
||||||
|
if (!p_result)
|
||||||
|
{
|
||||||
|
LYRA_PRINT_DEBUG("(!)", get_usage_text(style),
|
||||||
|
"!=", tokens ? tokens.argument().name : "");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LYRA_PRINT_DEBUG("(=)", get_usage_text(style),
|
||||||
|
"==", tokens ? tokens.argument().name : "", "==>",
|
||||||
|
p_result.value().type());
|
||||||
|
}
|
||||||
|
return p_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
group & optional();
|
||||||
|
group & required(size_t n = 1);
|
||||||
|
group & cardinality(size_t n);
|
||||||
|
group & cardinality(size_t n, size_t m);
|
||||||
|
detail::parser_cardinality cardinality() const override
|
||||||
|
{
|
||||||
|
return m_cardinality;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::unique_ptr<parser> clone() const override
|
||||||
|
{
|
||||||
|
return make_clone<group>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::function<void(const group &)> success_signal;
|
||||||
|
detail::parser_cardinality m_cardinality = { 0, 1 };
|
||||||
|
};
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_group_ctor]
|
||||||
|
== Construction
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_group_ctor_default]
|
||||||
|
=== Default
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
group();
|
||||||
|
----
|
||||||
|
|
||||||
|
Default constructing a `group` does not register the success callback.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
inline group::group()
|
||||||
|
: m_cardinality(0, 1)
|
||||||
|
{}
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_group_ctor_copy]
|
||||||
|
=== Copy
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
group::group(const group & other);
|
||||||
|
----
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
inline group::group(const group & other)
|
||||||
|
: arguments(other)
|
||||||
|
, success_signal(other.success_signal)
|
||||||
|
, m_cardinality(other.m_cardinality)
|
||||||
|
{}
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_group_ctor_success]
|
||||||
|
=== Success Handler
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
group::group(const std::function<void(const group &)> & f)
|
||||||
|
----
|
||||||
|
|
||||||
|
Registers a function to call when the group is successfully parsed. The
|
||||||
|
function is called with the group to facilitate customization.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
inline group::group(const std::function<void(const group &)> & f)
|
||||||
|
: success_signal(f)
|
||||||
|
{}
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_group_optional]
|
||||||
|
=== `lyra::group::optional`
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
group & group::optional();
|
||||||
|
----
|
||||||
|
|
||||||
|
Indicates that the argument is optional. This is equivalent to specifying
|
||||||
|
`cardinality(0, 1)`.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
inline group & group::optional()
|
||||||
|
{
|
||||||
|
m_cardinality.optional();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_group_required]
|
||||||
|
=== `lyra::group::required(n)`
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
group & group::required(size_t n);
|
||||||
|
----
|
||||||
|
|
||||||
|
Specifies that the argument needs to given the number of `n` times
|
||||||
|
(defaults to *1*).
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
inline group & group::required(size_t n)
|
||||||
|
{
|
||||||
|
m_cardinality.required(n);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_group_cardinality]
|
||||||
|
=== `lyra::group::cardinality(n)`
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
group & group::cardinality(size_t n);
|
||||||
|
group & group::cardinality(size_t n, size_t m);
|
||||||
|
----
|
||||||
|
|
||||||
|
Specifies the number of times the argument can and needs to appear in the list
|
||||||
|
of arguments. In the first form the argument can appear exactly `n` times. In
|
||||||
|
the second form it specifies that the argument can appear from `n` to `m` times
|
||||||
|
inclusive.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
inline group & group::cardinality(size_t n)
|
||||||
|
{
|
||||||
|
m_cardinality.counted(n);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
inline group & group::cardinality(size_t n, size_t m)
|
||||||
|
{
|
||||||
|
m_cardinality.bounded(n, m);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace lyra
|
||||||
|
|
||||||
|
#endif
|
78
3party/lyra/lyra/help.hpp
Normal file
78
3party/lyra/lyra/help.hpp
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
// Copyright 2018-2022 René Ferdinand Rivera Morell
|
||||||
|
// Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
#ifndef LYRA_HELP_HPP
|
||||||
|
#define LYRA_HELP_HPP
|
||||||
|
|
||||||
|
#include "lyra/opt.hpp"
|
||||||
|
|
||||||
|
namespace lyra {
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_help]
|
||||||
|
= `lyra::help`
|
||||||
|
|
||||||
|
Utility function that defines a default `--help` option. You can specify a
|
||||||
|
`bool` flag to indicate if the help option was specified and that you could
|
||||||
|
display a help message.
|
||||||
|
|
||||||
|
The option accepts `-?`, `-h`, and `--help` as allowed option names.
|
||||||
|
|
||||||
|
*/ // end::reference[]
|
||||||
|
class help : public opt
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
help(bool & showHelpFlag)
|
||||||
|
: opt([&](bool flag) {
|
||||||
|
showHelpFlag = flag;
|
||||||
|
return parser_result::ok(parser_result_type::short_circuit_all);
|
||||||
|
})
|
||||||
|
{
|
||||||
|
this->description("Display usage information.")
|
||||||
|
.optional()
|
||||||
|
.name("-?")
|
||||||
|
.name("-h")
|
||||||
|
.name("--help");
|
||||||
|
}
|
||||||
|
|
||||||
|
help & description(const std::string & text);
|
||||||
|
|
||||||
|
virtual std::string get_description_text(
|
||||||
|
const option_style &) const override
|
||||||
|
{
|
||||||
|
return description_text;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::unique_ptr<parser> clone() const override
|
||||||
|
{
|
||||||
|
return make_clone<help>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string description_text;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
help & help::description(const std::string &text)
|
||||||
|
----
|
||||||
|
|
||||||
|
Sets the given `text` as the general description to show with the help and
|
||||||
|
usage output for CLI parser. This text is displayed between the "Usage"
|
||||||
|
and "Options, arguments" sections.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
inline help & help::description(const std::string & text)
|
||||||
|
{
|
||||||
|
description_text = text;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace lyra
|
||||||
|
|
||||||
|
#endif
|
149
3party/lyra/lyra/literal.hpp
Normal file
149
3party/lyra/lyra/literal.hpp
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
// Copyright 2020-2022 René Ferdinand Rivera Morell
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
#ifndef LYRA_LITERAL_HPP
|
||||||
|
#define LYRA_LITERAL_HPP
|
||||||
|
|
||||||
|
#include "lyra/parser.hpp"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace lyra {
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_literal]
|
||||||
|
= `lyra::literal`
|
||||||
|
|
||||||
|
A parser that matches a single fixed value.
|
||||||
|
|
||||||
|
Is-a <<lyra_parser>>.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
class literal : public parser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Construction.
|
||||||
|
literal(std::string const & n);
|
||||||
|
|
||||||
|
// Help description.
|
||||||
|
literal & help(const std::string & help_description_text);
|
||||||
|
literal & operator()(std::string const & help_description_text);
|
||||||
|
|
||||||
|
// Singular argument allowed and required.
|
||||||
|
virtual detail::parser_cardinality cardinality() const override
|
||||||
|
{
|
||||||
|
return { 1, 1 };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal.
|
||||||
|
|
||||||
|
virtual std::string get_usage_text(const option_style &) const override
|
||||||
|
{
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::string get_description_text(
|
||||||
|
const option_style &) const override
|
||||||
|
{
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual help_text get_help_text(const option_style &) const override
|
||||||
|
{
|
||||||
|
return { { name, description } };
|
||||||
|
}
|
||||||
|
|
||||||
|
using parser::parse;
|
||||||
|
|
||||||
|
virtual parse_result parse(detail::token_iterator const & tokens,
|
||||||
|
const option_style &) const override
|
||||||
|
{
|
||||||
|
auto validationResult = validate();
|
||||||
|
if (!validationResult) return parse_result(validationResult);
|
||||||
|
|
||||||
|
auto const & token = tokens.argument();
|
||||||
|
if (name == token.name)
|
||||||
|
{
|
||||||
|
auto remainingTokens = tokens;
|
||||||
|
remainingTokens.pop(token);
|
||||||
|
return parse_result::ok(detail::parse_state(
|
||||||
|
parser_result_type::matched, remainingTokens));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return parse_result(parser_result::error(
|
||||||
|
parser_result_type::no_match, "Expected '" + name + "'."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::unique_ptr<parser> clone() const override
|
||||||
|
{
|
||||||
|
return make_clone<literal>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::string name;
|
||||||
|
std::string description;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_literal_ctor]
|
||||||
|
== Construction
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
=== Token
|
||||||
|
|
||||||
|
[#lyra_literal_ctor_token]
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
inline literal::literal(std::string const& n)
|
||||||
|
----
|
||||||
|
|
||||||
|
Constructs the literal with the name of the token to match.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
inline literal::literal(std::string const & n)
|
||||||
|
: name(n)
|
||||||
|
{}
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_literal_specification]
|
||||||
|
== Specification
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_literal_help]
|
||||||
|
=== `lyra:literal::help`
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
literal& literal::help(const std::string& help_description_text)
|
||||||
|
literal& literal::operator()(std::string const& help_description_text)
|
||||||
|
----
|
||||||
|
|
||||||
|
Specify a help description for the literal.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
inline literal & literal::help(const std::string & help_description_text)
|
||||||
|
{
|
||||||
|
description = help_description_text;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
inline literal & literal::operator()(std::string const & help_description_text)
|
||||||
|
{
|
||||||
|
return this->help(help_description_text);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace lyra
|
||||||
|
|
||||||
|
#endif
|
28
3party/lyra/lyra/lyra.hpp
Normal file
28
3party/lyra/lyra/lyra.hpp
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// Copyright 2018-2022 René Ferdinand Rivera Morell
|
||||||
|
// Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
#ifndef LYRA_LYRA_HPP
|
||||||
|
#define LYRA_LYRA_HPP
|
||||||
|
|
||||||
|
#include "lyra/version.hpp"
|
||||||
|
|
||||||
|
#include "lyra/arg.hpp"
|
||||||
|
#include "lyra/arguments.hpp"
|
||||||
|
#include "lyra/cli.hpp"
|
||||||
|
#include "lyra/cli_parser.hpp"
|
||||||
|
#include "lyra/command.hpp"
|
||||||
|
#include "lyra/exe_name.hpp"
|
||||||
|
#include "lyra/group.hpp"
|
||||||
|
#include "lyra/help.hpp"
|
||||||
|
#include "lyra/literal.hpp"
|
||||||
|
#include "lyra/main.hpp"
|
||||||
|
#include "lyra/opt.hpp"
|
||||||
|
#include "lyra/option_style.hpp"
|
||||||
|
#include "lyra/parser.hpp"
|
||||||
|
#include "lyra/parser_result.hpp"
|
||||||
|
#include "lyra/val.hpp"
|
||||||
|
|
||||||
|
#endif // LYRA_HPP_INCLUDED
|
244
3party/lyra/lyra/main.hpp
Normal file
244
3party/lyra/lyra/main.hpp
Normal file
@ -0,0 +1,244 @@
|
|||||||
|
// Copyright 2019-2022 René Ferdinand Rivera Morell
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
#ifndef LYRA_MAIN_HPP
|
||||||
|
#define LYRA_MAIN_HPP
|
||||||
|
|
||||||
|
#include "lyra/arg.hpp"
|
||||||
|
#include "lyra/args.hpp"
|
||||||
|
#include "lyra/cli.hpp"
|
||||||
|
#include "lyra/help.hpp"
|
||||||
|
#include "lyra/opt.hpp"
|
||||||
|
#include "lyra/parser.hpp"
|
||||||
|
#include "lyra/val.hpp"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace lyra {
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_main]
|
||||||
|
= `lyra::main`
|
||||||
|
|
||||||
|
Encapsulates the common use case of a main program that has a help option and
|
||||||
|
has a minimal way to specify and parse options. This provides for a way to
|
||||||
|
specify options and arguments in a simple function form. It handles checking for
|
||||||
|
errors and reporting problems.
|
||||||
|
|
||||||
|
*/ // end::reference[]
|
||||||
|
class main final : protected cli
|
||||||
|
{
|
||||||
|
bool show_help = false;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit main(const std::string & text = "");
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
main & operator()(const T & parser);
|
||||||
|
template <typename T>
|
||||||
|
main & add_argument(const T & parser);
|
||||||
|
template <typename T>
|
||||||
|
main & operator|=(const T & parser);
|
||||||
|
|
||||||
|
template <typename V>
|
||||||
|
main & operator()(
|
||||||
|
std::initializer_list<std::string> arg_names, V && default_value);
|
||||||
|
template <typename V>
|
||||||
|
main & operator()(const std::string & arg_name, V && default_value);
|
||||||
|
|
||||||
|
template <typename L>
|
||||||
|
int operator()(const args & argv, L action);
|
||||||
|
template <typename L>
|
||||||
|
int operator()(int argc, const char ** argv, L action);
|
||||||
|
|
||||||
|
using cli::operator[];
|
||||||
|
|
||||||
|
main & style(const option_style & style)
|
||||||
|
{
|
||||||
|
cli::style(style);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
main & style(option_style && style)
|
||||||
|
{
|
||||||
|
cli::style(style);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_main_ctor]
|
||||||
|
== Construction
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
main::main(const std::string & text);
|
||||||
|
----
|
||||||
|
|
||||||
|
Construct with text for description, which defaults to an empty string. The
|
||||||
|
description is specified for the help option that is added to the command line.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
inline main::main(const std::string & text)
|
||||||
|
{
|
||||||
|
this->add_argument(help(show_help).description(text));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_main_add_argument]
|
||||||
|
== Add Argument
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
template <typename T> main & main::operator()(const T & arg_parser)
|
||||||
|
template <typename T> main & main::add_argument(const T & arg_parser)
|
||||||
|
template <typename T> main & main::operator|=(const T & arg_parser)
|
||||||
|
----
|
||||||
|
|
||||||
|
Adds a parser as an argument to the command line. These forward directly to the
|
||||||
|
`lyra::cli` equivalents. The added parser can be any of the regular Lyra parsers
|
||||||
|
like `lyra::opt` or `lyra::arg`.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
template <typename T>
|
||||||
|
main & main::operator()(const T & arg_parser)
|
||||||
|
{
|
||||||
|
cli::add_argument(arg_parser);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
main & main::add_argument(const T & arg_parser)
|
||||||
|
{
|
||||||
|
cli::add_argument(arg_parser);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
main & main::operator|=(const T & arg_parser)
|
||||||
|
{
|
||||||
|
cli::operator|=(arg_parser);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_main_simple_args]
|
||||||
|
== Simple Args
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
template <typename V>
|
||||||
|
main & main::operator()(
|
||||||
|
std::initializer_list<std::string> arg_names, V && default_value)
|
||||||
|
template <typename V>
|
||||||
|
main & main::operator()(const std::string & arg_name, V && default_value)
|
||||||
|
----
|
||||||
|
|
||||||
|
Specifies, and adds, a new argument. Depending on the `arg_names` it can be
|
||||||
|
either a `lyra::opt` or `lyra::arg`. The first item in `arg_names` indicates
|
||||||
|
the type of argument created and added:
|
||||||
|
|
||||||
|
Specify either `-<name>` or `--<name>` to add a `lyra::opt`. You can specify as
|
||||||
|
many option names following the first name. A name that doesn't follow the
|
||||||
|
option syntax is considered the as the help text for the option.
|
||||||
|
|
||||||
|
Specify a non `-` prefixed name as the first item to signify a positional
|
||||||
|
`lyra::arg`.
|
||||||
|
|
||||||
|
The single `std::string` call is equivalent to specifying just the one option or
|
||||||
|
argument.
|
||||||
|
|
||||||
|
Example specifications:
|
||||||
|
|
||||||
|
|===
|
||||||
|
| `("-o", 0)` | Short `-o` option as `int` value.
|
||||||
|
| `("--opt", 0)` | Long `--opt` option as `int` value.
|
||||||
|
| `({"-o", "--opt"}, 1.0f)` | Short and long option as `float` value.
|
||||||
|
| `({"-o", "The option."}, 1.0f)` | Short option and help description as `float`
|
||||||
|
value.
|
||||||
|
| `("opt", 2)` | Positional, i.e. `lyra::arg`, argument as `int` value.
|
||||||
|
| `({"opt", "The option."}, 2)` | Positional argument and help description as
|
||||||
|
`int` value.
|
||||||
|
| `("--opt", std::vector<float>())` | Long option with as multiple
|
||||||
|
float values.
|
||||||
|
|===
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
template <typename V>
|
||||||
|
main & main::operator()(
|
||||||
|
std::initializer_list<std::string> arg_names, V && default_value)
|
||||||
|
{
|
||||||
|
auto bound_val = val(std::forward<V>(default_value));
|
||||||
|
if ((*arg_names.begin())[0] == '-')
|
||||||
|
{
|
||||||
|
// An option to add.
|
||||||
|
std::string hint = arg_names.begin()->substr(1);
|
||||||
|
if (hint[0] == '-') hint = hint.substr(1);
|
||||||
|
opt o(std::move(bound_val), hint);
|
||||||
|
for (auto arg_name : arg_names)
|
||||||
|
{
|
||||||
|
if (arg_name[0] == '-')
|
||||||
|
o.name(arg_name);
|
||||||
|
else
|
||||||
|
o.help(arg_name);
|
||||||
|
}
|
||||||
|
cli::add_argument(o);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// An argument to add.
|
||||||
|
arg a(std::move(bound_val), *arg_names.begin());
|
||||||
|
a.optional();
|
||||||
|
if (arg_names.size() > 2) a.help(*(arg_names.begin() + 1));
|
||||||
|
cli::add_argument(a);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
template <typename V>
|
||||||
|
main & main::operator()(const std::string & arg_name, V && default_value)
|
||||||
|
{
|
||||||
|
return (*this)({ arg_name }, std::forward<V>(default_value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_main_execute]
|
||||||
|
== Execute
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
template <typename L>
|
||||||
|
int main::operator()(const args & argv, L action)
|
||||||
|
template <typename L>
|
||||||
|
int main::operator()(int argc, const char ** argv, L action)
|
||||||
|
----
|
||||||
|
|
||||||
|
Executes the given action after parsing of the program input arguments. It
|
||||||
|
returns either `0` or `1` if the execution was successful or failed
|
||||||
|
respectively. The `action` is called with the `lyra::main` instance to provide
|
||||||
|
access to the parsed argument values.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
template <typename L>
|
||||||
|
int main::operator()(const args & argv, L action)
|
||||||
|
{
|
||||||
|
auto cli_result = cli::parse(argv);
|
||||||
|
if (!cli_result) std::cerr << cli_result.message() << "\n\n";
|
||||||
|
if (show_help || !cli_result)
|
||||||
|
std::cout << *this << "\n";
|
||||||
|
else
|
||||||
|
return action(*this);
|
||||||
|
return cli_result ? 0 : 1;
|
||||||
|
}
|
||||||
|
template <typename L>
|
||||||
|
int main::operator()(int argc, const char ** argv, L action)
|
||||||
|
{
|
||||||
|
return (*this)({ argc, argv }, action);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace lyra
|
||||||
|
|
||||||
|
#endif
|
372
3party/lyra/lyra/opt.hpp
Normal file
372
3party/lyra/lyra/opt.hpp
Normal file
@ -0,0 +1,372 @@
|
|||||||
|
// Copyright 2018-2022 René Ferdinand Rivera Morell
|
||||||
|
// Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
#ifndef LYRA_OPT_HPP
|
||||||
|
#define LYRA_OPT_HPP
|
||||||
|
|
||||||
|
#include "lyra/detail/print.hpp"
|
||||||
|
#include "lyra/detail/trait_utils.hpp"
|
||||||
|
#include "lyra/parser.hpp"
|
||||||
|
#include "lyra/val.hpp"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace lyra {
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_opt]
|
||||||
|
= `lyra::opt`
|
||||||
|
|
||||||
|
A parser for one option with multiple possible names. The option value(s) are
|
||||||
|
communicated through a reference to a variable, a container, or a callback.
|
||||||
|
|
||||||
|
Is-a <<lyra_bound_parser>>.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
class opt : public bound_parser<opt>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum class ctor_lambda_e
|
||||||
|
{
|
||||||
|
val
|
||||||
|
};
|
||||||
|
enum class ctor_ref_e
|
||||||
|
{
|
||||||
|
val
|
||||||
|
};
|
||||||
|
|
||||||
|
// Flag option ctors..
|
||||||
|
|
||||||
|
explicit opt(bool & ref);
|
||||||
|
|
||||||
|
template <typename L>
|
||||||
|
explicit opt(L const & ref,
|
||||||
|
typename std::enable_if<detail::is_invocable<L>::value,
|
||||||
|
ctor_lambda_e>::type
|
||||||
|
= ctor_lambda_e::val);
|
||||||
|
|
||||||
|
// Value option ctors..
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
opt(T & ref,
|
||||||
|
std::string const & hint,
|
||||||
|
typename std::enable_if<!detail::is_invocable<T>::value,
|
||||||
|
ctor_ref_e>::type
|
||||||
|
= ctor_ref_e::val);
|
||||||
|
|
||||||
|
template <typename L>
|
||||||
|
opt(L const & ref,
|
||||||
|
std::string const & hint,
|
||||||
|
typename std::enable_if<detail::is_invocable<L>::value,
|
||||||
|
ctor_lambda_e>::type
|
||||||
|
= ctor_lambda_e::val);
|
||||||
|
|
||||||
|
// Bound value ctors..
|
||||||
|
template <typename T>
|
||||||
|
explicit opt(detail::BoundVal<T> && val)
|
||||||
|
: bound_parser(val.move_to_shared())
|
||||||
|
{}
|
||||||
|
template <typename T>
|
||||||
|
explicit opt(detail::BoundVal<T> && val, std::string const & hint)
|
||||||
|
: bound_parser(val.move_to_shared(), hint)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// Option specifications..
|
||||||
|
|
||||||
|
opt & name(const std::string & opt_name);
|
||||||
|
opt & operator[](std::string const & opt_name);
|
||||||
|
|
||||||
|
// Internal..
|
||||||
|
|
||||||
|
virtual std::string get_usage_text(
|
||||||
|
const option_style & style) const override
|
||||||
|
{
|
||||||
|
std::string usage;
|
||||||
|
for (std::size_t o = 0; o < opt_names.size(); ++o)
|
||||||
|
{
|
||||||
|
if (o > 0) usage += "|";
|
||||||
|
usage += format_opt(opt_names[o], style);
|
||||||
|
}
|
||||||
|
if (!m_hint.empty()) usage += " <" + m_hint + ">";
|
||||||
|
return usage;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual help_text get_help_text(const option_style & style) const override
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
bool first = true;
|
||||||
|
for (auto const & opt_name : opt_names)
|
||||||
|
{
|
||||||
|
if (first)
|
||||||
|
first = false;
|
||||||
|
else
|
||||||
|
oss << ", ";
|
||||||
|
oss << format_opt(opt_name, style);
|
||||||
|
}
|
||||||
|
if (!m_hint.empty()) oss << " <" << m_hint << ">";
|
||||||
|
return { { oss.str(), m_description } };
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool is_named(const std::string & n) const override
|
||||||
|
{
|
||||||
|
return bound_parser::is_named(n)
|
||||||
|
|| (std::find(opt_names.begin(), opt_names.end(), n)
|
||||||
|
!= opt_names.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
using parser::parse;
|
||||||
|
|
||||||
|
parse_result parse(detail::token_iterator const & tokens,
|
||||||
|
const option_style & style) const override
|
||||||
|
{
|
||||||
|
LYRA_PRINT_SCOPE("opt::parse");
|
||||||
|
auto validationResult = validate();
|
||||||
|
if (!validationResult) return parse_result(validationResult);
|
||||||
|
|
||||||
|
auto remainingTokens = tokens;
|
||||||
|
if (remainingTokens && remainingTokens.has_option_prefix())
|
||||||
|
{
|
||||||
|
auto const & token = remainingTokens.option();
|
||||||
|
if (is_match(token.name, style))
|
||||||
|
{
|
||||||
|
if (m_ref->isFlag())
|
||||||
|
{
|
||||||
|
if (remainingTokens.has_value_delimiter())
|
||||||
|
{
|
||||||
|
return parse_result::error(
|
||||||
|
{ parser_result_type::short_circuit_all,
|
||||||
|
remainingTokens },
|
||||||
|
"Flag option '" + token.name + "' contains value '"
|
||||||
|
+ remainingTokens.value().name + "'.");
|
||||||
|
}
|
||||||
|
remainingTokens.pop(token);
|
||||||
|
auto flagRef
|
||||||
|
= static_cast<detail::BoundFlagRefBase *>(m_ref.get());
|
||||||
|
auto flag_result = flagRef->setFlag(true);
|
||||||
|
if (!flag_result) return parse_result(flag_result);
|
||||||
|
LYRA_PRINT_DEBUG(
|
||||||
|
"(=)", get_usage_text(style), "==", token.name);
|
||||||
|
if (flag_result.value() == parser_result_type::short_circuit_all)
|
||||||
|
return parse_result::ok(detail::parse_state(
|
||||||
|
flag_result.value(), remainingTokens));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto const & argToken = remainingTokens.value();
|
||||||
|
if (argToken.type == detail::token_type::unknown)
|
||||||
|
return parse_result::error(
|
||||||
|
{ parser_result_type::no_match, remainingTokens },
|
||||||
|
"Expected argument following " + token.name);
|
||||||
|
remainingTokens.pop(token, argToken);
|
||||||
|
auto valueRef
|
||||||
|
= static_cast<detail::BoundValueRefBase *>(m_ref.get());
|
||||||
|
if (value_choices)
|
||||||
|
{
|
||||||
|
auto choice_result
|
||||||
|
= value_choices->contains_value(argToken.name);
|
||||||
|
if (!choice_result) return parse_result(choice_result);
|
||||||
|
}
|
||||||
|
auto v_result = valueRef->setValue(argToken.name);
|
||||||
|
if (!v_result)
|
||||||
|
{
|
||||||
|
// Matched the option, but not the value. This is a
|
||||||
|
// hard fail that needs to skip subsequent parsing.
|
||||||
|
return parse_result::error(
|
||||||
|
{ parser_result_type::short_circuit_all,
|
||||||
|
remainingTokens },
|
||||||
|
v_result.message());
|
||||||
|
}
|
||||||
|
LYRA_PRINT_DEBUG("(=)", get_usage_text(style),
|
||||||
|
"==", token.name, argToken.name);
|
||||||
|
if (v_result.value() == parser_result_type::short_circuit_all)
|
||||||
|
return parse_result::ok(detail::parse_state(
|
||||||
|
v_result.value(), remainingTokens));
|
||||||
|
}
|
||||||
|
return parse_result::ok(detail::parse_state(
|
||||||
|
parser_result_type::matched, remainingTokens));
|
||||||
|
}
|
||||||
|
LYRA_PRINT_DEBUG("(!)", get_usage_text(style), "!= ", token.name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LYRA_PRINT_DEBUG("(!)", get_usage_text(style),
|
||||||
|
"!=", remainingTokens.argument().name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parse_result::ok(
|
||||||
|
detail::parse_state(parser_result_type::no_match, remainingTokens));
|
||||||
|
}
|
||||||
|
|
||||||
|
result validate() const override
|
||||||
|
{
|
||||||
|
if (opt_names.empty())
|
||||||
|
return result::error("No options supplied to opt");
|
||||||
|
if (m_ref->isFlag() && value_choices)
|
||||||
|
return result::error("Flag options cannot contain choices.");
|
||||||
|
for (auto const & name : opt_names)
|
||||||
|
{
|
||||||
|
if (name.empty())
|
||||||
|
return result::error("Option name cannot be empty");
|
||||||
|
if (name[0] != '-')
|
||||||
|
return result::error("Option name must begin with '-'");
|
||||||
|
}
|
||||||
|
return bound_parser::validate();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::unique_ptr<parser> clone() const override
|
||||||
|
{
|
||||||
|
return make_clone<opt>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::vector<std::string> opt_names;
|
||||||
|
|
||||||
|
bool is_match(
|
||||||
|
std::string const & opt_name, const option_style & style) const
|
||||||
|
{
|
||||||
|
auto opt_normalized = normalise_opt(opt_name, style);
|
||||||
|
for (auto const & name : opt_names)
|
||||||
|
{
|
||||||
|
if (normalise_opt(name, style) == opt_normalized) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string normalise_opt(
|
||||||
|
std::string const & opt_name, const option_style & style) const
|
||||||
|
{
|
||||||
|
if (detail::token_iterator::is_prefixed(
|
||||||
|
style.short_option_prefix, style.short_option_size, opt_name))
|
||||||
|
return std::string("-") + opt_name.substr(style.short_option_size);
|
||||||
|
|
||||||
|
if (detail::token_iterator::is_prefixed(
|
||||||
|
style.long_option_prefix, style.long_option_size, opt_name))
|
||||||
|
return std::string("--") + opt_name.substr(style.long_option_size);
|
||||||
|
|
||||||
|
return opt_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string format_opt(
|
||||||
|
std::string const & opt_name, const option_style & style) const
|
||||||
|
{
|
||||||
|
if (opt_name[0] == '-' && opt_name[1] == '-')
|
||||||
|
return style.long_option_string() + opt_name.substr(2);
|
||||||
|
else if (opt_name[0] == '-')
|
||||||
|
return style.short_option_string() + opt_name.substr(1);
|
||||||
|
else
|
||||||
|
return opt_name;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_opt_ctor]
|
||||||
|
== Construction
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_opt_ctor_flags]
|
||||||
|
=== Flags
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
lyra::opt::opt(bool& ref);
|
||||||
|
|
||||||
|
template <typename L>
|
||||||
|
lyra::opt::opt(L const& ref);
|
||||||
|
----
|
||||||
|
|
||||||
|
Constructs a flag option with a target `bool` to indicate if the flag is
|
||||||
|
present. The first form takes a reference to a variable to receive the
|
||||||
|
`bool`. The second takes a callback that is called with `true` when the
|
||||||
|
option is present.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
inline opt::opt(bool & ref)
|
||||||
|
: bound_parser(std::make_shared<detail::BoundFlagRef>(ref))
|
||||||
|
{}
|
||||||
|
template <typename L>
|
||||||
|
opt::opt(L const & ref,
|
||||||
|
typename std::enable_if<detail::is_invocable<L>::value,
|
||||||
|
opt::ctor_lambda_e>::type)
|
||||||
|
: bound_parser(std::make_shared<detail::BoundFlagLambda<L>>(ref))
|
||||||
|
{}
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_opt_ctor_values]
|
||||||
|
=== Values
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
template <typename T>
|
||||||
|
lyra::opt::opt(T& ref, std::string const& hint);
|
||||||
|
|
||||||
|
template <typename L>
|
||||||
|
lyra::opt::opt(L const& ref, std::string const& hint)
|
||||||
|
----
|
||||||
|
|
||||||
|
Constructs a value option with a target `ref`. The first form takes a reference
|
||||||
|
to a variable to receive the value. The second takes a callback that is called
|
||||||
|
with the value when the option is present.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
template <typename T>
|
||||||
|
opt::opt(T & ref,
|
||||||
|
std::string const & hint,
|
||||||
|
typename std::enable_if<!detail::is_invocable<T>::value,
|
||||||
|
opt::ctor_ref_e>::type)
|
||||||
|
: bound_parser(ref, hint)
|
||||||
|
{}
|
||||||
|
template <typename L>
|
||||||
|
opt::opt(L const & ref,
|
||||||
|
std::string const & hint,
|
||||||
|
typename std::enable_if<detail::is_invocable<L>::value,
|
||||||
|
opt::ctor_lambda_e>::type)
|
||||||
|
: bound_parser(ref, hint)
|
||||||
|
{}
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_opt_specification]
|
||||||
|
== Specification
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_opt_name]
|
||||||
|
=== `lyra::opt::name`
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
lyra::opt& lyra::opt::name(const std::string &opt_name)
|
||||||
|
lyra::opt& lyra::opt::operator[](const std::string &opt_name)
|
||||||
|
----
|
||||||
|
|
||||||
|
Add a spelling for the option of the form `--<name>` or `-n`.
|
||||||
|
One can add multiple short spellings at once with `-abc`.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
inline opt & opt::name(const std::string & opt_name)
|
||||||
|
{
|
||||||
|
if (opt_name.size() > 2 && opt_name[0] == '-' && opt_name[1] != '-')
|
||||||
|
for (auto o : opt_name.substr(1))
|
||||||
|
opt_names.push_back(std::string(1, opt_name[0]) + o);
|
||||||
|
else
|
||||||
|
opt_names.push_back(opt_name);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
inline opt & opt::operator[](const std::string & opt_name)
|
||||||
|
{
|
||||||
|
return this->name(opt_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace lyra
|
||||||
|
|
||||||
|
#endif
|
169
3party/lyra/lyra/option_style.hpp
Normal file
169
3party/lyra/lyra/option_style.hpp
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
// Copyright 2021-2022 René Ferdinand Rivera Morell
|
||||||
|
|
||||||
|
#ifndef LYRA_OPTION_STYLE_HPP
|
||||||
|
#define LYRA_OPTION_STYLE_HPP
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace lyra {
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_option_style]
|
||||||
|
= `lyra::option_style`
|
||||||
|
|
||||||
|
Specify the syntax style for options to the parser.
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
std::string value_delimiters;
|
||||||
|
std::string long_option_prefix;
|
||||||
|
std::size_t long_option_size = 0;
|
||||||
|
std::string short_option_prefix;
|
||||||
|
std::size_t short_option_size = 0;
|
||||||
|
----
|
||||||
|
|
||||||
|
* `value_delimiters` -- Specifies a set of characters that are accepted as a
|
||||||
|
delimiter/separator between an option name and an option value when a
|
||||||
|
single argument is used for the option+value (i.e. "--option=value").
|
||||||
|
* `long_option_prefix` -- Specifies a set of characters that are accepted as a
|
||||||
|
prefix for long options (i.e. multi-char single option name).
|
||||||
|
* `long_option_size` -- The number of prefix characters that indicates a long
|
||||||
|
option. A value of zero (0) indicates that long options are not accepted.
|
||||||
|
* `short_option_prefix` -- Specifies a set of characters that are accepted as a
|
||||||
|
prefix for short options (i.e. single-char multi-options).
|
||||||
|
* `short_option_size` -- The number of prefix characters that indicates a short
|
||||||
|
option. A value of zero (0) indicates that short options are not accepted.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
struct option_style
|
||||||
|
{
|
||||||
|
std::string value_delimiters;
|
||||||
|
std::string long_option_prefix;
|
||||||
|
std::size_t long_option_size = 0;
|
||||||
|
std::string short_option_prefix;
|
||||||
|
std::size_t short_option_size = 0;
|
||||||
|
|
||||||
|
// Construction..
|
||||||
|
|
||||||
|
option_style(std::string && value_delimiters_chars,
|
||||||
|
std::string && long_option_prefix_chars = {},
|
||||||
|
std::size_t long_option_prefix_size = 0,
|
||||||
|
std::string && short_option_prefix_chars = {},
|
||||||
|
std::size_t short_option_prefix_size = 0)
|
||||||
|
: value_delimiters(std::move(value_delimiters_chars))
|
||||||
|
, long_option_prefix(std::move(long_option_prefix_chars))
|
||||||
|
, long_option_size(long_option_prefix_size)
|
||||||
|
, short_option_prefix(std::move(short_option_prefix_chars))
|
||||||
|
, short_option_size(short_option_prefix_size)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// Definitions..
|
||||||
|
|
||||||
|
std::string long_option_string() const;
|
||||||
|
std::string short_option_string() const;
|
||||||
|
|
||||||
|
// Styles..
|
||||||
|
|
||||||
|
static const option_style & posix();
|
||||||
|
static const option_style & posix_brief();
|
||||||
|
static const option_style & windows();
|
||||||
|
};
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_option_style_ctor]
|
||||||
|
== Construction
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
lyra::option_style::option_style(
|
||||||
|
std::string && value_delimiters,
|
||||||
|
std::string && long_option_prefix = {},
|
||||||
|
std::size_t long_option_size = 0,
|
||||||
|
std::string && short_option_prefix = {},
|
||||||
|
std::size_t short_option_size = 0)
|
||||||
|
----
|
||||||
|
|
||||||
|
Utility constructor that defines all the settings.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_option_style_def]
|
||||||
|
== Definitions
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
std::string lyra::option_style::long_option_string() const
|
||||||
|
std::string lyra::option_style::short_option_string() const
|
||||||
|
----
|
||||||
|
|
||||||
|
Gives the default long or short option string, or prefix, for this option
|
||||||
|
style. If the type of option is not available, i.e. size is zero, an empty
|
||||||
|
string is returned.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
|
||||||
|
inline std::string option_style::long_option_string() const
|
||||||
|
{
|
||||||
|
return long_option_size > 0
|
||||||
|
? std::string(long_option_size, long_option_prefix[0])
|
||||||
|
: "";
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string option_style::short_option_string() const
|
||||||
|
{
|
||||||
|
return short_option_size > 0
|
||||||
|
? std::string(short_option_size, short_option_prefix[0])
|
||||||
|
: "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_option_style_styles]
|
||||||
|
== Styles
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
static const option_style & lyra::option_style::posix();
|
||||||
|
static const option_style & lyra::option_style::posix_brief();
|
||||||
|
static const option_style & lyra::option_style::windows();
|
||||||
|
----
|
||||||
|
|
||||||
|
These provide definitions for common syntax of option styles:
|
||||||
|
|
||||||
|
`posix`:: The overall _default_ that is two dashes (`--`) for long option
|
||||||
|
names and one dash (`-`) for short option names. Values for long options
|
||||||
|
use equal (`=`) between the option and value.
|
||||||
|
`posix_brief`:: Variant that only allows for long option names with a single
|
||||||
|
dash (`-`).
|
||||||
|
`windows`:: The common option style on Windows `CMD.EXE` shell. It only allows
|
||||||
|
long name options that start with slash (`/`) where the value is
|
||||||
|
specified after a colon (`:`). Single character flag style options are
|
||||||
|
only available as individual long options, for example `/A`.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
|
||||||
|
inline const option_style & option_style::posix()
|
||||||
|
{
|
||||||
|
static const option_style style("= ", "-", 2, "-", 1);
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const option_style & option_style::posix_brief()
|
||||||
|
{
|
||||||
|
static const option_style style("= ", "-", 1);
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const option_style & option_style::windows()
|
||||||
|
{
|
||||||
|
static const option_style style(":", "/", 1);
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace lyra
|
||||||
|
|
||||||
|
#endif
|
647
3party/lyra/lyra/parser.hpp
Normal file
647
3party/lyra/lyra/parser.hpp
Normal file
@ -0,0 +1,647 @@
|
|||||||
|
// Copyright 2018-2022 René Ferdinand Rivera Morell
|
||||||
|
// Copyright 2021 Max Ferger
|
||||||
|
// Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
#ifndef LYRA_PARSER_HPP
|
||||||
|
#define LYRA_PARSER_HPP
|
||||||
|
|
||||||
|
#include "lyra/args.hpp"
|
||||||
|
#include "lyra/detail/bound.hpp"
|
||||||
|
#include "lyra/detail/choices.hpp"
|
||||||
|
#include "lyra/detail/from_string.hpp"
|
||||||
|
#include "lyra/detail/result.hpp"
|
||||||
|
#include "lyra/detail/tokens.hpp"
|
||||||
|
#include "lyra/detail/trait_utils.hpp"
|
||||||
|
#include "lyra/option_style.hpp"
|
||||||
|
#include "lyra/parser_result.hpp"
|
||||||
|
#include "lyra/val.hpp"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace lyra {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
class parse_state
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
parse_state(parser_result_type type,
|
||||||
|
token_iterator const & remaining_tokens,
|
||||||
|
size_t parsed_tokens = 0)
|
||||||
|
: result_type(type)
|
||||||
|
, tokens(remaining_tokens)
|
||||||
|
{
|
||||||
|
(void)parsed_tokens;
|
||||||
|
}
|
||||||
|
|
||||||
|
parser_result_type type() const { return result_type; }
|
||||||
|
token_iterator remainingTokens() const { return tokens; }
|
||||||
|
bool have_tokens() const { return bool(tokens); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
parser_result_type result_type;
|
||||||
|
token_iterator tokens;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct parser_cardinality
|
||||||
|
{
|
||||||
|
size_t minimum = 0;
|
||||||
|
size_t maximum = 0;
|
||||||
|
|
||||||
|
parser_cardinality() = default;
|
||||||
|
|
||||||
|
parser_cardinality(size_t a, size_t b)
|
||||||
|
: minimum(a)
|
||||||
|
, maximum(b)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// If zero or more are accepted, it's optional.
|
||||||
|
bool is_optional() const { return (minimum == 0); }
|
||||||
|
|
||||||
|
// Anything that doesn't have an upper bound is considered unbounded.
|
||||||
|
bool is_unbounded() const { return (maximum == 0); }
|
||||||
|
|
||||||
|
bool is_bounded() const { return !is_unbounded(); }
|
||||||
|
|
||||||
|
// If one or more values are expected, it's required.
|
||||||
|
bool is_required() const { return (minimum > 0); }
|
||||||
|
|
||||||
|
void optional()
|
||||||
|
{
|
||||||
|
minimum = 0;
|
||||||
|
maximum = 1;
|
||||||
|
}
|
||||||
|
void required(size_t n = 1)
|
||||||
|
{
|
||||||
|
minimum = n;
|
||||||
|
maximum = n;
|
||||||
|
}
|
||||||
|
void counted(size_t n)
|
||||||
|
{
|
||||||
|
minimum = n;
|
||||||
|
maximum = n;
|
||||||
|
}
|
||||||
|
void bounded(size_t n, size_t m)
|
||||||
|
{
|
||||||
|
minimum = n;
|
||||||
|
maximum = m;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_parser_result]
|
||||||
|
= `lyra::parser_result`
|
||||||
|
|
||||||
|
The result of parsing arguments.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
class parse_result : public detail::basic_result<detail::parse_state>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using base = detail::basic_result<detail::parse_state>;
|
||||||
|
using base::basic_result;
|
||||||
|
using base::error;
|
||||||
|
using base::ok;
|
||||||
|
|
||||||
|
parse_result(const base & other)
|
||||||
|
: base(other)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_parser]
|
||||||
|
= `lyra::parser`
|
||||||
|
|
||||||
|
Base for all argument parser types.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
class parser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct help_text_item
|
||||||
|
{
|
||||||
|
std::string option;
|
||||||
|
std::string description;
|
||||||
|
};
|
||||||
|
|
||||||
|
using help_text = std::vector<help_text_item>;
|
||||||
|
|
||||||
|
[[deprecated]] help_text get_help_text() const { return {}; }
|
||||||
|
[[deprecated]] std::string get_usage_text() const { return ""; }
|
||||||
|
[[deprecated]] std::string get_description_text() const { return ""; }
|
||||||
|
|
||||||
|
virtual help_text get_help_text(const option_style &) const { return {}; }
|
||||||
|
virtual std::string get_usage_text(const option_style &) const
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
virtual std::string get_description_text(const option_style &) const
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~parser() = default;
|
||||||
|
|
||||||
|
virtual detail::parser_cardinality cardinality() const { return { 0, 1 }; }
|
||||||
|
bool is_optional() const { return cardinality().is_optional(); }
|
||||||
|
virtual bool is_group() const { return false; }
|
||||||
|
virtual result validate() const { return result::ok(); }
|
||||||
|
virtual std::unique_ptr<parser> clone() const { return nullptr; }
|
||||||
|
virtual bool is_named(const std::string & n) const
|
||||||
|
{
|
||||||
|
(void)n;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
virtual const parser * get_named(const std::string & n) const
|
||||||
|
{
|
||||||
|
if (is_named(n)) return this;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
virtual size_t get_value_count() const { return 0; }
|
||||||
|
virtual std::string get_value(size_t i) const
|
||||||
|
{
|
||||||
|
(void)i;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual parse_result parse(detail::token_iterator const & tokens,
|
||||||
|
const option_style & style) const = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void print_help_text(std::ostream & os, const option_style & style) const
|
||||||
|
{
|
||||||
|
std::string usage_test = get_usage_text(style);
|
||||||
|
if (!usage_test.empty())
|
||||||
|
os << "USAGE:\n"
|
||||||
|
<< " " << get_usage_text(style) << "\n\n";
|
||||||
|
|
||||||
|
std::string description_test = get_description_text(style);
|
||||||
|
if (!description_test.empty())
|
||||||
|
os << get_description_text(style) << "\n";
|
||||||
|
|
||||||
|
os << "OPTIONS, ARGUMENTS:\n";
|
||||||
|
const std::string::size_type left_col_size = 26 - 3;
|
||||||
|
const std::string left_pad(left_col_size, ' ');
|
||||||
|
for (auto const & cols : get_help_text(style))
|
||||||
|
{
|
||||||
|
if (cols.option.size() > left_pad.size())
|
||||||
|
os << " " << cols.option << "\n " << left_pad << " "
|
||||||
|
<< cols.description << "\n";
|
||||||
|
else
|
||||||
|
os << " " << cols.option
|
||||||
|
<< left_pad.substr(0, left_pad.size() - cols.option.size())
|
||||||
|
<< " " << cols.description << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_parser_specification]
|
||||||
|
== Specification
|
||||||
|
|
||||||
|
[#lyra_parser_help_text_item]
|
||||||
|
=== `lyra::parser::help_text_item`
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
struct lyra::parser::help_text_item
|
||||||
|
{
|
||||||
|
std::string option;
|
||||||
|
std::string description;
|
||||||
|
};
|
||||||
|
----
|
||||||
|
|
||||||
|
Holds the help information for a single argument option. The `option` member is
|
||||||
|
the long name of the option. And the `description` is the text describing the
|
||||||
|
option. A list of them is returned from the `lyra::parser::get_help_text`
|
||||||
|
method.
|
||||||
|
|
||||||
|
[#lyra_parser_help_text]
|
||||||
|
=== `lyra::parser::help_text`
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
using help_text = std::vector<help_text_item>;
|
||||||
|
----
|
||||||
|
|
||||||
|
The set of help texts for any options in the sub-parsers to this one, if any.
|
||||||
|
|
||||||
|
[#lyra_parser_get_help_text]
|
||||||
|
=== `lyra::parser::get_help_text`
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
virtual help_text get_help_text(const option_style &) const;
|
||||||
|
----
|
||||||
|
|
||||||
|
Collects, and returns, the set of help items for the sub-parser arguments in
|
||||||
|
this parser, if any. The default is to return an empty set. Which is what most
|
||||||
|
parsers will return. Parsers like `arguments`, `group`, and `cli` will return a
|
||||||
|
set for the arguments defined. This is called to print out the help text from
|
||||||
|
the stream operator.
|
||||||
|
|
||||||
|
[#lyra_parser_get_usage_text]
|
||||||
|
=== `lyra::parser::get_usage_text`
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
virtual std::string get_usage_text(const option_style &) const;
|
||||||
|
----
|
||||||
|
|
||||||
|
Returns the formatted `USAGE` text for this parser, and any contained
|
||||||
|
sub-parsers. This is called to print out the help text from the stream operator.
|
||||||
|
|
||||||
|
[#lyra_parser_get_description_text]
|
||||||
|
=== `lyra::parser::get_description_text`
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
virtual std::string get_description_text(const option_style &) const;
|
||||||
|
----
|
||||||
|
|
||||||
|
Returns the description text for this, and any contained sub-parsers. This is
|
||||||
|
called to print out the help text from the stream operator.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
|
||||||
|
template <typename T, typename U>
|
||||||
|
std::unique_ptr<parser> make_clone(const U * source)
|
||||||
|
{
|
||||||
|
return std::unique_ptr<parser>(new T(*static_cast<const T *>(source)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_composable_parser]
|
||||||
|
= `lyra::composable_parser`
|
||||||
|
|
||||||
|
A parser that can be composed with other parsers using `operator|`. Composing
|
||||||
|
two `composable_parser` instances generates a `cli` parser.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
template <typename Derived>
|
||||||
|
class composable_parser : public parser
|
||||||
|
{};
|
||||||
|
|
||||||
|
// Common code and state for args and Opts
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_bound_parser]
|
||||||
|
= `lyra::bound_parser`
|
||||||
|
|
||||||
|
Parser that binds a variable reference or callback to the value of an argument.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
template <typename Derived>
|
||||||
|
class bound_parser : public composable_parser<Derived>
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
std::shared_ptr<detail::BoundRef> m_ref;
|
||||||
|
std::string m_hint;
|
||||||
|
std::string m_description;
|
||||||
|
detail::parser_cardinality m_cardinality;
|
||||||
|
std::shared_ptr<detail::choices_base> value_choices;
|
||||||
|
|
||||||
|
explicit bound_parser(std::shared_ptr<detail::BoundRef> const & ref)
|
||||||
|
: m_ref(ref)
|
||||||
|
{
|
||||||
|
if (m_ref->isContainer())
|
||||||
|
m_cardinality = { 0, 0 };
|
||||||
|
else
|
||||||
|
m_cardinality = { 0, 1 };
|
||||||
|
}
|
||||||
|
bound_parser(
|
||||||
|
std::shared_ptr<detail::BoundRef> const & ref, std::string const & hint)
|
||||||
|
: m_ref(ref)
|
||||||
|
, m_hint(hint)
|
||||||
|
{
|
||||||
|
if (m_ref->isContainer())
|
||||||
|
m_cardinality = { 0, 0 };
|
||||||
|
else
|
||||||
|
m_cardinality = { 0, 1 };
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum class ctor_lambda_e
|
||||||
|
{
|
||||||
|
val
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Reference>
|
||||||
|
bound_parser(Reference & ref, std::string const & hint);
|
||||||
|
|
||||||
|
template <typename Lambda>
|
||||||
|
bound_parser(Lambda const & ref,
|
||||||
|
std::string const & hint,
|
||||||
|
typename std::enable_if<detail::is_invocable<Lambda>::value,
|
||||||
|
ctor_lambda_e>::type
|
||||||
|
= ctor_lambda_e::val);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
explicit bound_parser(detail::BoundVal<T> && val)
|
||||||
|
: bound_parser(val.move_to_shared())
|
||||||
|
{}
|
||||||
|
template <typename T>
|
||||||
|
bound_parser(detail::BoundVal<T> && val, std::string const & hint)
|
||||||
|
: bound_parser(val.move_to_shared(), hint)
|
||||||
|
{}
|
||||||
|
|
||||||
|
Derived & help(const std::string & text);
|
||||||
|
Derived & operator()(std::string const & description);
|
||||||
|
Derived & optional();
|
||||||
|
Derived & required(size_t n = 1);
|
||||||
|
Derived & cardinality(size_t n);
|
||||||
|
Derived & cardinality(size_t n, size_t m);
|
||||||
|
detail::parser_cardinality cardinality() const override
|
||||||
|
{
|
||||||
|
return m_cardinality;
|
||||||
|
}
|
||||||
|
std::string hint() const;
|
||||||
|
Derived & hint(std::string const & hint);
|
||||||
|
|
||||||
|
template <typename T,
|
||||||
|
typename... Rest,
|
||||||
|
typename std::enable_if<!detail::is_invocable<T>::value, int>::type = 0>
|
||||||
|
Derived & choices(T val0, Rest... rest);
|
||||||
|
template <typename Lambda,
|
||||||
|
typename std::enable_if<detail::is_invocable<Lambda>::value, int>::type
|
||||||
|
= 1>
|
||||||
|
Derived & choices(Lambda const & check_choice);
|
||||||
|
template <typename T, std::size_t N>
|
||||||
|
Derived & choices(const T (&choice_values)[N]);
|
||||||
|
|
||||||
|
virtual std::unique_ptr<parser> clone() const override
|
||||||
|
{
|
||||||
|
return make_clone<Derived>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool is_named(const std::string & n) const override
|
||||||
|
{
|
||||||
|
return n == m_hint;
|
||||||
|
}
|
||||||
|
virtual size_t get_value_count() const override
|
||||||
|
{
|
||||||
|
return m_ref->get_value_count();
|
||||||
|
}
|
||||||
|
virtual std::string get_value(size_t i) const override
|
||||||
|
{
|
||||||
|
return m_ref->get_value(i);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_bound_parser_ctor]
|
||||||
|
== Construction
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
template <typename Derived>
|
||||||
|
template <typename Reference>
|
||||||
|
bound_parser<Derived>::bound_parser(Reference& ref, std::string const& hint);
|
||||||
|
|
||||||
|
template <typename Derived>
|
||||||
|
template <typename Lambda>
|
||||||
|
bound_parser<Derived>::bound_parser(Lambda const& ref, std::string const& hint);
|
||||||
|
----
|
||||||
|
|
||||||
|
Constructs a value option with a target typed variable or callback. These are
|
||||||
|
options that take a value as in `--opt=value`. In the first form the given
|
||||||
|
`ref` receives the value of the option after parsing. The second form the
|
||||||
|
callback is called during the parse with the given value. Both take a
|
||||||
|
`hint` that is used in the help text. When the option can be specified
|
||||||
|
multiple times the callback will be called consecutively for each option value
|
||||||
|
given. And if a container is given as a reference on the first form it will
|
||||||
|
contain all the specified values.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
template <typename Derived>
|
||||||
|
template <typename Reference>
|
||||||
|
bound_parser<Derived>::bound_parser(Reference & ref, std::string const & hint)
|
||||||
|
: bound_parser(
|
||||||
|
std::make_shared<detail::BoundValueRef<Reference>>(ref), hint)
|
||||||
|
{}
|
||||||
|
|
||||||
|
template <typename Derived>
|
||||||
|
template <typename Lambda>
|
||||||
|
bound_parser<Derived>::bound_parser(Lambda const & ref,
|
||||||
|
std::string const & hint,
|
||||||
|
typename std::enable_if<detail::is_invocable<Lambda>::value,
|
||||||
|
ctor_lambda_e>::type)
|
||||||
|
: bound_parser(std::make_shared<detail::BoundLambda<Lambda>>(ref), hint)
|
||||||
|
{}
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_bound_parser_specification]
|
||||||
|
== Specification
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_bound_parser_help]
|
||||||
|
=== `lyra::bound_parser::help`, `lyra::bound_parser::operator(help)`
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
template <typename Derived>
|
||||||
|
Derived& bound_parser<Derived>::help(std::string const& help_description_text);
|
||||||
|
template <typename Derived>
|
||||||
|
Derived& bound_parser<Derived>::operator()(std::string const& help_description_text);
|
||||||
|
----
|
||||||
|
|
||||||
|
Defines the help description of an argument.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
template <typename Derived>
|
||||||
|
Derived & bound_parser<Derived>::help(const std::string & help_description_text)
|
||||||
|
{
|
||||||
|
m_description = help_description_text;
|
||||||
|
return static_cast<Derived &>(*this);
|
||||||
|
}
|
||||||
|
template <typename Derived>
|
||||||
|
Derived & bound_parser<Derived>::operator()(std::string const & help_description_text)
|
||||||
|
{
|
||||||
|
return this->help(help_description_text);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_bound_parser_optional]
|
||||||
|
=== `lyra::bound_parser::optional`
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
template <typename Derived>
|
||||||
|
Derived& bound_parser<Derived>::optional();
|
||||||
|
----
|
||||||
|
|
||||||
|
Indicates that the argument is optional. This is equivalent to specifying
|
||||||
|
`cardinality(0, 1)`.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
template <typename Derived>
|
||||||
|
Derived & bound_parser<Derived>::optional()
|
||||||
|
{
|
||||||
|
return this->cardinality(0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_bound_parser_required]
|
||||||
|
=== `lyra::bound_parser::required(n)`
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
template <typename Derived>
|
||||||
|
Derived& bound_parser<Derived>::required(size_t n);
|
||||||
|
----
|
||||||
|
|
||||||
|
Specifies that the argument needs to given the number of `n` times
|
||||||
|
(defaults to *1*).
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
template <typename Derived>
|
||||||
|
Derived & bound_parser<Derived>::required(size_t n)
|
||||||
|
{
|
||||||
|
if (m_ref->isContainer())
|
||||||
|
return this->cardinality(1, 0);
|
||||||
|
else
|
||||||
|
return this->cardinality(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_bound_parser_cardinality]
|
||||||
|
=== `lyra::bound_parser::cardinality(n, m)`
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
template <typename Derived>
|
||||||
|
Derived& bound_parser<Derived>::cardinality(size_t n);
|
||||||
|
|
||||||
|
template <typename Derived>
|
||||||
|
Derived& bound_parser<Derived>::cardinality(size_t n, size_t m);
|
||||||
|
----
|
||||||
|
|
||||||
|
Specifies the number of times the argument can and needs to appear in the list
|
||||||
|
of arguments. In the first form the argument can appear exactly `n` times. In
|
||||||
|
the second form it specifies that the argument can appear from `n` to `m` times
|
||||||
|
inclusive.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
template <typename Derived>
|
||||||
|
Derived & bound_parser<Derived>::cardinality(size_t n)
|
||||||
|
{
|
||||||
|
m_cardinality = { n, n };
|
||||||
|
return static_cast<Derived &>(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Derived>
|
||||||
|
Derived & bound_parser<Derived>::cardinality(size_t n, size_t m)
|
||||||
|
{
|
||||||
|
m_cardinality = { n, m };
|
||||||
|
return static_cast<Derived &>(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_bound_parser_choices]
|
||||||
|
=== `lyra::bound_parser::choices`
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
template <typename Derived>
|
||||||
|
template <typename T, typename... Rest>
|
||||||
|
lyra::opt& lyra::bound_parser<Derived>::choices(T val0, Rest... rest)
|
||||||
|
|
||||||
|
template <typename Derived>
|
||||||
|
template <typename Lambda>
|
||||||
|
lyra::opt& lyra::bound_parser<Derived>::choices(Lambda const &check_choice)
|
||||||
|
----
|
||||||
|
|
||||||
|
Limit the allowed values of an argument. In the first form the value is
|
||||||
|
limited to the ones listed in the call (two or more values). In the second
|
||||||
|
form the `check_choice` function is called with the parsed value and returns
|
||||||
|
`true` if it's an allowed value.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
template <typename Derived>
|
||||||
|
template <typename T,
|
||||||
|
typename... Rest,
|
||||||
|
typename std::enable_if<!detail::is_invocable<T>::value, int>::type>
|
||||||
|
Derived & bound_parser<Derived>::choices(T val0, Rest... rest)
|
||||||
|
{
|
||||||
|
value_choices = std::make_shared<detail::choices_set<T>>(val0, rest...);
|
||||||
|
return static_cast<Derived &>(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Derived>
|
||||||
|
template <typename Lambda,
|
||||||
|
typename std::enable_if<detail::is_invocable<Lambda>::value, int>::type>
|
||||||
|
Derived & bound_parser<Derived>::choices(Lambda const & check_choice)
|
||||||
|
{
|
||||||
|
value_choices
|
||||||
|
= std::make_shared<detail::choices_check<Lambda>>(check_choice);
|
||||||
|
return static_cast<Derived &>(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Derived>
|
||||||
|
template <typename T, std::size_t N>
|
||||||
|
Derived & bound_parser<Derived>::choices(const T (&choice_values)[N])
|
||||||
|
{
|
||||||
|
value_choices = std::make_shared<detail::choices_set<T>>(
|
||||||
|
std::vector<T> { choice_values, choice_values + N });
|
||||||
|
return static_cast<Derived &>(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_bound_parser_hint]
|
||||||
|
=== `lyra::bound_parser::hint`
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
template <typename Derived>
|
||||||
|
std::string lyra::bound_parser<Derived>::hint() const
|
||||||
|
|
||||||
|
template <typename Derived>
|
||||||
|
Derived & lyra::bound_parser<Derived>::hint(std::string const & hint)
|
||||||
|
----
|
||||||
|
|
||||||
|
Selectors to read and write the hint of a variable-bound parser.
|
||||||
|
|
||||||
|
The hint should not be modified anymore, once the parser is applied to arguments
|
||||||
|
or used in a `lyra::composable_parser`.
|
||||||
|
|
||||||
|
end::reference[] */
|
||||||
|
template <typename Derived>
|
||||||
|
std::string bound_parser<Derived>::hint() const
|
||||||
|
{
|
||||||
|
return m_hint;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Derived>
|
||||||
|
Derived & bound_parser<Derived>::hint(std::string const & hint)
|
||||||
|
{
|
||||||
|
m_hint = hint;
|
||||||
|
return static_cast<Derived &>(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace lyra
|
||||||
|
|
||||||
|
#endif
|
41
3party/lyra/lyra/parser_result.hpp
Normal file
41
3party/lyra/lyra/parser_result.hpp
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
// Copyright 2018-2022 René Ferdinand Rivera Morell
|
||||||
|
// Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
#ifndef LYRA_PARSER_RESULT_HPP
|
||||||
|
#define LYRA_PARSER_RESULT_HPP
|
||||||
|
|
||||||
|
#include "lyra/detail/result.hpp"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace lyra {
|
||||||
|
|
||||||
|
// enum of result types from a parse
|
||||||
|
enum class parser_result_type
|
||||||
|
{
|
||||||
|
matched,
|
||||||
|
no_match,
|
||||||
|
short_circuit_all
|
||||||
|
};
|
||||||
|
|
||||||
|
inline std::string to_string(parser_result_type v)
|
||||||
|
{
|
||||||
|
switch (v)
|
||||||
|
{
|
||||||
|
case parser_result_type::matched: return "matched";
|
||||||
|
case parser_result_type::no_match: return "no_match";
|
||||||
|
case parser_result_type::short_circuit_all: return "short_circuit_all";
|
||||||
|
}
|
||||||
|
return "?";
|
||||||
|
}
|
||||||
|
|
||||||
|
using result = detail::basic_result<void>;
|
||||||
|
|
||||||
|
// Result type for parser operation
|
||||||
|
using parser_result = detail::basic_result<parser_result_type>;
|
||||||
|
|
||||||
|
} // namespace lyra
|
||||||
|
|
||||||
|
#endif
|
44
3party/lyra/lyra/val.hpp
Normal file
44
3party/lyra/lyra/val.hpp
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
// Copyright 2020-2022 René Ferdinand Rivera Morell
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
#ifndef LYRA_VAL_HPP
|
||||||
|
#define LYRA_VAL_HPP
|
||||||
|
|
||||||
|
#include "lyra/detail/bound.hpp"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace lyra {
|
||||||
|
|
||||||
|
/* tag::reference[]
|
||||||
|
|
||||||
|
[#lyra_val]
|
||||||
|
= `lyra::val`
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
auto val(T && v);
|
||||||
|
auto val(const char * v);
|
||||||
|
----
|
||||||
|
|
||||||
|
Makes a bound self-contained value of the type of the given r-value. The created
|
||||||
|
bound values can be used in place of the value references for arguments. And can
|
||||||
|
be retrieved with the
|
||||||
|
<<lyra_cli_array_ref>> call.
|
||||||
|
|
||||||
|
*/ // end::reference[]
|
||||||
|
template <typename T>
|
||||||
|
detail::BoundVal<T> val(T && v)
|
||||||
|
{
|
||||||
|
return detail::BoundVal<T>(std::forward<T>(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline detail::BoundVal<std::string> val(const char * v)
|
||||||
|
{
|
||||||
|
return detail::BoundVal<std::string>(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace lyra
|
||||||
|
|
||||||
|
#endif
|
17
3party/lyra/lyra/version.hpp
Normal file
17
3party/lyra/lyra/version.hpp
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2019-2022 René Ferdinand Rivera Morell
|
||||||
|
//
|
||||||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
#ifndef LYRA_VERSION_HPP
|
||||||
|
#define LYRA_VERSION_HPP
|
||||||
|
|
||||||
|
#define LYRA_VERSION_MAJOR 1
|
||||||
|
#define LYRA_VERSION_MINOR 6
|
||||||
|
#define LYRA_VERSION_PATCH 1
|
||||||
|
|
||||||
|
#define LYRA_VERSION \
|
||||||
|
(((LYRA_VERSION_MAJOR)*10000000) + ((LYRA_VERSION_MINOR)*100000) \
|
||||||
|
+ (LYRA_VERSION_PATCH))
|
||||||
|
|
||||||
|
#endif // LYRA_VERSION_HPP
|
@ -102,6 +102,7 @@ target_include_directories(
|
|||||||
3party/bnflite
|
3party/bnflite
|
||||||
3party/eventbus/include
|
3party/eventbus/include
|
||||||
3party/inja
|
3party/inja
|
||||||
|
3party/lyra
|
||||||
3party/mongoose
|
3party/mongoose
|
||||||
3party/nlohmann
|
3party/nlohmann
|
||||||
3party/nonstd
|
3party/nonstd
|
||||||
@ -125,5 +126,5 @@ if(ULIB_BUILD_TESTS)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(ULIB_BUILD_EXAMPLES)
|
if(ULIB_BUILD_EXAMPLES)
|
||||||
add_subdirectory(examples)
|
add_subdirectory(examples)
|
||||||
endif()
|
endif()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user