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/eventbus/include
|
||||
3party/inja
|
||||
3party/lyra
|
||||
3party/mongoose
|
||||
3party/nlohmann
|
||||
3party/nonstd
|
||||
@ -125,5 +126,5 @@ if(ULIB_BUILD_TESTS)
|
||||
endif()
|
||||
|
||||
if(ULIB_BUILD_EXAMPLES)
|
||||
add_subdirectory(examples)
|
||||
add_subdirectory(examples)
|
||||
endif()
|
||||
|
Loading…
Reference in New Issue
Block a user