Skip to content

Commit

Permalink
Support raise_nested.
Browse files Browse the repository at this point in the history
  • Loading branch information
ColinH committed Jul 9, 2023
1 parent fe639ef commit f0abcde
Show file tree
Hide file tree
Showing 9 changed files with 115 additions and 14 deletions.
11 changes: 11 additions & 0 deletions include/tao/pegtl/contrib/coverage.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ namespace TAO_PEGTL_NAMESPACE
std::size_t failure = 0;
std::size_t unwind = 0;
std::size_t raise = 0;
std::size_t raise_nested = 0;
};

struct coverage_entry
Expand Down Expand Up @@ -113,6 +114,16 @@ namespace TAO_PEGTL_NAMESPACE
}
}

template< typename Rule, typename Ambient, typename... States >
void raise_nested( const Ambient& /*unused*/, States&&... /*unused*/ )
{
const auto name = demangle< Rule >();
++result.at( name ).raise_nested;
if( !stack.empty() ) {
++result.at( stack.back() ).branches.at( name ).raise_nested;
}
}

template< typename Rule, typename ParseInput, typename... States >
void unwind( const ParseInput& /*unused*/, States&&... /*unused*/ )
{
Expand Down
3 changes: 1 addition & 2 deletions include/tao/pegtl/contrib/nested_exceptions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,9 @@

#include "../config.hpp"
#include "../parse_error.hpp"
#include "../position.hpp"

// Various utility functions and classes to handle nested exceptions given that parse_nested() now uses them.
// At this point it's not clear how many, and which, of these will become part of the PEGTL. Experimental.
// At this point it's not clear yet how many, and which, of these will become and stay part of the PEGTL.

namespace TAO_PEGTL_NAMESPACE::nested
{
Expand Down
12 changes: 9 additions & 3 deletions include/tao/pegtl/contrib/remove_first_state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
namespace TAO_PEGTL_NAMESPACE
{
// The first state is removed for most of the control functions forwarded to Base,
// start(), success(), failure(), unwind(), raise(), apply(), and apply0(). The call
// to match() is unchanged because it can call other grammar rules that require all
// states when starting their match to keep an even playing field.
// start(), success(), failure(), unwind(), raise(), raise_nested(), apply(), and apply0().
// The call to match() is unchanged because it can call other grammar rules that require
// all states when starting their match to keep an even playing field.

template< typename Base >
struct remove_first_state
Expand Down Expand Up @@ -46,6 +46,12 @@ namespace TAO_PEGTL_NAMESPACE
Base::raise( in, st... );
}

template< typename Ambient, typename State, typename... States >
[[noreturn]] static void raise_nested( const Ambient& am, State&& /*unused*/, States&&... st )
{
Base::raise_nested( am, st... );
}

template< typename ParseInput, typename State, typename... States >
static auto unwind( const ParseInput& in, State&& /*unused*/, States&&... st )
-> std::enable_if_t< internal::has_unwind< Base, void, const ParseInput&, States... > >
Expand Down
22 changes: 17 additions & 5 deletions include/tao/pegtl/contrib/remove_last_states.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
namespace TAO_PEGTL_NAMESPACE
{
// The last N states are removed for most of the control functions forwarded to Base,
// start(), success(), failure(), unwind(), raise(), apply(), and apply0(). The call
// to match() is unchanged because it can call other grammar rules that require all
// states when starting their match to keep an even playing field.
// start(), success(), failure(), unwind(), raise(), raise_nested(),apply(), and apply0().
// The call to match() is unchanged because it can call other grammar rules that require
// all states when starting their match to keep an even playing field.

template< typename Base, std::size_t N >
struct remove_last_states
Expand Down Expand Up @@ -71,11 +71,23 @@ namespace TAO_PEGTL_NAMESPACE
raise_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - N >() );
}

template< typename Ambient, typename Tuple, std::size_t... Is >
[[noreturn]] static void raise_nested_impl( const Ambient& am, const Tuple& t, std::index_sequence< Is... > /*unused*/ )
{
Base::raise_nested( am, std::get< Is >( t )... );
}

template< typename Ambient, typename... States >
[[noreturn]] static void raise_nested( const Ambient& am, States&&... st )
{
raise_nested_impl( am, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - N >() );
}

template< typename ParseInput, typename Tuple, std::size_t... Is >
static auto unwind_impl( const ParseInput& in, const Tuple& t, std::index_sequence< Is... > /*unused*/ )
static auto unwind_impl( const ParseInput& am, const Tuple& t, std::index_sequence< Is... > /*unused*/ )
-> std::enable_if_t< internal::has_unwind< Base, void, const ParseInput&, std::tuple_element_t< Is, Tuple >... > >
{
Base::unwind( in, std::get< Is >( t )... );
Base::unwind( am, std::get< Is >( t )... );
}

template< typename ParseInput, typename... States >
Expand Down
20 changes: 19 additions & 1 deletion include/tao/pegtl/contrib/shuffle_states.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ namespace TAO_PEGTL_NAMESPACE

} // namespace internal

// Applies 'Shuffle' to the states of start(), success(), failure(), raise(), apply(), and apply0()
// Applies 'Shuffle' to the states of start(), success(), failure(), raise(), raise_nested(), apply(), and apply0()
template< typename Base, typename Shuffle >
struct shuffle_states
: Base
Expand Down Expand Up @@ -116,6 +116,24 @@ namespace TAO_PEGTL_NAMESPACE
Base::raise( in, st );
}

template< typename Ambient, typename Tuple, std::size_t... Is >
[[noreturn]] static void raise_nested_impl( const Ambient& in, const Tuple& t, std::index_sequence< Is... > /*unused*/ )
{
Base::raise_nested( in, std::get< Shuffle::template value< Is, sizeof...( Is ) > >( t )... );
}

template< typename Ambient, typename... States >
[[noreturn]] static void raise_nested( const Ambient& in, States&&... st )
{
raise_nested_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) >() );
}

template< typename Ambient, typename State >
[[noreturn]] static void raise_nested( const Ambient& in, State&& st )
{
Base::raise_nested( in, st );
}

template< typename ParseInput, typename Tuple, std::size_t... Is >
static auto unwind_impl( const ParseInput& in, const Tuple& t, std::index_sequence< Is... > /*unused*/ )
-> std::enable_if_t< internal::has_unwind< Base, void, const ParseInput&, std::tuple_element_t< Shuffle::template value< Is, sizeof...( Is ) >, Tuple >... > >
Expand Down
9 changes: 9 additions & 0 deletions include/tao/pegtl/contrib/state_control.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,15 @@ namespace TAO_PEGTL_NAMESPACE
Control< Rule >::raise( in, st... );
}

template< typename Ambient, typename State, typename... States >
[[noreturn]] static void raise_nested( const Ambient& am, [[maybe_unused]] State& state, States&&... st )
{
if constexpr( State::template enable< Rule > ) {
state.template raise_nested< Rule >( am, st... );
}
Control< Rule >::raise_nested( am, st... );
}

template< typename ParseInput, typename State, typename... States >
static auto unwind( [[maybe_unused]] const ParseInput& in, [[maybe_unused]] State& state, [[maybe_unused]] States&&... st )
-> std::enable_if_t< State::template enable< Rule > || ( Control< Rule >::enable && internal::has_unwind< Control< Rule >, void, const ParseInput&, States... > ) >
Expand Down
6 changes: 6 additions & 0 deletions include/tao/pegtl/contrib/trace.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,12 @@ namespace TAO_PEGTL_NAMESPACE
std::cerr << std::setw( indent() ) << ' ' << TracerTraits::ansi_raise << "raise" << TracerTraits::ansi_reset << ' ' << TracerTraits::ansi_rule << demangle< Rule >() << TracerTraits::ansi_reset << '\n';
}

template< typename Rule, typename Ambient, typename... States >
void raise_nested( const Ambient& /*unused*/, States&&... /*unused*/ )
{
std::cerr << std::setw( indent() ) << ' ' << TracerTraits::ansi_raise << "raise_nested" << TracerTraits::ansi_reset << ' ' << TracerTraits::ansi_rule << demangle< Rule >() << TracerTraits::ansi_reset << '\n';
}

template< typename Rule, typename ParseInput, typename... States >
void unwind( const ParseInput& in, States&&... /*unused*/ )
{
Expand Down
4 changes: 2 additions & 2 deletions include/tao/pegtl/internal/try_catch_raise_nested.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ namespace TAO_PEGTL_NAMESPACE::internal
return m( Control< Rule >::template match< A, m_t::next_rewind_mode, Action, Control >( in, st... ) );
}
catch( ... ) {
Control< try_catch_raise_nested >::raise_nested( in.previous_position( m.saved() ), st... );
Control< Rule >::raise_nested( in.position( m.frobnicator() ), st... );
}
}
};
Expand Down Expand Up @@ -83,7 +83,7 @@ namespace TAO_PEGTL_NAMESPACE::internal
return m( Control< Rule >::template match< A, m_t::next_rewind_mode, Action, Control >( in, st... ) );
}
catch( const Exception& ) {
Control< try_catch_raise_nested >::raise_nested( in.previous_position( m.saved() ), st... );
Control< Rule >::raise_nested( in.position( m.frobnicator() ), st... );
}
}
};
Expand Down
42 changes: 41 additions & 1 deletion src/test/pegtl/contrib_state_control.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,13 @@ namespace TAO_PEGTL_NAMESPACE
std::size_t b;
};

inline bool operator==( const test_entry& l, const test_entry& r ) noexcept
std::ostream& operator<<( std::ostream& os, const test_entry& te )
{
os << te.rule << " " << te.func << " " << te.b;
return os;
}

[[nodiscard]] inline bool operator==( const test_entry& l, const test_entry& r ) noexcept
{
return ( l.rule == r.rule ) && ( l.func == r.func ) && ( l.b == r.b );
}
Expand Down Expand Up @@ -68,6 +74,13 @@ namespace TAO_PEGTL_NAMESPACE
trace.push_back( { demangle< Rule >(), "raise", ++b } );
}

template< typename Rule, typename Input, typename... States >
void raise_nested( const Input& /*unused*/, const int a, std::size_t& b )
{
TAO_PEGTL_TEST_ASSERT( a == -1 );
trace.push_back( { demangle< Rule >(), "raise_nested", ++b } );
}

template< typename Rule, typename Input, typename... States >
void unwind( const Input& /*unused*/, const int a, std::size_t& b )
{
Expand Down Expand Up @@ -137,8 +150,12 @@ namespace TAO_PEGTL_NAMESPACE
}
};

struct test_nested : not_at< try_catch_return_false< try_catch_raise_nested< must< one< 'x' > > > > >
{};

void unit_test()
{
// must< sor< one< 'a' >, try_catch_return_false< seq< one< 'b' >, must< one< 'c' > > > >, two< 'b' > >, eof >
{
test_state< true > st;
memory_input in( "bb", __FUNCTION__ );
Expand Down Expand Up @@ -192,6 +209,29 @@ namespace TAO_PEGTL_NAMESPACE
TAO_PEGTL_TEST_ASSERT( st.trace.empty() );
TAO_PEGTL_TEST_ASSERT( b == 0 );
}
// not_at< try_catch_return_false< try_catch_raise_nested< must< one< 'x' > > > > >
{
test_state< true > st;
memory_input in( "a", __FUNCTION__ );
std::size_t b = 0;
const bool result = parse< test_nested, nothing, state_control< normal >::type >( in, -1, b, st );
TAO_PEGTL_TEST_ASSERT( result );
TAO_PEGTL_TEST_ASSERT( b == st.trace.size() );
b = 0;
std::size_t i = 0;
TAO_PEGTL_TEST_ASSERT( st.trace[ i++ ] == test_entry{ demangle< test_nested >(), "start", ++b } );
TAO_PEGTL_TEST_ASSERT( st.trace[ i++ ] == test_entry{ demangle< try_catch_return_false< try_catch_raise_nested< must< one< 'x' > > > > >(), "start", ++b } );
TAO_PEGTL_TEST_ASSERT( st.trace[ i++ ] == test_entry{ demangle< try_catch_raise_nested< must< one< 'x' > > > >(), "start", ++b } );
TAO_PEGTL_TEST_ASSERT( st.trace[ i++ ] == test_entry{ demangle< must< one< 'x' > > >(), "start", ++b } );
TAO_PEGTL_TEST_ASSERT( st.trace[ i++ ] == test_entry{ demangle< one< 'x' > >(), "start", ++b } );
TAO_PEGTL_TEST_ASSERT( st.trace[ i++ ] == test_entry{ demangle< one< 'x' > >(), "failure", ++b } );
TAO_PEGTL_TEST_ASSERT( st.trace[ i++ ] == test_entry{ demangle< one< 'x' > >(), "raise", ++b } );
TAO_PEGTL_TEST_ASSERT( st.trace[ i++ ] == test_entry{ demangle< must< one< 'x' > > >(), "unwind", ++b } );
TAO_PEGTL_TEST_ASSERT( st.trace[ i++ ] == test_entry{ demangle< must< one< 'x' > > >(), "raise_nested", ++b } );
TAO_PEGTL_TEST_ASSERT( st.trace[ i++ ] == test_entry{ demangle< try_catch_raise_nested< must< one< 'x' > > > >(), "unwind", ++b } );
TAO_PEGTL_TEST_ASSERT( st.trace[ i++ ] == test_entry{ demangle< try_catch_return_false< try_catch_raise_nested< must< one< 'x' > > > > >(), "failure", ++b } );
TAO_PEGTL_TEST_ASSERT( st.trace[ i++ ] == test_entry{ demangle< test_nested >(), "success", ++b } );
}
}

} // namespace TAO_PEGTL_NAMESPACE
Expand Down

0 comments on commit f0abcde

Please sign in to comment.