File indexing completed on 2025-01-18 09:54:05
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef CATCH_CLARA_HPP_INCLUDED
0009 #define CATCH_CLARA_HPP_INCLUDED
0010
0011 #if defined( __clang__ )
0012 # pragma clang diagnostic push
0013 # pragma clang diagnostic ignored "-Wweak-vtables"
0014 # pragma clang diagnostic ignored "-Wshadow"
0015 # pragma clang diagnostic ignored "-Wdeprecated"
0016 #endif
0017
0018 #if defined( __GNUC__ )
0019 # pragma GCC diagnostic push
0020 # pragma GCC diagnostic ignored "-Wsign-conversion"
0021 #endif
0022
0023 #ifndef CLARA_CONFIG_OPTIONAL_TYPE
0024 # ifdef __has_include
0025 # if __has_include( <optional>) && __cplusplus >= 201703L
0026 # include <optional>
0027 # define CLARA_CONFIG_OPTIONAL_TYPE std::optional
0028 # endif
0029 # endif
0030 #endif
0031
0032 #include <catch2/internal/catch_move_and_forward.hpp>
0033 #include <catch2/internal/catch_noncopyable.hpp>
0034 #include <catch2/internal/catch_void_type.hpp>
0035
0036 #include <cassert>
0037 #include <memory>
0038 #include <ostream>
0039 #include <sstream>
0040 #include <string>
0041 #include <type_traits>
0042 #include <vector>
0043
0044 namespace Catch {
0045 namespace Clara {
0046
0047 class Args;
0048 class Parser;
0049
0050
0051 enum class ParseResultType {
0052 Matched,
0053 NoMatch,
0054 ShortCircuitAll,
0055 ShortCircuitSame
0056 };
0057
0058 struct accept_many_t {};
0059 constexpr accept_many_t accept_many {};
0060
0061 namespace Detail {
0062 struct fake_arg {
0063 template <typename T>
0064 operator T();
0065 };
0066
0067 template <typename F, typename = void>
0068 struct is_unary_function : std::false_type {};
0069
0070 template <typename F>
0071 struct is_unary_function<
0072 F,
0073 Catch::Detail::void_t<decltype(
0074 std::declval<F>()( fake_arg() ) )
0075 >
0076 > : std::true_type {};
0077
0078
0079
0080 template <typename L>
0081 struct UnaryLambdaTraits
0082 : UnaryLambdaTraits<decltype( &L::operator() )> {};
0083
0084 template <typename ClassT, typename ReturnT, typename... Args>
0085 struct UnaryLambdaTraits<ReturnT ( ClassT::* )( Args... ) const> {
0086 static const bool isValid = false;
0087 };
0088
0089 template <typename ClassT, typename ReturnT, typename ArgT>
0090 struct UnaryLambdaTraits<ReturnT ( ClassT::* )( ArgT ) const> {
0091 static const bool isValid = true;
0092 using ArgType = std::remove_const_t<std::remove_reference_t<ArgT>>;
0093 using ReturnType = ReturnT;
0094 };
0095
0096 class TokenStream;
0097
0098
0099
0100
0101 enum class TokenType { Option, Argument };
0102 struct Token {
0103 TokenType type;
0104 std::string token;
0105 };
0106
0107
0108
0109 class TokenStream {
0110 using Iterator = std::vector<std::string>::const_iterator;
0111 Iterator it;
0112 Iterator itEnd;
0113 std::vector<Token> m_tokenBuffer;
0114
0115 void loadBuffer();
0116
0117 public:
0118 explicit TokenStream( Args const& args );
0119 TokenStream( Iterator it, Iterator itEnd );
0120
0121 explicit operator bool() const {
0122 return !m_tokenBuffer.empty() || it != itEnd;
0123 }
0124
0125 size_t count() const {
0126 return m_tokenBuffer.size() + ( itEnd - it );
0127 }
0128
0129 Token operator*() const {
0130 assert( !m_tokenBuffer.empty() );
0131 return m_tokenBuffer.front();
0132 }
0133
0134 Token const* operator->() const {
0135 assert( !m_tokenBuffer.empty() );
0136 return &m_tokenBuffer.front();
0137 }
0138
0139 TokenStream& operator++();
0140 };
0141
0142
0143 enum class ResultType {
0144 Ok,
0145 LogicError,
0146
0147 RuntimeError
0148 };
0149
0150 class ResultBase {
0151 protected:
0152 ResultBase( ResultType type ): m_type( type ) {}
0153 virtual ~ResultBase();
0154
0155
0156 ResultBase(ResultBase const&) = default;
0157 ResultBase& operator=(ResultBase const&) = default;
0158 ResultBase(ResultBase&&) = default;
0159 ResultBase& operator=(ResultBase&&) = default;
0160
0161 virtual void enforceOk() const = 0;
0162
0163 ResultType m_type;
0164 };
0165
0166 template <typename T> class ResultValueBase : public ResultBase {
0167 public:
0168 auto value() const -> T const& {
0169 enforceOk();
0170 return m_value;
0171 }
0172
0173 protected:
0174 ResultValueBase( ResultType type ): ResultBase( type ) {}
0175
0176 ResultValueBase( ResultValueBase const& other ):
0177 ResultBase( other ) {
0178 if ( m_type == ResultType::Ok )
0179 new ( &m_value ) T( other.m_value );
0180 }
0181
0182 ResultValueBase( ResultType, T const& value ): ResultBase( ResultType::Ok ) {
0183 new ( &m_value ) T( value );
0184 }
0185
0186 auto operator=( ResultValueBase const& other )
0187 -> ResultValueBase& {
0188 if ( m_type == ResultType::Ok )
0189 m_value.~T();
0190 ResultBase::operator=( other );
0191 if ( m_type == ResultType::Ok )
0192 new ( &m_value ) T( other.m_value );
0193 return *this;
0194 }
0195
0196 ~ResultValueBase() override {
0197 if ( m_type == ResultType::Ok )
0198 m_value.~T();
0199 }
0200
0201 union {
0202 T m_value;
0203 };
0204 };
0205
0206 template <> class ResultValueBase<void> : public ResultBase {
0207 protected:
0208 using ResultBase::ResultBase;
0209 };
0210
0211 template <typename T = void>
0212 class BasicResult : public ResultValueBase<T> {
0213 public:
0214 template <typename U>
0215 explicit BasicResult( BasicResult<U> const& other ):
0216 ResultValueBase<T>( other.type() ),
0217 m_errorMessage( other.errorMessage() ) {
0218 assert( type() != ResultType::Ok );
0219 }
0220
0221 template <typename U>
0222 static auto ok( U const& value ) -> BasicResult {
0223 return { ResultType::Ok, value };
0224 }
0225 static auto ok() -> BasicResult { return { ResultType::Ok }; }
0226 static auto logicError( std::string&& message )
0227 -> BasicResult {
0228 return { ResultType::LogicError, CATCH_MOVE(message) };
0229 }
0230 static auto runtimeError( std::string&& message )
0231 -> BasicResult {
0232 return { ResultType::RuntimeError, CATCH_MOVE(message) };
0233 }
0234
0235 explicit operator bool() const {
0236 return m_type == ResultType::Ok;
0237 }
0238 auto type() const -> ResultType { return m_type; }
0239 auto errorMessage() const -> std::string const& {
0240 return m_errorMessage;
0241 }
0242
0243 protected:
0244 void enforceOk() const override {
0245
0246
0247
0248 assert( m_type != ResultType::LogicError );
0249 assert( m_type != ResultType::RuntimeError );
0250 if ( m_type != ResultType::Ok )
0251 std::abort();
0252 }
0253
0254 std::string
0255 m_errorMessage;
0256
0257 BasicResult( ResultType type,
0258 std::string&& message ):
0259 ResultValueBase<T>( type ), m_errorMessage( CATCH_MOVE(message) ) {
0260 assert( m_type != ResultType::Ok );
0261 }
0262
0263 using ResultValueBase<T>::ResultValueBase;
0264 using ResultBase::m_type;
0265 };
0266
0267 class ParseState {
0268 public:
0269 ParseState( ParseResultType type,
0270 TokenStream const& remainingTokens );
0271
0272 ParseResultType type() const { return m_type; }
0273 TokenStream const& remainingTokens() const {
0274 return m_remainingTokens;
0275 }
0276
0277 private:
0278 ParseResultType m_type;
0279 TokenStream m_remainingTokens;
0280 };
0281
0282 using Result = BasicResult<void>;
0283 using ParserResult = BasicResult<ParseResultType>;
0284 using InternalParseResult = BasicResult<ParseState>;
0285
0286 struct HelpColumns {
0287 std::string left;
0288 std::string right;
0289 };
0290
0291 template <typename T>
0292 ParserResult convertInto( std::string const& source, T& target ) {
0293 std::stringstream ss( source );
0294 ss >> target;
0295 if ( ss.fail() ) {
0296 return ParserResult::runtimeError(
0297 "Unable to convert '" + source +
0298 "' to destination type" );
0299 } else {
0300 return ParserResult::ok( ParseResultType::Matched );
0301 }
0302 }
0303 ParserResult convertInto( std::string const& source,
0304 std::string& target );
0305 ParserResult convertInto( std::string const& source, bool& target );
0306
0307 #ifdef CLARA_CONFIG_OPTIONAL_TYPE
0308 template <typename T>
0309 auto convertInto( std::string const& source,
0310 CLARA_CONFIG_OPTIONAL_TYPE<T>& target )
0311 -> ParserResult {
0312 T temp;
0313 auto result = convertInto( source, temp );
0314 if ( result )
0315 target = CATCH_MOVE( temp );
0316 return result;
0317 }
0318 #endif
0319
0320 struct BoundRef : Catch::Detail::NonCopyable {
0321 virtual ~BoundRef() = default;
0322 virtual bool isContainer() const;
0323 virtual bool isFlag() const;
0324 };
0325 struct BoundValueRefBase : BoundRef {
0326 virtual auto setValue( std::string const& arg )
0327 -> ParserResult = 0;
0328 };
0329 struct BoundFlagRefBase : BoundRef {
0330 virtual auto setFlag( bool flag ) -> ParserResult = 0;
0331 bool isFlag() const override;
0332 };
0333
0334 template <typename T> struct BoundValueRef : BoundValueRefBase {
0335 T& m_ref;
0336
0337 explicit BoundValueRef( T& ref ): m_ref( ref ) {}
0338
0339 ParserResult setValue( std::string const& arg ) override {
0340 return convertInto( arg, m_ref );
0341 }
0342 };
0343
0344 template <typename T>
0345 struct BoundValueRef<std::vector<T>> : BoundValueRefBase {
0346 std::vector<T>& m_ref;
0347
0348 explicit BoundValueRef( std::vector<T>& ref ): m_ref( ref ) {}
0349
0350 auto isContainer() const -> bool override { return true; }
0351
0352 auto setValue( std::string const& arg )
0353 -> ParserResult override {
0354 T temp;
0355 auto result = convertInto( arg, temp );
0356 if ( result )
0357 m_ref.push_back( temp );
0358 return result;
0359 }
0360 };
0361
0362 struct BoundFlagRef : BoundFlagRefBase {
0363 bool& m_ref;
0364
0365 explicit BoundFlagRef( bool& ref ): m_ref( ref ) {}
0366
0367 ParserResult setFlag( bool flag ) override;
0368 };
0369
0370 template <typename ReturnType> struct LambdaInvoker {
0371 static_assert(
0372 std::is_same<ReturnType, ParserResult>::value,
0373 "Lambda must return void or clara::ParserResult" );
0374
0375 template <typename L, typename ArgType>
0376 static auto invoke( L const& lambda, ArgType const& arg )
0377 -> ParserResult {
0378 return lambda( arg );
0379 }
0380 };
0381
0382 template <> struct LambdaInvoker<void> {
0383 template <typename L, typename ArgType>
0384 static auto invoke( L const& lambda, ArgType const& arg )
0385 -> ParserResult {
0386 lambda( arg );
0387 return ParserResult::ok( ParseResultType::Matched );
0388 }
0389 };
0390
0391 template <typename ArgType, typename L>
0392 auto invokeLambda( L const& lambda, std::string const& arg )
0393 -> ParserResult {
0394 ArgType temp{};
0395 auto result = convertInto( arg, temp );
0396 return !result ? result
0397 : LambdaInvoker<typename UnaryLambdaTraits<
0398 L>::ReturnType>::invoke( lambda, temp );
0399 }
0400
0401 template <typename L> struct BoundLambda : BoundValueRefBase {
0402 L m_lambda;
0403
0404 static_assert(
0405 UnaryLambdaTraits<L>::isValid,
0406 "Supplied lambda must take exactly one argument" );
0407 explicit BoundLambda( L const& lambda ): m_lambda( lambda ) {}
0408
0409 auto setValue( std::string const& arg )
0410 -> ParserResult override {
0411 return invokeLambda<typename UnaryLambdaTraits<L>::ArgType>(
0412 m_lambda, arg );
0413 }
0414 };
0415
0416 template <typename L> struct BoundManyLambda : BoundLambda<L> {
0417 explicit BoundManyLambda( L const& lambda ): BoundLambda<L>( lambda ) {}
0418 bool isContainer() const override { return true; }
0419 };
0420
0421 template <typename L> struct BoundFlagLambda : BoundFlagRefBase {
0422 L m_lambda;
0423
0424 static_assert(
0425 UnaryLambdaTraits<L>::isValid,
0426 "Supplied lambda must take exactly one argument" );
0427 static_assert(
0428 std::is_same<typename UnaryLambdaTraits<L>::ArgType,
0429 bool>::value,
0430 "flags must be boolean" );
0431
0432 explicit BoundFlagLambda( L const& lambda ):
0433 m_lambda( lambda ) {}
0434
0435 auto setFlag( bool flag ) -> ParserResult override {
0436 return LambdaInvoker<typename UnaryLambdaTraits<
0437 L>::ReturnType>::invoke( m_lambda, flag );
0438 }
0439 };
0440
0441 enum class Optionality { Optional, Required };
0442
0443 class ParserBase {
0444 public:
0445 virtual ~ParserBase() = default;
0446 virtual auto validate() const -> Result { return Result::ok(); }
0447 virtual auto parse( std::string const& exeName,
0448 TokenStream const& tokens ) const
0449 -> InternalParseResult = 0;
0450 virtual size_t cardinality() const;
0451
0452 InternalParseResult parse( Args const& args ) const;
0453 };
0454
0455 template <typename DerivedT>
0456 class ComposableParserImpl : public ParserBase {
0457 public:
0458 template <typename T>
0459 auto operator|( T const& other ) const -> Parser;
0460 };
0461
0462
0463 template <typename DerivedT>
0464 class ParserRefImpl : public ComposableParserImpl<DerivedT> {
0465 protected:
0466 Optionality m_optionality = Optionality::Optional;
0467 std::shared_ptr<BoundRef> m_ref;
0468 std::string m_hint;
0469 std::string m_description;
0470
0471 explicit ParserRefImpl( std::shared_ptr<BoundRef> const& ref ):
0472 m_ref( ref ) {}
0473
0474 public:
0475 template <typename LambdaT>
0476 ParserRefImpl( accept_many_t,
0477 LambdaT const& ref,
0478 std::string const& hint ):
0479 m_ref( std::make_shared<BoundManyLambda<LambdaT>>( ref ) ),
0480 m_hint( hint ) {}
0481
0482 template <typename T,
0483 typename = typename std::enable_if_t<
0484 !Detail::is_unary_function<T>::value>>
0485 ParserRefImpl( T& ref, std::string const& hint ):
0486 m_ref( std::make_shared<BoundValueRef<T>>( ref ) ),
0487 m_hint( hint ) {}
0488
0489 template <typename LambdaT,
0490 typename = typename std::enable_if_t<
0491 Detail::is_unary_function<LambdaT>::value>>
0492 ParserRefImpl( LambdaT const& ref, std::string const& hint ):
0493 m_ref( std::make_shared<BoundLambda<LambdaT>>( ref ) ),
0494 m_hint( hint ) {}
0495
0496 auto operator()( std::string const& description ) -> DerivedT& {
0497 m_description = description;
0498 return static_cast<DerivedT&>( *this );
0499 }
0500
0501 auto optional() -> DerivedT& {
0502 m_optionality = Optionality::Optional;
0503 return static_cast<DerivedT&>( *this );
0504 }
0505
0506 auto required() -> DerivedT& {
0507 m_optionality = Optionality::Required;
0508 return static_cast<DerivedT&>( *this );
0509 }
0510
0511 auto isOptional() const -> bool {
0512 return m_optionality == Optionality::Optional;
0513 }
0514
0515 auto cardinality() const -> size_t override {
0516 if ( m_ref->isContainer() )
0517 return 0;
0518 else
0519 return 1;
0520 }
0521
0522 std::string const& hint() const { return m_hint; }
0523 };
0524
0525 }
0526
0527
0528
0529 class Arg : public Detail::ParserRefImpl<Arg> {
0530 public:
0531 using ParserRefImpl::ParserRefImpl;
0532 using ParserBase::parse;
0533
0534 Detail::InternalParseResult
0535 parse(std::string const&,
0536 Detail::TokenStream const& tokens) const override;
0537 };
0538
0539
0540 class Opt : public Detail::ParserRefImpl<Opt> {
0541 protected:
0542 std::vector<std::string> m_optNames;
0543
0544 public:
0545 template <typename LambdaT>
0546 explicit Opt(LambdaT const& ref) :
0547 ParserRefImpl(
0548 std::make_shared<Detail::BoundFlagLambda<LambdaT>>(ref)) {}
0549
0550 explicit Opt(bool& ref);
0551
0552 template <typename LambdaT,
0553 typename = typename std::enable_if_t<
0554 Detail::is_unary_function<LambdaT>::value>>
0555 Opt( LambdaT const& ref, std::string const& hint ):
0556 ParserRefImpl( ref, hint ) {}
0557
0558 template <typename LambdaT>
0559 Opt( accept_many_t, LambdaT const& ref, std::string const& hint ):
0560 ParserRefImpl( accept_many, ref, hint ) {}
0561
0562 template <typename T,
0563 typename = typename std::enable_if_t<
0564 !Detail::is_unary_function<T>::value>>
0565 Opt( T& ref, std::string const& hint ):
0566 ParserRefImpl( ref, hint ) {}
0567
0568 auto operator[](std::string const& optName) -> Opt& {
0569 m_optNames.push_back(optName);
0570 return *this;
0571 }
0572
0573 std::vector<Detail::HelpColumns> getHelpColumns() const;
0574
0575 bool isMatch(std::string const& optToken) const;
0576
0577 using ParserBase::parse;
0578
0579 Detail::InternalParseResult
0580 parse(std::string const&,
0581 Detail::TokenStream const& tokens) const override;
0582
0583 Detail::Result validate() const override;
0584 };
0585
0586
0587 class ExeName : public Detail::ComposableParserImpl<ExeName> {
0588 std::shared_ptr<std::string> m_name;
0589 std::shared_ptr<Detail::BoundValueRefBase> m_ref;
0590
0591 public:
0592 ExeName();
0593 explicit ExeName(std::string& ref);
0594
0595 template <typename LambdaT>
0596 explicit ExeName(LambdaT const& lambda) : ExeName() {
0597 m_ref = std::make_shared<Detail::BoundLambda<LambdaT>>(lambda);
0598 }
0599
0600
0601
0602 Detail::InternalParseResult
0603 parse(std::string const&,
0604 Detail::TokenStream const& tokens) const override;
0605
0606 std::string const& name() const { return *m_name; }
0607 Detail::ParserResult set(std::string const& newName);
0608 };
0609
0610
0611
0612 class Parser : Detail::ParserBase {
0613 mutable ExeName m_exeName;
0614 std::vector<Opt> m_options;
0615 std::vector<Arg> m_args;
0616
0617 public:
0618
0619 auto operator|=(ExeName const& exeName) -> Parser& {
0620 m_exeName = exeName;
0621 return *this;
0622 }
0623
0624 auto operator|=(Arg const& arg) -> Parser& {
0625 m_args.push_back(arg);
0626 return *this;
0627 }
0628
0629 auto operator|=(Opt const& opt) -> Parser& {
0630 m_options.push_back(opt);
0631 return *this;
0632 }
0633
0634 Parser& operator|=(Parser const& other);
0635
0636 template <typename T>
0637 auto operator|(T const& other) const -> Parser {
0638 return Parser(*this) |= other;
0639 }
0640
0641 std::vector<Detail::HelpColumns> getHelpColumns() const;
0642
0643 void writeToStream(std::ostream& os) const;
0644
0645 friend auto operator<<(std::ostream& os, Parser const& parser)
0646 -> std::ostream& {
0647 parser.writeToStream(os);
0648 return os;
0649 }
0650
0651 Detail::Result validate() const override;
0652
0653 using ParserBase::parse;
0654 Detail::InternalParseResult
0655 parse(std::string const& exeName,
0656 Detail::TokenStream const& tokens) const override;
0657 };
0658
0659
0660
0661 class Args {
0662 friend Detail::TokenStream;
0663 std::string m_exeName;
0664 std::vector<std::string> m_args;
0665
0666 public:
0667 Args(int argc, char const* const* argv);
0668 Args(std::initializer_list<std::string> args);
0669
0670 std::string const& exeName() const { return m_exeName; }
0671 };
0672
0673
0674
0675 struct Help : Opt {
0676 Help(bool& showHelpFlag);
0677 };
0678
0679
0680 using Detail::ParserResult;
0681
0682 namespace Detail {
0683 template <typename DerivedT>
0684 template <typename T>
0685 Parser
0686 ComposableParserImpl<DerivedT>::operator|(T const& other) const {
0687 return Parser() | static_cast<DerivedT const&>(*this) | other;
0688 }
0689 }
0690
0691 }
0692 }
0693
0694 #if defined( __clang__ )
0695 # pragma clang diagnostic pop
0696 #endif
0697
0698 #if defined( __GNUC__ )
0699 # pragma GCC diagnostic pop
0700 #endif
0701
0702 #endif