kicad/thirdparty/pegtl/pegtl/match.hpp

175 lines
6.8 KiB
C++

// Copyright (c) 2019-2021 Dr. Colin Hirsch and Daniel Frey
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
#ifndef TAO_PEGTL_MATCH_HPP
#define TAO_PEGTL_MATCH_HPP
#include <type_traits>
#include "apply_mode.hpp"
#include "config.hpp"
#include "nothing.hpp"
#include "require_apply.hpp"
#include "require_apply0.hpp"
#include "rewind_mode.hpp"
#include "internal/has_apply.hpp"
#include "internal/has_apply0.hpp"
#include "internal/has_unwind.hpp"
#include "internal/marker.hpp"
#include "internal/missing_apply.hpp"
#include "internal/missing_apply0.hpp"
#if defined( _MSC_VER )
#pragma warning( push )
#pragma warning( disable : 4702 )
#endif
namespace TAO_PEGTL_NAMESPACE
{
namespace internal
{
template< typename Rule,
apply_mode A,
rewind_mode M,
template< typename... >
class Action,
template< typename... >
class Control,
typename ParseInput,
typename... States >
[[nodiscard]] static auto match_no_control( ParseInput& in, States&&... st )
-> decltype( Rule::template match< A, M, Action, Control >( in, st... ) )
{
return Rule::template match< A, M, Action, Control >( in, st... );
}
template< typename Rule,
apply_mode A,
rewind_mode M,
template< typename... >
class Action,
template< typename... >
class Control,
typename ParseInput,
typename... States >
[[nodiscard]] static auto match_no_control( ParseInput& in, States&&... /*unused*/ )
-> decltype( Rule::match( in ) )
{
return Rule::match( in );
}
template< typename Rule,
apply_mode A,
rewind_mode M,
template< typename... >
class Action,
template< typename... >
class Control,
typename ParseInput,
typename... States >
[[nodiscard]] auto match_control_unwind( ParseInput& in, States&&... st )
{
#if defined( __cpp_exceptions )
if constexpr( has_unwind< Control< Rule >, void, const ParseInput&, States... > ) {
try {
return match_no_control< Rule, A, M, Action, Control >( in, st... );
}
catch( ... ) {
Control< Rule >::unwind( static_cast< const ParseInput& >( in ), st... );
throw;
}
}
else {
return match_no_control< Rule, A, M, Action, Control >( in, st... );
}
#else
return match_no_control< Rule, A, M, Action, Control >( in, st... );
#endif
}
} // namespace internal
template< typename Rule,
apply_mode A,
rewind_mode M,
template< typename... >
class Action,
template< typename... >
class Control,
typename ParseInput,
typename... States >
[[nodiscard]] auto match( ParseInput& in, States&&... st )
{
if constexpr( !Control< Rule >::enable ) {
return internal::match_no_control< Rule, A, M, Action, Control >( in, st... );
}
else {
constexpr bool enable_action = ( A == apply_mode::action );
using iterator_t = typename ParseInput::iterator_t;
constexpr bool has_apply_void = enable_action && internal::has_apply< Control< Rule >, void, Action, const iterator_t&, const ParseInput&, States... >;
constexpr bool has_apply_bool = enable_action && internal::has_apply< Control< Rule >, bool, Action, const iterator_t&, const ParseInput&, States... >;
constexpr bool has_apply = has_apply_void || has_apply_bool;
constexpr bool has_apply0_void = enable_action && internal::has_apply0< Control< Rule >, void, Action, const ParseInput&, States... >;
constexpr bool has_apply0_bool = enable_action && internal::has_apply0< Control< Rule >, bool, Action, const ParseInput&, States... >;
constexpr bool has_apply0 = has_apply0_void || has_apply0_bool;
static_assert( !( has_apply && has_apply0 ), "both apply() and apply0() defined" );
constexpr bool is_nothing = std::is_base_of_v< nothing< Rule >, Action< Rule > >;
static_assert( !( has_apply && is_nothing ), "unexpected apply() defined" );
static_assert( !( has_apply0 && is_nothing ), "unexpected apply0() defined" );
if constexpr( !has_apply && std::is_base_of_v< require_apply, Action< Rule > > ) {
internal::missing_apply< Control< Rule >, Action >( in, st... );
}
if constexpr( !has_apply0 && std::is_base_of_v< require_apply0, Action< Rule > > ) {
internal::missing_apply0< Control< Rule >, Action >( in, st... );
}
constexpr bool validate_nothing = std::is_base_of_v< maybe_nothing, Action< void > >;
constexpr bool is_maybe_nothing = std::is_base_of_v< maybe_nothing, Action< Rule > >;
static_assert( !enable_action || !validate_nothing || is_nothing || is_maybe_nothing || has_apply || has_apply0, "either apply() or apply0() must be defined" );
constexpr bool use_marker = has_apply || has_apply0_bool;
auto m = in.template mark< ( use_marker ? rewind_mode::required : rewind_mode::dontcare ) >();
Control< Rule >::start( static_cast< const ParseInput& >( in ), st... );
auto result = internal::match_control_unwind< Rule, A, ( use_marker ? rewind_mode::active : M ), Action, Control >( in, st... );
if( result ) {
if constexpr( has_apply_void ) {
Control< Rule >::template apply< Action >( m.iterator(), static_cast< const ParseInput& >( in ), st... );
}
else if constexpr( has_apply_bool ) {
result = Control< Rule >::template apply< Action >( m.iterator(), static_cast< const ParseInput& >( in ), st... );
}
else if constexpr( has_apply0_void ) {
Control< Rule >::template apply0< Action >( static_cast< const ParseInput& >( in ), st... );
}
else if constexpr( has_apply0_bool ) {
result = Control< Rule >::template apply0< Action >( static_cast< const ParseInput& >( in ), st... );
}
}
if( result ) {
Control< Rule >::success( static_cast< const ParseInput& >( in ), st... );
}
else {
Control< Rule >::failure( static_cast< const ParseInput& >( in ), st... );
}
(void)m( result );
return result;
}
}
} // namespace TAO_PEGTL_NAMESPACE
#if defined( _MSC_VER )
#pragma warning( pop )
#endif
#endif