Skip to content

Commit

Permalink
Add rule 'partial'.
Browse files Browse the repository at this point in the history
  • Loading branch information
ColinH committed Mar 15, 2023
1 parent 412e92b commit dffdff0
Show file tree
Hide file tree
Showing 10 changed files with 142 additions and 22 deletions.
2 changes: 2 additions & 0 deletions doc/Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
* Added new customization point for error messages.
* Added optional source line output for the tracer.
* Added new atomic rule `everything`.
* Added new convenience rule `partial`.
* Added new convenience rule `star_partial`.
* Moved depth counter to adapter class in contrib.
* Changed default top-level `rewind_mode` to `dontcare`.
* Removed the `TAO_PEGTL_NAMESPACE` macro.
Expand Down
1 change: 1 addition & 0 deletions doc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@
* [`opt_must< R, S...>`](Rule-Reference.md#opt_must-r-s-) <sup>[(convenience)](Rule-Reference.md#convenience)</sup>
* [`pad< R, S, T = S >`](Rule-Reference.md#pad-r-s-t--s-) <sup>[(convenience)](Rule-Reference.md#convenience)</sup>
* [`pad_opt< R, P >`](Rule-Reference.md#pad_opt-r-p-) <sup>[(convenience)](Rule-Reference.md#convenience)</sup>
* [`partial< R... >`](Rule-Reference.md#partial-r-) <sup>[(convenience)](Rule-Reference.md#convenience)</sup>
* [`pattern_syntax`](Rule-Reference.md#pattern_syntax) <sup>[(icu rules)](Rule-Reference.md#icu-rules-for-binary-properties)</sup>
* [`pattern_white_space`](Rule-Reference.md#pattern_white_space) <sup>[(icu rules)](Rule-Reference.md#icu-rules-for-binary-properties)</sup>
* [`plus< R... >`](Rule-Reference.md#plus-r-) <sup>[(combinators)](Rule-Reference.md#combinators)</sup>
Expand Down
14 changes: 14 additions & 0 deletions doc/Rule-Reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,19 @@ Note that the `true` template parameter to `internal::if_must` corresponds to th
- `pad_opt< R, P >::rule_t` is `internal::seq< internal::star< P >, internal::opt< R, internal::star< P > > >`
- `pad_opt< R, P >::subs_t` is `type_list< internal::star< P >, internal::opt< R, internal::star< P > > >`

###### `partial< R... >`

* Similar to `opt< R... >` with one important difference:
* Does *not* rewind the input after a partial match of `R...`.
* Attempts to match the given rules `R...` in the given order.
* Succeeds and stops matching when one of the given rules fails.
* Consumes everything that the successful rules of `R...` consumed.
* `R` must be a non-empty rule pack.
* [Equivalent] to `opt< R >` when `R...` is a single rule.
* [Meta data] and [implementation] mapping:
- `partial< R... >::rule_t` is `internal::partial< R... >`
- `partial< R... >::subs_t` is `type_list< R... >`

###### `rematch< R, S... >`

* Succeeds if `R` matches, and each `S` matches the input that `R` matched.
Expand Down Expand Up @@ -1518,6 +1531,7 @@ Binary rules do not rely on other rules.
* [`opt_must< R, S...>`](#opt_must-r-s-) <sup>[(convenience)](#convenience)</sup>
* [`pad< R, S, T = S >`](#pad-r-s-t--s-) <sup>[(convenience)](#convenience)</sup>
* [`pad_opt< R, P >`](#pad_opt-r-p-) <sup>[(convenience)](#convenience)</sup>
* [`partial< R... >`](#partial-r-) <sup>[(convenience)](#convenience)</sup>
* [`pattern_syntax`](#pattern_syntax) <sup>[(icu rules)](#icu-rules-for-binary-properties)</sup>
* [`pattern_white_space`](#pattern_white_space) <sup>[(icu rules)](#icu-rules-for-binary-properties)</sup>
* [`plus< R... >`](#plus-r-) <sup>[(combinators)](#combinators)</sup>
Expand Down
11 changes: 8 additions & 3 deletions include/tao/pegtl/contrib/analyze_traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,14 @@ namespace tao::pegtl
: analyze_any_traits<>
{};

template< typename Name, typename Rule, typename... Rules >
struct analyze_traits< Name, internal::opt< Rule, Rules... > >
: analyze_opt_traits< Rule, Rules... >
template< typename Name, typename... Rules >
struct analyze_traits< Name, internal::opt< Rules... > >
: analyze_opt_traits< Rules... >
{};

template< typename Name, typename... Rules >
struct analyze_traits< Name, internal::partial< Rules... > >
: analyze_opt_traits< Rules... >
{};

template< typename Name, typename... Rules >
Expand Down
21 changes: 2 additions & 19 deletions include/tao/pegtl/internal/opt.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,10 @@
#define TAO_PEGTL_INTERNAL_OPT_HPP

#include "enable_control.hpp"
#include "partial.hpp"
#include "seq.hpp"
#include "success.hpp"

#include "../apply_mode.hpp"
#include "../rewind_mode.hpp"
#include "../type_list.hpp"

namespace tao::pegtl::internal
{
template< typename... Rules >
Expand All @@ -27,23 +24,9 @@ namespace tao::pegtl::internal

template< typename Rule >
struct opt< Rule >
: partial< Rule >
{
using rule_t = opt;
using subs_t = type_list< Rule >;

template< apply_mode A,
rewind_mode,
template< typename... >
class Action,
template< typename... >
class Control,
typename ParseInput,
typename... States >
[[nodiscard]] static bool match( ParseInput& in, States&&... st )
{
(void)Control< Rule >::template match< A, rewind_mode::required, Action, Control >( in, st... );
return true;
}
};

template< typename... Rules >
Expand Down
42 changes: 42 additions & 0 deletions include/tao/pegtl/internal/partial.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright (c) 2023 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_INTERNAL_PARTIAL_HPP
#define TAO_PEGTL_INTERNAL_PARTIAL_HPP

#include "enable_control.hpp"

#include "../apply_mode.hpp"
#include "../rewind_mode.hpp"
#include "../type_list.hpp"

namespace tao::pegtl::internal
{
template< typename... Rules >
struct partial
{
using rule_t = partial;
using subs_t = type_list< Rules... >;

template< apply_mode A,
rewind_mode,
template< typename... >
class Action,
template< typename... >
class Control,
typename ParseInput,
typename... States >
[[nodiscard]] static bool match( ParseInput& in, States&&... st )
{
(void)( Control< Rules >::template match< A, rewind_mode::required, Action, Control >( in, st... ) && ... );
return true;
}
};

template< typename... Rules >
inline constexpr bool enable_control< partial< Rules... > > = false;

} // namespace tao::pegtl::internal

#endif
1 change: 1 addition & 0 deletions include/tao/pegtl/internal/rules.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include "opt.hpp"
#include "pad.hpp"
#include "pad_opt.hpp"
#include "partial.hpp"
#include "plus.hpp"
#include "range.hpp"
#include "ranges.hpp"
Expand Down
1 change: 1 addition & 0 deletions include/tao/pegtl/rules.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ namespace tao::pegtl
template< typename... Rules > struct opt : internal::opt< Rules... > {};
template< typename Rule, typename Pad1, typename Pad2 = Pad1 > struct pad : internal::pad< Rule, Pad1, Pad2 > {};
template< typename Rule, typename Pad > struct pad_opt : internal::pad_opt< Rule, Pad > {};
template< typename Rule, typename... Rules > struct partial : internal::partial< Rule, Rules... > {};
template< typename Rule, typename... Rules > struct plus : internal::plus< Rule, Rules... > {};
template< typename Head, typename... Rules > struct rematch : internal::rematch< Head, Rules... > {};
template< unsigned Num, typename... Rules > struct rep : internal::rep< Num, Rules... > {};
Expand Down
1 change: 1 addition & 0 deletions src/test/pegtl/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ set(test_sources
rule_opt_must.cpp
rule_pad.cpp
rule_pad_opt.cpp
rule_partial.cpp
rule_plus.cpp
rule_raise.cpp
rule_rematch.cpp
Expand Down
70 changes: 70 additions & 0 deletions src/test/pegtl/rule_partial.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright (c) 2023 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)

#include "test.hpp"

#include "verify_meta.hpp"
#include "verify_rule.hpp"

namespace tao::pegtl
{
template< typename Rule >
struct my_action
{};

template<>
struct my_action< eof >
{
static void apply0( bool& b )
{
b = true;
}
};

void unit_test()
{
verify_meta< partial< eof >, internal::partial< eof >, eof >();
verify_meta< partial< eof, any >, internal::partial< eof, any >, eof, any >();

verify_analyze< partial< any > >( __LINE__, __FILE__, false, false );
verify_analyze< partial< eof > >( __LINE__, __FILE__, false, false );

verify_rule< partial< one< 'a' > > >( __LINE__, __FILE__, "", result_type::success, 0 );
verify_rule< partial< one< 'a' > > >( __LINE__, __FILE__, "a", result_type::success, 0 );
verify_rule< partial< one< 'a' > > >( __LINE__, __FILE__, "aa", result_type::success, 1 );
verify_rule< partial< one< 'a' > > >( __LINE__, __FILE__, "ab", result_type::success, 1 );
verify_rule< partial< one< 'a' > > >( __LINE__, __FILE__, "ba", result_type::success, 2 );

verify_rule< partial< one< 'a' >, one< 'b' > > >( __LINE__, __FILE__, "", result_type::success, 0 );
verify_rule< partial< one< 'a' >, one< 'b' > > >( __LINE__, __FILE__, "a", result_type::success, 0 );
verify_rule< partial< one< 'a' >, one< 'b' > > >( __LINE__, __FILE__, "ab", result_type::success, 0 );
verify_rule< partial< one< 'a' >, one< 'b' > > >( __LINE__, __FILE__, "aba", result_type::success, 1 );
verify_rule< partial< one< 'a' >, one< 'b' > > >( __LINE__, __FILE__, "abab", result_type::success, 2 );
verify_rule< partial< one< 'a' >, one< 'b' > > >( __LINE__, __FILE__, "bab", result_type::success, 3 );
verify_rule< partial< one< 'a' >, one< 'b' > > >( __LINE__, __FILE__, "cb", result_type::success, 2 );

#if defined( __cpp_exceptions )
verify_rule< must< partial< one< 'a' > > > >( __LINE__, __FILE__, "", result_type::success, 0 );
verify_rule< must< partial< one< 'a' > > > >( __LINE__, __FILE__, "a", result_type::success, 0 );
verify_rule< must< partial< one< 'a' > > > >( __LINE__, __FILE__, "aa", result_type::success, 1 );
verify_rule< must< partial< one< 'a' > > > >( __LINE__, __FILE__, "ab", result_type::success, 1 );
verify_rule< must< partial< one< 'a' > > > >( __LINE__, __FILE__, "ba", result_type::success, 2 );

verify_rule< must< partial< one< 'a' >, one< 'b' > > > >( __LINE__, __FILE__, "", result_type::success, 0 );
verify_rule< must< partial< one< 'a' >, one< 'b' > > > >( __LINE__, __FILE__, "a", result_type::success, 0 );
verify_rule< must< partial< one< 'a' >, one< 'b' > > > >( __LINE__, __FILE__, "ab", result_type::success, 0 );
verify_rule< must< partial< one< 'a' >, one< 'b' > > > >( __LINE__, __FILE__, "aba", result_type::success, 1 );
verify_rule< must< partial< one< 'a' >, one< 'b' > > > >( __LINE__, __FILE__, "abab", result_type::success, 2 );
verify_rule< must< partial< one< 'a' >, one< 'b' > > > >( __LINE__, __FILE__, "bab", result_type::success, 3 );
verify_rule< must< partial< one< 'a' >, one< 'b' > > > >( __LINE__, __FILE__, "cb", result_type::success, 2 );
#endif

bool success = false;
TAO_PEGTL_TEST_ASSERT( parse< partial< eof >, my_action >( memory_input( "", __FUNCTION__ ), success ) );
TAO_PEGTL_TEST_ASSERT( success );
}

} // namespace tao::pegtl

#include "main.hpp"

0 comments on commit dffdff0

Please sign in to comment.