diff --git a/packages/PEGTL/.gitrepo b/packages/PEGTL/.gitrepo
index 76f9ade4da3d712501a1125fdbd270c619586607..7eea19117c858927ae7c942b0fe1631d3c411044 100644
--- a/packages/PEGTL/.gitrepo
+++ b/packages/PEGTL/.gitrepo
@@ -6,7 +6,7 @@
 [subrepo]
 	remote = git@github.com:taocpp/PEGTL.git
 	branch = master
-	commit = 83b6cdc717b68a3714e6c76e13dbc4a571b491c1
-	parent = 6a6f7b2c81c10365515dc8302a829ba6200d27b0
+	commit = 1a4a2d0df43f773893e0e4102d56d85e6b3fb7fc
+	parent = 28dff7b443629a23205fd32909491e7e5de495a3
 	cmdver = 0.4.1
 	method = merge
diff --git a/packages/PEGTL/.travis.yml b/packages/PEGTL/.travis.yml
index 4164eefa4d0022a6126b0df99fbfcfd20f55deb5..95e20d5032f8e6f5e3cd3adb8f7d200153d039a8 100644
--- a/packages/PEGTL/.travis.yml
+++ b/packages/PEGTL/.travis.yml
@@ -112,7 +112,7 @@ jobs:
       osx_image: xcode10.3
 
     - <<: *osx
-      osx_image: xcode11.3
+      osx_image: xcode11.4
 
     - &android
       compiler: clang
diff --git a/packages/PEGTL/Makefile b/packages/PEGTL/Makefile
index 692ba2392598d9198501fafdec6055cdb7da0bd5..9ff538aff11cec39c905b5d76871e6338af76b73 100644
--- a/packages/PEGTL/Makefile
+++ b/packages/PEGTL/Makefile
@@ -39,7 +39,7 @@ SOURCES := $(shell find src -name '*.cpp')
 DEPENDS := $(SOURCES:%.cpp=build/%.d)
 BINARIES := $(SOURCES:%.cpp=build/%)
 
-CLANG_TIDY_HEADERS := $(filter-out include/tao/pegtl/internal/endian_win.hpp include/tao/pegtl/internal/file_mapper_win32.hpp,$(HEADERS))
+CLANG_TIDY_HEADERS := $(filter-out include/tao/pegtl/internal/file_mapper_win32.hpp include/tao/pegtl/contrib/internal/endian_win.hpp,$(HEADERS))
 
 UNIT_TESTS := $(filter build/src/test/%,$(BINARIES))
 
diff --git a/packages/PEGTL/README.md b/packages/PEGTL/README.md
index e7d168d600b2cb3c23f05579b31b0a3b5c7ea725..2b57955028ddacc5d5418558f98a2589c1fa6680 100644
--- a/packages/PEGTL/README.md
+++ b/packages/PEGTL/README.md
@@ -67,7 +67,7 @@ Each commit is automatically tested with multiple architectures, operating syste
 
   * macOS 10.13, Xcode 9.4
   * macOS 10.14, Xcode 10.3
-  * macOS 10.14, Xcode 11.3
+  * macOS 10.14, Xcode 11.4
 
 * Ubuntu 16.04 LTS (using libstdc++)
 
@@ -85,46 +85,47 @@ For details see the [changelog](doc/Changelog.md).
 
 In appreciation of all contributions here are the people that have [directly contributed](https://github.com/taocpp/PEGTL/graphs/contributors) to the PEGTL and/or its development.
 
-[<img alt="andoma" src="https://avatars2.githubusercontent.com/u/216384?v=4&s=117" width="117">](https://github.com/andoma)
-[<img alt="Bjoe" src="https://avatars3.githubusercontent.com/u/727911?v=4&s=117" width="117">](https://github.com/Bjoe)
-[<img alt="bwagner" src="https://avatars3.githubusercontent.com/u/447049?v=4&s=117" width="117">](https://github.com/bwagner)
-[<img alt="cdiggins" src="https://avatars2.githubusercontent.com/u/1759994?s=460&v=4?v=4&s=117" width="117">](https://github.com/cdiggins)
-[<img alt="delpinux" src="https://avatars0.githubusercontent.com/u/35096584?v=4&s=117" width="117">](https://github.com/delpinux)
-[<img alt="dkopecek" src="https://avatars2.githubusercontent.com/u/1353140?v=4&s=117" width="117">](https://github.com/dkopecek)
-[<img alt="irrequietus" src="https://avatars0.githubusercontent.com/u/231192?v=4&s=117" width="117">](https://github.com/irrequietus)
-[<img alt="jedelbo" src="https://avatars2.githubusercontent.com/u/572755?v=4&s=117" width="117">](https://github.com/jedelbo)
-[<img alt="joelfrederico" src="https://avatars0.githubusercontent.com/u/458871?v=4&s=117" width="117">](https://github.com/joelfrederico)
-[<img alt="johelegp" src="https://avatars3.githubusercontent.com/u/21071787?v=4&s=117" width="117">](https://github.com/johelegp)
-[<img alt="jovermann" src="https://avatars3.githubusercontent.com/u/6087443?v=4&s=117" width="117">](https://github.com/jovermann)
-[<img alt="kneth" src="https://avatars0.githubusercontent.com/u/1225363?v=4&s=117" width="117">](https://github.com/kneth)
-[<img alt="kuzmas" src="https://avatars1.githubusercontent.com/u/1858553?v=4&s=117" width="117">](https://github.com/kuzmas)
-[<img alt="lambdafu" src="https://avatars1.githubusercontent.com/u/1138455?v=4&s=117" width="117">](https://github.com/lambdafu)
-[<img alt="lichray" src="https://avatars2.githubusercontent.com/u/433009?v=4&s=117" width="117">](https://github.com/lichray)
-[<img alt="michael-brade" src="https://avatars0.githubusercontent.com/u/8768950?v=4&s=117" width="117">](https://github.com/michael-brade)
-[<img alt="mkrupcale" src="https://avatars1.githubusercontent.com/u/13936020?v=4&s=117" width="117">](https://github.com/mkrupcale)
-[<img alt="NewProggie" src="https://avatars3.githubusercontent.com/u/162319?s=460&v=4?v=4&s=117" width="117">](https://github.com/NewProggie)
-[<img alt="ohanar" src="https://avatars0.githubusercontent.com/u/1442822?v=4&s=117" width="117">](https://github.com/ohanar)
-[<img alt="pauloscustodio" src="https://avatars1.githubusercontent.com/u/70773?v=4&s=117" width="117">](https://github.com/pauloscustodio)
-[<img alt="pleroux0" src="https://avatars2.githubusercontent.com/u/39619854?v=4&s=117" width="117">](https://github.com/pleroux0)
-[<img alt="quadfault" src="https://avatars3.githubusercontent.com/u/30195320?v=4&s=117" width="117">](https://github.com/quadfault)
-[<img alt="robertcampion" src="https://avatars2.githubusercontent.com/u/4220569?v=4&s=117" width="117">](https://github.com/robertcampion)
-[<img alt="samhocevar" src="https://avatars2.githubusercontent.com/u/245089?v=4&s=117" width="117">](https://github.com/samhocevar)
-[<img alt="sanssecours" src="https://avatars2.githubusercontent.com/u/691989?v=4&s=117" width="117">](https://github.com/sanssecours)
-[<img alt="sgbeal" src="https://avatars1.githubusercontent.com/u/235303?v=4&s=117" width="117">](https://github.com/sgbeal)
-[<img alt="skyrich62" src="https://avatars3.githubusercontent.com/u/23705081?v=4&s=117" width="117">](https://github.com/skyrich62)
-[<img alt="studoot" src="https://avatars1.githubusercontent.com/u/799344?v=4&s=117" width="117">](https://github.com/studoot)
-[<img alt="SvenJo" src="https://avatars1.githubusercontent.com/u/1538181?s=460&v=4?v=4&s=117" width="117">](https://github.com/SvenJo)
-[<img alt="wickedmic" src="https://avatars1.githubusercontent.com/u/12001183?v=4&s=117" width="117">](https://github.com/wickedmic)
-[<img alt="wravery" src="https://avatars0.githubusercontent.com/u/6502881?v=4&s=117" width="117">](https://github.com/wravery)
-[<img alt="zhihaoy" src="https://avatars2.githubusercontent.com/u/43971430?v=4&s=117" width="117">](https://github.com/zhihaoy)
+[<img alt="andoma" src="https://avatars.githubusercontent.com/u/216384?s=117" width="117">](https://github.com/andoma)
+[<img alt="bjoe" src="https://avatars.githubusercontent.com/u/727911?s=117" width="117">](https://github.com/bjoe)
+[<img alt="bwagner" src="https://avatars.githubusercontent.com/u/447049?s=117" width="117">](https://github.com/bwagner)
+[<img alt="cdiggins" src="https://avatars.githubusercontent.com/u/1759994?s=460&v=4?s=117" width="117">](https://github.com/cdiggins)
+[<img alt="delpinux" src="https://avatars.githubusercontent.com/u/35096584?s=117" width="117">](https://github.com/delpinux)
+[<img alt="dkopecek" src="https://avatars.githubusercontent.com/u/1353140?s=117" width="117">](https://github.com/dkopecek)
+[<img alt="irrequietus" src="https://avatars.githubusercontent.com/u/231192?s=117" width="117">](https://github.com/irrequietus)
+[<img alt="jedelbo" src="https://avatars.githubusercontent.com/u/572755?s=117" width="117">](https://github.com/jedelbo)
+[<img alt="joelfrederico" src="https://avatars.githubusercontent.com/u/458871?s=117" width="117">](https://github.com/joelfrederico)
+[<img alt="johelegp" src="https://avatars.githubusercontent.com/u/21071787?s=117" width="117">](https://github.com/johelegp)
+[<img alt="jovermann" src="https://avatars.githubusercontent.com/u/6087443?s=117" width="117">](https://github.com/jovermann)
+[<img alt="kneth" src="https://avatars.githubusercontent.com/u/1225363?s=117" width="117">](https://github.com/kneth)
+[<img alt="kuzmas" src="https://avatars.githubusercontent.com/u/1858553?s=117" width="117">](https://github.com/kuzmas)
+[<img alt="lambdafu" src="https://avatars.githubusercontent.com/u/1138455?s=117" width="117">](https://github.com/lambdafu)
+[<img alt="lichray" src="https://avatars.githubusercontent.com/u/433009?s=117" width="117">](https://github.com/lichray)
+[<img alt="michael-brade" src="https://avatars.githubusercontent.com/u/8768950?s=117" width="117">](https://github.com/michael-brade)
+[<img alt="mkrupcale" src="https://avatars.githubusercontent.com/u/13936020?s=117" width="117">](https://github.com/mkrupcale)
+[<img alt="newproggie" src="https://avatars.githubusercontent.com/u/162319?s=460&v=4?s=117" width="117">](https://github.com/newproggie)
+[<img alt="obiwahn" src="https://avatars.githubusercontent.com/u/741109?s=117" width="117">](https://github.com/obiwahn)
+[<img alt="ohanar" src="https://avatars.githubusercontent.com/u/1442822?s=117" width="117">](https://github.com/ohanar)
+[<img alt="pauloscustodio" src="https://avatars.githubusercontent.com/u/70773?s=117" width="117">](https://github.com/pauloscustodio)
+[<img alt="pleroux0" src="https://avatars.githubusercontent.com/u/39619854?s=117" width="117">](https://github.com/pleroux0)
+[<img alt="quadfault" src="https://avatars.githubusercontent.com/u/30195320?s=117" width="117">](https://github.com/quadfault)
+[<img alt="robertcampion" src="https://avatars.githubusercontent.com/u/4220569?s=117" width="117">](https://github.com/robertcampion)
+[<img alt="samhocevar" src="https://avatars.githubusercontent.com/u/245089?s=117" width="117">](https://github.com/samhocevar)
+[<img alt="sanssecours" src="https://avatars.githubusercontent.com/u/691989?s=117" width="117">](https://github.com/sanssecours)
+[<img alt="sgbeal" src="https://avatars.githubusercontent.com/u/235303?s=117" width="117">](https://github.com/sgbeal)
+[<img alt="skyrich62" src="https://avatars.githubusercontent.com/u/23705081?s=117" width="117">](https://github.com/skyrich62)
+[<img alt="studoot" src="https://avatars.githubusercontent.com/u/799344?s=117" width="117">](https://github.com/studoot)
+[<img alt="svenjo" src="https://avatars.githubusercontent.com/u/1538181?s=460&v=4?s=117" width="117">](https://github.com/svenjo)
+[<img alt="wickedmic" src="https://avatars.githubusercontent.com/u/12001183?s=117" width="117">](https://github.com/wickedmic)
+[<img alt="wravery" src="https://avatars.githubusercontent.com/u/6502881?s=117" width="117">](https://github.com/wravery)
+[<img alt="zhihaoy" src="https://avatars.githubusercontent.com/u/43971430?s=117" width="117">](https://github.com/zhihaoy)
 
 ## The Art of C++
 
 The PEGTL is part of [The Art of C++](https://taocpp.github.io/).
 
-[<img alt="ColinH" src="https://avatars0.githubusercontent.com/u/113184?v=4&s=117" width="117">](https://github.com/ColinH)
-[<img alt="d-frey" src="https://avatars2.githubusercontent.com/u/3956325?v=4&s=117" width="117">](https://github.com/d-frey)
-[<img alt="uilianries" src="https://avatars0.githubusercontent.com/u/4870173?v=4&s=117" width="117">](https://github.com/uilianries)
+[<img alt="colinh" src="https://avatars.githubusercontent.com/u/113184?s=117" width="117">](https://github.com/colinh)
+[<img alt="d-frey" src="https://avatars.githubusercontent.com/u/3956325?s=117" width="117">](https://github.com/d-frey)
+[<img alt="uilianries" src="https://avatars.githubusercontent.com/u/4870173?s=117" width="117">](https://github.com/uilianries)
 
 ## Contact
 
diff --git a/packages/PEGTL/doc/Actions-and-States.md b/packages/PEGTL/doc/Actions-and-States.md
index 0045ef7b48191706e85d47296ce8d635fd345c1f..ae234dc28007583c315f81b06205a7198dfb8dc1 100644
--- a/packages/PEGTL/doc/Actions-and-States.md
+++ b/packages/PEGTL/doc/Actions-and-States.md
@@ -59,8 +59,8 @@ An example for a simple action for a specific state might look like this.
 template<>
 struct my_action< my_rule >
 {
-   template< typename Input >
-   static void apply( const Input& in, my_state& s )
+   template< typename ActionInput >
+   static void apply( const ActionInput& in, my_state& s )
    {
       // ... implement
    }
@@ -93,8 +93,8 @@ struct my_action< tao::pegtl::any >
    // Implement an apply() function that will be called by
    // the PEGTL every time tao::pegtl::any matches during
    // the parsing run.
-   template< typename Input >
-   static void apply( const Input& in, std::string& out )
+   template< typename ActionInput >
+   static void apply( const ActionInput& in, std::string& out )
    {
       // Get the portion of the original input that the
       // rule matched this time as string and append it
@@ -103,8 +103,8 @@ struct my_action< tao::pegtl::any >
    }
 };
 
-template< typename Input >
-std::string as_string( Input& in )
+template< typename ParseInput >
+std::string as_string( ParseInput& in )
 {
    // Set up the states, here a single std::string as that is
    // what our action requires as additional function argument.
@@ -143,8 +143,8 @@ As seen above, the actual functions that are called when an action is applied ar
 template<>
 struct my_action< my_rule >
 {
-   template< typename Input >
-   static void apply( const Input& in, /* all the states */ )
+   template< typename ActionInput >
+   static void apply( const ActionInput& in, /* all the states */ )
    {
       // Called whenever matching my_rule during a parsing run
       // succeeds (and actions are not disabled). The argument
@@ -166,12 +166,12 @@ For illustrative purposes, we will assume that the input passed to `apply()` is
 Any resemblance to real classes is not a coincidence, see `include/tao/pegtl/internal/action_input.hpp`.
 
 ```c++
-template< typename Input >
+template< typename ParseInput >
 class action_input
 {
 public:
-   using input_t = Input;
-   using iterator_t = typename Input::iterator_t;
+   using input_t = ParseInput;
+   using iterator_t = typename ParseInput::iterator_t;
 
    bool empty() const noexcept;
    std::size_t size() const noexcept;
@@ -187,7 +187,7 @@ public:
 
    pegtl::position position() const noexcept;  // Not efficient with tracking_mode::lazy.
 
-   const Input& input() const noexcept;
+   const ParseInput& input() const noexcept;
    const iterator_t& iterator() const noexcept;
 };
 ```
@@ -421,8 +421,8 @@ template<>
 struct my_action< my_rule >
    : tao::pegtl::change_states< new_state_1, new_state_2 >
 {
-   template< typename Input >
-   static void success( const Input&, new_state_1&, new_state_2&, /* the previous states*/ )
+   template< typename ParseInput >
+   static void success( const ParseInput&, new_state_1&, new_state_2&, /* the previous states*/ )
    {
       // Do whatever with both the new and the old states...
    }
@@ -452,9 +452,9 @@ struct my_action< my_rule >
              rewind_mode M,
              template< typename... > class Action,
              template< typename... > class Control,
-             typename Input,
+             typename ParseInput,
              typename... States >
-   static bool match( Input& in, States&&... st )
+   static bool match( ParseInput& in, States&&... st )
    {
       // Call the function that would have been called otherwise,
       // in this case without changing anything...
diff --git a/packages/PEGTL/doc/Changelog.md b/packages/PEGTL/doc/Changelog.md
index 25c9c3738ad28483b3834d784917f3ce1f000563..3198b38dfad39a10d59ff81600ee256c3b0ded67 100644
--- a/packages/PEGTL/doc/Changelog.md
+++ b/packages/PEGTL/doc/Changelog.md
@@ -9,16 +9,26 @@
 * Updated required [CMake](https://cmake.org/) version to 3.8.
 * The macro `TAO_PEGTL_NAMESPACE` now contains the fully qualified namespace, e.g. `tao::pegtl`.
 * Replaced `tao::pegtl::input_error` with `std::system_error`.
-* Added `tao::pegtl::error_message< Rule >` as a non-intrusive way to define global parse errors.
+* Moved the analysis function and header to contrib.
+* Replaced `analysis_t` with more general and complete `rule_t` and `subs_t`.
+* Added functions to visit all rules of a grammar.
+* Added infrastructure and functions to measure rule coverage of a parsing run.
+* Added [`must_if<>`](Errors-and-Exceptions.md#custom-exception-messages)
+  * Allows to define custom error messages for global errors.
+  * As a non-intrusive way to define global parse errors for a grammar retroactively.
+* Moved rule `eolf` from inline namespace `tao::pegtl::ascii` to `tao::pegtl`.
 * Changed message of `tao::pegtl::parse_error` to no longer contain the position redundantly.
 * Changed rules in `tao/pegtl/contrib/integer.hpp` to not accept redundant leading zeros.
 * Added rules to `tao/pegtl/contrib/integer.hpp` that test unsigned values against a maximum.
 * Removed option of [state](Rule-Reference.md#state-s-r-)'s `S::success()` to have an extended signature to get access to the current `apply_mode`, `rewind_mode`, *action*- and *control* class (template).
-* Added `[[nodiscard]]` to most non-void functions.
+* Added `[[nodiscard]]` or `[[noreturn]]` to most non-void functions.
 * Removed compatibility macros starting with `TAOCPP_PEGTL_`.
 * Removed compatibility uppercase enumerators.
 * Removed compatibility `peek_byte()` member functions.
 * Removed compatibility header `changes.hpp` from contrib.
+* Demoted UTF-16 and UTF-32 support to contrib.
+* Demoted UINT-8, UINT-16, UINT-32 and UINT-64 support to contrib.
+* Folded `contrib/counter.hpp` into `json_count.cpp`, count is superceded by coverage.
 * Refactored demangling.
   * Improves generated code to be shorter and more efficient.
   * Removes the need for RTTI.
diff --git a/packages/PEGTL/doc/Contrib-and-Examples.md b/packages/PEGTL/doc/Contrib-and-Examples.md
index 7afc0fe8e4dc06d854ca167e49bccfa8765d6264..c4292ae83ed82089782a279c56bbef373c19080a 100644
--- a/packages/PEGTL/doc/Contrib-and-Examples.md
+++ b/packages/PEGTL/doc/Contrib-and-Examples.md
@@ -51,13 +51,6 @@ For all questions and remarks contact us at **taocpp(at)icemx.net**.
 * Changes the state.
 * Ready for production use but might be changed in the future.
 
-###### `<tao/pegtl/contrib/counter.hpp>`
-
-* Control class for obtaining basic statistics from a parsing run, namely how often each rule
-  1. was attempted to match,
-  2. succeeded to match,
-  3. failed to match.
-
 ###### `<tao/pegtl/contrib/disable_action.hpp>`
 
 * Disables actions.
@@ -186,8 +179,7 @@ Extends on `json_parse.cpp` by parsing JSON files into generic JSON data structu
 
 ###### `src/example/pegtl/json_count.cpp`
 
-Shows how to use the included [counter control](#taopegtlcontribcounterhpp), here together with the JSON grammar from `<tao/pegtl/contrib/json.hpp>`.
-Invoked with one or more JSON files as argument, will attempt to parse the files and print the statistics counters to `std::cout`.
+Shows how to use a simple custom control to create some parsing statistics while parsing JSON files.
 
 ###### `src/example/pegtl/lua53_parse.cpp`
 
diff --git a/packages/PEGTL/doc/Control-and-Debug.md b/packages/PEGTL/doc/Control-and-Debug.md
index e6581e30d950d34d5b933a9d231e1089ad6d4e93..c8817e611e8a84e2c7894da571b74798bf6edf7c 100644
--- a/packages/PEGTL/doc/Control-and-Debug.md
+++ b/packages/PEGTL/doc/Control-and-Debug.md
@@ -28,42 +28,44 @@ The `normal` control class template included with the PEGTL is used by default a
 template< typename Rule >
 struct normal
 {
-   template< typename Input,
+   static constexpr bool enable;  // See Meta-Data-and-Visit.md
+
+   template< typename ParseInput,
              typename... States >
-   static void start( const Input&, States&&... );
+   static void start( const ParseInput&, States&&... );
 
-   template< typename Input,
+   template< typename ParseInput,
              typename... States >
-   static void success( const Input&, States&&... );
+   static void success( const ParseInput&, States&&... );
 
-   template< typename Input,
+   template< typename ParseInput,
              typename... States >
-   static void failure( const Input&, States&&... );
+   static void failure( const ParseInput&, States&&... );
 
-   template< typename Input,
+   template< typename ParseInput,
              typename... States >
-   static void raise( const Input& in, States&&... );
+   static void raise( const ParseInput& in, States&&... );
 
    template< template< typename... > class Action,
              typename Iterator,
-             typename Input,
+             typename ParseInput,
              typename... States >
-   static auto apply( const Iterator& begin, const Input& in, States&&... st )
+   static auto apply( const Iterator& begin, const ParseInput& in, States&&... st )
       -> decltype( ... );
 
    template< template< typename... > class Action,
-             typename Input,
+             typename ParseInput,
              typename... States >
-   static auto apply0( const Input&, States&&... st )
+   static auto apply0( const ParseInput&, States&&... st )
       -> decltype( ... );
 
    template< apply_mode A,
              rewind_mode M,
              template< typename... > class Action,
              template< typename... > class Control,
-             typename Input,
+             typename ParseInput,
              typename... States >
-   static bool match( Input& in, States&&... st );
+   static bool match( ParseInput& in, States&&... st );
 };
 ```
 
diff --git a/packages/PEGTL/doc/Errors-and-Exceptions.md b/packages/PEGTL/doc/Errors-and-Exceptions.md
index eb042568405fae96949908d4dddfcc8289549c9f..7cd752ef7eb009d7489070f9286d447613113e58 100644
--- a/packages/PEGTL/doc/Errors-and-Exceptions.md
+++ b/packages/PEGTL/doc/Errors-and-Exceptions.md
@@ -12,12 +12,16 @@ Other exception classes can be used freely from actions and custom parsing rules
 ## Contents
 
 * [Local to Global Failure](#local-to-global-failure)
+  * [Intrusive Local to Global Failure](#intrusive-local-to-global-failure)
+  * [Non-Intrusive Local to Global Failure](#non-intrusive-local-to-global-failure)
 * [Global to Local Failure](#global-to-local-failure)
 * [Examples for Must Rules](#examples-for-must-rules)
 * [Custom Exception Messages](#custom-exception-messages)
 
 ## Local to Global Failure
 
+### Intrusive Local to Global Failure
+
 A local failure returned by a parsing rule is not necessarily propagated to the top, for example when the rule is
 
 * in a rule like `not_at<>`, `opt<>` or `star<>`, or
@@ -33,16 +37,12 @@ In any case, the task of actually throwing an exception is delegated to the [con
 
 Note that rules and actions can throw exceptions directly, meaning those are not generated from the [control class'](Control-and-Debug.md) `raise()`.
 
-If a (pre-defined) grammar does not contain any `must<>` rule (or a related rule), one can still turn any local error into a global error by specializing `tao::pegtl::error_message`.
+### Non-Intrusive Local to Global Failure
 
-```c++
-namespace tao::pegtl
-{
-   template<> constexpr const char* error_message< my_rule > = "my_rule failed!";
-}
-```
-
-If the parser tries to match `my_rule`, and it fails, a `parse_error` with the current position and the provided error message is thrown.
+If a grammar does not contain any `must<>` rule(s) (or `raise<>`, `if_must<>`, ...), one can still convert a local failure for a rule into a global failure via `must_if<>`.
+This helper allows one to create a [control class'](Control-and-Debug.md) and provide custom error messages for global failures.
+If an error message is provided for a rule that would normally return a local failure, it is automatically converted to a global failure.
+See [Custom Exception Messages](#custom-exception-messages) for more information.
 
 ## Global to Local Failure
 
@@ -110,64 +110,48 @@ The same use of `if_must<>` can be applied to the `literal` rule assuming that i
 
 ## Custom Exception Messages
 
-By default, when using any `must<>` error points, the exceptions generated by the PEGTL use the demangled name of the failed parsing rule as descriptive part of the error message. This is often insufficient and one would like to provide more meaningful error messages.
+By default, when using any `must<>` error points, the exceptions generated by the PEGTL use the demangled name of the failed parsing rule as descriptive part of the error message.
+This is often insufficient and one would like to provide more meaningful error messages.
 
-A practical technique to provide customised error message for all `must<>` error points uses a custom control class whose `raise()` uses a static string as error message.
+A practical technique to provide customised error messages for all `must<>` error points uses the `must_if<>` helper.
+
+For an example of this method see `src/examples/pegtl/json_errors.hpp`, where all errors that might occur in the supplied JSON grammar are customised like this:
 
 ```c++
-template< typename Rule >
-struct my_control
-   : tao::pegtl::normal< Rule >
-{
-   static const std::string error_message;
-
-   template< typename Input, typename... States >
-   static void raise( const Input& in, States&&... )
-   {
-      throw tao::pegtl::parse_error( error_message, in );
-   }
-};
-```
+template< typename > inline constexpr const char* error_message = nullptr;
 
-Now only the `error_message` string needs to be specialised per error point as follows.
+template<> inline constexpr auto error_message< tao::pegtl::json::text > = "no valid JSON";
 
-```c++
-template<> inline const std::string my_control< MyRule >::error_message = "expected ...";
-```
+template<> inline constexpr auto error_message< tao::pegtl::json::end_array > = "incomplete array, expected ']'";
+template<> inline constexpr auto error_message< tao::pegtl::json::end_object > = "incomplete object, expected '}'";
+template<> inline constexpr auto error_message< tao::pegtl::json::member > = "expected member";
+template<> inline constexpr auto error_message< tao::pegtl::json::name_separator > = "expected ':'";
+template<> inline constexpr auto error_message< tao::pegtl::json::array_element > = "expected value";
+template<> inline constexpr auto error_message< tao::pegtl::json::value > = "expected value";
 
-Since `raise()` is only instantiated for those rules for which `must<>` could trigger an exception, it is sufficient to provide specialisations of the error message string for those rules.
-Furthermore, there will be a linker error for all rules for which the specialisation was forgotten although `raise()` could be called.
-For an example of this method see `src/examples/pegtl/json_errors.hpp`, where all errors that might occur in the supplied JSON grammar are customised like this:
+template<> inline constexpr auto error_message< tao::pegtl::json::digits > = "expected at least one digit";
+template<> inline constexpr auto error_message< tao::pegtl::json::xdigit > = "incomplete universal character name";
+template<> inline constexpr auto error_message< tao::pegtl::json::escaped > = "unknown escape sequence";
+template<> inline constexpr auto error_message< tao::pegtl::json::char_ > = "invalid character in string";
+template<> inline constexpr auto error_message< tao::pegtl::json::string::content > = "unterminated string";
+template<> inline constexpr auto error_message< tao::pegtl::json::key::content > = "unterminated key";
 
-```c++
-template<> inline const std::string errors< tao::pegtl::json::text >::error_message = "no valid JSON";
-
-template<> inline const std::string errors< tao::pegtl::json::end_array >::error_message = "incomplete array, expected ']'";
-template<> inline const std::string errors< tao::pegtl::json::end_object >::error_message = "incomplete object, expected '}'";
-template<> inline const std::string errors< tao::pegtl::json::member >::error_message = "expected member";
-template<> inline const std::string errors< tao::pegtl::json::name_separator >::error_message = "expected ':'";
-template<> inline const std::string errors< tao::pegtl::json::array_element >::error_message = "expected value";
-template<> inline const std::string errors< tao::pegtl::json::value >::error_message = "expected value";
-
-template<> inline const std::string errors< tao::pegtl::json::digits >::error_message = "expected at least one digit";
-template<> inline const std::string errors< tao::pegtl::json::xdigit >::error_message = "incomplete universal character name";
-template<> inline const std::string errors< tao::pegtl::json::escaped >::error_message = "unknown escape sequence";
-template<> inline const std::string errors< tao::pegtl::json::char_ >::error_message = "invalid character in string";
-template<> inline const std::string errors< tao::pegtl::json::string::content >::error_message = "unterminated string";
-template<> inline const std::string errors< tao::pegtl::json::key::content >::error_message = "unterminated key";
-
-template<> inline const std::string errors< tao::pegtl::eof >::error_message = "unexpected character after JSON value";
-```
+template<> inline constexpr auto error_message< tao::pegtl::eof > = "unexpected character after JSON value";
 
-It is also possible to provide a default error message that will be chosen by the compiler in the absence of a specialised one as follows.
+// As must_if can not take error_message as a template parameter directly, we need to wrap it:
+struct error { template< typename Rule > static constexpr auto message = error_message< Rule >; };
 
-```c++
-template< typename T >
-inline const std::string my_control< T >::error_message =
-   "parse error matching " + tao::pegtl::internal::demangle< T >();
+template< typename Rule > using control = tao::pegtl::must_if< error >::control< Rule >;
 ```
 
-This is similar to the default behaviour, but one will not get a linker error in case as error point is missed.
+Since `raise()` is only instantiated for those rules for which `must<>` could trigger an exception, it is sufficient to provide specialisations of the error message string for those rules.
+Furthermore, there will be a compile-time error (i.e. a `static_assert`) for all rules for which the specialisation was forgotten although `raise()` could be called.
+
+The [control class](Control-and-Debug.md) provided by `must_if<>` also turns local failures into global failure if an error message is provided, i.e. if the error message is not `nullptr`.
+This means that one can provide additional points in the grammar where a global failure is triggered, even when the grammar contains no `must<>` error points.
+
+`must_if<>` expects a wrapper for the error message as its first template parameter.
+There is a second parameter for the base control class, which defaults to `tao::pegtl::normal`, and which can combine `must_if`'s control class with other control classes.
 
 It is advisable to choose the error points in the grammar with prudence.
 This choice becoming particularly cumbersome and/or resulting in a large number of error points might be an indication of the grammar needing some kind of simplification or restructuring.
diff --git a/packages/PEGTL/doc/Getting-Started.md b/packages/PEGTL/doc/Getting-Started.md
index 9681ece206b4158de675735efefe360742da5070..d2ef73f544ed8e824f94101b2c967c789e9227bc 100644
--- a/packages/PEGTL/doc/Getting-Started.md
+++ b/packages/PEGTL/doc/Getting-Started.md
@@ -52,8 +52,8 @@ namespace hello
    template<>
    struct action< name >
    {
-      template< typename Input >
-      static void apply( const Input& in, std::string& v )
+      template< typename ParseInput >
+      static void apply( const ParseInput& in, std::string& v )
       {
          v = in.string();
       }
diff --git a/packages/PEGTL/doc/Grammar-Analysis.md b/packages/PEGTL/doc/Grammar-Analysis.md
index 74e181c5752a9adf064eed217aa51202718d9887..fa5e17230df1130fe8b4415473588507057fe683 100644
--- a/packages/PEGTL/doc/Grammar-Analysis.md
+++ b/packages/PEGTL/doc/Grammar-Analysis.md
@@ -1,33 +1,33 @@
 # Grammar Analysis
 
-The PEGTL contains an `analyze()` function that checks a grammar for rules that can go into an infinite loop without consuming input.
-
-Unfortunately, given the expressive power of PEGs and the possibility of arbitrary custom combinator rules, it is impossible to detect *all* kinds of infinite loops.
-
-It does however catch most cases of left-recursion that are typical for grammars converted from CFGs or other formalisms that gracefully handle left-recursion.
+The PEGTL contains an `analyze()` function that checks a grammar for rules that can enter an infinite loop without consuming input.
 
 ## Content
 
-* [Rule Analysis](#rule-analysis)
-* [Background](#background)
-* [Custom Rules](#custom-rules)
+* [Running](#running)
+* [Example](#example)
+* [Requirements](#requirements)
+* [Limitations](#limitations)
 
-## Rule Analysis
+## Running
 
-In order to run an analysis on a grammar it is necessary to explicitly include `<tao/pegtl/analyze.hpp>`.
+In order to run an analysis on a grammar it is necessary to explicitly include `<tao/pegtl/contrib/analyze.hpp>`.
 Then call `tao::pegtl::analyze()` with the top-level grammar rule as template argument.
 
 ```c++
-#include <tao/pegtl/analyze.hpp>
+#include <tao/pegtl/contrib/analyze.hpp>
 
-const std::size_t issues_found = tao::pegtl::analyze< my_grammar >();
+const std::size_t issues = tao::pegtl::analyze< my_grammar >();
 ```
 
-`analyze()` returns the number of issues found and writes some information about them to `std::cout`.
+The `analyze()` function prints some information about the found issues to `std::cout` and returns the total number of issues found.
+The output can be suppressed by passing `false` as sole function argument.
 
 Analysing a grammar is usually only done while developing and debugging a grammar, or after changing it.
 
-Regarding the kinds of issues that are detected, consider the following example grammar rules.
+## Example
+
+Regarding the kinds of issues that are detected, consider the following example rules.
 
 ```c++
 struct bar;
@@ -45,40 +45,83 @@ As shown by the example program `src/example/pegtl/analyze.cpp`, the grammar ana
 
 Due to the differences regarding back-tracking and non-deterministic behaviour, this kind of infinite loop is a frequent issue when translating a CFG into a PEG.
 
-## Background
+## Requirements
 
-In order to look for infinite loops in a grammar, `analyze()` needs some information about all rules in the grammar.
-This "information" consists of a classification of the rules according to the following enum, plus, for non-atomic rules, a list of the sub-rules.
+The `analyze()` function operates on an abstract form of the grammar that is mostly equivalent to the original grammar regarding the possibility of infinite cycles without progress.
 
-```c++
-// namespace tao::pegtl::analysis
+This abstract form is obtained via specialisations of the `analyze_traits<>` class template which each must have exactly one of `analyze_any_traits`, `analyze_opt_traits`, `analyze_seq_traits` and `analyze_sor_traits` as public (direct or indirect) base class.
+
+Specialisations of the `analyze_traits<>` class template are appropriately implemented for all grammar rule classes included with the PEGTL.
+This support automatically extends to all custom rules built "the usual way" via public inheritance of (combinations and specialisations of) rules included with the PEGTL.
+
+For true custom rules, i.e. rules that implement their own `match()` function, the following steps need to be taken for them to work with the grammar analysis.
 
-enum class rule_type : char
+1. The rule needs a `rule_t` that, usually for true custom rules, is a type alias for the grammar rule itself.
+2. There needs to be a specialisation of the `analyze_traits<>` for the custom rule, with an additional first template parameter:
+
+Assuming a custom rule like the following
+
+```c++
+struct my_rule
 {
-   any,
-   opt,
-   seq,
-   sor
+   using rule_t = my_rule;
+
+   template< typename Input >
+   bool match( Input& in )
+   {
+      return /* Something that always consumes on success... */ ;
+   }
 };
 ```
 
-This enum value and rule list are provided to `analyze()` via an `analyze_t` type member that all rules that are part of a grammar that is to be analysed with `analyze()` need to define.
+the analyze traits need to be set up as
+
+```c++
+// In namespace TAO_PEGTL_NAMESPACE
+
+template< typename Name >
+struct analyze_traits< Name, my_rule >
+   : analyze_any_traits<>
+{};
+```
+
+where the base class is chosen as follows.
+
+1. `analyze_any_traits<>` is used for rules that always consume when they succeed.
+2. `analyze_opt_traits<>` is used for rules that (can also) succeed without consuming.
+3. `analyze_seq_traits<>` is used for rules that, regarding their match behaviour, are equivalent to `seq<>`.
+4. `analyze_sor_traits<>` is used for rules that, regarding their match behaviour, are equivalent to `sor<>`.
+
+If `my_rule` has rules, that it calls upon as sub-rules, as template parameters, these need to be passed as template parameters to the chosen base class.
+
+Note that the first template parameter `Name` is required by the analyse traits of some rules in order to facilitate their transcription in terms of the basic combinators `seq`, `sor` and `opt`.
+
+For example `R = plus< T >` is equivalent to `seq< T, opt< R > >`, and the corresponding specialisation of the analyse traits is as follows.
+
+```c++
+   template< typename Name, typename... Rules >
+   struct analyze_traits< Name, internal::plus< Rules... > >
+      : analyze_traits< Name, typename seq< Rules..., opt< Name > >::rule_t >
+   {};
+```
+
+Note how the specialisation is for `internal::plus` rather than `plus`.
+The convention is that only the classes that actually implement `match()` define `rule_t`.
+This greatly reduces both the number of classes that need to define `rule_t` as well as the number of required `analyze_traits` specialisations.
+
+Note further how `Name` is required to transform the implicitly iterative rule `plus` into an explicitly recursive form that only uses `seq` and `opt`.
+The analyse traits have the task of simplifying the grammar in order to keep the core analysis algorithm as simple as possible.
 
-The names of the enum values correspond to one of the PEGTL rule classes that has this rule type, however some rule types are used by many different classes.
+Please consult `include/tao/pegtl/contrib/analyze_traits.hpp` for many examples of how to correctly set up analyse traits for more complex rules, in particular for rules that do not directly fall into one of the aforementioned four categories.
 
-* `any` is for rules where "success implies consumption" is true; assumes bounded repetition of conjunction of sub-rules.
-* `opt` is for rules where "success implies consumption" is false; assumes bounded repetition of conjunction of sub-rules.
-* `seq` is for rules where consumption on success depends on non-zero bounded repetition of the conjunction of sub-rules.
-* `sor` is for rules where consumption on success depends on non-zero bounded repetition of the disjunction of sub-rules.
+For any further reaching questions regarding how to set up the traits for custom rules please contact the authors at **taocpp(at)icemx.net**.
 
-At the beginning of an `analyze()` run the function `R::analyze_t::insert()` is called for all rules `R` in the grammar in order to insert the information about the rule `R` into a data structure.
+## Limitations
 
-## Custom Rules
+It has been conjectured, but, given the expressive power of PEGs, not proven, that *all* potential infinite loops are correctly detected.
 
-For custom rules it should usually be sufficient to follow the lead of the rules supplied with the PEGTL and define `analyze_t` to either `tao::pegtl::analysis::generic` or `tao::pegtl::analysis::counted`.
-In both cases, the `rule_type` and the list of sub-rules must be supplied as template parameters.
-Class `tao::pegtl::analysis::counted` additionally takes an integer argument `Count` with the assumption being that a count of zero indicates that everything the rule type is `opt` while a non-zero count uses the rule type given as template parameter.
+In practice it appears to catch all cases of left-recursion that are typical for grammars converted from CFGs or other formalisms that gracefully handle left-recursion.
 
-When a custom rule goes beyond what can be currently expressed and all other questions, please contact the authors at **taocpp(at)icemx.net**.
+False positives are a theoretical problem in that, while relatively easy to trigger, they are not usually encountered when dealing with real world grammars.
 
 Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey
diff --git a/packages/PEGTL/doc/Inputs-and-Parsing.md b/packages/PEGTL/doc/Inputs-and-Parsing.md
index 55a76696902166ed15f2f32999182945ac5a875e..689f0938c74c7c99f6dec5555dd554839524b925 100644
--- a/packages/PEGTL/doc/Inputs-and-Parsing.md
+++ b/packages/PEGTL/doc/Inputs-and-Parsing.md
@@ -303,9 +303,9 @@ template< typename Rule,
           template< typename... > class Control = normal,
           apply_mode A = apply_mode::action,
           rewind_mode M = rewind_mode::required,
-          typename Input,
+          typename ParseInput,
           typename... States >
-bool parse( Input& in,
+bool parse( ParseInput& in,
             States&&... st );
 ```
 
@@ -325,11 +325,11 @@ template< typename Rule,
           template< typename... > class Control = normal,
           apply_mode A = apply_mode::action,
           rewind_mode M = rewind_mode::required,
-          typename Outer,
-          typename Input,
+          typename OuterInput,
+          typename ParseInput,
           typename... States >
-bool parse_nested( const Outer& oi,
-                   Input& in,
+bool parse_nested( const OuterInput& oi,
+                   ParseInput& in,
                    States&&... st );
 ```
 
@@ -440,8 +440,8 @@ template<>
 struct my_action< rep< 4, must< xdigit > >
    : tao::pegtl::discard_input
 {
-   template< typename Input >
-   static void apply( const Input& in, /* the states */ )
+   template< typename ActionInput >
+   static void apply( const ActionInput& in, /* the states */ )
    {
       assert( in.size() == 4 );
       // process the 4 xdigits
diff --git a/packages/PEGTL/doc/Meta-Data-and-Visit.md b/packages/PEGTL/doc/Meta-Data-and-Visit.md
new file mode 100644
index 0000000000000000000000000000000000000000..e8c5f5223abe862508dab87112698284c40851a4
--- /dev/null
+++ b/packages/PEGTL/doc/Meta-Data-and-Visit.md
@@ -0,0 +1,92 @@
+# Meta Data and Visit
+
+Each rule has several type aliases that allow for automatic inspection of a grammar and all of its rules for multiple purposes.
+Note that true custom rules, i.e. rules that implement custom `match()` functions, do **not** need to define these type aliases for parsing.
+They are only required to support functions based on `visit()` and the [grammar analysis](Grammar-Analysis.md).
+
+* [Internals](#internals)
+* [Rule Type](#rule-type)
+* [Sub Rules](#sub-rules)
+* [Grammar Visit](#grammar-visit)
+* [Grammar Print](#grammar-print)
+* [Rule Coverage](#rule-coverage)
+
+## Internals
+
+While accessible in the namespace `TAO_PEGTL_NAMESPACE`, which defaults to `tao::pegtl`, the [rules and combinators](Rule-Reference.md) included with the PEGTL all have their actual implementation in the sub-namespace `internal`.
+For example the header `include/tao/pegtl/rules.hpp` shows how the user-facing rules are nothing more than forwarders to their `internal` implementation.
+
+The original motivation for this additional level of indirection was to prevent uninteded invocation of user-defined actions due to some PEGTL rules being built from exisiting rules instead of having a dedicated implementation.
+For example consider `rep_min` from `include/tao/pegtl/internal/rep_min.hpp`.
+
+```c++
+template< unsigned Min, typename Rule, typename... Rules >
+using rep_min = seq< rep< Min, Rule, Rules... >, star< Rule, Rules... > >;
+```
+
+The expansion of `rep_min` uses the sub-rule `star< Rule, Rules... >`.
+If a grammar were to contain both `rep_min` and `star` with the same sub-rules, and an action were provided for `star` with these exact sub-rules, then the action would not only be called for the explicit occurrences of `star` in the grammar but *also* for the corresponding sub-rule of `rep_min`.
+
+The action invocation for the sub-rule of `rep_min` is considered surprising and undesirable because it exposes implementation details to the user, forces her to deal with them, and breaks her grammar if the implementation were to change.
+
+Therefore it is possible to selectively disable most of the [control](Control-and-Debug.md) functions, including the `apply`-functions that perform action invocation, on a rule-by-rule basis.
+More precisely, the action and debug control functions are only invoked for a rule `R` when `control< R >::enable` is `true`.
+
+```c++
+template< typename Rule >
+struct normal
+{
+   static constexpr bool enable = internal::enable_control< Rule >;
+
+// ...
+};
+```
+
+The default control class template `normal` defines `normal< R >::enable` in terms of `internal::enable_control< R >` which is `true` by default, but `false` for all rules in sub-namespace `internal`, thereby hiding all invocations of `internal` rules from all actions and most of the control class functions.
+
+The facilities documented on this page however do **not** hide the implementation details since, while debugging a grammar or a parsing run, it is essential to have a complete picture.
+
+## Rule Type
+
+For each rule `R`, the type alias `R::rule_t` is defined as the type of the class that actually implements the `match()` function.
+This is usually the root of the inheritance hierarchy.
+
+Note that `R::rule_t` can be completely different from `R`.
+For example while `seq< R >::rule_t` is `internal::seq< R >`, due to `seq<>` being not only equivalent to `success`, but also implemented in terms of it, `seq<>::rule_t` is actually `internal::success`.
+
+In each rule's implementation mapping section the [rule reference](Rule-Reference.md) shows how `rule_t` is defined depending on the template parameters.
+
+## Sub Rules
+
+For each rule `R`, the type alias `R::subs_t` is an instantiation of `type_list` with all the direct sub-rules of `R` as template parameters.
+
+For example `seq< R, S >::subs_t` is `type_list< R, S >` and `alpha::subs_t` is `type_list<>`.
+
+Note that for many rules with sub-rules the corresponding `subs_t` is not as might be expected.
+For example `enable< R, S >::subs_t` is `type_list< internal::seq< R, S > >` instead of the probably expected `type_list< R, S >`.
+
+Please again consult the [Rule Reference](Rule-Reference.md) (or the source) for how `subs_t` is defined for all included rules.
+
+## Grammar Visit
+
+The `visit()` function uses `subs_t` to recursively find all sub-rules of a grammar and call a function for each of them.
+
+1. The first, explicit, template parameter of `visit()` is the starting rule of the grammar that is to be inspected.
+
+2. The second, explicit, template parameter of `visit()` is a class template `F` where, for every sub-rule `R`, `visit()` will call `F< R >::visit()`.
+
+All arguments given to `visit()` will be passed on to all `F< R >::visit()` calls.
+
+The header `include/tao/pegtl/contrib/visit_rt.hpp` contains a drop-in replacement for `visit()` called `visit_rt()` that uses a run-time data structure, rather than compile-time type lists, to make sure the visitor is called only once for every grammar rule.
+This can be a advantageous when working with large grammars since it reduces the template instantiation depth by shifting some of the work from compile time to run time.
+Unlike `visit()`, `visit_rt()` returns the number of rules visited.
+
+## Grammar Print
+
+TODO.
+
+## Rule Coverage
+
+TODO.
+
+Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey
diff --git a/packages/PEGTL/doc/Parse-Tree.md b/packages/PEGTL/doc/Parse-Tree.md
index 80d10aac244a39d304325dcdad41ebfb8f46728d..59d5e6ec3f46da0f75f2375f0b15aadd052d1d91 100644
--- a/packages/PEGTL/doc/Parse-Tree.md
+++ b/packages/PEGTL/doc/Parse-Tree.md
@@ -218,16 +218,16 @@ struct my_node
 
    // All non-root nodes receive a call to start() when
    // a match is attempted for Rule in a parsing run...
-   template< typename Rule, typename Input, typename... States >
-   void start( const Input& in, States&&... st );
+   template< typename Rule, typename ParseInput, typename... States >
+   void start( const ParseInput& in, States&&... st );
 
    // ...and later a call to success() when the match succeeded...
-   template< typename Rule, typename Input, typename... States >
-   void success( const Input& in, States&&... st );
+   template< typename Rule, typename ParseInput, typename... States >
+   void success( const ParseInput& in, States&&... st );
 
    // ...or to failure() when a (local) failure was encountered.
-   template< typename Rule, typename Input, typename... States >
-   void failure( const Input& in, States&&... st );
+   template< typename Rule, typename ParseInput, typename... States >
+   void failure( const ParseInput& in, States&&... st );
 
    // After a call to success(), and the (optional) call to the selector's
    // transform() did not discard a node, it is passed to its parent node
diff --git a/packages/PEGTL/doc/README.md b/packages/PEGTL/doc/README.md
index 333592dd355f0ebefa60a54bfd8c2fdfeb6ef0b6..435f23193261a357715b02597dfa93a6c3148a3f 100644
--- a/packages/PEGTL/doc/README.md
+++ b/packages/PEGTL/doc/README.md
@@ -46,6 +46,8 @@
   * [Legacy Actions](Actions-and-States.md#legacy-actions)
 * [Errors and Exceptions](Errors-and-Exceptions.md)
   * [Local to Global Failure](Errors-and-Exceptions.md#local-to-global-failure)
+    * [Intrusive Local to Global Failure](Errors-and-Exceptions.md#intrusive-local-to-global-failure)
+    * [Non-Intrusive Local to Global Failure](Errors-and-Exceptions.md#non-intrusive-local-to-global-failure)
   * [Global to Local Failure](Errors-and-Exceptions.md#global-to-local-failure)
   * [Examples for Must Rules](Errors-and-Exceptions.md#examples-for-must-rules)
   * [Custom Exception Messages](Errors-and-Exceptions.md#custom-exception-messages)
@@ -96,13 +98,15 @@
   * [Transformers](Parse-Tree.md#transformers)
   * [`tao::pegtl::parse_tree::node`](Parse-Tree.md#taopegtlparse_treenode)
   * [Custom Node Class](Parse-Tree.md#custom-node-class)
+* [Meta Data and Visit](Meta-Data-and-Visit.md)
 * [Contrib and Examples](Contrib-and-Examples.md)
   * [Contrib](Contrib-and-Examples.md#contrib)
   * [Examples](Contrib-and-Examples.md#examples)
 * [Grammar Analysis](Grammar-Analysis.md)
-  * [Rule Analysis](Grammar-Analysis.md#rule-analysis)
-  * [Background](Grammar-Analysis.md#background)
-  * [Custom Rules](Grammar-Analysis.md#custom-rules)
+  * [Running](Grammar-Analysis.md#running)
+  * [Example](Grammar-Analysis.md#example)
+  * [Requirements](Grammar-Analysis.md#requirements)
+  * [Limitations](Grammar-Analysis.md#limitations)
 * [Changelog](Changelog.md)
 * [Migration Guide](Migration-Guide.md)
 
@@ -144,8 +148,8 @@
 * [`east_asian_width< V >`](Rule-Reference.md#east_asian_width-v-) <sup>[(icu rules)](Rule-Reference.md#icu-rules-for-enumerated-properties)</sup>
 * [`enable< R... >`](Rule-Reference.md#enable-r-) <sup>[(meta-rules)](Rule-Reference.md#meta-rules)</sup>
 * [`eof`](Rule-Reference.md#eof) <sup>[(atomic rules)](Rule-Reference.md#atomic-rules)</sup>
-* [`eol`](Rule-Reference.md#eol) <sup>[(ascii rules)](Rule-Reference.md#ascii-rules)</sup>
-* [`eolf`](Rule-Reference.md#eolf) <sup>[(ascii rules)](Rule-Reference.md#ascii-rules)</sup>
+* [`eol`](Rule-Reference.md#eol) <sup>[(atomic rules)](Rule-Reference.md#atomic-rules)</sup>
+* [`eolf`](Rule-Reference.md#eolf) <sup>[(atomic rules)](Rule-Reference.md#atomic-rules)</sup>
 * [`extender`](Rule-Reference.md#extender) <sup>[(icu rules)](Rule-Reference.md#icu-rules-for-binary-properties)</sup>
 * [`failure`](Rule-Reference.md#failure) <sup>[(atomic rules)](Rule-Reference.md#atomic-rules)</sup>
 * [`forty_two< C... >`](Rule-Reference.md#forty_two-c-) <sup>[(ascii rules)](Rule-Reference.md#ascii-rules)</sup>
diff --git a/packages/PEGTL/doc/Rule-Reference.md b/packages/PEGTL/doc/Rule-Reference.md
index 8e12810182b59cdd5829c07668c2f72f043432dc..8464355a5ed3125ce0bf02a2300cd52818e8eb1b 100644
--- a/packages/PEGTL/doc/Rule-Reference.md
+++ b/packages/PEGTL/doc/Rule-Reference.md
@@ -13,15 +13,15 @@ Remember that there are two failure modes, only the first of which usually leads
 
 ## Equivalence
 
-Some rule classes are said to be *equivalent* to a combination of other rules.
-These rules are not completely equivalent to the shown definition because that
-is not how they are implemented, therefore:
+Some rule classes are said to be *equivalent to* a combination of other rules.
+Here, *equivalence* is with respect to which inputs are matched, but not (necessarily) how the rule is implemented.
 
-- Rule equivalence is with regard to which inputs will match, but:
-- *not* with regard to which actions will be invoked while matching.
+For rules other than `must<>` that contain "must" in their name, rule equivalence shows which rule will be used to call the control class' `raise()` function when certain sub-rules fail to match.
 
-However, rule equivalence does show exactly where the `raise<>` rule is inserted
-and therefore which rule will be used to call the control class' `raise()`.
+## Implementation
+
+The "meta data and implementation mapping" section of each rule's description shows both how the rule is implemented and what the [meta data](Meta-Data-and-Visit.md) looks like.
+When the list of sub-rules is empty then the definition of `subs_t` is omitted from the description.
 
 ## Parameter Packs
 
@@ -53,49 +53,84 @@ These rules are in namespace `tao::pegtl`.
 
 ###### `action< A, R... >`
 
-* Equivalent to `seq< R... >`, but:
+* [Equivalent] to `seq< R... >`, but:
 * Uses the given class template `A` for [actions](Actions-and-States.md).
-* Actions can still be disabled explicitly (via `disable`) or implicitly (via `at` or `not_at`).
+* Does not `enable` or `disable` actions while matching `R...`.
+* [Meta data] and [implementation] mapping:
+  - `action< A >::rule_t` is `internal::success`
+  - `action< A, R >::rule_t` is `internal::action< A, R >`
+  - `action< A, R >::subs_t` is `type_list< R >`
+  - `action< A, R... >::rule_t` is `internal::action< A, internal::seq< R... > >`
+  - `action< A, R... >::subs_t` is `type_list< internal::seq< R... > >`
 
 ###### `control< C, R... >`
 
-* Equivalent to `seq< R... >`, but:
+* [Equivalent] to `seq< R... >`, but:
 * Uses the given class template `C` as [control class](Control-and-Debug.md).
+* [Meta data] and [implementation] mapping:
+  - `control< C >::rule_t` is `internal::success`
+  - `control< C, R >::rule_t` is `internal::control< C, R >`
+  - `control< C, R >::subs_t` is `type_list< R >`
+  - `control< C, R... >:rule_t` is `internal::control< C, internal::seq< R... > >`
+  - `control< C, R... >:subs_t` is `type_list< internal::seq< R... > >`
 
 ###### `disable< R... >`
 
-* Equivalent to `seq< R... >`, but:
+* [Equivalent] to `seq< R... >`, but:
 * Disables all actions.
+* [Meta data] and [implementation] mapping:
+  - `disable<>::rule_t` is `internal::success`
+  - `disable< R >::rule_t` is `internal::disable<, R >`
+  - `disable< R >::subs_t` is `type_list< R >`
+  - `disable< R... >::rule_t` is `internal::disable< internal::seq< R... > >`
+  - `disable< R... >::subs_t` is `type_list< internal::seq< R... > >`
 
 ###### `discard`
 
-* Equivalent to `success`, but:
+* [Equivalent] to `success`, but:
 * Calls the input's `discard()` member function.
 * Must not be used where backtracking to before the `discard` might occur and/or nested within a rule for which an action with input can be called.
 * See [Incremental Input](Inputs-and-Parsing.md#incremental-input) for details.
+* [Meta data] and [implementation] mapping:
+  - `discard::rule_t` is `internal::discard`
 
 ###### `enable< R... >`
 
-* Equivalent to `seq< R... >`, but:
+* [Equivalent] to `seq< R... >`, but:
 * Enables all actions (if any).
+* [Meta data] and [implementation] mapping:
+  - `enable<>::rule_t` is `internal::success`
+  - `enable< R >::rule_t` is `internal::enable<, R >`
+  - `enable< R >::subs_t` is `type_list< R >`
+  - `enable< R... >::rule_t` is `internal::enable< internal::seq< R... > >`
+  - `enable< R... >::subs_t` is `type_list< internal::seq< R... > >`
 
 ###### `require< Num >`
 
 * Succeeds if at least `Num` further input bytes are available.
 * With [Incremental Input](Inputs-and-Parsing.md#incremental-input) reads the bytes into the buffer.
+* [Meta data] and [implementation] mapping:
+  - `require< 0 >::rule_t` is `internal::success`
+  - `require< N >::rule_t` is `internal::require< N >`
 
 ###### `state< S, R... >`
 
-* Equivalent to `seq< R... >`, but:
+* [Equivalent] to `seq< R... >`, but:
 * Replaces all state arguments with a new instance `s` of type `S`.
 * `s` is constructed with the input and all previous states as arguments.
 * If `seq< R... >` succeeds then `s.success()` is called with the input after the match and all previous states as arguments.
+* [Meta data] and [implementation] mapping:
+  - `state< S >::rule_t` is `internal::success`
+  - `state< S, R >::rule_t` is `internal::state< S, R >`
+  - `state< S, R >::subs_t` is `type_list< R >`
+  - `state< S, R... >::rule_t` is `internal::state< S, internal::seq< R... > >`
+  - `state< S, R... >::subs_t` is `type_list< internal::seq< R... > >`
 
 ## Combinators
 
 Combinators (or combinator rules) are rules that combine (other) rules into new ones.
 
-These are the classical PEG combinator rules defined in namespace `tao::pegtl`.
+These are the classical **PEG** combinator rules and are defined in namespace `tao::pegtl`.
 
 ###### `at< R... >`
 
@@ -103,6 +138,12 @@ These are the classical PEG combinator rules defined in namespace `tao::pegtl`.
 * Succeeds if and only if `seq< R... >` would succeed.
 * Consumes nothing, i.e. rewinds after matching.
 * Disables all actions.
+* [Meta data] and [implementation] mapping:
+  - `at<>::rule_t` is `internal::success`
+  - `at< R >::rule_t` is `internal::at< R >`
+  - `at< R >::subs_t` is `type_list< R >`
+  - `at< R... >::rule_t` is `internal::at< internal::seq< R... > >`
+  - `at< R... >::subs_t` is `type_list< internal::seq< R... > >`
 
 ###### `not_at< R... >`
 
@@ -110,19 +151,36 @@ These are the classical PEG combinator rules defined in namespace `tao::pegtl`.
 * Succeeds if and only if `seq< R... >` would **not** succeed.
 * Consumes nothing, i.e. rewinds after matching.
 * Disables all actions.
+* [Meta data] and [implementation] mapping:
+  - `not_at<>::rule_t` is `internal::failure`
+  - `not_at< R >::rule_t` is `internal::not_at< R >`
+  - `not_at< R >::subs_t` is `type_list< R >`
+  - `not_at< R... >::rule_t` is `internal::not_at< internal::seq< R... > >`
+  - `not_at< R... >::subs_t` is `type_list< internal::seq< R... > >`
 
 ###### `opt< R... >`
 
 * PEG **optional** *e*?
 * Optional `seq< R... >`, i.e. attempt to match `seq< R... >` and signal success regardless of the result.
-* Equivalent to `sor< seq< R... >, success >`.
+* [Equivalent] to `sor< seq< R... >, success >`.
+* [Meta data] and [implementation] mapping:
+  - `opt<>::rule_t` is `internal::success`
+  - `opt< R >::rule_t` is `internal::opt< R >`
+  - `opt< R >::subs_t` is `type_list< R >`
+  - `opt< R... >::rule_t` is `internal::opt< internal::seq< R... > >`
+  - `opt< R... >::subs_t` is `type_list< internal::seq< R... > >`
 
 ###### `plus< R... >`
 
 * PEG **one-or-more** *e*+
 * Matches `seq< R... >` as often as possible and succeeds if it matches at least once.
-* Equivalent to `rep_min< 1, R... >`.
+* [Equivalent] to `rep_min< 1, R... >`.
 * `R` must be a non-empty rule pack.
+* [Meta data] and [implementation] mapping:
+  - `plus< R >::rule_t` is `internal::plus< R >`
+  - `plus< R >::subs_t` is `type_list< R >`
+  - `plus< R... >::rule_t` is `internal::plus< internal::seq< R... > >`
+  - `plus< R... >::subs_t` is `type_list< internal::seq< R... > >`
 
 ###### `seq< R... >`
 
@@ -132,6 +190,12 @@ These are the classical PEG combinator rules defined in namespace `tao::pegtl`.
 * Fails and stops matching when one of the given rules fails.
 * Consumes everything that the rules `R...` consumed.
 * Succeeds if `R` is an empty rule pack.
+* [Meta data] and [implementation] mapping:
+  - `seq<>::rule_t` is `internal::success`
+  - `seq< R >::rule_t` is `internal::seq< R >`
+  - `seq< R >::subs_t` is `type_list< R >`
+  - `seq< R... >::rule_t` is `internal::seq< R... >`
+  - `seq< R... >::subs_t` is `type_list< R... >`
 
 ###### `sor< R... >`
 
@@ -141,12 +205,23 @@ These are the classical PEG combinator rules defined in namespace `tao::pegtl`.
 * Succeeds and stops matching when one of the given rules succeeds.
 * Consumes whatever the first rule that succeeded consumed.
 * Fails if `R` is an empty rule pack.
+* [Meta data] and [implementation] mapping:
+  - `sor<>::rule_t` is `internal::failure`
+  - `sor< R >::rule_t` is `internal::sor< R >`
+  - `sor< R >::subs_t` is `type_list< R >`
+  - `sor< R... >::rule_t` is `internal::sor< R... >`
+  - `sor< R... >::subs_t` is `type_list< R... >`
 
 ###### `star< R... >`
 
 * PEG **zero-or-more** *e**
 * Matches `seq< R... >` as often as possible and always succeeds.
 * `R` must be a non-empty rule pack.
+* [Meta data] and [implementation] mapping:
+  - `star< R >::rule_t` is `internal::star< R >`
+  - `star< R >::subs_t` is `type_list< R >`
+  - `star< R... >::rule_t` is `internal::star< internal::seq< R... > >`
+  - `star< R... >::subs_t` is `type_list< internal::seq< R... > >`
 
 ## Convenience
 
@@ -159,133 +234,252 @@ These rules are in namespace `tao::pegtl`.
 ###### `if_must< R, S... >`
 
 * Attempts to match `R` and depending on the result proceeds with either `must< S... >` or `failure`.
-* Equivalent to `seq< R, must< S... > >`.
-* Equivalent to `if_then_else< R, must< S... >, failure >`.
+* [Equivalent] to `seq< R, must< S... > >`.
+* [Equivalent] to `if_then_else< R, must< S... >, failure >`.
+* [Meta data] and [implementation] mapping:
+  - `if_must< R >::rule_t` is `internal::if_must< false, R >`
+  - `if_must< R >::subs_t` is `type_list< R >`
+  - `if_must< R, S... >::rule_t` is `internal::if_must< false, R, S... >`
+  - `if_must< R, S... >::subs_t` is `type_list< R, internal::must< S... > >`
+
+Note that the `false` template parameter to `internal::if_must` corresponds to the `failure` in the equivalent description using `if_then_else`.
 
 ###### `if_must_else< R, S, T >`
 
 * Attempts to match `R` and depending on the result proceeds with either `must< S >` or `must< T >`.
-* Equivalent to `if_then_else< R, must< S >, must< T > >`.
+* [Equivalent] to `if_then_else< R, must< S >, must< T > >`.
+* [Meta data] and [implementation] mapping:
+  - `if_must_else< R, S, T >::rule_t` is `internal::if_then_else< R, internal::must< S >, internal::must< T > >`
+  - `if_must_else< R, S, T >::subs_t` is `type_list< R, internal::must< S >, internal::must< T > >`
 
 ###### `if_then_else< R, S, T >`
 
-* Equivalent to `sor< seq< R, S >, seq< not_at< R >, T > >`.
+* [Equivalent] to `sor< seq< R, S >, seq< not_at< R >, T > >`.
+* [Meta data] and [implementation] mapping:
+  - `if_then_else< R, S, T >::rule_t` is `internal::if_then_else< R, S, T>`
+  - `if_then_else< R, S, T >::subs_t` is `type_list< R, S, T >`
 
 ###### `list< R, S >`
 
 * Matches a non-empty list of `R` separated by `S`.
-* Equivalent to `seq< R, star< S, R > >`.
+* [Equivalent] to `seq< R, star< S, R > >`.
+* [Meta data] and [implementation] mapping:
+  - `list< R, S >::rule_t` is `internal::seq< R, internal::star< S, R > >`
+  - `list< R, S >::subs_t` is `type_list< R, internal::star< S, R > >`
 
 ###### `list< R, S, P >`
 
 * Matches a non-empty list of `R` separated by `S` where each `S` can be padded by `P`.
-* Equivalent to `seq< R, star< pad< S, P >, R > >`.
+* [Equivalent] to `seq< R, star< pad< S, P >, R > >`.
+* [Meta data] and [implementation] mapping:
+  - `list< R, S, P >::rule_t` is `internal::seq< R, internal::star< internal::pad< S, P >, R > >`
+  - `list< R, S, P >::subs_t` is `type_list< R, internal::star< internal::pad< S, P >, R > >`
 
 ###### `list_must< R, S >`
 
 * Matches a non-empty list of `R` separated by `S`.
 * Similar to `list< R, S >`, but if there is an `S` it **must** be followed by an `R`.
-* Equivalent to `seq< R, star< if_must< S, R > > >`.
+* [Equivalent] to `seq< R, star< if_must< S, R > > >`.
+* [Meta data] and [implementation] mapping:
+  - `list_must< R, S >::rule_t` is `internal::seq< R, internal::star< S, internal::must< R > > >`
+  - `list_must< R, S >::subs_t` is `type_list< R, internal::star< S, internal::must< R > > >`
 
 ###### `list_must< R, S, P >`
 
 * Matches a non-empty list of `R` separated by `S` where each `S` can be padded by `P`.
 * Similar to `list< R, S, P >`, but if there is an `S` it **must** be followed by an `R`.
-* Equivalent to `seq< R, star< if_must< pad< S, P >, R > > >`.
+* [Equivalent] to `seq< R, star< if_must< pad< S, P >, R > > >`.
+* [Meta data] and [implementation] mapping:
+  - `list_must< R, S, P >::rule_t` is `internal::seq< R, internal::star< internal::pad< S, P >, internal::must< R > > >`
+  - `list_must< R, S, P >::subs_t` is `type_list< R, internal::star< internal::pad< S, P >, internal::must< R > > >`
 
 ###### `list_tail< R, S >`
 
 * Matches a non-empty list of `R` separated by `S` with optional trailing `S`.
-* Equivalent to `seq< list< R, S >, opt< S > >`.
+* [Equivalent] to `seq< list< R, S >, opt< S > >`.
+* [Meta data] and [implementation] mapping:
+  - `list_tail< R, S >::rule_t` is `internal::seq< R, internal::star< S, R >, internal::opt< S > >`
+  - `list_tail< R, S >::subs_t` is `type_list< R, internal::star< S, R >, internal::opt< S > >`
 
 ###### `list_tail< R, S, P >`
 
 * Matches a non-empty list of `R` separated by `S` with optional trailing `S` and padding `P` inside the list.
-* Equivalent to `seq< list< R, S, P >, opt< star< P >, S > >`.
+* [Equivalent] to `seq< list< R, S, P >, opt< star< P >, S > >`.
+* [Meta data] and [implementation] mapping:
+  - `list_tail< R, S, P >::rule_t` is `internal::seq< R, internal::star< internal::pad< S, P >, R >, internal::opt< internal::star< P >, S > >`
+  - `list_tail< R, S, P >::subs_t` is `type_list< R, internal::star< internal::pad< S, P >, R > >, internal::opt< internal::star< P >, S > >`
 
 ###### `minus< M, S >`
 
 * Succeeds if `M` matches, and `S` does *not* match *all* of the input that `M` matched.
-* Equivalent to `rematch< M, not_at< S, eof > >`.
+* [Equivalent] to `rematch< M, not_at< S, eof > >`.
+* [Meta data] and [implementation] mapping:
+  - `minus< M, S >::rule_t` is `internal::rematch< M, internal::not_at< S, internal::eof > >`
+  - `minus< M, S >::subs_t` is `type_list< M, internal::not_at< S, internal::eof > >`
 
 ###### `must< R... >`
 
-* Equivalent to `seq< R... >`, but:
+* [Equivalent] to `seq< R... >`, but:
 * Converts local failure of `R...` into global failure.
 * Calls `raise< R >` for the `R` that failed.
-* Equivalent to `seq< sor< R, raise< R > >... >`.
+* [Equivalent] to `seq< sor< R, raise< R > >... >`.
+* [Meta data] and [implementation] mapping:
+  - `must<>::rule_t` is `internal::success`
+  - `must< R >::rule_t` is `internal::must< R >`
+  - `must< R >::subs_t` is `type_list< R >`
+  - `must< R... >::rule_t` is `internal::seq< internal::must< R >... >::rule_t`
+  - `must< R... >::subs_t` is `type_list< internal::must< R... > >`
+
+Note that `must` uses a different pattern to handle multiple sub-rules compared to the other `seq`-equivalent rules (which use `rule< seq< R... > >` rather than `seq< rule< R >... >`).
 
 ###### `opt_must< R, S... >`
 
-* Equivalent to `opt< if_must< R, S... > >`.
+* [Equivalent] to `opt< if_must< R, S... > >`.
+* [Equivalent] to `if_then_else< R, must< S... >, success >`.
+* [Meta data] and [implementation] mapping:
+  - `opt_must< R >::rule_t` is `internal::if_must< true, R >`
+  - `opt_must< R >::subs_t` is `type_list< R >`
+  - `opt_must< R, S... >::rule_t` is `internal::if_must< true, R, S... >`
+  - `opt_must< R, S... >::subs_t` is `type_list< R, internal::must< S... > >`
+
+Note that the `true` template parameter to `internal::if_must` corresponds to the `success` in the equivalent description using `if_then_else`.
 
 ###### `pad< R, S, T = S >`
 
 * Matches an `R` that can be padded by arbitrary many `S` on the left and `T` on the right.
-* Equivalent to `seq< star< S >, R, star< T > >`.
+* [Equivalent] to `seq< star< S >, R, star< T > >`.
+* [Meta data] and [implementation] mapping:
+  - `pad< R, S, T >::rule_t` is `internal::seq< internal::star< S >, R, internal::star< T > >`
+  - `pad< R, S, T >::subs_t` is `type_list< internal::star< S >, R, internal::star< T > >`
 
 ###### `pad_opt< R, P >`
 
 * Matches an optional `R` that can be padded by arbitrary many `P` or just arbitrary many `P`.
-* Equivalent to `seq< star< P >, opt< R, star< P > > >`.
+* [Equivalent] to `seq< star< P >, opt< R, star< P > > >`.
+* [Meta data] and [implementation] mapping:
+  - `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 > > >`
 
 ###### `rematch< R, S... >`
 
 * Succeeds if `R` matches, and each `S` matches the input that `R` matched.
 * Ignores all `S` for the [grammar analysis](Grammar-Analysis.md).
+* [Meta data] and [implementation] mapping:
+  - `rematch< R, S... >::rule_t` is `internal::rematch< R, S... >`
+  - `rematch< R, S... >::subs_t` is `type_list< R, S... >`
 
 ###### `rep< Num, R... >`
 
 * Matches `seq< R... >` for `Num` times without checking for further matches.
-* Equivalent to `seq< seq< R... >, ..., seq< R... > >` where `seq< R... >` is repeated `Num` times.
+* [Equivalent] to `seq< seq< R... >, ..., seq< R... > >` where `seq< R... >` is repeated `Num` times.
+* [Meta data] and [implementation] mapping:
+  - `rep< 0, R... >::rule_t` is `internal::success`
+  - `rep< N >::rule_t` is `internal::success`
+  - `rep< N, R >::rule_t` is `internal::rep< N, R >`
+  - `rep< N, R >::subs_t` is `type_list< R >`
+  - `rep< N, R... >::rule_t` is `internal::rep< N, internal::seq< R... > >`
+  - `rep< N, R... >::subs_t` is `type_list< internal::seq< R... > >`
 
 ###### `rep_max< Max, R... >`
 
 * Matches `seq< R... >` for at most `Max` times and verifies that it doesn't match more often.
-* Equivalent to `rep_min_max< 0, Max, R... >`.
+* [Equivalent] to `rep_min_max< 0, Max, R... >`.
+* [Meta data] and [implementation] mapping:
+  - `rep_max< 0, R >::rule_t` is `internal::not_at< R >`
+  - `rep_max< 0, R >::subs_t` is `type_list< R >`
+  - `rep_max< 0, R... >::rule_t` is `internal::not_at< internal::seq< R... > >`
+  - `rep_max< 0, R... >::subs_t` is `type_list< internal::seq< R... > >`
+  - `rep_max< Max >::rule_t` is `internal::failure`
+  - `rep_max< Max, R >::rule_t` is `internal::rep_min_max< 0, Max, R >`
+  - `rep_max< Max, R >::subs_t` is `type_list< R >`
+  - `rep_max< Max, R... >::rule_t` is `internal::rep_min_max< 0, Max, internal::seq< R... > >`
+  - `rep_max< Max, R... >::subs_t` is `type_list< internal::seq< R... > >`
 
 ###### `rep_min< Min, R... >`
 
 * Matches `seq< R... >` as often as possible and succeeds if it matches at least `Min` times.
-* Equivalent to `seq< rep< Min, R... >, star< R... > >`.
+* [Equivalent] to `seq< rep< Min, R... >, star< R... > >`.
 * `R` must be a non-empty rule pack.
+* [Meta data] and [implementation] mapping:
+  - `rep_min< Min, R... >::rule_t` is `internal::seq< internal::rep< Min, R... >, internal::star< R... > >`
+  - `rep_min< Min, R... >::subs_t` is `type_list< internal::rep< Min, R... >, internal::star< R... > >`
 
 ###### `rep_min_max< Min, Max, R... >`
 
 * Matches `seq< R... >` for `Min` to `Max` times and verifies that it doesn't match more often.
-* Equivalent to `seq< rep< Min, R... >, rep_opt< Max - Min, R... >, not_at< R... > >`.
+* [Equivalent] to `seq< rep< Min, R... >, rep_opt< Max - Min, R... >, not_at< R... > >`.
+* [Meta data] and [implementation] mapping:
+  - `rep_min_max< 0, 0, R >::rule_t` is `internal::not_at< R >`
+  - `rep_min_max< 0, 0, R >::subs_t` is `type_list< R >`
+  - `rep_min_max< 0, 0, R... >::rule_t` is `internal::not_at< internal::seq< R... > >`
+  - `rep_min_max< 0, 0, R... >::subs_t` is `type_list< internal::seq< R... > >`
+  - `rep_min_max< Min, Max >::rule_t` is `internal::failure`
+  - `rep_min_max< Min, Max, R >::rule_t` is `internal::rep_min_max< Min, Max, R >`
+  - `rep_min_max< Min, Max, R >::subs_t` is `type_list< R >`
+  - `rep_min_max< Min, Max, R... >::rule_t` is `internal::rep_min_max< Min, Max, internal::seq< R... > >`
+  - `rep_min_max< Min, Max, R... >::subs_t` is `type_list< internal::seq< R... > >`
 
 ###### `rep_opt< Num, R... >`
 
 * Matches `seq< R... >` for zero to `Num` times without check for further matches.
-* Equivalent to `rep< Num, opt< R... > >`.
+* [Equivalent] to `rep< Num, opt< R... > >`.
+* [Meta data] and [implementation] mapping:
+  - `rep_opt< 0, R... >::rule_t` is `internal::success`
+  - `rep_opt< Num >::rule_t` is `internal::success`
+  - `rep_opt< Num, R... >::rule_t` is `internal::seq< internal::rep< Num, R... >, internal::star< R... > >`
+  - `rep_opt< Num, R... >::subs_t` is `type_list< internal::rep< Num, R... >, internal::star< R... > >`
 
 ###### `star_must< R, S... >`
 
-* Equivalent to `star< if_must< R, S... > >`.
+* [Equivalent] to `star< if_must< R, S... > >`.
+* [Meta data] and [implementation] mapping:
+  - `star_must< R >::rule_t` is `internal::star< internal::if_must< false, R > >`
+  - `star_must< R >::subs_t` is `type_list< internal::if_must< false, R > >`
+  - `star_must< R, S... >::rule_t` is `internal::star< internal::if_must< false, R, S... > >`
+  - `star_must< R, S... >::subs_t` is `type_list< internal::if_must< false, R, S... > >`
 
 ###### `try_catch< R... >`
 
-* Equivalent to `seq< R... >`, but:
+* [Equivalent] to `seq< R... >`, but:
 * Converts global failure (exception) into local failure (return value `false`).
 * Catches exceptions of type `tao::pegtl::parse_error`.
+* [Meta data] and [implementation] mapping:
+  - `try_catch<>::rule_t` is `internal::success`
+  - `try_catch< R >::rule_t` is `internal::try_catch_type< parse_error, R >`
+  - `try_catch< R >::subs_t` is `type_list< R >`
+  - `try_catch< R... >::rule_t` is `internal::try_catch_type< parse_error, internal::seq< R... > >`
+  - `try_catch< R... >::subs_t` is `type_list< internal::seq< R... > >`
 
 ###### `try_catch_type< E, R... >`
 
-* Equivalent to `seq< R... >`, but:
+* [Equivalent] to `seq< R... >`, but:
 * Converts global failure (exception) into local failure (return value `false`).
 * Catches exceptions of type `E`.
+* [Meta data] and [implementation] mapping:
+  - `try_catch_type< E >::rule_t` is `internal::success`
+  - `try_catch_type< E, R >::rule_t` is `internal::try_catch_type< E, R >`
+  - `try_catch_type< E, R >::subs_t` is `type_list< R >`
+  - `try_catch_type< E, R... >::rule_t` is `internal::try_catch_type< E, internal::seq< R... > >`
+  - `try_catch_type< E, R... >::subs_t` is `type_list< internal::seq< R... > >`
 
 ###### `until< R >`
 
 * Consumes all input until `R` matches.
-* Equivalent to `until< R, any >`.
+* [Equivalent] to `until< R, any >`.
+* [Meta data] and [implementation] mapping:
+  - `until< R >::rule_t` is `internal::until< R >`
+  - `until< R >::subs_t` is `type_list< R >`
 
 ###### `until< R, S... >`
 
 * Matches `seq< S... >` as long as `at< R >` does not match and succeeds when `R` matches.
-* Equivalent to `seq< star< not_at< R >, not_at< eof >, S... >, R >`.
+* [Equivalent] to `seq< star< not_at< R >, not_at< eof >, S... >, R >`.
 * Does not apply if `S` is an empty rule pack, see the previous entry for the semantics of `until< R >`.
+* [Meta data] and [implementation] mapping:
+  - `until< R, S >::rule_t` is `internal::until< R, S >`
+  - `until< R, S >::subs_t` is `type_list< R, S >`
+  - `until< R, S... >::rule_t` is `internal::until< R, internal::seq< S... > >`
+  - `until< R, S... >::subs_t` is `type_list< R, internal::seq< S... > >`
 
 ## Action Rules
 
@@ -293,25 +487,32 @@ These rules are in namespace `tao::pegtl`.
 
 These rules replicate the intrusive way actions were called from within the grammar in the PEGTL 0.x with the `apply<>` and `if_apply<>` rules.
 The actions for these rules are classes (rather than class templates as required for `parse()` and the `action<>`-rule).
-These rules respect the current `apply_mode`, but don't use the control-class to invoke the actions.
+These rules respect the current `apply_mode`, but do **not** use the control class to invoke the actions.
 
 ###### `apply< A... >`
 
 * Calls `A::apply()` for all `A`, in order, with an empty input and all states as arguments.
 * If any `A::apply()` has a boolean return type and returns `false`, no further `A::apply()` calls are made and the result is equivalent to `failure`, otherwise:
-* Equivalent to `success` wrt. parsing.
+* [Equivalent] to `success` wrt. parsing.
+* [Meta data] and [implementation] mapping:
+  - `apply< A... >::rule_t` is `internal::apply< A... >`
 
 ###### `apply0< A... >`
 
 * Calls `A::apply0()` for all `A`, in order, with all states as arguments.
 * If any `A::apply0()` has a boolean return type and returns `false`, no further `A::apply0()` calls are made and the result is equivalent to `failure`, otherwise:
-* Equivalent to `success` wrt. parsing.
+* [Equivalent] to `success` wrt. parsing.
+* [Meta data] and [implementation] mapping:
+  - `apply0< A... >::rule_t` is `internal::apply0< A... >`
 
 ###### `if_apply< R, A... >`
 
-* Equivalent to `seq< R, apply< A... > >` wrt. parsing, but also:
+* [Equivalent] to `seq< R, apply< A... > >` wrt. parsing, but also:
 * If `R` matches, calls `A::apply()`, for all `A`, in order, with the input matched by `R` and all states as arguments.
 * If any `A::apply()` has a boolean return type and returns `false`, no further `A::apply()` calls are made.
+* [Meta data] and [implementation] mapping:
+  - `if_apply< R, A... >::rule_t` is `internal::if_apply< R, A... >`
+  - `if_apply< R, A... >::subs_t` is `type_list< R >`
 
 ## Atomic Rules
 
@@ -324,27 +525,52 @@ Atomic rules do not rely on other rules.
 * Succeeds at "beginning-of-file", i.e. when the input's `byte()` member function returns zero.
 * Does not consume input.
 * Does **not** work with inputs that don't have a `byte()` member function.
+* [Meta data] and [implementation] mapping:
+  - `bof::rule_t` is `internal::bof`
 
 ###### `bol`
 
 * Succeeds at "beginning-of-line", i.e. when the input's `byte_in_line()` member function returns zero.
 * Does not consume input.
 * Does **not** work with inputs that don't have a `byte_in_line()` member function.
+* [Meta data] and [implementation] mapping:
+  - `bol::rule_t` is `internal::bol`
 
 ###### `bytes< Num >`
 
 * Succeeds when the input contains at least `Num` further bytes.
 * Consumes these `Num` bytes from the input.
+* [Meta data] and [implementation] mapping:
+  - `bytes< 0 >::rule_t` is `internal::success`
+  - `bytes< Num >::rule_t` is `internal::bytes< Num >`
 
 ###### `eof`
 
 * Succeeds at "end-of-file", i.e. when the input is empty or all input has been consumed.
 * Does not consume input.
+* [Meta data] and [implementation] mapping:
+  - `eof::rule_t` is `internal::eof`
+
+###### `eol`
+
+* Depends on the `Eol` template parameter of the input, by default:
+* Matches and consumes a Unix or MS-DOS line ending, that is:
+* [Equivalent] to `sor< one< '\n' >, string< '\r', '\n' > >`.
+* [Meta data] and [implementation] mapping:
+  - `eol::rule_t` is `internal::eol`
+
+###### `eolf`
+
+* [Equivalent] to `sor< eof, eol >`.
+* [Meta data] and [implementation] mapping:
+  - `eolf::rule_t` is `internal::eolf`
 
 ###### `failure`
 
 * Dummy rule that never succeeds.
 * Does not consume input.
+* [Meta data] and [implementation] mapping:
+  - `failure::rule_t` is `internal::failure`
 
 ###### `raise< T >`
 
@@ -352,11 +578,15 @@ Atomic rules do not rely on other rules.
 * Calls the control-class' `Control< T >::raise()` static member function.
 * `T` *can* be a rule, but it does not have to be a rule.
 * Does not consume input.
+* [Meta data] and [implementation] mapping:
+  - `raise< T >::rule_t` is `internal::raise< T >`
 
 ###### `success`
 
 * Dummy rule that always succeeds.
 * Does not consume input.
+* [Meta data] and [implementation] mapping:
+  - `success::rule_t` is `internal::success`
 
 ## ASCII Rules
 
@@ -372,97 +602,124 @@ and all possible byte values excluding `'a'`, respectively. However the characte
 for example the Euro sign code point `U+20AC`, which is encoded by the UTF-8 sequence `E2 82 AC`,
 can be matched by either `tao::pegtl::ascii::string< 0xe2, 0x82, 0xac >` or `tao::pegtl::utf8::one< 0x20ac >`.)
 
+ASCII rules do not usually rely on other rules.
+
 ###### `alnum`
 
 * Matches and consumes a single ASCII alphabetic or numeric character.
-* Equivalent to `ranges< 'a', 'z', 'A', 'Z', '0', '9' >`.
+* [Equivalent] to `ranges< 'a', 'z', 'A', 'Z', '0', '9' >`.
+* [Meta data] and [implementation] mapping:
+  - `ascii::alnum::rule_t` is `internal::ranges< internal::peek_char, 'a', 'z', 'A', 'Z', '0', '9' >`
 
 ###### `alpha`
 
 * Matches and consumes a single ASCII alphabetic character.
-* Equivalent to `ranges< 'a', 'z', 'A', 'Z' >`.
+* [Equivalent] to `ranges< 'a', 'z', 'A', 'Z' >`.
+* [Meta data] and [implementation] mapping:
+  - `ascii::alpha::rule_t` is `internal::ranges< internal::peek_char, 'a', 'z', 'A', 'Z' >`
 
 ###### `any`
 
 * Matches and consumes any single byte, including all ASCII characters.
-* Equivalent to `bytes< 1 >`.
+* [Equivalent] to `bytes< 1 >`.
+* [Meta data] and [implementation] mapping:
+  - `ascii::any::rule_t` is `internal::any< internal::peek_char >`
 
 ###### `blank`
 
 * Matches and consumes a single ASCII horizontal space or horizontal tabulator character.
-* Equivalent to `one< ' ', '\t' >`.
+* [Equivalent] to `one< ' ', '\t' >`.
+* [Meta data] and [implementation] mapping:
+  - `ascii::blank::rule_t` is `internal::one< internal::result_on_found::success, internal::peek_char, ' ', '\t' >`
 
 ###### `digit`
 
 * Matches and consumes a single ASCII decimal digit character.
-* Equivalent to `range< '0', '9' >`.
+* [Equivalent] to `range< '0', '9' >`.
+* [Meta data] and [implementation] mapping:
+  - `ascii::digit::rule_t` is `internal::range< internal::result_on_found::success, internal::peek_char, '0', '9' >`
 
 ###### `ellipsis`
 
 * Matches and consumes three dots.
-* Equivalent to `three< '.' >`.
-
-###### `eol`
-
-* Depends on the `Eol` template parameter of the input, by default:
-* Matches and consumes a Unix or MS-DOS line ending, that is:
-* Equivalent to `sor< one< '\n' >, string< '\r', '\n' > >`.
-
-###### `eolf`
-
-* Equivalent to `sor< eof, eol >`.
+* [Equivalent] to `three< '.' >`.
+* [Meta data] and [implementation] mapping:
+  - `ascii::ellipsis::rule_t` is `internal::string< '.', '.', '.' >`
 
 ###### `forty_two< C... >`
 
-* Equivalent to `rep< 42, one< C... > >`.
+* [Equivalent] to `rep< 42, one< C... > >`.
+* [Meta data] and [implementation] mapping:
+  - `ascii::forty_two< C >::rule_t` is `internal_rep< 42, internal::one< internal::result_on_found::success, internal::peek_char, C > >`
 
 ###### `identifier_first`
 
 * Matches and consumes a single ASCII character permissible as first character of a C identifier.
-* Equivalent to `ranges< 'a', 'z', 'A', 'Z', '_' >`.
+* [Equivalent] to `ranges< 'a', 'z', 'A', 'Z', '_' >`.
+* [Meta data] and [implementation] mapping:
+  - `ascii::identifier_first::rule_t` is `internal::ranges< internal::peek_char, 'a', 'z', 'A', 'Z', '_' >`
 
 ###### `identifier_other`
 
 * Matches and consumes a single ASCII character permissible as subsequent character of a C identifier.
-* Equivalent to `ranges< 'a', 'z', 'A', 'Z', '0', '9', '_' >`.
+* [Equivalent] to `ranges< 'a', 'z', 'A', 'Z', '0', '9', '_' >`.
+* [Meta data] and [implementation] mapping:
+  - `ascii::identifier_first::rule_t` is `internal::ranges< internal::peek_char, 'a', 'z', 'A', 'Z', '0', '9', '_' >`
 
 ###### `identifier`
 
 * Matches and consumes an ASCII identifier as defined for the C programming language.
-* Equivalent to `seq< identifier_first, star< identifier_other > >`.
+* [Equivalent] to `seq< identifier_first, star< identifier_other > >`.
+* [Meta data] and [implementation] mapping:
+  - `ascii::identifier::rule_t` is `internal::seq< identifier_first, internal::star< identifier_other > >`.
 
 ###### `istring< C... >`
 
 * Matches and consumes the given ASCII string `C...` with case insensitive matching.
 * Similar to `string< C... >`, but:
 * For ASCII letters a-z and A-Z the match is case insensitive.
+* [Meta data] and [implementation] mapping:
+  - `ascii::istring<>::rule_t` is `internal::success`
+  - `ascii::istring< C... >::rule_t` is `internal::istring< C... >`
 
 ###### `keyword< C... >`
 
-* Matches and consumes a non-empty string not followed by a subsequent identifier character.
-* Equivalent to `seq< string< C... >, not_at< identifier_other > >`.
+* Matches and consumes a non-empty string not followed by an identifier character.
+* [Equivalent] to `seq< string< C... >, not_at< identifier_other > >`.
+* `C` must be a non-empty character pack.
+* [Meta data] and [implementation] mapping:
+  - `ascii::keyword< C... >::rule_t` is `internal::seq< internal::string< C... >, internal::not_at< internal::ranges< internal::peek_char, 'a', 'z', 'A', 'Z', '0', '9', '_' > > >`
 
 ###### `lower`
 
 * Matches and consumes a single ASCII lower-case alphabetic character.
-* Equivalent to `range< 'a', 'z' >`.
+* [Equivalent] to `range< 'a', 'z' >`.
+* [Meta data] and [implementation] mapping:
+  - `ascii::lower::rule_t` is `internal::range< internal::result_on_found::success, internal::peek_char, 'a', 'z' >`
 
 ###### `not_one< C... >`
 
 * Succeeds when the input is not empty, and:
 * `C` is an empty character pack or the next input byte is **not** one of `C...`.
 * Consumes one byte when it succeeds.
+* [Meta data] and [implementation] mapping:
+  - `ascii::not_one<>::rule_t` is `internal::any< internal::peek_char >`
+  - `ascii::not_one< C... >::rule_t` is `internal::one< result_on_found::failure, internal::peek_char, C... >`
 
 ###### `not_range< C, D >`
 
 * Succeeds when the input is not empty, and:
 * The next input byte is **not** in the closed range `C ... D`.
 * Consumes one byte when it succeeds.
+* [Meta data] and [implementation] mapping:
+  - `ascii::not_range< C, C >::rule_t` is `internal::one< result_on_found::failure, internal::peek_char, C >`
+  - `ascii::not_range< C, D >::rule_t` is `internal::range< result_on_found::failure, internal::peek_char, C, D >`
 
 ###### `nul`
 
 * Matches and consumes an ASCII nul character.
-* Equivalent to `one< 0 >`.
+* [Equivalent] to `one< '\0' >`.
+  - `ascii::nul::rule_t` is `internal::one< result_on_found::success, internal::peek_char, 0 >`
 
 ###### `one< C... >`
 
@@ -470,44 +727,63 @@ can be matched by either `tao::pegtl::ascii::string< 0xe2, 0x82, 0xac >` or `tao
 * The next input byte is one of `C...`.
 * Consumes one byte when it succeeds.
 * Fails if `C` is an empty character pack.
+* [Meta data] and [implementation] mapping:
+  - `ascii::not_one<>::rule_t` is `internal::failure`
+  - `ascii::not_one< C... >::rule_t` is `internal::one< result_on_found::success, internal::peek_char, C... >`
 
 ###### `print`
 
 * Matches and consumes any single ASCII character traditionally defined as printable.
-* Equivalent to `range< 32, 126 >`.
+* [Equivalent] to `range< 32, 126 >`.
+* [Meta data] and [implementation] mapping:
+  - `ascii::print::rule_t` is `internal::range< internal::result_on_found::success, internal::peek_char, 32, 126 >`
 
 ###### `range< C, D >`
 
 * Succeeds when the input is not empty, and:
 * The next input byte is in the closed range `C ... D`.
 * Consumes one byte when it succeeds.
+* [Meta data] and [implementation] mapping:
+  - `ascii::range< C, C >::rule_t` is `internal::one< result_on_found::success, internal::peek_char, C >`
+  - `ascii::range< C, D >::rule_t` is `internal::range< result_on_found::success, internal::peek_char, C, D >`
 
 ###### `ranges< C1, D1, C2, D2, ... >`
-
-* Equivalent to `sor< range< C1, D1 >, range< C2, D2 >, ... >`.
-
 ###### `ranges< C1, D1, C2, D2, ..., E >`
 
-* Equivalent to `sor< range< C1, D1 >, range< C2, D2 >, ..., one< E > >`.
+* [Equivalent] to `sor< range< C1, D1 >, range< C2, D2 >, ... >`.
+* [Equivalent] to `sor< range< C1, D1 >, range< C2, D2 >, ..., one< E > >`.
+* [Meta data] and [implementation] mapping:
+  - `ascii::ranges<>::rule_t` is `internal::failure`
+  - `ascii::ranges< E >::rule_t` is `internal::one< result_on_found::success, internal::peek_char, E >`
+  - `ascii::ranges< C, D >::rule_t` is `internal::range< result_on_found::success, internal::peek_char, C, D >`
+  - `ascii::ranges< C... >::rule_t` is `internal::ranges< internal::peek_char, C... >`
 
 ###### `seven`
 
 * Matches and consumes any single true ASCII character that fits into 7 bits.
-* Equivalent to `range< 0, 127 >`.
+* [Equivalent] to `range< 0, 127 >`.
+* [Meta data] and [implementation] mapping:
+  - `ascii::seven::rule_t` is `internal::range< internal::result_on_found::success, internal::peek_char, 0, 127 >`
 
 ###### `shebang`
 
-* Equivalent to `seq< string< '#', '!' >, until< eolf > >`.
+* [Equivalent] to `if_must< string< '#', '!' >, until< eolf > >`.
 
 ###### `space`
 
 * Matches and consumes a single space, line-feed, carriage-return, horizontal-tab, vertical-tab or form-feed.
-* Equivalent to `one< ' ', '\n', '\r', '\t', '\v', '\f' >`.
+* [Equivalent] to `one< ' ', '\n', '\r', '\t', '\v', '\f' >`.
+* [Meta data] and [implementation] mapping:
+  - `ascii::shebang::rule_t` is `internal::seq< false, internal::string< '#', '!' >, internal::until< internal::eolf > >`
+  - `ascii::shebang::subs_t` is `type_list< internal::string< '#', '!' >, internal::until< internal::eolf > >`
 
 ###### `string< C... >`
 
 * Matches and consumes a string, a sequence of bytes or single-byte characters.
-* Equivalent to `seq< one< C >... >`.
+* [Equivalent] to `seq< one< C >... >`.
+* [Meta data] and [implementation] mapping:
+  - `ascii::string<>::rule_t` is `internal::success`
+  - `ascii::string< C... >::rule_t` is `internal::string< C... >`
 
 ###### `TAO_PEGTL_ISTRING( "..." )`
 
@@ -535,22 +811,30 @@ can be matched by either `tao::pegtl::ascii::string< 0xe2, 0x82, 0xac >` or `tao
 * Succeeds when the input contains at least three bytes, and:
 * These three input bytes are all `C`.
 * Consumes three bytes when it succeeds.
+* [Meta data] and [implementation] mapping:
+  - `ascii::three< C >::rule_t` is `internal::string< C, C, C >`
 
 ###### `two< C >`
 
 * Succeeds when the input contains at least two bytes, and:
 * These two input bytes are both `C`.
 * Consumes two bytes when it succeeds.
+* [Meta data] and [implementation] mapping:
+  - `ascii::two< C >::rule_t` is `internal::string< C, C >`
 
 ###### `upper`
 
 * Matches and consumes a single ASCII upper-case alphabetic character.
-* Equivalent to `range< 'A', 'Z' >`.
+* [Equivalent] to `range< 'A', 'Z' >`.
+* [Meta data] and [implementation] mapping:
+  - `ascii::upper::rule_t` is `internal::range< internal::result_on_found::success, internal::peek_char, 'A', 'Z' >`
 
 ###### `xdigit`
 
 * Matches and consumes a single ASCII hexadecimal digit character.
-* Equivalent to `ranges< '0', '9', 'a', 'f', 'A', 'F' >`.
+* [Equivalent] to `ranges< '0', '9', 'a', 'f', 'A', 'F' >`.
+* [Meta data] and [implementation] mapping:
+  - `ascii::xdigit::rule_t` is `internal::ranges< internal::peek_char, '0', '9', 'a', 'f', 'A', 'F' >`
 
 ## Unicode Rules
 
@@ -571,8 +855,11 @@ The following limitations apply to the UTF-16 and UTF-32 rules:
 
 * Unaligned input leads to unaligned memory access.
 * The line and column numbers are not counted correctly.
+* They are not automatically included with `tao/pegtl.hpp`.
 
-Unaligned memory is no problem on x86 compatible processors; on some other architectures like ARM an unaligned access will crash the application.
+The UTF-16 and UTF-32 rules need to be manually included from their corresponding headers in the `contrib` section.
+
+Unaligned memory is no problem on x86 compatible processors; on ARM and most other architectures an unaligned access will crash the application.
 
 In the following descriptions a Unicode code point is considered *valid* when it is in the range `0` to `0x10ffff`.
 The parameter N stands for the size of the encoding of the next Unicode code point in the input, i.e.
@@ -583,6 +870,8 @@ The parameter N stands for the size of the encoding of the next Unicode code poi
 
 It is an error when a code unit in the range `0xd800` to `0xdfff` is encountered outside of a valid UTF-16 surrogate pair (this changed in version 2.6.0).
 
+Unicode rules do not rely on other rules.
+
 ###### `any`
 
 * Succeeds when the input is not empty, and:
@@ -591,7 +880,7 @@ It is an error when a code unit in the range `0xd800` to `0xdfff` is encountered
 
 ###### `bom`
 
-* Equivalent to `one< 0xfeff >`.
+* [Equivalent] to `one< 0xfeff >`.
 
 ###### `not_one< C... >`
 
@@ -623,20 +912,20 @@ It is an error when a code unit in the range `0xd800` to `0xdfff` is encountered
 
 ###### `ranges< C1, D1, C2, D2, ... >`
 
-* Equivalent to `sor< range< C1, D1 >, range< C2, D2 >, ... >`.
+* [Equivalent] to `sor< range< C1, D1 >, range< C2, D2 >, ... >`.
 
 ###### `ranges< C1, D1, C2, D2, ..., E >`
 
-* Equivalent to `sor< range< C1, D1 >, range< C2, D2 >, ..., one< E > >`.
+* [Equivalent] to `sor< range< C1, D1 >, range< C2, D2 >, ..., one< E > >`.
 
 ###### `string< C... >`
 
-* Equivalent to `seq< one< C >... >`.
+* [Equivalent] to `seq< one< C >... >`.
 
 ### ICU Support
 
 The following rules depend on the [International Components for Unicode (ICU)](http://icu-project.org/) that provide the means to match characters with specific Unicode character properties.
-Because of the external dependency, the rules are in the contrib-section, and the required header files are not automatically included in `tao/pegtl.hpp`.
+Because of the external dependency, the rules are in contrib, and the required header files are not automatically included in `tao/pegtl.hpp`.
 
 The ICU-based rules are again available in multiple versions,
 
@@ -646,6 +935,11 @@ The ICU-based rules are again available in multiple versions,
 * in namespace `tao::pegtl::utf32_be::icu` for big-endian UTF-32 encoded inputs, and
 * in namespace `tao::pegtl::utf32_le::icu` for little-endian UTF-32 encoded inputs.
 
+And, for convenience, they again appear in multiple namespace aliases,
+
+* namespace alias `tao::pegtl::utf16::icu` for native-endian UTF-16 encoded inputs,
+* namespace alias `tao::pegtl::utf32::icu` for native-endian UTF-32 encoded inputs.
+
 To use these rules it is necessary to provide an include path to the ICU library, to link the application against `libicu`, and to manually include one or more of the following header files:
 
 * `tao/pegtl/contrib/icu/utf8.hpp`
@@ -687,199 +981,199 @@ Convenience wrappers for binary properties.
 
 ###### `alphabetic`
 
-* Equivalent to `binary_property< UCHAR_ALPHABETIC >`.
+* [Equivalent] to `binary_property< UCHAR_ALPHABETIC >`.
 
 ###### `ascii_hex_digit`
 
-* Equivalent to `binary_property< UCHAR_ASCII_HEX_DIGIT >`.
+* [Equivalent] to `binary_property< UCHAR_ASCII_HEX_DIGIT >`.
 
 ###### `bidi_control`
 
-* Equivalent to `binary_property< UCHAR_BIDI_CONTROL >`.
+* [Equivalent] to `binary_property< UCHAR_BIDI_CONTROL >`.
 
 ###### `bidi_mirrored`
 
-* Equivalent to `binary_property< UCHAR_BIDI_MIRRORED >`.
+* [Equivalent] to `binary_property< UCHAR_BIDI_MIRRORED >`.
 
 ###### `case_sensitive`
 
-* Equivalent to `binary_property< UCHAR_CASE_SENSITIVE >`.
+* [Equivalent] to `binary_property< UCHAR_CASE_SENSITIVE >`.
 
 ###### `dash`
 
-* Equivalent to `binary_property< UCHAR_DASH >`.
+* [Equivalent] to `binary_property< UCHAR_DASH >`.
 
 ###### `default_ignorable_code_point`
 
-* Equivalent to `binary_property< UCHAR_DEFAULT_IGNORABLE_CODE_POINT >`.
+* [Equivalent] to `binary_property< UCHAR_DEFAULT_IGNORABLE_CODE_POINT >`.
 
 ###### `deprecated`
 
-* Equivalent to `binary_property< UCHAR_DEPRECATED >`.
+* [Equivalent] to `binary_property< UCHAR_DEPRECATED >`.
 
 ###### `diacritic`
 
-* Equivalent to `binary_property< UCHAR_DIACRITIC >`.
+* [Equivalent] to `binary_property< UCHAR_DIACRITIC >`.
 
 ###### `extender`
 
-* Equivalent to `binary_property< UCHAR_EXTENDER >`.
+* [Equivalent] to `binary_property< UCHAR_EXTENDER >`.
 
 ###### `full_composition_exclusion`
 
-* Equivalent to `binary_property< UCHAR_FULL_COMPOSITION_EXCLUSION >`.
+* [Equivalent] to `binary_property< UCHAR_FULL_COMPOSITION_EXCLUSION >`.
 
 ###### `grapheme_base`
 
-* Equivalent to `binary_property< UCHAR_GRAPHEME_BASE >`.
+* [Equivalent] to `binary_property< UCHAR_GRAPHEME_BASE >`.
 
 ###### `grapheme_extend`
 
-* Equivalent to `binary_property< UCHAR_GRAPHEME_EXTEND >`.
+* [Equivalent] to `binary_property< UCHAR_GRAPHEME_EXTEND >`.
 
 ###### `grapheme_link`
 
-* Equivalent to `binary_property< UCHAR_GRAPHEME_LINK >`.
+* [Equivalent] to `binary_property< UCHAR_GRAPHEME_LINK >`.
 
 ###### `hex_digit`
 
-* Equivalent to `binary_property< UCHAR_HEX_DIGIT >`.
+* [Equivalent] to `binary_property< UCHAR_HEX_DIGIT >`.
 
 ###### `hyphen`
 
-* Equivalent to `binary_property< UCHAR_HYPHEN >`.
+* [Equivalent] to `binary_property< UCHAR_HYPHEN >`.
 
 ###### `id_continue`
 
-* Equivalent to `binary_property< UCHAR_ID_CONTINUE >`.
+* [Equivalent] to `binary_property< UCHAR_ID_CONTINUE >`.
 
 ###### `id_start`
 
-* Equivalent to `binary_property< UCHAR_ID_START >`.
+* [Equivalent] to `binary_property< UCHAR_ID_START >`.
 
 ###### `ideographic`
 
-* Equivalent to `binary_property< UCHAR_IDEOGRAPHIC >`.
+* [Equivalent] to `binary_property< UCHAR_IDEOGRAPHIC >`.
 
 ###### `ids_binary_operator`
 
-* Equivalent to `binary_property< UCHAR_IDS_BINARY_OPERATOR >`.
+* [Equivalent] to `binary_property< UCHAR_IDS_BINARY_OPERATOR >`.
 
 ###### `ids_trinary_operator`
 
-* Equivalent to `binary_property< UCHAR_IDS_TRINARY_OPERATOR >`.
+* [Equivalent] to `binary_property< UCHAR_IDS_TRINARY_OPERATOR >`.
 
 ###### `join_control`
 
-* Equivalent to `binary_property< UCHAR_JOIN_CONTROL >`.
+* [Equivalent] to `binary_property< UCHAR_JOIN_CONTROL >`.
 
 ###### `logical_order_exception`
 
-* Equivalent to `binary_property< UCHAR_LOGICAL_ORDER_EXCEPTION >`.
+* [Equivalent] to `binary_property< UCHAR_LOGICAL_ORDER_EXCEPTION >`.
 
 ###### `lowercase`
 
-* Equivalent to `binary_property< UCHAR_LOWERCASE >`.
+* [Equivalent] to `binary_property< UCHAR_LOWERCASE >`.
 
 ###### `math`
 
-* Equivalent to `binary_property< UCHAR_MATH >`.
+* [Equivalent] to `binary_property< UCHAR_MATH >`.
 
 ###### `nfc_inert`
 
-* Equivalent to `binary_property< UCHAR_NFC_INERT >`.
+* [Equivalent] to `binary_property< UCHAR_NFC_INERT >`.
 
 ###### `nfd_inert`
 
-* Equivalent to `binary_property< UCHAR_NFD_INERT >`.
+* [Equivalent] to `binary_property< UCHAR_NFD_INERT >`.
 
 ###### `nfkc_inert`
 
-* Equivalent to `binary_property< UCHAR_NFKC_INERT >`.
+* [Equivalent] to `binary_property< UCHAR_NFKC_INERT >`.
 
 ###### `nfkd_inert`
 
-* Equivalent to `binary_property< UCHAR_NFKD_INERT >`.
+* [Equivalent] to `binary_property< UCHAR_NFKD_INERT >`.
 
 ###### `noncharacter_code_point`
 
-* Equivalent to `binary_property< UCHAR_NONCHARACTER_CODE_POINT >`.
+* [Equivalent] to `binary_property< UCHAR_NONCHARACTER_CODE_POINT >`.
 
 ###### `pattern_syntax`
 
-* Equivalent to `binary_property< UCHAR_PATTERN_SYNTAX >`.
+* [Equivalent] to `binary_property< UCHAR_PATTERN_SYNTAX >`.
 
 ###### `pattern_white_space`
 
-* Equivalent to `binary_property< UCHAR_PATTERN_WHITE_SPACE >`.
+* [Equivalent] to `binary_property< UCHAR_PATTERN_WHITE_SPACE >`.
 
 ###### `posix_alnum`
 
-* Equivalent to `binary_property< UCHAR_POSIX_ALNUM >`.
+* [Equivalent] to `binary_property< UCHAR_POSIX_ALNUM >`.
 
 ###### `posix_blank`
 
-* Equivalent to `binary_property< UCHAR_POSIX_BLANK >`.
+* [Equivalent] to `binary_property< UCHAR_POSIX_BLANK >`.
 
 ###### `posix_graph`
 
-* Equivalent to `binary_property< UCHAR_POSIX_GRAPH >`.
+* [Equivalent] to `binary_property< UCHAR_POSIX_GRAPH >`.
 
 ###### `posix_print`
 
-* Equivalent to `binary_property< UCHAR_POSIX_PRINT >`.
+* [Equivalent] to `binary_property< UCHAR_POSIX_PRINT >`.
 
 ###### `posix_xdigit`
 
-* Equivalent to `binary_property< UCHAR_POSIX_XDIGIT >`.
+* [Equivalent] to `binary_property< UCHAR_POSIX_XDIGIT >`.
 
 ###### `quotation_mark`
 
-* Equivalent to `binary_property< UCHAR_QUOTATION_MARK >`.
+* [Equivalent] to `binary_property< UCHAR_QUOTATION_MARK >`.
 
 ###### `radical`
 
-* Equivalent to `binary_property< UCHAR_RADICAL >`.
+* [Equivalent] to `binary_property< UCHAR_RADICAL >`.
 
 ###### `s_term`
 
-* Equivalent to `binary_property< UCHAR_S_TERM >`.
+* [Equivalent] to `binary_property< UCHAR_S_TERM >`.
 
 ###### `segment_starter`
 
-* Equivalent to `binary_property< UCHAR_SEGMENT_STARTER >`.
+* [Equivalent] to `binary_property< UCHAR_SEGMENT_STARTER >`.
 
 ###### `soft_dotted`
 
-* Equivalent to `binary_property< UCHAR_SOFT_DOTTED >`.
+* [Equivalent] to `binary_property< UCHAR_SOFT_DOTTED >`.
 
 ###### `terminal_punctuation`
 
-* Equivalent to `binary_property< UCHAR_TERMINAL_PUNCTUATION >`.
+* [Equivalent] to `binary_property< UCHAR_TERMINAL_PUNCTUATION >`.
 
 ###### `unified_ideograph`
 
-* Equivalent to `binary_property< UCHAR_UNIFIED_IDEOGRAPH >`.
+* [Equivalent] to `binary_property< UCHAR_UNIFIED_IDEOGRAPH >`.
 
 ###### `uppercase`
 
-* Equivalent to `binary_property< UCHAR_UPPERCASE >`.
+* [Equivalent] to `binary_property< UCHAR_UPPERCASE >`.
 
 ###### `variation_selector`
 
-* Equivalent to `binary_property< UCHAR_VARIATION_SELECTOR >`.
+* [Equivalent] to `binary_property< UCHAR_VARIATION_SELECTOR >`.
 
 ###### `white_space`
 
-* Equivalent to `binary_property< UCHAR_WHITE_SPACE >`.
+* [Equivalent] to `binary_property< UCHAR_WHITE_SPACE >`.
 
 ###### `xid_continue`
 
-* Equivalent to `binary_property< UCHAR_XID_CONTINUE >`.
+* [Equivalent] to `binary_property< UCHAR_XID_CONTINUE >`.
 
 ###### `xid_start`
 
-* Equivalent to `binary_property< UCHAR_XID_START >`.
+* [Equivalent] to `binary_property< UCHAR_XID_START >`.
 
 ### ICU Rules for Enumerated Properties
 
@@ -888,67 +1182,67 @@ Convenience wrappers for enumerated properties.
 ###### `bidi_class< V >`
 
 * `V` is of type `UCharDirection`.
-* Equivalent to `property_value< UCHAR_BIDI_CLASS, V >`.
+* [Equivalent] to `property_value< UCHAR_BIDI_CLASS, V >`.
 
 ###### `block< V >`
 
 * `V` is of type `UBlockCode`.
-* Equivalent to `property_value< UCHAR_BLOCK, V >`.
+* [Equivalent] to `property_value< UCHAR_BLOCK, V >`.
 
 ###### `decomposition_type< V >`
 
 * `V` is of type `UDecompositionType`.
-* Equivalent to `property_value< UCHAR_DECOMPOSITION_TYPE, V >`.
+* [Equivalent] to `property_value< UCHAR_DECOMPOSITION_TYPE, V >`.
 
 ###### `east_asian_width< V >`
 
 * `V` is of type `UEastAsianWidth`.
-* Equivalent to `property_value< UCHAR_EAST_ASIAN_WIDTH, V >`.
+* [Equivalent] to `property_value< UCHAR_EAST_ASIAN_WIDTH, V >`.
 
 ###### `general_category< V >`
 
 * `V` is of type `UCharCategory`.
-* Equivalent to `property_value< UCHAR_GENERAL_CATEGORY, V >`.
+* [Equivalent] to `property_value< UCHAR_GENERAL_CATEGORY, V >`.
 
 ###### `grapheme_cluster_break< V >`
 
 * `V` is of type `UGraphemeClusterBreak`.
-* Equivalent to `property_value< UCHAR_GRAPHEME_CLUSTER_BREAK, V >`.
+* [Equivalent] to `property_value< UCHAR_GRAPHEME_CLUSTER_BREAK, V >`.
 
 ###### `hangul_syllable_type< V >`
 
 * `V` is of type `UHangulSyllableType`.
-* Equivalent to `property_value< UCHAR_HANGUL_SYLLABLE_TYPE, V >`.
+* [Equivalent] to `property_value< UCHAR_HANGUL_SYLLABLE_TYPE, V >`.
 
 ###### `joining_group< V >`
 
 * `V` is of type `UJoiningGroup`.
-* Equivalent to `property_value< UCHAR_JOINING_GROUP, V >`.
+* [Equivalent] to `property_value< UCHAR_JOINING_GROUP, V >`.
 
 ###### `joining_type< V >`
 
 * `V` is of type `UJoiningType`.
-* Equivalent to `property_value< UCHAR_JOINING_TYPE, V >`.
+* [Equivalent] to `property_value< UCHAR_JOINING_TYPE, V >`.
 
 ###### `line_break< V >`
 
 * `V` is of type `ULineBreak`.
-* Equivalent to `property_value< UCHAR_LINE_BREAK, V >`.
+* [Equivalent] to `property_value< UCHAR_LINE_BREAK, V >`.
 
 ###### `numeric_type< V >`
 
 * `V` is of type `UNumericType`.
-* Equivalent to `property_value< UCHAR_NUMERIC_TYPE, V >`.
+* [Equivalent] to `property_value< UCHAR_NUMERIC_TYPE, V >`.
 
 ###### `sentence_break< V >`
 
 * `V` is of type `USentenceBreak`.
-* Equivalent to `property_value< UCHAR_SENTENCE_BREAK, V >`.
+* [Equivalent] to `property_value< UCHAR_SENTENCE_BREAK, V >`.
 
 ###### `word_break< V >`
 
 * `V` is of type `UWordBreakValues`.
-* Equivalent to `property_value< UCHAR_WORD_BREAK, V >`.
+* [Equivalent] to `property_value< UCHAR_WORD_BREAK, V >`.
 
 ### ICU Rules for Value Properties
 
@@ -957,17 +1251,17 @@ Convenience wrappers for enumerated properties that return a value instead of an
 ###### `canonical_combining_class< V >`
 
 * `V` is of type `std::uint8_t`.
-* Equivalent to `property_value< UCHAR_CANONICAL_COMBINING_CLASS, V >`.
+* [Equivalent] to `property_value< UCHAR_CANONICAL_COMBINING_CLASS, V >`.
 
 ###### `lead_canonical_combining_class< V >`
 
 * `V` is of type `std::uint8_t`.
-* Equivalent to `property_value< UCHAR_LEAD_CANONICAL_COMBINING_CLASS, V >`.
+* [Equivalent] to `property_value< UCHAR_LEAD_CANONICAL_COMBINING_CLASS, V >`.
 
 ###### `trail_canonical_combining_class< V >`
 
 * `V` is of type `std::uint8_t`.
-* Equivalent to `property_value< UCHAR_TRAIL_CANONICAL_COMBINING_CLASS, V >`.
+* [Equivalent] to `property_value< UCHAR_TRAIL_CANONICAL_COMBINING_CLASS, V >`.
 
 ## Binary Rules
 
@@ -981,11 +1275,15 @@ These rules are available in multiple versions,
 * in namespace `tao::pegtl::uint64_be` for big-endian 64-bit integer values, and
 * in namespace `tao::pegtl::uint64_le` for little-endian 64-bit integer values.
 
-These rules read one or more bytes from the input to form (and match) an 8, 16, 32 or 64-bit value, respectively, and template parameters are given as matching `std::uint8_t`, `std::uint16_t`, `std::uint32_t` or `std::uin64_t`.
+The binary rules need to be manually included from their corresponding headers in the `contrib` section.
 
-In the following descriptions the parameter N is the size of a single value in bytes, i.e. either 1, 2, 4 or 8.
+These rules read one or more bytes from the input to form (and match) an 8, 16, 32 or 64-bit value, respectively, and corresponding template parameters are given as either `std::uint8_t`, `std::uint16_t`, `std::uint32_t` or `std::uin64_t`.
+
+In the following descriptions, the parameter N is the size of a single value in bytes, i.e. either 1, 2, 4 or 8.
 The term *input value* indicates a correspondingly sized integer value read from successive bytes of the input.
 
+Binary rules do not rely on other rules.
+
 ###### `any`
 
 * Succeeds when the input contains at least N bytes.
@@ -1017,15 +1315,15 @@ The term *input value* indicates a correspondingly sized integer value read from
 
 ###### `mask_ranges< M, C1, D1, C2, D2, ... >`
 
-* Equivalent to `sor< mask_range< M, C1, D1 >, mask_range< M, C2, D2 >, ... >`.
+* [Equivalent] to `sor< mask_range< M, C1, D1 >, mask_range< M, C2, D2 >, ... >`.
 
 ###### `mask_ranges< M, C1, D1, C2, D2, ..., E >`
 
-* Equivalent to `sor< mask_range< M, C1, D1 >, mask_range< M, C2, D2 >, ..., mask_one< M, E > >`.
+* [Equivalent] to `sor< mask_range< M, C1, D1 >, mask_range< M, C2, D2 >, ..., mask_one< M, E > >`.
 
 ###### `mask_string< M, C... >`
 
-* Equivalent to `seq< mask_one< M, C >... >`.
+* [Equivalent] to `seq< mask_one< M, C >... >`.
 
 ###### `not_one< C... >`
 
@@ -1053,15 +1351,15 @@ The term *input value* indicates a correspondingly sized integer value read from
 
 ###### `ranges< C1, D1, C2, D2, ... >`
 
-* Equivalent to `sor< range< C1, D1 >, range< C2, D2 >, ... >`.
+* [Equivalent] to `sor< range< C1, D1 >, range< C2, D2 >, ... >`.
 
 ###### `ranges< C1, D1, C2, D2, ..., E >`
 
-* Equivalent to `sor< range< C1, D1 >, range< C2, D2 >, ..., one< E > >`.
+* [Equivalent] to `sor< range< C1, D1 >, range< C2, D2 >, ..., one< E > >`.
 
 ###### `string< C... >`
 
-* Equivalent to `seq< one< C >... >`.
+* [Equivalent] to `seq< one< C >... >`.
 
 ## Full Index
 
@@ -1101,8 +1399,8 @@ The term *input value* indicates a correspondingly sized integer value read from
 * [`east_asian_width< V >`](#east_asian_width-v-) <sup>[(icu rules)](#icu-rules-for-enumerated-properties)</sup>
 * [`enable< R... >`](#enable-r-) <sup>[(meta-rules)](#meta-rules)</sup>
 * [`eof`](#eof) <sup>[(atomic rules)](#atomic-rules)</sup>
-* [`eol`](#eol) <sup>[(ascii rules)](#ascii-rules)</sup>
-* [`eolf`](#eolf) <sup>[(ascii rules)](#ascii-rules)</sup>
+* [`eol`](#eol) <sup>[(atomic rules)](#atomic-rules)</sup>
+* [`eolf`](#eolf) <sup>[(atomic rules)](#atomic-rules)</sup>
 * [`extender`](#extender) <sup>[(icu rules)](#icu-rules-for-binary-properties)</sup>
 * [`failure`](#failure) <sup>[(atomic rules)](#atomic-rules)</sup>
 * [`forty_two< C... >`](#forty_two-c-) <sup>[(ascii rules)](#ascii-rules)</sup>
@@ -1241,3 +1539,7 @@ The term *input value* indicates a correspondingly sized integer value read from
 * [`xid_start`](#xid_start) <sup>[(icu rules)](#icu-rules-for-binary-properties)</sup>
 
 Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey
+
+[Equivalent]: #equivalence
+[implementation]: #implementation
+[Meta data]: Meta-Data-and-Visit.md
diff --git a/packages/PEGTL/doc/Rules-and-Grammars.md b/packages/PEGTL/doc/Rules-and-Grammars.md
index 58905c1539432614d3717e90f64afa70214c08e1..0fd0caa4c0a206832cc5baa886629277f686dec2 100644
--- a/packages/PEGTL/doc/Rules-and-Grammars.md
+++ b/packages/PEGTL/doc/Rules-and-Grammars.md
@@ -136,8 +136,8 @@ Rules with the simplified interface are called without the states as arguments.
 ```c++
 struct simple_rule
 {
-   template< typename Input >
-   static bool match( Input& in ) { ... }
+   template< typename ParseInput >
+   static bool match( ParseInput& in ) { ... }
 };
 ```
 
@@ -162,8 +162,8 @@ namespace modulus
       static_assert( M > 1, "Modulus must be greater than 1" );
       static_assert( R < M, "Remainder must be less than modulus" );
 
-      template< typename Input >
-      static bool match( Input& in )
+      template< typename ParseInput >
+      static bool match( ParseInput& in )
       {
          if( ! in.empty() ) {
             if( ( ( *in.begin() ) % M ) == R ) {
@@ -200,16 +200,16 @@ The signature of `match()` in a complex rule takes the following form.
 ```c++
 struct complex_rule
 {
-   // Optional; explained in the section on Grammar Analysis:
-   using analyze_t = ...;
+   using rule_t = complex_rule;
+   using subs_t = tao::pegtl::empty_list;  // Or tao::pegtl::rule_list< sub_rules_of_complex_rule... >.
 
    template< tao::pegtl::apply_mode A,
              tao::pegtl::rewind_mode M,
              template< typename... > class Action,
              template< typename... > class Control,
-             typename Input,
+             typename ParseInput,
              typename... States >
-   static bool match( Input& in, States&&... )
+   static bool match( ParseInput& in, States&&... )
    { ... }
 };
 ```
@@ -238,9 +238,9 @@ struct seq
               rewind_mode M,
               template< typename... > class Action,
               template< typename... > class Control,
-              typename Input,
+              typename ParseInput,
               typename... States >
-    static bool match( Input& in, States&&... st )
+    static bool match( ParseInput& in, States&&... st )
     {
        auto m = in.template mark< M >();
        using m_t = decltype( m );
@@ -286,8 +286,8 @@ The action stores the matched string that corresponds to `"foo"` in a string var
    template<>
    struct action< long_literal_id >
    {
-      template< typename Input >
-      static void apply( const Input& in,
+      template< typename ActionInput >
+      static void apply( const ActionInput& in,
                          std::string& id,
                          const std::string& )
       {
@@ -320,8 +320,8 @@ The custom rule itself
                 tao::pegtl::rewind_mode M,
                 template< typename... > class Action,
                 template< typename... > class Control,
-                typename Input >
-      static bool match( Input& in,
+                typename ParseInput >
+      static bool match( ParseInput& in,
                          const std::string& id,
                          const std::string& )
       {
@@ -351,8 +351,8 @@ In this case the rule `long_literal_body` is redundant, however real-world examp
 
    template<> struct action< long_literal_body >
    {
-      template< typename Input >
-      static void apply( const Input& in,
+      template< typename ActionInput >
+      static void apply( const ActionInput& in,
                          const std::string&,
                          std::string& body )
       {
diff --git a/packages/PEGTL/include/tao/pegtl.hpp b/packages/PEGTL/include/tao/pegtl.hpp
index d20c4e3e4c56d7a78eb63a675028562454ea17c4..9ef19286fdc5f4663f284e70ee9c70a91133fe33 100644
--- a/packages/PEGTL/include/tao/pegtl.hpp
+++ b/packages/PEGTL/include/tao/pegtl.hpp
@@ -5,18 +5,11 @@
 #define TAO_PEGTL_HPP
 
 #include "pegtl/config.hpp"
-#include "pegtl/version.hpp"
-
 #include "pegtl/parse.hpp"
+#include "pegtl/version.hpp"
 
 #include "pegtl/ascii.hpp"
 #include "pegtl/rules.hpp"
-#include "pegtl/uint16.hpp"
-#include "pegtl/uint32.hpp"
-#include "pegtl/uint64.hpp"
-#include "pegtl/uint8.hpp"
-#include "pegtl/utf16.hpp"
-#include "pegtl/utf32.hpp"
 #include "pegtl/utf8.hpp"
 
 #include "pegtl/argv_input.hpp"
@@ -27,7 +20,7 @@
 #include "pegtl/read_input.hpp"
 #include "pegtl/string_input.hpp"
 
-// this has to be included *after* the above inputs,
+// This has to be included *after* the above inputs,
 // otherwise the amalgamated header will not work!
 #include "pegtl/file_input.hpp"
 
@@ -45,9 +38,7 @@
 #include "pegtl/discard_input_on_failure.hpp"
 #include "pegtl/discard_input_on_success.hpp"
 
-// The following are not included by
-// default because they include <iostream>.
-
-// #include "pegtl/analyze.hpp"
+#include "pegtl/must_if.hpp"
+#include "pegtl/visit.hpp"
 
 #endif
diff --git a/packages/PEGTL/include/tao/pegtl/analysis/analyze_cycles.hpp b/packages/PEGTL/include/tao/pegtl/analysis/analyze_cycles.hpp
deleted file mode 100644
index 8b8e5d3daef149fc16681134c4de008e140a803a..0000000000000000000000000000000000000000
--- a/packages/PEGTL/include/tao/pegtl/analysis/analyze_cycles.hpp
+++ /dev/null
@@ -1,126 +0,0 @@
-// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey
-// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
-
-#ifndef TAO_PEGTL_ANALYSIS_ANALYZE_CYCLES_HPP
-#define TAO_PEGTL_ANALYSIS_ANALYZE_CYCLES_HPP
-
-#include <cassert>
-
-#include <map>
-#include <set>
-#include <stdexcept>
-#include <string_view>
-
-#include <iostream>
-#include <utility>
-
-#include "../config.hpp"
-
-#include "grammar_info.hpp"
-#include "insert_guard.hpp"
-
-namespace TAO_PEGTL_NAMESPACE::analysis
-{
-   struct analyze_cycles_impl
-   {
-   protected:
-      explicit analyze_cycles_impl( const bool verbose ) noexcept
-         : m_verbose( verbose ),
-           m_problems( 0 )
-      {}
-
-      const bool m_verbose;
-      unsigned m_problems;
-      grammar_info m_info;
-      std::set< std::string_view > m_stack;
-      std::map< std::string_view, bool > m_cache;
-      std::map< std::string_view, bool > m_results;
-
-      [[nodiscard]] std::map< std::string_view, rule_info >::const_iterator find( const std::string_view name ) const noexcept
-      {
-         const auto iter = m_info.map.find( name );
-         assert( iter != m_info.map.end() );
-         return iter;
-      }
-
-      [[nodiscard]] bool work( const std::map< std::string_view, rule_info >::const_iterator& start, const bool accum )
-      {
-         const auto j = m_cache.find( start->first );
-
-         if( j != m_cache.end() ) {
-            return j->second;
-         }
-         if( const auto g = insert_guard( m_stack, start->first ) ) {
-            switch( start->second.type ) {
-               case rule_type::any: {
-                  bool a = false;
-                  for( const auto& r : start->second.rules ) {
-                     a = a || work( find( r ), accum || a );
-                  }
-                  return m_cache[ start->first ] = true;
-               }
-               case rule_type::opt: {
-                  bool a = false;
-                  for( const auto& r : start->second.rules ) {
-                     a = a || work( find( r ), accum || a );
-                  }
-                  return m_cache[ start->first ] = false;
-               }
-               case rule_type::seq: {
-                  bool a = false;
-                  for( const auto& r : start->second.rules ) {
-                     a = a || work( find( r ), accum || a );
-                  }
-                  return m_cache[ start->first ] = a;
-               }
-               case rule_type::sor: {
-                  bool a = true;
-                  for( const auto& r : start->second.rules ) {
-                     a = a && work( find( r ), accum );
-                  }
-                  return m_cache[ start->first ] = a;
-               }
-            }
-            throw std::logic_error( "code should be unreachable: invalid rule_type value" );  // LCOV_EXCL_LINE
-         }
-         if( !accum ) {
-            ++m_problems;
-            if( m_verbose ) {
-               std::cout << "problem: cycle without progress detected at rule class " << start->first << std::endl;  // LCOV_EXCL_LINE
-            }
-         }
-         return m_cache[ start->first ] = accum;
-      }
-   };
-
-   template< typename Grammar >
-   struct analyze_cycles
-      : private analyze_cycles_impl
-   {
-      explicit analyze_cycles( const bool verbose )
-         : analyze_cycles_impl( verbose )
-      {
-         Grammar::analyze_t::template insert< Grammar >( m_info );
-      }
-
-      [[nodiscard]] std::size_t problems()
-      {
-         for( auto i = m_info.map.begin(); i != m_info.map.end(); ++i ) {
-            m_results[ i->first ] = work( i, false );
-            m_cache.clear();
-         }
-         return m_problems;
-      }
-
-      template< typename Rule >
-      [[nodiscard]] bool consumes() const noexcept
-      {
-         const auto i = m_results.find( internal::demangle< Rule >() );
-         assert( i != m_results.end() );
-         return i->second;
-      }
-   };
-
-}  // namespace TAO_PEGTL_NAMESPACE::analysis
-
-#endif
diff --git a/packages/PEGTL/include/tao/pegtl/analysis/counted.hpp b/packages/PEGTL/include/tao/pegtl/analysis/counted.hpp
deleted file mode 100644
index 63773db19c21623dc9b646d5785fbd5e7bcabb2b..0000000000000000000000000000000000000000
--- a/packages/PEGTL/include/tao/pegtl/analysis/counted.hpp
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey
-// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
-
-#ifndef TAO_PEGTL_ANALYSIS_COUNTED_HPP
-#define TAO_PEGTL_ANALYSIS_COUNTED_HPP
-
-#include "../config.hpp"
-
-#include <cstddef>
-
-#include "generic.hpp"
-
-namespace TAO_PEGTL_NAMESPACE::analysis
-{
-   template< rule_type Type, std::size_t Count, typename... Rules >
-   struct counted
-      : generic< ( Count != 0 ) ? Type : rule_type::opt, Rules... >
-   {};
-
-}  // namespace TAO_PEGTL_NAMESPACE::analysis
-
-#endif
diff --git a/packages/PEGTL/include/tao/pegtl/analysis/generic.hpp b/packages/PEGTL/include/tao/pegtl/analysis/generic.hpp
deleted file mode 100644
index ddf3a9c9aea56de2f40e3e4ee3704cf1c7e34c2c..0000000000000000000000000000000000000000
--- a/packages/PEGTL/include/tao/pegtl/analysis/generic.hpp
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey
-// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
-
-#ifndef TAO_PEGTL_ANALYSIS_GENERIC_HPP
-#define TAO_PEGTL_ANALYSIS_GENERIC_HPP
-
-#include "../config.hpp"
-
-#include "grammar_info.hpp"
-#include "rule_type.hpp"
-
-namespace TAO_PEGTL_NAMESPACE::analysis
-{
-   template< rule_type Type, typename... Rules >
-   struct generic
-   {
-      template< typename Name >
-      static std::string_view insert( grammar_info& g )
-      {
-         const auto [ it, success ] = g.insert< Name >( Type );
-         if( success ) {
-            ( it->second.rules.emplace_back( Rules::analyze_t::template insert< Rules >( g ) ), ... );
-         }
-         return it->first;
-      }
-   };
-
-}  // namespace TAO_PEGTL_NAMESPACE::analysis
-
-#endif
diff --git a/packages/PEGTL/include/tao/pegtl/analysis/grammar_info.hpp b/packages/PEGTL/include/tao/pegtl/analysis/grammar_info.hpp
deleted file mode 100644
index 9cfdd3870808cf3d69aead815775efbaed8366dd..0000000000000000000000000000000000000000
--- a/packages/PEGTL/include/tao/pegtl/analysis/grammar_info.hpp
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey
-// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
-
-#ifndef TAO_PEGTL_ANALYSIS_GRAMMAR_INFO_HPP
-#define TAO_PEGTL_ANALYSIS_GRAMMAR_INFO_HPP
-
-#include <map>
-#include <string>
-#include <utility>
-
-#include "../config.hpp"
-#include "../internal/demangle.hpp"
-
-#include "rule_info.hpp"
-
-namespace TAO_PEGTL_NAMESPACE::analysis
-{
-   struct grammar_info
-   {
-      using map_t = std::map< std::string_view, rule_info >;
-      map_t map;
-
-      template< typename Name >
-      auto insert( const rule_type type )
-      {
-         return map.try_emplace( internal::demangle< Name >(), rule_info( type ) );
-      }
-   };
-
-}  // namespace TAO_PEGTL_NAMESPACE::analysis
-
-#endif
diff --git a/packages/PEGTL/include/tao/pegtl/analysis/insert_guard.hpp b/packages/PEGTL/include/tao/pegtl/analysis/insert_guard.hpp
deleted file mode 100644
index 5ced82dcde374720ae33a7398b00b9788b0ab1d7..0000000000000000000000000000000000000000
--- a/packages/PEGTL/include/tao/pegtl/analysis/insert_guard.hpp
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey
-// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
-
-#ifndef TAO_PEGTL_ANALYSIS_INSERT_GUARD_HPP
-#define TAO_PEGTL_ANALYSIS_INSERT_GUARD_HPP
-
-#include <utility>
-
-#include "../config.hpp"
-
-namespace TAO_PEGTL_NAMESPACE::analysis
-{
-   template< typename C >
-   class insert_guard
-   {
-   public:
-      insert_guard( C& container, const typename C::value_type& value )
-         : m_i( container.insert( value ) ),
-           m_c( container )
-      {}
-
-      insert_guard( const insert_guard& ) = delete;
-      insert_guard( insert_guard&& ) = delete;
-
-      ~insert_guard()
-      {
-         if( m_i.second ) {
-            m_c.erase( m_i.first );
-         }
-      }
-
-      void operator=( const insert_guard& ) = delete;
-      void operator=( insert_guard&& ) = delete;
-
-      explicit operator bool() const noexcept
-      {
-         return m_i.second;
-      }
-
-   private:
-      const std::pair< typename C::iterator, bool > m_i;
-      C& m_c;
-   };
-
-   template< typename C >
-   insert_guard( C&, const typename C::value_type& )->insert_guard< C >;
-
-}  // namespace TAO_PEGTL_NAMESPACE::analysis
-
-#endif
diff --git a/packages/PEGTL/include/tao/pegtl/analysis/rule_info.hpp b/packages/PEGTL/include/tao/pegtl/analysis/rule_info.hpp
deleted file mode 100644
index 68dc182672283c0bad2844ad51adec1f5b32829e..0000000000000000000000000000000000000000
--- a/packages/PEGTL/include/tao/pegtl/analysis/rule_info.hpp
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey
-// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
-
-#ifndef TAO_PEGTL_ANALYSIS_RULE_INFO_HPP
-#define TAO_PEGTL_ANALYSIS_RULE_INFO_HPP
-
-#include <string>
-#include <vector>
-
-#include "../config.hpp"
-
-#include "rule_type.hpp"
-
-namespace TAO_PEGTL_NAMESPACE::analysis
-{
-   struct rule_info
-   {
-      explicit rule_info( const rule_type in_type ) noexcept
-         : type( in_type )
-      {}
-
-      rule_type type;
-      std::vector< std::string > rules;
-   };
-
-}  // namespace TAO_PEGTL_NAMESPACE::analysis
-
-#endif
diff --git a/packages/PEGTL/include/tao/pegtl/analysis/rule_type.hpp b/packages/PEGTL/include/tao/pegtl/analysis/rule_type.hpp
deleted file mode 100644
index c598c1c3794c9b95f9ad7e4daf1370b4404caaae..0000000000000000000000000000000000000000
--- a/packages/PEGTL/include/tao/pegtl/analysis/rule_type.hpp
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey
-// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
-
-#ifndef TAO_PEGTL_ANALYSIS_RULE_TYPE_HPP
-#define TAO_PEGTL_ANALYSIS_RULE_TYPE_HPP
-
-#include "../config.hpp"
-
-namespace TAO_PEGTL_NAMESPACE::analysis
-{
-   enum class rule_type : char
-   {
-      any,  // Consumption-on-success is always true; assumes bounded repetition of conjunction of sub-rules.
-      opt,  // Consumption-on-success not necessarily true; assumes bounded repetition of conjunction of sub-rules.
-      seq,  // Consumption-on-success depends on consumption of (non-zero bounded repetition of) conjunction of sub-rules.
-      sor   // Consumption-on-success depends on consumption of (non-zero bounded repetition of) disjunction of sub-rules.
-   };
-
-}  // namespace TAO_PEGTL_NAMESPACE::analysis
-
-#endif
diff --git a/packages/PEGTL/include/tao/pegtl/analyze.hpp b/packages/PEGTL/include/tao/pegtl/analyze.hpp
deleted file mode 100644
index fc766944c7d34027b677c0c0ecafbee6f3614afc..0000000000000000000000000000000000000000
--- a/packages/PEGTL/include/tao/pegtl/analyze.hpp
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey
-// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
-
-#ifndef TAO_PEGTL_ANALYZE_HPP
-#define TAO_PEGTL_ANALYZE_HPP
-
-#include "config.hpp"
-
-#include "analysis/analyze_cycles.hpp"
-
-namespace TAO_PEGTL_NAMESPACE
-{
-   template< typename Rule >
-   [[nodiscard]] std::size_t analyze( const bool verbose = true )
-   {
-      return analysis::analyze_cycles< Rule >( verbose ).problems();
-   }
-
-}  // namespace TAO_PEGTL_NAMESPACE
-
-#endif
diff --git a/packages/PEGTL/include/tao/pegtl/ascii.hpp b/packages/PEGTL/include/tao/pegtl/ascii.hpp
index e376e7bbb7e27bb1e21c9357e904591b8ce8a3a6..1e4f1032f4287f4aac2c711c5659086c7666ad1d 100644
--- a/packages/PEGTL/include/tao/pegtl/ascii.hpp
+++ b/packages/PEGTL/include/tao/pegtl/ascii.hpp
@@ -5,9 +5,8 @@
 #define TAO_PEGTL_ASCII_HPP
 
 #include "config.hpp"
-#include "eol.hpp"
 
-#include "internal/always_false.hpp"
+#include "internal/dependent_false.hpp"
 #include "internal/result_on_found.hpp"
 #include "internal/rules.hpp"
 
@@ -22,13 +21,12 @@ namespace TAO_PEGTL_NAMESPACE
       struct blank : internal::one< internal::result_on_found::success, internal::peek_char, ' ', '\t' > {};
       struct digit : internal::range< internal::result_on_found::success, internal::peek_char, '0', '9' > {};
       struct ellipsis : internal::string< '.', '.', '.' > {};
-      struct eolf : internal::eolf {};
       template< char... Cs > struct forty_two : internal::rep< 42, internal::one< internal::result_on_found::success, internal::peek_char, Cs... > > {};
       struct identifier_first : internal::identifier_first {};
       struct identifier_other : internal::identifier_other {};
       struct identifier : internal::identifier {};
       template< char... Cs > struct istring : internal::istring< Cs... > {};
-      template< char... Cs > struct keyword : internal::seq< internal::string< Cs... >, internal::not_at< internal::identifier_other > > {};
+      template< char... Cs > struct keyword : internal::seq< internal::string< Cs... >, internal::not_at< internal::identifier_other > > { static_assert( sizeof...( Cs ) > 0 ); };
       struct lower : internal::range< internal::result_on_found::success, internal::peek_char, 'a', 'z' > {};
       template< char... Cs > struct not_one : internal::one< internal::result_on_found::failure, internal::peek_char, Cs... > {};
       template< char Lo, char Hi > struct not_range : internal::range< internal::result_on_found::failure, internal::peek_char, Lo, Hi > {};
@@ -38,7 +36,7 @@ namespace TAO_PEGTL_NAMESPACE
       template< char Lo, char Hi > struct range : internal::range< internal::result_on_found::success, internal::peek_char, Lo, Hi > {};
       template< char... Cs > struct ranges : internal::ranges< internal::peek_char, Cs... > {};
       struct seven : internal::range< internal::result_on_found::success, internal::peek_char, char( 0 ), char( 127 ) > {};
-      struct shebang : internal::if_must< false, internal::string< '#', '!' >, internal::until< internal::eolf > > {};
+      struct shebang : internal::seq< internal::string< '#', '!' >, internal::until< internal::eolf > > {};
       struct space : internal::one< internal::result_on_found::success, internal::peek_char, ' ', '\n', '\r', '\t', '\v', '\f' > {};
       template< char... Cs > struct string : internal::string< Cs... > {};
       template< char C > struct three : internal::string< C, C, C > {};
@@ -47,17 +45,6 @@ namespace TAO_PEGTL_NAMESPACE
       struct xdigit : internal::ranges< internal::peek_char, '0', '9', 'a', 'f', 'A', 'F' > {};
       // clang-format on
 
-      template<>
-      struct keyword<>
-      {
-         template< typename Input >
-         [[nodiscard]] static bool match( Input& /*unused*/ ) noexcept
-         {
-            static_assert( internal::always_false< Input >::value, "empty keywords not allowed" );
-            return false;
-         }
-      };
-
    }  // namespace ascii
 
 }  // namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/include/tao/pegtl/change_action.hpp b/packages/PEGTL/include/tao/pegtl/change_action.hpp
index fdef488a79a5f142615d1c1df54d0b8b77bd61b0..e7ae6d96a8398e1b780bf659bffb31728ef594f9 100644
--- a/packages/PEGTL/include/tao/pegtl/change_action.hpp
+++ b/packages/PEGTL/include/tao/pegtl/change_action.hpp
@@ -24,9 +24,9 @@ namespace TAO_PEGTL_NAMESPACE
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
       {
          static_assert( !std::is_same_v< Action< void >, NewAction< void > >, "old and new action class templates are identical" );
          return Control< Rule >::template match< A, M, NewAction, Control >( in, st... );
diff --git a/packages/PEGTL/include/tao/pegtl/change_action_and_state.hpp b/packages/PEGTL/include/tao/pegtl/change_action_and_state.hpp
index 5ce3a0506aedba7e5fd88944d97df7ca7b17ce67..953e3a4bde64cc0476b02218b99484569b44069b 100644
--- a/packages/PEGTL/include/tao/pegtl/change_action_and_state.hpp
+++ b/packages/PEGTL/include/tao/pegtl/change_action_and_state.hpp
@@ -25,24 +25,24 @@ namespace TAO_PEGTL_NAMESPACE
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
       {
          static_assert( !std::is_same_v< Action< void >, NewAction< void > >, "old and new action class templates are identical" );
-         NewState s( static_cast< const Input& >( in ), st... );
+         NewState s( static_cast< const ParseInput& >( in ), st... );
          if( Control< Rule >::template match< A, M, NewAction, Control >( in, s ) ) {
             if constexpr( A == apply_mode::action ) {
-               Action< Rule >::success( static_cast< const Input& >( in ), s, st... );
+               Action< Rule >::success( static_cast< const ParseInput& >( in ), s, st... );
             }
             return true;
          }
          return false;
       }
 
-      template< typename Input,
+      template< typename ParseInput,
                 typename... States >
-      static void success( const Input& in, NewState& s, States&&... st ) noexcept( noexcept( s.success( in, st... ) ) )
+      static void success( const ParseInput& in, NewState& s, States&&... st ) noexcept( noexcept( s.success( in, st... ) ) )
       {
          s.success( in, st... );
       }
diff --git a/packages/PEGTL/include/tao/pegtl/change_action_and_states.hpp b/packages/PEGTL/include/tao/pegtl/change_action_and_states.hpp
index ae700726db9be47e2361392bb55d3c1a41ef90bd..91ec5bcf8915342fbed441787845a480c7004115 100644
--- a/packages/PEGTL/include/tao/pegtl/change_action_and_states.hpp
+++ b/packages/PEGTL/include/tao/pegtl/change_action_and_states.hpp
@@ -27,14 +27,14 @@ namespace TAO_PEGTL_NAMESPACE
                 template< typename... >
                 class Control,
                 std::size_t... Ns,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( std::index_sequence< Ns... > /*unused*/, Input& in, States&&... st )
+      [[nodiscard]] static bool match( std::index_sequence< Ns... > /*unused*/, ParseInput& in, States&&... st )
       {
          auto t = std::tie( st... );
          if( Control< Rule >::template match< A, M, NewAction, Control >( in, std::get< Ns >( t )... ) ) {
             if constexpr( A == apply_mode::action ) {
-               Action< Rule >::success( static_cast< const Input& >( in ), st... );
+               Action< Rule >::success( static_cast< const ParseInput& >( in ), st... );
             }
             return true;
          }
@@ -48,9 +48,9 @@ namespace TAO_PEGTL_NAMESPACE
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
       {
          static_assert( !std::is_same_v< Action< void >, NewAction< void > >, "old and new action class templates are identical" );
          return match< Rule, A, M, Action, Control >( std::index_sequence_for< NewStates... >(), in, NewStates()..., st... );
diff --git a/packages/PEGTL/include/tao/pegtl/change_control.hpp b/packages/PEGTL/include/tao/pegtl/change_control.hpp
index 11e9c55137833211b90aa4af0dc9d327c061b000..0440e723df9292a529d47c7714e68ea31a40cff7 100644
--- a/packages/PEGTL/include/tao/pegtl/change_control.hpp
+++ b/packages/PEGTL/include/tao/pegtl/change_control.hpp
@@ -23,9 +23,9 @@ namespace TAO_PEGTL_NAMESPACE
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
       {
          return TAO_PEGTL_NAMESPACE::match< Rule, A, M, Action, NewControl >( in, st... );
       }
diff --git a/packages/PEGTL/include/tao/pegtl/change_state.hpp b/packages/PEGTL/include/tao/pegtl/change_state.hpp
index 2b2093cc010144936d2d7b914fcd7a7ed6962929..c433dd8a936948b704b991cf50636e0603cf70b8 100644
--- a/packages/PEGTL/include/tao/pegtl/change_state.hpp
+++ b/packages/PEGTL/include/tao/pegtl/change_state.hpp
@@ -23,23 +23,23 @@ namespace TAO_PEGTL_NAMESPACE
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
       {
-         NewState s( static_cast< const Input& >( in ), st... );
+         NewState s( static_cast< const ParseInput& >( in ), st... );
          if( TAO_PEGTL_NAMESPACE::match< Rule, A, M, Action, Control >( in, s ) ) {
             if constexpr( A == apply_mode::action ) {
-               Action< Rule >::success( static_cast< const Input& >( in ), s, st... );
+               Action< Rule >::success( static_cast< const ParseInput& >( in ), s, st... );
             }
             return true;
          }
          return false;
       }
 
-      template< typename Input,
+      template< typename ParseInput,
                 typename... States >
-      static void success( const Input& in, NewState& s, States&&... st ) noexcept( noexcept( s.success( in, st... ) ) )
+      static void success( const ParseInput& in, NewState& s, States&&... st ) noexcept( noexcept( s.success( in, st... ) ) )
       {
          s.success( in, st... );
       }
diff --git a/packages/PEGTL/include/tao/pegtl/change_states.hpp b/packages/PEGTL/include/tao/pegtl/change_states.hpp
index d1570a7a801856ba10d2c2d47166d2c04c3b9571..bc7ac78d0de92c2c8ecde6da7cbd9d5f9e2107c4 100644
--- a/packages/PEGTL/include/tao/pegtl/change_states.hpp
+++ b/packages/PEGTL/include/tao/pegtl/change_states.hpp
@@ -27,14 +27,14 @@ namespace TAO_PEGTL_NAMESPACE
                 template< typename... >
                 class Control,
                 std::size_t... Ns,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( std::index_sequence< Ns... > /*unused*/, Input& in, States&&... st )
+      [[nodiscard]] static bool match( std::index_sequence< Ns... > /*unused*/, ParseInput& in, States&&... st )
       {
          auto t = std::tie( st... );
          if( TAO_PEGTL_NAMESPACE::match< Rule, A, M, Action, Control >( in, std::get< Ns >( t )... ) ) {
             if constexpr( A == apply_mode::action ) {
-               Action< Rule >::success( static_cast< const Input& >( in ), st... );
+               Action< Rule >::success( static_cast< const ParseInput& >( in ), st... );
             }
             return true;
          }
@@ -48,9 +48,9 @@ namespace TAO_PEGTL_NAMESPACE
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
       {
          return match< Rule, A, M, Action, Control >( std::index_sequence_for< NewStates... >(), in, NewStates()..., st... );
       }
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/analyze.hpp b/packages/PEGTL/include/tao/pegtl/contrib/analyze.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..128017d0f9397aa2b0c29f32398d102b9787fcfb
--- /dev/null
+++ b/packages/PEGTL/include/tao/pegtl/contrib/analyze.hpp
@@ -0,0 +1,209 @@
+// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#ifndef TAO_PEGTL_CONTRIB_ANALYZE_HPP
+#define TAO_PEGTL_CONTRIB_ANALYZE_HPP
+
+#include <cassert>
+#include <cstddef>
+#include <iostream>
+#include <map>
+#include <set>
+#include <stdexcept>
+#include <string_view>
+#include <utility>
+#include <vector>
+
+#include "../config.hpp"
+
+#include "analyze_traits.hpp"
+
+#include "../internal/demangle.hpp"
+#include "../internal/dependent_false.hpp"
+
+namespace TAO_PEGTL_NAMESPACE
+{
+   namespace internal
+   {
+      struct analyze_entry
+      {
+         explicit analyze_entry( const analyze_type in_type ) noexcept
+            : type( in_type )
+         {}
+
+         const analyze_type type;
+         std::vector< std::string_view > subs;
+      };
+
+      template< typename C >
+      class analyze_guard
+      {
+      public:
+         analyze_guard( C& container, const typename C::value_type& value )
+            : m_i( container.insert( value ) ),
+              m_c( container )
+         {}
+
+         analyze_guard( analyze_guard&& ) = delete;
+         analyze_guard( const analyze_guard& ) = delete;
+
+         void operator=( analyze_guard&& ) = delete;
+         void operator=( const analyze_guard& ) = delete;
+
+         ~analyze_guard()
+         {
+            if( m_i.second ) {
+               m_c.erase( m_i.first );
+            }
+         }
+
+         explicit operator bool() const noexcept
+         {
+            return m_i.second;
+         }
+
+      private:
+         const std::pair< typename C::iterator, bool > m_i;
+         C& m_c;
+      };
+
+      template< typename C >
+      analyze_guard( C&, const typename C::value_type& )->analyze_guard< C >;
+
+      class analyze_cycles_impl
+      {
+      public:
+         analyze_cycles_impl( analyze_cycles_impl&& ) = delete;
+         analyze_cycles_impl( const analyze_cycles_impl& ) = delete;
+
+         ~analyze_cycles_impl() = default;
+
+         void operator=( analyze_cycles_impl&& ) = delete;
+         void operator=( const analyze_cycles_impl& ) = delete;
+
+         [[nodiscard]] std::size_t problems()
+         {
+            for( auto i = m_info.begin(); i != m_info.end(); ++i ) {
+               m_results[ i->first ] = work( i, false );
+               m_cache.clear();
+            }
+            return m_problems;
+         }
+
+         template< typename Rule >
+         [[nodiscard]] bool consumes() const
+         {
+            return m_results.at( demangle< Rule >() );
+         }
+
+      protected:
+         explicit analyze_cycles_impl( const bool verbose ) noexcept
+            : m_verbose( verbose ),
+              m_problems( 0 )
+         {}
+
+         [[nodiscard]] std::map< std::string_view, analyze_entry >::const_iterator find( const std::string_view name ) const noexcept
+         {
+            const auto iter = m_info.find( name );
+            assert( iter != m_info.end() );
+            return iter;
+         }
+
+         [[nodiscard]] bool work( const std::map< std::string_view, analyze_entry >::const_iterator& start, const bool accum )
+         {
+            if( const auto j = m_cache.find( start->first ); j != m_cache.end() ) {
+               return j->second;
+            }
+            if( const auto g = analyze_guard( m_stack, start->first ) ) {
+               switch( start->second.type ) {
+                  case analyze_type::any: {
+                     bool a = false;
+                     for( const auto& r : start->second.subs ) {
+                        a = a || work( find( r ), accum || a );
+                     }
+                     return m_cache[ start->first ] = true;
+                  }
+                  case analyze_type::opt: {
+                     bool a = false;
+                     for( const auto& r : start->second.subs ) {
+                        a = a || work( find( r ), accum || a );
+                     }
+                     return m_cache[ start->first ] = false;
+                  }
+                  case analyze_type::seq: {
+                     bool a = false;
+                     for( const auto& r : start->second.subs ) {
+                        a = a || work( find( r ), accum || a );
+                     }
+                     return m_cache[ start->first ] = a;
+                  }
+                  case analyze_type::sor: {
+                     bool a = true;
+                     for( const auto& r : start->second.subs ) {
+                        a = a && work( find( r ), accum );
+                     }
+                     return m_cache[ start->first ] = a;
+                  }
+               }
+               assert( false );  // LCOV_EXCL_LINE
+            }
+            if( !accum ) {
+               ++m_problems;
+               if( m_verbose ) {
+                  std::cout << "problem: cycle without progress detected at rule class " << start->first << std::endl;  // LCOV_EXCL_LINE
+               }
+            }
+            return m_cache[ start->first ] = accum;
+         }
+
+         const bool m_verbose;
+
+         std::size_t m_problems;
+
+         std::map< std::string_view, analyze_entry > m_info;
+         std::set< std::string_view > m_stack;
+         std::map< std::string_view, bool > m_cache;
+         std::map< std::string_view, bool > m_results;
+      };
+
+      template< typename Name >
+      std::string_view analyze_insert( std::map< std::string_view, analyze_entry >& info )
+      {
+         using Traits = analyze_traits< Name, typename Name::rule_t >;
+
+         const auto [ i, b ] = info.try_emplace( demangle< Name >(), Traits::type_v );
+         if( b ) {
+            analyze_insert_impl( typename Traits::subs_t(), i->second.subs, info );
+         }
+         return i->first;
+      }
+
+      template< typename... Subs >
+      void analyze_insert_impl( type_list< Subs... > /*unused*/, std::vector< std::string_view >& subs, std::map< std::string_view, analyze_entry >& info )
+      {
+         ( subs.emplace_back( analyze_insert< Subs >( info ) ), ... );
+      }
+
+      template< typename Grammar >
+      class analyze_cycles
+         : public analyze_cycles_impl
+      {
+      public:
+         explicit analyze_cycles( const bool verbose )
+            : analyze_cycles_impl( verbose )
+         {
+            analyze_insert< Grammar >( m_info );
+         }
+      };
+
+   }  // namespace internal
+
+   template< typename Grammar >
+   [[nodiscard]] std::size_t analyze( const bool verbose = true )
+   {
+      return internal::analyze_cycles< Grammar >( verbose ).problems();
+   }
+
+}  // namespace TAO_PEGTL_NAMESPACE
+
+#endif
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/analyze_traits.hpp b/packages/PEGTL/include/tao/pegtl/contrib/analyze_traits.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..608f35b3f34d23862c07e9515c09030dfd91a2bf
--- /dev/null
+++ b/packages/PEGTL/include/tao/pegtl/contrib/analyze_traits.hpp
@@ -0,0 +1,275 @@
+// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#ifndef TAO_PEGTL_CONTRIB_ANALYZE_TRAITS_HPP
+#define TAO_PEGTL_CONTRIB_ANALYZE_TRAITS_HPP
+
+#include <type_traits>
+
+#include "../ascii.hpp"
+#include "../config.hpp"
+#include "../rules.hpp"
+#include "../type_list.hpp"
+
+#include "forward.hpp"
+
+namespace TAO_PEGTL_NAMESPACE
+{
+   namespace internal
+   {
+      enum class analyze_type
+      {
+         any,  // Consumption-on-success is always true; assumes bounded repetition of conjunction of sub-rules.
+         opt,  // Consumption-on-success not necessarily true; assumes bounded repetition of conjunction of sub-rules.
+         seq,  // Consumption-on-success depends on consumption of (non-zero bounded repetition of) conjunction of sub-rules.
+         sor   // Consumption-on-success depends on consumption of (non-zero bounded repetition of) disjunction of sub-rules.
+      };
+
+   }  // namespace internal
+
+   template< typename... Rules >
+   struct analyze_any_traits
+   {
+      static constexpr internal::analyze_type type_v = internal::analyze_type::any;
+      using subs_t = type_list< Rules... >;
+   };
+
+   template< typename... Rules >
+   struct analyze_opt_traits
+   {
+      static constexpr internal::analyze_type type_v = internal::analyze_type::opt;
+      using subs_t = type_list< Rules... >;
+   };
+
+   template< typename... Rules >
+   struct analyze_seq_traits
+   {
+      static constexpr internal::analyze_type type_v = internal::analyze_type::seq;
+      using subs_t = type_list< Rules... >;
+   };
+
+   template< typename... Rules >
+   struct analyze_sor_traits
+   {
+      static constexpr internal::analyze_type type_v = internal::analyze_type::sor;
+      using subs_t = type_list< Rules... >;
+   };
+
+   template< typename Name, template< typename... > class Action, typename... Rules >
+   struct analyze_traits< Name, internal::action< Action, Rules... > >
+      : analyze_traits< Name, typename seq< Rules... >::rule_t >
+   {};
+
+   template< typename Name, typename Peek >
+   struct analyze_traits< Name, internal::any< Peek > >
+      : analyze_any_traits<>
+   {};
+
+   template< typename Name, typename... Actions >
+   struct analyze_traits< Name, internal::apply< Actions... > >
+      : analyze_opt_traits<>
+   {};
+
+   template< typename Name, typename... Actions >
+   struct analyze_traits< Name, internal::apply0< Actions... > >
+      : analyze_opt_traits<>
+   {};
+
+   template< typename Name, typename... Rules >
+   struct analyze_traits< Name, internal::at< Rules... > >
+      : analyze_traits< Name, typename opt< Rules... >::rule_t >
+   {};
+
+   template< typename Name >
+   struct analyze_traits< Name, internal::bof >
+      : analyze_opt_traits<>
+   {};
+
+   template< typename Name >
+   struct analyze_traits< Name, internal::bol >
+      : analyze_opt_traits<>
+   {};
+
+   template< typename Name, unsigned Cnt >
+   struct analyze_traits< Name, internal::bytes< Cnt > >
+      : std::conditional_t< ( Cnt != 0 ), analyze_any_traits<>, analyze_opt_traits<> >
+   {};
+
+   template< typename Name, template< typename... > class Control, typename... Rules >
+   struct analyze_traits< Name, internal::control< Control, Rules... > >
+      : analyze_traits< Name, typename seq< Rules... >::rule_t >
+   {};
+
+   template< typename Name, typename... Rules >
+   struct analyze_traits< Name, internal::disable< Rules... > >
+      : analyze_traits< Name, typename seq< Rules... >::rule_t >
+   {};
+
+   template< typename Name >
+   struct analyze_traits< Name, internal::discard >
+      : analyze_opt_traits<>
+   {};
+
+   template< typename Name, typename... Rules >
+   struct analyze_traits< Name, internal::enable< Rules... > >
+      : analyze_traits< Name, typename seq< Rules... >::rule_t >
+   {};
+
+   template< typename Name >
+   struct analyze_traits< Name, internal::eof >
+      : analyze_opt_traits<>
+   {};
+
+   template< typename Name >
+   struct analyze_traits< Name, internal::eol >
+      : analyze_any_traits<>
+   {};
+
+   template< typename Name >
+   struct analyze_traits< Name, internal::eolf >
+      : analyze_opt_traits<>
+   {};
+
+   template< typename Name >
+   struct analyze_traits< Name, internal::failure >
+      : analyze_any_traits<>
+   {};
+
+   template< typename Name, typename Rule, typename... Actions >
+   struct analyze_traits< Name, internal::if_apply< Rule, Actions... > >
+      : analyze_traits< Name, typename Rule::rule_t >
+   {};
+
+   template< typename Name, typename Cond, typename... Rules >
+   struct analyze_traits< Name, internal::if_must< true, Cond, Rules... > >
+      : analyze_traits< Name, typename opt< Cond, Rules... >::rule_t >
+   {};
+
+   template< typename Name, typename Cond, typename... Rules >
+   struct analyze_traits< Name, internal::if_must< false, Cond, Rules... > >
+      : analyze_traits< Name, typename seq< Cond, Rules... >::rule_t >
+   {};
+
+   template< typename Name, typename Cond, typename Then, typename Else >
+   struct analyze_traits< Name, internal::if_then_else< Cond, Then, Else > >
+      : analyze_traits< Name, typename sor< seq< Cond, Then >, Else >::rule_t >
+   {};
+
+   template< typename Name, char... Cs >
+   struct analyze_traits< Name, internal::istring< Cs... > >
+      : std::conditional_t< ( sizeof...( Cs ) != 0 ), analyze_any_traits<>, analyze_opt_traits<> >
+   {};
+
+   template< typename Name, typename... Rules >
+   struct analyze_traits< Name, internal::must< Rules... > >
+      : analyze_traits< Name, typename seq< Rules... >::rule_t >
+   {};
+
+   template< typename Name, typename... Rules >
+   struct analyze_traits< Name, internal::not_at< Rules... > >
+      : analyze_traits< Name, typename opt< Rules... >::rule_t >
+   {};
+
+   template< typename Name, internal::result_on_found R, typename Peek, typename Peek::data_t... Cs >
+   struct analyze_traits< Name, internal::one< R, Peek, Cs... > >
+      : 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::plus< Rules... > >
+      : analyze_traits< Name, typename seq< Rules..., opt< Name > >::rule_t >
+   {};
+
+   template< typename Name, typename T >
+   struct analyze_traits< Name, internal::raise< T > >
+      : analyze_any_traits<>
+   {};
+
+   template< typename Name, internal::result_on_found R, typename Peek, typename Peek::data_t Lo, typename Peek::data_t Hi >
+   struct analyze_traits< Name, internal::range< R, Peek, Lo, Hi > >
+      : analyze_any_traits<>
+   {};
+
+   template< typename Name, typename Peek, typename Peek::data_t... Cs >
+   struct analyze_traits< Name, internal::ranges< Peek, Cs... > >
+      : analyze_any_traits<>
+   {};
+
+   template< typename Name, typename Head, typename... Rules >
+   struct analyze_traits< Name, internal::rematch< Head, Rules... > >
+      : analyze_traits< Name, typename sor< Head, sor< seq< Rules, any >... > >::rule_t >  // TODO: Correct (enough)?
+   {};
+
+   template< typename Name, unsigned Cnt, typename... Rules >
+   struct analyze_traits< Name, internal::rep< Cnt, Rules... > >
+      : analyze_traits< Name, std::conditional_t< ( Cnt != 0 ), typename seq< Rules... >::rule_t, typename opt< Rules... >::rule_t > >
+   {};
+
+   template< typename Name, unsigned Min, unsigned Max, typename... Rules >
+   struct analyze_traits< Name, internal::rep_min_max< Min, Max, Rules... > >
+      : analyze_traits< Name, std::conditional_t< ( Min != 0 ), typename seq< Rules... >::rule_t, typename opt< Rules... >::rule_t > >
+   {};
+
+   template< typename Name, unsigned Max, typename... Rules >
+   struct analyze_traits< Name, internal::rep_opt< Max, Rules... > >
+      : analyze_traits< Name, typename opt< Rules... >::rule_t >
+   {};
+
+   template< typename Name, unsigned Amount >
+   struct analyze_traits< Name, internal::require< Amount > >
+      : analyze_opt_traits<>
+   {};
+
+   template< typename Name, typename Rule, typename... Rules >
+   struct analyze_traits< Name, internal::seq< Rule, Rules... > >
+      : analyze_seq_traits< Rule, Rules... >
+   {};
+
+   template< typename Name, typename Rule, typename... Rules >
+   struct analyze_traits< Name, internal::sor< Rule, Rules... > >
+      : analyze_sor_traits< Rule, Rules... >
+   {};
+
+   template< typename Name, typename... Rules >
+   struct analyze_traits< Name, internal::star< Rules... > >
+      : analyze_traits< Name, typename opt< Rules..., Name >::rule_t >
+   {};
+
+   template< typename Name, typename State, typename... Rules >
+   struct analyze_traits< Name, internal::state< State, Rules... > >
+      : analyze_traits< Name, typename seq< Rules... >::rule_t >
+   {};
+
+   template< typename Name, char... Cs >
+   struct analyze_traits< Name, internal::string< Cs... > >
+      : std::conditional_t< ( sizeof...( Cs ) != 0 ), analyze_any_traits<>, analyze_opt_traits<> >
+   {};
+
+   template< typename Name >
+   struct analyze_traits< Name, internal::success >
+      : analyze_opt_traits<>
+   {};
+
+   template< typename Name, typename Exception, typename... Rules >
+   struct analyze_traits< Name, internal::try_catch_type< Exception, Rules... > >
+      : analyze_traits< Name, typename seq< Rules... >::rule_t >
+   {};
+
+   template< typename Name, typename Cond >
+   struct analyze_traits< Name, internal::until< Cond > >
+      : analyze_traits< Name, typename Cond::rule_t >
+   {};
+
+   template< typename Name, typename Cond, typename... Rules >
+   struct analyze_traits< Name, internal::until< Cond, Rules... > >
+      : analyze_traits< Name, typename seq< star< Rules... >, Cond >::rule_t >
+   {};
+
+}  // namespace TAO_PEGTL_NAMESPACE
+
+#endif
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/counter.hpp b/packages/PEGTL/include/tao/pegtl/contrib/counter.hpp
deleted file mode 100644
index 04e8762d036d2e823dd03f86e70ea78a45c4cfb9..0000000000000000000000000000000000000000
--- a/packages/PEGTL/include/tao/pegtl/contrib/counter.hpp
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey
-// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
-
-#ifndef TAO_PEGTL_CONTRIB_COUNTER_HPP
-#define TAO_PEGTL_CONTRIB_COUNTER_HPP
-
-#include <map>
-#include <string_view>
-
-#include "../config.hpp"
-#include "../normal.hpp"
-
-#include "../internal/demangle.hpp"
-
-namespace TAO_PEGTL_NAMESPACE
-{
-   struct counter_data
-   {
-      unsigned start = 0;
-      unsigned success = 0;
-      unsigned failure = 0;
-   };
-
-   struct counter_state
-   {
-      std::map< std::string_view, counter_data > counts;
-   };
-
-   template< typename Rule >
-   struct counter
-      : normal< Rule >
-   {
-      template< typename Input >
-      static void start( const Input& /*unused*/, counter_state& ts )
-      {
-         ++ts.counts[ internal::demangle< Rule >() ].start;
-      }
-
-      template< typename Input >
-      static void success( const Input& /*unused*/, counter_state& ts )
-      {
-         ++ts.counts[ internal::demangle< Rule >() ].success;
-      }
-
-      template< typename Input >
-      static void failure( const Input& /*unused*/, counter_state& ts )
-      {
-         ++ts.counts[ internal::demangle< Rule >() ].failure;
-      }
-   };
-
-}  // namespace TAO_PEGTL_NAMESPACE
-
-#endif
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/coverage.hpp b/packages/PEGTL/include/tao/pegtl/contrib/coverage.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..582813a8c6de1a450eeb3cb5770fab60d1bd05c1
--- /dev/null
+++ b/packages/PEGTL/include/tao/pegtl/contrib/coverage.hpp
@@ -0,0 +1,159 @@
+// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#ifndef TAO_PEGTL_CONTRIB_COVERAGE_HPP
+#define TAO_PEGTL_CONTRIB_COVERAGE_HPP
+
+#include <cassert>
+#include <cstddef>
+#include <map>
+#include <string>
+#include <string_view>
+#include <vector>
+
+#include "remove_first_state.hpp"
+#include "shuffle_states.hpp"
+
+#include "../config.hpp"
+#include "../normal.hpp"
+#include "../nothing.hpp"
+#include "../parse.hpp"
+#include "../type_list.hpp"
+#include "../visit.hpp"
+
+#include "../internal/demangle.hpp"
+
+namespace TAO_PEGTL_NAMESPACE
+{
+   struct coverage_info
+   {
+      std::size_t start = 0;
+      std::size_t success = 0;
+      std::size_t local_failure = 0;
+      std::size_t global_failure = 0;
+      std::size_t raise = 0;
+   };
+
+   struct coverage_entry
+      : coverage_info
+   {
+      std::map< std::string_view, coverage_info > branches;
+   };
+
+   struct coverage_state
+   {
+      std::string_view grammar;
+      std::string source;
+
+      std::map< std::string_view, coverage_entry > map;
+      bool result;
+
+      std::vector< std::string_view > stack;
+   };
+
+   namespace internal
+   {
+      template< typename Rule >
+      struct coverage_insert
+      {
+         static void visit( coverage_state& state )
+         {
+            visit_branches( state.map.try_emplace( internal::demangle< Rule >() ).first->second.branches, typename Rule::subs_t() );
+         }
+
+         template< typename... Ts >
+         static void visit_branches( std::map< std::string_view, coverage_info >& branches, type_list< Ts... > /*unused*/ )
+         {
+            ( branches.try_emplace( internal::demangle< Ts >() ), ... );
+         }
+      };
+
+      template< template< typename... > class Control = normal >
+      struct make_coverage_control
+      {
+         template< typename Rule >
+         struct control
+            : remove_first_state< Control< Rule > >
+         {
+            template< typename ParseInput, typename... States >
+            [[noreturn]] static void raise( const ParseInput& in, coverage_state& state, States&&... st )
+            {
+               const auto name = internal::demangle< Rule >();
+               ++state.map.at( name ).raise;
+               if( state.stack.size() > 1 ) {
+                  ++state.map.at( state.stack.at( state.stack.size() - 2 ) ).branches.at( name ).raise;
+               }
+               Control< Rule >::raise( in, st... );
+            }
+
+            template< apply_mode A,
+                      rewind_mode M,
+                      template< typename... >
+                      class Action,
+                      template< typename... >
+                      class Control2,
+                      typename ParseInput,
+                      typename... States >
+            [[nodiscard]] static bool match( ParseInput& in, States&&... st )
+            {
+               coverage_entry dummy;
+               auto& state = std::get< sizeof...( st ) - 1 >( std::tie( st... ) );
+               const auto name = internal::demangle< Rule >();
+               auto& entry = state.map.at( name );
+               auto& previous = state.stack.empty() ? dummy : state.map.at( state.stack.back() ).branches.at( name );
+               ++entry.start;
+               ++previous.start;
+               state.stack.push_back( name );
+               try {
+                  const bool result = Control< Rule >::template match< A, M, Action, Control2 >( in, st... );
+                  state.stack.pop_back();
+                  if( result ) {
+                     ++entry.success;
+                     ++previous.success;
+                  }
+                  else {
+                     ++entry.local_failure;
+                     ++previous.local_failure;
+                  }
+                  return result;
+               }
+               catch( ... ) {
+                  state.stack.pop_back();
+                  ++entry.global_failure;
+                  ++previous.global_failure;
+                  throw;
+               }
+            }
+         };
+
+         template< typename Rule >
+         using type = rotate_states_right< control< Rule > >;
+      };
+
+   }  // namespace internal
+
+   template< typename Rule,
+             template< typename... > class Action = nothing,
+             template< typename... > class Control = normal,
+             typename ParseInput,
+             typename... States >
+   coverage_state coverage( ParseInput&& in, States&&... st )
+   {
+      coverage_state state;
+
+      state.grammar = internal::demangle< Rule >();
+      state.source = in.source();
+
+      // populate state
+      visit< Rule, internal::coverage_insert >( state );
+
+      // parse
+      state.result = parse< Rule, Action, internal::make_coverage_control<>::template type >( in, st..., state );
+      assert( state.stack.empty() );
+
+      return state;
+   }
+
+}  // namespace TAO_PEGTL_NAMESPACE
+
+#endif
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/forward.hpp b/packages/PEGTL/include/tao/pegtl/contrib/forward.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..4e2a592ef95accdc4e4b82dec6ceaf0edff50578
--- /dev/null
+++ b/packages/PEGTL/include/tao/pegtl/contrib/forward.hpp
@@ -0,0 +1,16 @@
+// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#ifndef TAO_PEGTL_CONTRIB_FORWARD_HPP
+#define TAO_PEGTL_CONTRIB_FORWARD_HPP
+
+#include "../config.hpp"
+
+namespace TAO_PEGTL_NAMESPACE
+{
+   template< typename Name, typename Rule, typename = void >
+   struct analyze_traits;
+
+}  // namespace TAO_PEGTL_NAMESPACE
+
+#endif
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/http.hpp b/packages/PEGTL/include/tao/pegtl/contrib/http.hpp
index c4a60d614b73205e85d80abd444a34457ea142a2..74b0e9eb7f080ea6570217e3cfd879a5b4307576 100644
--- a/packages/PEGTL/include/tao/pegtl/contrib/http.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/http.hpp
@@ -11,6 +11,7 @@
 #include "../utf8.hpp"
 
 #include "abnf.hpp"
+#include "forward.hpp"
 #include "remove_first_state.hpp"
 #include "uri.hpp"
 
@@ -125,7 +126,7 @@ namespace TAO_PEGTL_NAMESPACE::http
    // clang-format on
    struct chunk_size
    {
-      using analyze_t = plus< abnf::HEXDIG >::analyze_t;
+      using rule_t = plus< abnf::HEXDIG >::rule_t;
 
       template< apply_mode A,
                 rewind_mode M,
@@ -133,9 +134,9 @@ namespace TAO_PEGTL_NAMESPACE::http
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( Input& in, std::size_t& size, States&&... /*unused*/ )
+      [[nodiscard]] static bool match( ParseInput& in, std::size_t& size, States&&... /*unused*/ )
       {
          size = 0;
          std::size_t i = 0;
@@ -174,7 +175,7 @@ namespace TAO_PEGTL_NAMESPACE::http
    // clang-format on
    struct chunk_data
    {
-      using analyze_t = star< abnf::OCTET >::analyze_t;
+      using rule_t = star< abnf::OCTET >::rule_t;
 
       template< apply_mode A,
                 rewind_mode M,
@@ -182,9 +183,9 @@ namespace TAO_PEGTL_NAMESPACE::http
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( Input& in, const std::size_t size, States&&... /*unused*/ )
+      [[nodiscard]] static bool match( ParseInput& in, const std::size_t size, States&&... /*unused*/ )
       {
          if( in.size( size ) >= size ) {
             in.bump( size );
@@ -196,26 +197,43 @@ namespace TAO_PEGTL_NAMESPACE::http
 
    namespace internal::chunk_helper
    {
-      template< typename Rule, template< typename... > class Control >
-      struct control
-         : remove_self_and_first_state< Rule, Control >
-      {};
+      template< typename Base >
+      struct control;
+
+      template< template< typename... > class Control, typename Rule >
+      struct control< Control< Rule > >
+         : Control< Rule >
+      {
+         template< apply_mode A,
+                   rewind_mode M,
+                   template< typename... >
+                   class Action,
+                   template< typename... >
+                   class,
+                   typename ParseInput,
+                   typename State,
+                   typename... States >
+         [[nodiscard]] static bool match( ParseInput& in, State&& /*unused*/, States&&... st )
+         {
+            return Control< Rule >::template match< A, M, Action, Control >( in, st... );
+         }
+      };
 
       template< template< typename... > class Control >
-      struct control< chunk_size, Control >
-         : remove_first_state_after_match< chunk_size, Control >
+      struct control< Control< chunk_size > >
+         : remove_first_state< Control< chunk_size > >
       {};
 
       template< template< typename... > class Control >
-      struct control< chunk_data, Control >
-         : remove_first_state_after_match< chunk_data, Control >
+      struct control< Control< chunk_data > >
+         : remove_first_state< Control< chunk_data > >
       {};
 
       template< template< typename... > class Control >
       struct bind
       {
          template< typename Rule >
-         using type = control< Rule, Control >;
+         using type = control< Control< Rule > >;
       };
 
    }  // namespace internal::chunk_helper
@@ -223,7 +241,8 @@ namespace TAO_PEGTL_NAMESPACE::http
    struct chunk
    {
       using impl = seq< chunk_size, chunk_ext, abnf::CRLF, chunk_data, abnf::CRLF >;
-      using analyze_t = impl::analyze_t;
+
+      using rule_t = impl::rule_t;
 
       template< apply_mode A,
                 rewind_mode M,
@@ -231,9 +250,9 @@ namespace TAO_PEGTL_NAMESPACE::http
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
       {
          std::size_t size{};
          return impl::template match< A, M, Action, internal::chunk_helper::bind< Control >::template type >( in, size, st... );
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/icu/internal.hpp b/packages/PEGTL/include/tao/pegtl/contrib/icu/internal.hpp
index 80c0538ac821a99ed348b38f965bb38df60fe356..9ee98a1420d5682e5523a10bc6b1c0f696da1c9c 100644
--- a/packages/PEGTL/include/tao/pegtl/contrib/icu/internal.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/icu/internal.hpp
@@ -7,9 +7,9 @@
 #include <unicode/uchar.h>
 
 #include "../../config.hpp"
+#include "../../type_list.hpp"
 
-#include "../../analysis/generic.hpp"
-#include "../../internal/skip_control.hpp"
+#include "../../internal/enable_control.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
@@ -18,17 +18,16 @@ namespace TAO_PEGTL_NAMESPACE::internal
       template< typename Peek, UProperty P, bool V = true >
       struct binary_property
       {
-         using analyze_t = analysis::generic< analysis::rule_type::any >;
+         using rule_t = binary_property;
+         using subs_t = empty_list;
 
-         template< typename Input >
-         [[nodiscard]] static bool match( Input& in ) noexcept( noexcept( in.size( Peek::max_input_size ) ) )
+         template< typename ParseInput >
+         [[nodiscard]] static bool match( ParseInput& in ) noexcept( noexcept( Peek::peek( in ) ) )
          {
-            if( const std::size_t s = in.size( Peek::max_input_size ); s >= Peek::min_input_size ) {
-               if( const auto r = Peek::peek( in, s ) ) {
-                  if( u_hasBinaryProperty( r.data, P ) == V ) {
-                     in.bump( r.size );
-                     return true;
-                  }
+            if( const auto r = Peek::peek( in ) ) {
+               if( u_hasBinaryProperty( r.data, P ) == V ) {
+                  in.bump( r.size );
+                  return true;
                }
             }
             return false;
@@ -38,17 +37,16 @@ namespace TAO_PEGTL_NAMESPACE::internal
       template< typename Peek, UProperty P, int V >
       struct property_value
       {
-         using analyze_t = analysis::generic< analysis::rule_type::any >;
+         using rule_t = property_value;
+         using subs_t = empty_list;
 
-         template< typename Input >
-         [[nodiscard]] static bool match( Input& in ) noexcept( noexcept( in.size( Peek::max_input_size ) ) )
+         template< typename ParseInput >
+         [[nodiscard]] static bool match( ParseInput& in ) noexcept( noexcept( Peek::peek( in ) ) )
          {
-            if( const std::size_t s = in.size( Peek::max_input_size ); s >= Peek::min_input_size ) {
-               if( const auto r = Peek::peek( in, s ) ) {
-                  if( u_getIntPropertyValue( r.data, P ) == V ) {
-                     in.bump( r.size );
-                     return true;
-                  }
+            if( const auto r = Peek::peek( in ) ) {
+               if( u_getIntPropertyValue( r.data, P ) == V ) {
+                  in.bump( r.size );
+                  return true;
                }
             }
             return false;
@@ -58,10 +56,10 @@ namespace TAO_PEGTL_NAMESPACE::internal
    }  // namespace icu
 
    template< typename Peek, UProperty P, bool V >
-   inline constexpr bool skip_control< icu::binary_property< Peek, P, V > > = true;
+   inline constexpr bool enable_control< icu::binary_property< Peek, P, V > > = false;
 
    template< typename Peek, UProperty P, int V >
-   inline constexpr bool skip_control< icu::property_value< Peek, P, V > > = true;
+   inline constexpr bool enable_control< icu::property_value< Peek, P, V > > = false;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/icu/utf16.hpp b/packages/PEGTL/include/tao/pegtl/contrib/icu/utf16.hpp
index bc5ee54365e9cdd1fa5d05cca7947404c42a308e..22c05ba0f1cc899682a95575313dc7fe78cd7e3a 100644
--- a/packages/PEGTL/include/tao/pegtl/contrib/icu/utf16.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/icu/utf16.hpp
@@ -7,9 +7,9 @@
 #include "internal.hpp"
 
 #include "../../config.hpp"
-#include "../../utf16.hpp"
+#include "../utf16.hpp"
 
-#include "../../internal/peek_utf16.hpp"
+#include "../internal/peek_utf16.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
 {
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/icu/utf32.hpp b/packages/PEGTL/include/tao/pegtl/contrib/icu/utf32.hpp
index 54cfe071d28b374f50521325d0868216abc82118..aa59b04c753c58c5ca0b8fdbf28335e09f705c31 100644
--- a/packages/PEGTL/include/tao/pegtl/contrib/icu/utf32.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/icu/utf32.hpp
@@ -7,9 +7,9 @@
 #include "internal.hpp"
 
 #include "../../config.hpp"
-#include "../../utf32.hpp"
+#include "../utf32.hpp"
 
-#include "../../internal/peek_utf32.hpp"
+#include "../internal/peek_utf32.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
 {
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/if_then.hpp b/packages/PEGTL/include/tao/pegtl/contrib/if_then.hpp
index 22e97247f4cd4e1bf89b32e7f0be4d73f79e27ae..734523c75376ca14bd933447c1f0ed21dafb8325 100644
--- a/packages/PEGTL/include/tao/pegtl/contrib/if_then.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/if_then.hpp
@@ -8,10 +8,11 @@
 
 #include "../config.hpp"
 
+#include "../internal/enable_control.hpp"
+#include "../internal/failure.hpp"
 #include "../internal/if_then_else.hpp"
 #include "../internal/seq.hpp"
-#include "../internal/skip_control.hpp"
-#include "../internal/trivial.hpp"
+#include "../internal/success.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
 {
@@ -32,21 +33,23 @@ namespace TAO_PEGTL_NAMESPACE
          using else_if_then = if_then< if_pair< Cond, Then >, Pairs..., if_pair< ElseCond, seq< Thens... > > >;
 
          template< typename... Thens >
-         using else_then = if_then_else< Cond, Then, if_then< Pairs..., if_pair< trivial< true >, seq< Thens... > > > >;
+         using else_then = if_then_else< Cond, Then, if_then< Pairs..., if_pair< success, seq< Thens... > > > >;
       };
 
       template<>
       struct if_then<>
-         : trivial< false >
+         : failure
       {};
 
       template< typename... Pairs >
-      inline constexpr bool skip_control< if_then< Pairs... > > = true;
+      inline constexpr bool enable_control< if_then< Pairs... > > = false;
 
    }  // namespace internal
 
    template< typename Cond, typename... Thens >
-   using if_then = internal::if_then< internal::if_pair< Cond, internal::seq< Thens... > > >;
+   struct if_then
+      : internal::if_then< internal::if_pair< Cond, internal::seq< Thens... > > >
+   {};
 
 }  // namespace TAO_PEGTL_NAMESPACE
 
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/integer.hpp b/packages/PEGTL/include/tao/pegtl/contrib/integer.hpp
index 7d93d8cab3a18f912d69eadfa4a76bdacae125d4..9bbbf9977be4e39782f869ee288758fe33b34157 100644
--- a/packages/PEGTL/include/tao/pegtl/contrib/integer.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/integer.hpp
@@ -14,44 +14,44 @@
 #include "../parse_error.hpp"
 #include "../rules.hpp"
 
-namespace TAO_PEGTL_NAMESPACE::integer
+#include "analyze_traits.hpp"
+
+namespace TAO_PEGTL_NAMESPACE
 {
-   namespace internal
+   struct unsigned_rule_old
+      : plus< digit >
    {
-      struct unsigned_rule_old
-         : plus< digit >
-      {
-         // Pre-3.0 version of this rule.
-      };
+      // Pre-3.0 version of this rule.
+   };
 
-      struct unsigned_rule_new
-         : if_then_else< one< '0' >, not_at< digit >, plus< digit > >
-      {
-         // New version that does not allow leading zeros.
-      };
+   struct unsigned_rule_new
+      : if_then_else< one< '0' >, not_at< digit >, plus< digit > >
+   {
+      // New version that does not allow leading zeros.
+   };
 
-      struct signed_rule_old
-         : seq< opt< one< '-', '+' > >, plus< digit > >
-      {
-         // Pre-3.0 version of this rule.
-      };
+   struct signed_rule_old
+      : seq< opt< one< '-', '+' > >, plus< digit > >
+   {
+      // Pre-3.0 version of this rule.
+   };
 
-      struct signed_rule_new
-         : seq< opt< one< '-', '+' > >, if_then_else< one< '0' >, not_at< digit >, plus< digit > > >
-      {
-         // New version that does not allow leading zeros.
-      };
+   struct signed_rule_new
+      : seq< opt< one< '-', '+' > >, if_then_else< one< '0' >, not_at< digit >, plus< digit > > >
+   {
+      // New version that does not allow leading zeros.
+   };
 
-      struct signed_rule_bis
-         : seq< opt< one< '-' > >, if_then_else< one< '0' >, not_at< digit >, plus< digit > > >
-      {
-      };
+   struct signed_rule_bis
+      : seq< opt< one< '-' > >, if_then_else< one< '0' >, not_at< digit >, plus< digit > > >
+   {};
 
-      struct signed_rule_ter
-         : seq< one< '-', '+' >, if_then_else< one< '0' >, not_at< digit >, plus< digit > > >
-      {
-      };
+   struct signed_rule_ter
+      : seq< one< '-', '+' >, if_then_else< one< '0' >, not_at< digit >, plus< digit > > >
+   {};
 
+   namespace internal
+   {
       [[nodiscard]] constexpr bool is_digit( const char c ) noexcept
       {
          // We don't use std::isdigit() because it might
@@ -140,8 +140,8 @@ namespace TAO_PEGTL_NAMESPACE::integer
          return convert_positive< Signed >( result, std::string_view( input.data() + offset, input.size() - offset ) );
       }
 
-      template< typename Input >
-      [[nodiscard]] bool match_unsigned( Input& in ) noexcept( noexcept( in.empty() ) )
+      template< typename ParseInput >
+      [[nodiscard]] bool match_unsigned( ParseInput& in ) noexcept( noexcept( in.empty() ) )
       {
          if( !in.empty() ) {
             const char c = in.peek_char();
@@ -159,10 +159,10 @@ namespace TAO_PEGTL_NAMESPACE::integer
          return false;
       }
 
-      template< typename Input,
+      template< typename ParseInput,
                 typename Unsigned,
                 Unsigned Maximum = ( std::numeric_limits< Unsigned >::max )() >
-      [[nodiscard]] bool match_and_convert_unsigned_with_maximum( Input& in, Unsigned& st )
+      [[nodiscard]] bool match_and_convert_unsigned_with_maximum( ParseInput& in, Unsigned& st )
       {
          // Assumes st == 0.
 
@@ -191,8 +191,8 @@ namespace TAO_PEGTL_NAMESPACE::integer
    {
       // Assumes that 'in' contains a non-empty sequence of ASCII digits.
 
-      template< typename Input, typename Unsigned >
-      static auto apply( const Input& in, Unsigned& st ) -> std::enable_if_t< std::is_unsigned_v< Unsigned >, void >
+      template< typename ActionInput, typename Unsigned >
+      static auto apply( const ActionInput& in, Unsigned& st ) -> std::enable_if_t< std::is_unsigned_v< Unsigned >, void >
       {
          // This function "only" offers basic exception safety.
          st = 0;
@@ -201,14 +201,14 @@ namespace TAO_PEGTL_NAMESPACE::integer
          }
       }
 
-      template< typename Input, typename State >
-      static auto apply( const Input& in, State& st ) -> std::enable_if_t< std::is_class_v< State >, void >
+      template< typename ActionInput, typename State >
+      static auto apply( const ActionInput& in, State& st ) -> std::enable_if_t< std::is_class_v< State >, void >
       {
          apply( in, st.converted );  // Compatibility for pre-3.0 behaviour.
       }
 
-      template< typename Input, typename Unsigned, typename... Ts >
-      static auto apply( const Input& in, std::vector< Unsigned, Ts... >& st ) -> std::enable_if_t< std::is_unsigned_v< Unsigned >, void >
+      template< typename ActionInput, typename Unsigned, typename... Ts >
+      static auto apply( const ActionInput& in, std::vector< Unsigned, Ts... >& st ) -> std::enable_if_t< std::is_unsigned_v< Unsigned >, void >
       {
          Unsigned u = 0;
          apply( in, u );
@@ -218,10 +218,11 @@ namespace TAO_PEGTL_NAMESPACE::integer
 
    struct unsigned_rule
    {
-      using analyze_t = internal::unsigned_rule_new::analyze_t;
+      using rule_t = unsigned_rule;
+      using subs_t = empty_list;
 
-      template< typename Input >
-      [[nodiscard]] static bool match( Input& in ) noexcept( noexcept( in.empty() ) )
+      template< typename ParseInput >
+      [[nodiscard]] static bool match( ParseInput& in ) noexcept( noexcept( in.empty() ) )
       {
          return internal::match_unsigned( in );  // Does not check for any overflow.
       }
@@ -229,7 +230,8 @@ namespace TAO_PEGTL_NAMESPACE::integer
 
    struct unsigned_rule_with_action
    {
-      using analyze_t = internal::unsigned_rule_new::analyze_t;
+      using rule_t = unsigned_rule_with_action;
+      using subs_t = empty_list;
 
       template< apply_mode A,
                 rewind_mode M,
@@ -237,9 +239,9 @@ namespace TAO_PEGTL_NAMESPACE::integer
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static auto match( Input& in, States&&... /*unused*/ ) noexcept( noexcept( in.empty() ) ) -> std::enable_if_t< A == apply_mode::nothing, bool >
+      [[nodiscard]] static auto match( ParseInput& in, States&&... /*unused*/ ) noexcept( noexcept( in.empty() ) ) -> std::enable_if_t< A == apply_mode::nothing, bool >
       {
          return internal::match_unsigned( in );  // Does not check for any overflow.
       }
@@ -250,9 +252,9 @@ namespace TAO_PEGTL_NAMESPACE::integer
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename Unsigned >
-      [[nodiscard]] static auto match( Input& in, Unsigned& st ) -> std::enable_if_t< ( A == apply_mode::action ) && std::is_unsigned_v< Unsigned >, bool >
+      [[nodiscard]] static auto match( ParseInput& in, Unsigned& st ) -> std::enable_if_t< ( A == apply_mode::action ) && std::is_unsigned_v< Unsigned >, bool >
       {
          // This function "only" offers basic exception safety.
          st = 0;
@@ -270,8 +272,8 @@ namespace TAO_PEGTL_NAMESPACE::integer
 
       static_assert( std::is_unsigned_v< Unsigned > );
 
-      template< typename Input, typename Unsigned2 >
-      static auto apply( const Input& in, Unsigned2& st ) -> std::enable_if_t< std::is_same_v< Unsigned, Unsigned2 >, void >
+      template< typename ActionInput, typename Unsigned2 >
+      static auto apply( const ActionInput& in, Unsigned2& st ) -> std::enable_if_t< std::is_same_v< Unsigned, Unsigned2 >, void >
       {
          // This function "only" offers basic exception safety.
          st = 0;
@@ -280,14 +282,14 @@ namespace TAO_PEGTL_NAMESPACE::integer
          }
       }
 
-      template< typename Input, typename State >
-      static auto apply( const Input& in, State& st ) -> std::enable_if_t< std::is_class_v< State >, void >
+      template< typename ActionInput, typename State >
+      static auto apply( const ActionInput& in, State& st ) -> std::enable_if_t< std::is_class_v< State >, void >
       {
          apply( in, st.converted );  // Compatibility for pre-3.0 behaviour.
       }
 
-      template< typename Input, typename Unsigned2, typename... Ts >
-      static auto apply( const Input& in, std::vector< Unsigned2, Ts... >& st ) -> std::enable_if_t< std::is_same_v< Unsigned, Unsigned2 >, void >
+      template< typename ActionInput, typename Unsigned2, typename... Ts >
+      static auto apply( const ActionInput& in, std::vector< Unsigned2, Ts... >& st ) -> std::enable_if_t< std::is_same_v< Unsigned, Unsigned2 >, void >
       {
          Unsigned u = 0;
          apply( in, u );
@@ -298,24 +300,26 @@ namespace TAO_PEGTL_NAMESPACE::integer
    template< typename Unsigned, Unsigned Maximum = ( std::numeric_limits< Unsigned >::max )() >
    struct maximum_rule
    {
-      static_assert( std::is_unsigned_v< Unsigned > );
+      using rule_t = maximum_rule;
+      using subs_t = empty_list;
 
-      using analyze_t = internal::unsigned_rule_new::analyze_t;
+      static_assert( std::is_unsigned_v< Unsigned > );
 
-      template< typename Input >
-      [[nodiscard]] static bool match( Input& in )
+      template< typename ParseInput >
+      [[nodiscard]] static bool match( ParseInput& in )
       {
          Unsigned st = 0;
-         return internal::match_and_convert_unsigned_with_maximum< Input, Unsigned, Maximum >( in, st );  // Throws on overflow.
+         return internal::match_and_convert_unsigned_with_maximum< ParseInput, Unsigned, Maximum >( in, st );  // Throws on overflow.
       }
    };
 
    template< typename Unsigned, Unsigned Maximum = ( std::numeric_limits< Unsigned >::max )() >
    struct maximum_rule_with_action
    {
-      static_assert( std::is_unsigned_v< Unsigned > );
+      using rule_t = maximum_rule_with_action;
+      using subs_t = empty_list;
 
-      using analyze_t = internal::unsigned_rule_new::analyze_t;
+      static_assert( std::is_unsigned_v< Unsigned > );
 
       template< apply_mode A,
                 rewind_mode M,
@@ -323,12 +327,12 @@ namespace TAO_PEGTL_NAMESPACE::integer
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static auto match( Input& in, States&&... /*unused*/ ) -> std::enable_if_t< A == apply_mode::nothing, bool >
+      [[nodiscard]] static auto match( ParseInput& in, States&&... /*unused*/ ) -> std::enable_if_t< A == apply_mode::nothing, bool >
       {
          Unsigned st = 0;
-         return internal::match_and_convert_unsigned_with_maximum< Input, Unsigned, Maximum >( in, st );  // Throws on overflow.
+         return internal::match_and_convert_unsigned_with_maximum< ParseInput, Unsigned, Maximum >( in, st );  // Throws on overflow.
       }
 
       template< apply_mode A,
@@ -337,13 +341,13 @@ namespace TAO_PEGTL_NAMESPACE::integer
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename Unsigned2 >
-      [[nodiscard]] static auto match( Input& in, Unsigned2& st ) -> std::enable_if_t< ( A == apply_mode::action ) && std::is_same_v< Unsigned, Unsigned2 >, bool >
+      [[nodiscard]] static auto match( ParseInput& in, Unsigned2& st ) -> std::enable_if_t< ( A == apply_mode::action ) && std::is_same_v< Unsigned, Unsigned2 >, bool >
       {
          // This function "only" offers basic exception safety.
          st = 0;
-         return internal::match_and_convert_unsigned_with_maximum< Input, Unsigned, Maximum >( in, st );  // Throws on overflow.
+         return internal::match_and_convert_unsigned_with_maximum< ParseInput, Unsigned, Maximum >( in, st );  // Throws on overflow.
       }
 
       // TODO: Overload for st.converted?
@@ -355,8 +359,8 @@ namespace TAO_PEGTL_NAMESPACE::integer
       // Assumes that 'in' contains a non-empty sequence of ASCII digits,
       // with optional leading sign; with sign, in.size() must be >= 2.
 
-      template< typename Input, typename Signed >
-      static auto apply( const Input& in, Signed& st ) -> std::enable_if_t< std::is_signed_v< Signed >, void >
+      template< typename ActionInput, typename Signed >
+      static auto apply( const ActionInput& in, Signed& st ) -> std::enable_if_t< std::is_signed_v< Signed >, void >
       {
          // This function "only" offers basic exception safety.
          st = 0;
@@ -365,14 +369,14 @@ namespace TAO_PEGTL_NAMESPACE::integer
          }
       }
 
-      template< typename Input, typename State >
-      static auto apply( const Input& in, State& st ) -> std::enable_if_t< std::is_class_v< State >, void >
+      template< typename ActionInput, typename State >
+      static auto apply( const ActionInput& in, State& st ) -> std::enable_if_t< std::is_class_v< State >, void >
       {
          apply( in, st.converted );  // Compatibility for pre-3.0 behaviour.
       }
 
-      template< typename Input, typename Signed, typename... Ts >
-      static auto apply( const Input& in, std::vector< Signed, Ts... >& st ) -> std::enable_if_t< std::is_signed_v< Signed >, void >
+      template< typename ActionInput, typename Signed, typename... Ts >
+      static auto apply( const ActionInput& in, std::vector< Signed, Ts... >& st ) -> std::enable_if_t< std::is_signed_v< Signed >, void >
       {
          Signed s = 0;
          apply( in, s );
@@ -382,12 +386,13 @@ namespace TAO_PEGTL_NAMESPACE::integer
 
    struct signed_rule
    {
-      using analyze_t = internal::signed_rule_new::analyze_t;
+      using rule_t = signed_rule;
+      using subs_t = empty_list;
 
-      template< typename Input >
-      [[nodiscard]] static bool match( Input& in ) noexcept( noexcept( in.empty() ) )
+      template< typename ParseInput >
+      [[nodiscard]] static bool match( ParseInput& in ) noexcept( noexcept( in.empty() ) )
       {
-         return TAO_PEGTL_NAMESPACE::parse< internal::signed_rule_new >( in );  // Does not check for any overflow.
+         return TAO_PEGTL_NAMESPACE::parse< signed_rule_new >( in );  // Does not check for any overflow.
       }
    };
 
@@ -396,20 +401,19 @@ namespace TAO_PEGTL_NAMESPACE::integer
       template< typename Rule >
       struct signed_action_action
          : nothing< Rule >
-      {
-      };
+      {};
 
       template<>
       struct signed_action_action< signed_rule_new >
          : signed_action
-      {
-      };
+      {};
 
    }  // namespace internal
 
    struct signed_rule_with_action
    {
-      using analyze_t = internal::signed_rule_new::analyze_t;
+      using rule_t = signed_rule_with_action;
+      using subs_t = empty_list;
 
       template< apply_mode A,
                 rewind_mode M,
@@ -417,11 +421,11 @@ namespace TAO_PEGTL_NAMESPACE::integer
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static auto match( Input& in, States&&... /*unused*/ ) noexcept( noexcept( in.empty() ) ) -> std::enable_if_t< A == apply_mode::nothing, bool >
+      [[nodiscard]] static auto match( ParseInput& in, States&&... /*unused*/ ) noexcept( noexcept( in.empty() ) ) -> std::enable_if_t< A == apply_mode::nothing, bool >
       {
-         return TAO_PEGTL_NAMESPACE::parse< internal::signed_rule_new >( in );  // Does not check for any overflow.
+         return TAO_PEGTL_NAMESPACE::parse< signed_rule_new >( in );  // Does not check for any overflow.
       }
 
       template< apply_mode A,
@@ -430,17 +434,47 @@ namespace TAO_PEGTL_NAMESPACE::integer
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename Signed >
-      [[nodiscard]] static auto match( Input& in, Signed& st ) -> std::enable_if_t< ( A == apply_mode::action ) && std::is_signed_v< Signed >, bool >
+      [[nodiscard]] static auto match( ParseInput& in, Signed& st ) -> std::enable_if_t< ( A == apply_mode::action ) && std::is_signed_v< Signed >, bool >
       {
-         return TAO_PEGTL_NAMESPACE::parse< internal::signed_rule_new, internal::signed_action_action >( in, st );  // Throws on overflow.
+         return TAO_PEGTL_NAMESPACE::parse< signed_rule_new, internal::signed_action_action >( in, st );  // Throws on overflow.
       }
 
       // TODO: Overload for st.converted?
       // TODO: Overload for std::vector< Signed >?
    };
 
-}  // namespace TAO_PEGTL_NAMESPACE::integer
+   template< typename Name >
+   struct analyze_traits< Name, unsigned_rule >
+      : analyze_any_traits<>
+   {};
+
+   template< typename Name >
+   struct analyze_traits< Name, unsigned_rule_with_action >
+      : analyze_any_traits<>
+   {};
+
+   template< typename Name, typename Integer, Integer Maximum >
+   struct analyze_traits< Name, maximum_rule< Integer, Maximum > >
+      : analyze_any_traits<>
+   {};
+
+   template< typename Name, typename Integer, Integer Maximum >
+   struct analyze_traits< Name, maximum_rule_with_action< Integer, Maximum > >
+      : analyze_any_traits<>
+   {};
+
+   template< typename Name >
+   struct analyze_traits< Name, signed_rule >
+      : analyze_any_traits<>
+   {};
+
+   template< typename Name >
+   struct analyze_traits< Name, signed_rule_with_action >
+      : analyze_any_traits<>
+   {};
+
+}  // namespace TAO_PEGTL_NAMESPACE
 
 #endif
diff --git a/packages/PEGTL/include/tao/pegtl/internal/endian.hpp b/packages/PEGTL/include/tao/pegtl/contrib/internal/endian.hpp
similarity index 91%
rename from packages/PEGTL/include/tao/pegtl/internal/endian.hpp
rename to packages/PEGTL/include/tao/pegtl/contrib/internal/endian.hpp
index 6be1b00538331b281f35042c51a6b30215db8542..9edcd67d0b49ea85fc14e7ec097ab7d5587b50e5 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/endian.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/internal/endian.hpp
@@ -1,13 +1,13 @@
 // Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
-#ifndef TAO_PEGTL_INTERNAL_ENDIAN_HPP
-#define TAO_PEGTL_INTERNAL_ENDIAN_HPP
+#ifndef TAO_PEGTL_CONTRIB_INTERNAL_ENDIAN_HPP
+#define TAO_PEGTL_CONTRIB_INTERNAL_ENDIAN_HPP
 
 #include <cstdint>
 #include <cstring>
 
-#include "../config.hpp"
+#include "../../config.hpp"
 
 #if defined( _WIN32 ) && !defined( __MINGW32__ ) && !defined( __CYGWIN__ )
 #include "endian_win.hpp"
diff --git a/packages/PEGTL/include/tao/pegtl/internal/endian_gcc.hpp b/packages/PEGTL/include/tao/pegtl/contrib/internal/endian_gcc.hpp
similarity index 98%
rename from packages/PEGTL/include/tao/pegtl/internal/endian_gcc.hpp
rename to packages/PEGTL/include/tao/pegtl/contrib/internal/endian_gcc.hpp
index 776b3cc3102cd3c71f9795407fd99ee1da11acb5..55f96d71a658be481c41c6b81ff868b323caf8af 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/endian_gcc.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/internal/endian_gcc.hpp
@@ -1,8 +1,8 @@
 // Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
-#ifndef TAO_PEGTL_INTERNAL_ENDIAN_GCC_HPP
-#define TAO_PEGTL_INTERNAL_ENDIAN_GCC_HPP
+#ifndef TAO_PEGTL_CONTRIB_INTERNAL_ENDIAN_GCC_HPP
+#define TAO_PEGTL_CONTRIB_INTERNAL_ENDIAN_GCC_HPP
 
 #include <cstdint>
 #include <cstring>
diff --git a/packages/PEGTL/include/tao/pegtl/internal/endian_win.hpp b/packages/PEGTL/include/tao/pegtl/contrib/internal/endian_win.hpp
similarity index 96%
rename from packages/PEGTL/include/tao/pegtl/internal/endian_win.hpp
rename to packages/PEGTL/include/tao/pegtl/contrib/internal/endian_win.hpp
index ae3aab5bea126c83733ef8bcafbea8cb92fb44c4..db0b835c9862925d47a9e4ba5b4bb4a7e5c23bf6 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/endian_win.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/internal/endian_win.hpp
@@ -1,8 +1,8 @@
 // Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
-#ifndef TAO_PEGTL_INTERNAL_ENDIAN_WIN_HPP
-#define TAO_PEGTL_INTERNAL_ENDIAN_WIN_HPP
+#ifndef TAO_PEGTL_CONTRIB_INTERNAL_ENDIAN_WIN_HPP
+#define TAO_PEGTL_CONTRIB_INTERNAL_ENDIAN_WIN_HPP
 
 #include <cstdint>
 #include <cstdlib>
diff --git a/packages/PEGTL/include/tao/pegtl/internal/peek_mask_uint.hpp b/packages/PEGTL/include/tao/pegtl/contrib/internal/peek_mask_uint.hpp
similarity index 74%
rename from packages/PEGTL/include/tao/pegtl/internal/peek_mask_uint.hpp
rename to packages/PEGTL/include/tao/pegtl/contrib/internal/peek_mask_uint.hpp
index ca0b93d5f2f00ac772c99185c974ff21c60fe630..e5930c104a482981dc74d628676283fbc8be9e44 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/peek_mask_uint.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/internal/peek_mask_uint.hpp
@@ -1,15 +1,15 @@
 // Copyright (c) 2018-2020 Dr. Colin Hirsch and Daniel Frey
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
-#ifndef TAO_PEGTL_INTERNAL_PEEK_MASK_UINT_HPP
-#define TAO_PEGTL_INTERNAL_PEEK_MASK_UINT_HPP
+#ifndef TAO_PEGTL_CONTRIB_INTERNAL_PEEK_MASK_UINT_HPP
+#define TAO_PEGTL_CONTRIB_INTERNAL_PEEK_MASK_UINT_HPP
 
 #include <cstddef>
 #include <cstdint>
 
-#include "../config.hpp"
+#include "../../config.hpp"
+#include "../../internal/input_pair.hpp"
 
-#include "input_pair.hpp"
 #include "read_uint.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
@@ -20,12 +20,12 @@ namespace TAO_PEGTL_NAMESPACE::internal
       using data_t = typename R::type;
       using pair_t = input_pair< data_t >;
 
-      static constexpr std::size_t min_input_size = sizeof( data_t );
-      static constexpr std::size_t max_input_size = sizeof( data_t );
-
-      template< typename Input >
-      [[nodiscard]] static pair_t peek( const Input& in, const std::size_t /*unused*/ ) noexcept
+      template< typename ParseInput >
+      [[nodiscard]] static pair_t peek( ParseInput& in ) noexcept( noexcept( in.size( sizeof( data_t ) ) ) )
       {
+         if( in.size( sizeof( data_t ) ) < sizeof( data_t ) ) {
+            return { 0, 0 };
+         }
          const data_t data = R::read( in.current() ) & M;
          return { data, sizeof( data_t ) };
       }
diff --git a/packages/PEGTL/include/tao/pegtl/internal/peek_mask_uint8.hpp b/packages/PEGTL/include/tao/pegtl/contrib/internal/peek_mask_uint8.hpp
similarity index 56%
rename from packages/PEGTL/include/tao/pegtl/internal/peek_mask_uint8.hpp
rename to packages/PEGTL/include/tao/pegtl/contrib/internal/peek_mask_uint8.hpp
index 3c6550dbb1622c342209e21bd594f426db0515be..1d214fa100d3acb8e24a88446d266657ce658bb4 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/peek_mask_uint8.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/internal/peek_mask_uint8.hpp
@@ -1,15 +1,14 @@
 // Copyright (c) 2018-2020 Dr. Colin Hirsch and Daniel Frey
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
-#ifndef TAO_PEGTL_INTERNAL_PEEK_MASK_UINT8_HPP
-#define TAO_PEGTL_INTERNAL_PEEK_MASK_UINT8_HPP
+#ifndef TAO_PEGTL_CONTRIB_INTERNAL_PEEK_MASK_UINT8_HPP
+#define TAO_PEGTL_CONTRIB_INTERNAL_PEEK_MASK_UINT8_HPP
 
 #include <cstddef>
 #include <cstdint>
 
-#include "../config.hpp"
-
-#include "input_pair.hpp"
+#include "../../config.hpp"
+#include "../../internal/input_pair.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
@@ -19,12 +18,12 @@ namespace TAO_PEGTL_NAMESPACE::internal
       using data_t = std::uint8_t;
       using pair_t = input_pair< std::uint8_t >;
 
-      static constexpr std::size_t min_input_size = 1;
-      static constexpr std::size_t max_input_size = 1;
-
-      template< typename Input >
-      [[nodiscard]] static pair_t peek( const Input& in, const std::size_t /*unused*/ = 1 ) noexcept
+      template< typename ParseInput >
+      [[nodiscard]] static pair_t peek( ParseInput& in ) noexcept( noexcept( in.empty() ) )
       {
+         if( in.empty() ) {
+            return { 0, 0 };
+         }
          return { std::uint8_t( in.peek_uint8() & M ), 1 };
       }
    };
diff --git a/packages/PEGTL/include/tao/pegtl/internal/peek_uint.hpp b/packages/PEGTL/include/tao/pegtl/contrib/internal/peek_uint.hpp
similarity index 68%
rename from packages/PEGTL/include/tao/pegtl/internal/peek_uint.hpp
rename to packages/PEGTL/include/tao/pegtl/contrib/internal/peek_uint.hpp
index 608318effa1f93a238c889826494f14dbe234b7f..cdd0cf43706829f7269ce7b4bbc76b1037df8f13 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/peek_uint.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/internal/peek_uint.hpp
@@ -1,15 +1,15 @@
 // Copyright (c) 2018-2020 Dr. Colin Hirsch and Daniel Frey
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
-#ifndef TAO_PEGTL_INTERNAL_PEEK_UINT_HPP
-#define TAO_PEGTL_INTERNAL_PEEK_UINT_HPP
+#ifndef TAO_PEGTL_CONTRIB_INTERNAL_PEEK_UINT_HPP
+#define TAO_PEGTL_CONTRIB_INTERNAL_PEEK_UINT_HPP
 
 #include <cstddef>
 #include <cstdint>
 
-#include "../config.hpp"
+#include "../../config.hpp"
+#include "../../internal/input_pair.hpp"
 
-#include "input_pair.hpp"
 #include "read_uint.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
@@ -20,12 +20,12 @@ namespace TAO_PEGTL_NAMESPACE::internal
       using data_t = typename R::type;
       using pair_t = input_pair< data_t >;
 
-      static constexpr std::size_t min_input_size = sizeof( data_t );
-      static constexpr std::size_t max_input_size = sizeof( data_t );
-
-      template< typename Input >
-      [[nodiscard]] static pair_t peek( const Input& in, const std::size_t /*unused*/ ) noexcept
+      template< typename ParseInput >
+      [[nodiscard]] static pair_t peek( ParseInput& in ) noexcept( noexcept( in.size( sizeof( data_t ) ) ) )
       {
+         if( in.size( sizeof( data_t ) ) < sizeof( data_t ) ) {
+            return { 0, 0 };
+         }
          const data_t data = R::read( in.current() );
          return { data, sizeof( data_t ) };
       }
diff --git a/packages/PEGTL/include/tao/pegtl/internal/peek_uint8.hpp b/packages/PEGTL/include/tao/pegtl/contrib/internal/peek_uint8.hpp
similarity index 54%
rename from packages/PEGTL/include/tao/pegtl/internal/peek_uint8.hpp
rename to packages/PEGTL/include/tao/pegtl/contrib/internal/peek_uint8.hpp
index 8361e1c8d5ac97501642db291c81f9451d61ea85..43010dda933ae454907b0f844366b713e14b962f 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/peek_uint8.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/internal/peek_uint8.hpp
@@ -1,15 +1,14 @@
 // Copyright (c) 2018-2020 Dr. Colin Hirsch and Daniel Frey
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
-#ifndef TAO_PEGTL_INTERNAL_PEEK_UINT8_HPP
-#define TAO_PEGTL_INTERNAL_PEEK_UINT8_HPP
+#ifndef TAO_PEGTL_CONTRIB_INTERNAL_PEEK_UINT8_HPP
+#define TAO_PEGTL_CONTRIB_INTERNAL_PEEK_UINT8_HPP
 
 #include <cstddef>
 #include <cstdint>
 
-#include "../config.hpp"
-
-#include "input_pair.hpp"
+#include "../../config.hpp"
+#include "../../internal/input_pair.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
@@ -18,12 +17,12 @@ namespace TAO_PEGTL_NAMESPACE::internal
       using data_t = std::uint8_t;
       using pair_t = input_pair< std::uint8_t >;
 
-      static constexpr std::size_t min_input_size = 1;
-      static constexpr std::size_t max_input_size = 1;
-
-      template< typename Input >
-      [[nodiscard]] static pair_t peek( const Input& in, const std::size_t /*unused*/ = 1 ) noexcept
+      template< typename ParseInput >
+      [[nodiscard]] static pair_t peek( ParseInput& in ) noexcept( noexcept( in.empty() ) )
       {
+         if( in.empty() ) {
+            return { 0, 0 };
+         }
          return { in.peek_uint8(), 1 };
       }
    };
diff --git a/packages/PEGTL/include/tao/pegtl/internal/peek_utf16.hpp b/packages/PEGTL/include/tao/pegtl/contrib/internal/peek_utf16.hpp
similarity index 72%
rename from packages/PEGTL/include/tao/pegtl/internal/peek_utf16.hpp
rename to packages/PEGTL/include/tao/pegtl/contrib/internal/peek_utf16.hpp
index 495b6219aa3adbce830f34e3ea4057aabd669f85..e52a87e256cb72365e76bb64a2eb4b4e5f320cea 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/peek_utf16.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/internal/peek_utf16.hpp
@@ -1,14 +1,14 @@
 // Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
-#ifndef TAO_PEGTL_INTERNAL_PEEK_UTF16_HPP
-#define TAO_PEGTL_INTERNAL_PEEK_UTF16_HPP
+#ifndef TAO_PEGTL_CONTRIB_INTERNAL_PEEK_UTF16_HPP
+#define TAO_PEGTL_CONTRIB_INTERNAL_PEEK_UTF16_HPP
 
 #include <type_traits>
 
-#include "../config.hpp"
+#include "../../config.hpp"
+#include "../../internal/input_pair.hpp"
 
-#include "input_pair.hpp"
 #include "read_uint.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
@@ -24,17 +24,17 @@ namespace TAO_PEGTL_NAMESPACE::internal
       static_assert( sizeof( short_t ) == 2 );
       static_assert( sizeof( char16_t ) == 2 );
 
-      static constexpr std::size_t min_input_size = 2;
-      static constexpr std::size_t max_input_size = 4;
-
-      template< typename Input >
-      [[nodiscard]] static pair_t peek( const Input& in, const std::size_t s ) noexcept
+      template< typename ParseInput >
+      [[nodiscard]] static pair_t peek( ParseInput& in ) noexcept( noexcept( in.size( 4 ) ) )
       {
+         if( in.size( 2 ) < 2 ) {
+            return { 0, 0 };
+         }
          const char32_t t = R::read( in.current() );
          if( ( t < 0xd800 ) || ( t > 0xdfff ) ) {
             return { t, 2 };
          }
-         if( ( t >= 0xdc00 ) || ( s < 4 ) ) {
+         if( ( t >= 0xdc00 ) || ( in.size( 4 ) < 4 ) ) {
             return { 0, 0 };
          }
          const char32_t u = R::read( in.current() + 2 );
diff --git a/packages/PEGTL/include/tao/pegtl/internal/peek_utf32.hpp b/packages/PEGTL/include/tao/pegtl/contrib/internal/peek_utf32.hpp
similarity index 67%
rename from packages/PEGTL/include/tao/pegtl/internal/peek_utf32.hpp
rename to packages/PEGTL/include/tao/pegtl/contrib/internal/peek_utf32.hpp
index 4e5f60c7face47eecacb916e05cf22a694c6c44d..19958a0fa7fdb90871417e04681309101411e25f 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/peek_utf32.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/internal/peek_utf32.hpp
@@ -1,14 +1,14 @@
 // Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
-#ifndef TAO_PEGTL_INTERNAL_PEEK_UTF32_HPP
-#define TAO_PEGTL_INTERNAL_PEEK_UTF32_HPP
+#ifndef TAO_PEGTL_CONTRIB_INTERNAL_PEEK_UTF32_HPP
+#define TAO_PEGTL_CONTRIB_INTERNAL_PEEK_UTF32_HPP
 
 #include <cstddef>
 
-#include "../config.hpp"
+#include "../../config.hpp"
+#include "../../internal/input_pair.hpp"
 
-#include "input_pair.hpp"
 #include "read_uint.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
@@ -21,12 +21,12 @@ namespace TAO_PEGTL_NAMESPACE::internal
 
       static_assert( sizeof( char32_t ) == 4 );
 
-      static constexpr std::size_t min_input_size = 4;
-      static constexpr std::size_t max_input_size = 4;
-
-      template< typename Input >
-      [[nodiscard]] static pair_t peek( const Input& in, const std::size_t /*unused*/ ) noexcept
+      template< typename ParseInput >
+      [[nodiscard]] static pair_t peek( ParseInput& in ) noexcept( noexcept( in.size( 4 ) ) )
       {
+         if( in.size( 4 ) < 4 ) {
+            return { 0, 0 };
+         }
          const char32_t t = R::read( in.current() );
          if( ( t <= 0x10ffff ) && !( t >= 0xd800 && t <= 0xdfff ) ) {
             return { t, 4 };
diff --git a/packages/PEGTL/include/tao/pegtl/internal/read_uint.hpp b/packages/PEGTL/include/tao/pegtl/contrib/internal/read_uint.hpp
similarity index 92%
rename from packages/PEGTL/include/tao/pegtl/internal/read_uint.hpp
rename to packages/PEGTL/include/tao/pegtl/contrib/internal/read_uint.hpp
index a851d6a0c4435b1ae0f03914534d8d0150c04b93..bf102357642d100387af5d83075abcb4fa10e338 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/read_uint.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/internal/read_uint.hpp
@@ -1,12 +1,12 @@
 // Copyright (c) 2018-2020 Dr. Colin Hirsch and Daniel Frey
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
-#ifndef TAO_PEGTL_INTERNAL_READ_UINT_HPP
-#define TAO_PEGTL_INTERNAL_READ_UINT_HPP
+#ifndef TAO_PEGTL_CONTRIB_INTERNAL_READ_UINT_HPP
+#define TAO_PEGTL_CONTRIB_INTERNAL_READ_UINT_HPP
 
 #include <cstdint>
 
-#include "../config.hpp"
+#include "../../config.hpp"
 
 #include "endian.hpp"
 
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/parse_tree.hpp b/packages/PEGTL/include/tao/pegtl/contrib/parse_tree.hpp
index 67bde63ed73bd3c97bcd1f0f000f3e4cd91c52fd..964fdf6f0ec8ef74e98c58cc29d87d69c44eb4ee 100644
--- a/packages/PEGTL/include/tao/pegtl/contrib/parse_tree.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/parse_tree.hpp
@@ -14,17 +14,20 @@
 #include <utility>
 #include <vector>
 
+#include "remove_first_state.hpp"
+#include "shuffle_states.hpp"
+
+#include "../apply_mode.hpp"
 #include "../config.hpp"
 #include "../memory_input.hpp"
 #include "../normal.hpp"
 #include "../nothing.hpp"
 #include "../parse.hpp"
+#include "../rewind_mode.hpp"
 
-#include "../analysis/counted.hpp"
-#include "../analysis/generic.hpp"
 #include "../internal/demangle.hpp"
+#include "../internal/enable_control.hpp"
 #include "../internal/iterator.hpp"
-#include "../internal/skip_control.hpp"
 #include "../internal/try_catch_type.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::parse_tree
@@ -114,8 +117,8 @@ namespace TAO_PEGTL_NAMESPACE::parse_tree
       }
 
       // all non-root nodes are initialized by calling this method
-      template< typename Rule, typename Input, typename... States >
-      void start( const Input& in, States&&... /*unused*/ )
+      template< typename Rule, typename ParseInput, typename... States >
+      void start( const ParseInput& in, States&&... /*unused*/ )
       {
          set_type< Rule >();
          source = in.source();
@@ -123,15 +126,15 @@ namespace TAO_PEGTL_NAMESPACE::parse_tree
       }
 
       // if parsing of the rule succeeded, this method is called
-      template< typename Rule, typename Input, typename... States >
-      void success( const Input& in, States&&... /*unused*/ ) noexcept
+      template< typename Rule, typename ParseInput, typename... States >
+      void success( const ParseInput& in, States&&... /*unused*/ ) noexcept
       {
          m_end = TAO_PEGTL_NAMESPACE::internal::iterator( in.iterator() );
       }
 
       // if parsing of the rule failed, this method is called
-      template< typename Rule, typename Input, typename... States >
-      void failure( const Input& /*unused*/, States&&... /*unused*/ ) noexcept
+      template< typename Rule, typename ParseInput, typename... States >
+      void failure( const ParseInput& /*unused*/, States&&... /*unused*/ ) noexcept
       {}
 
       // if parsing succeeded and the (optional) transform call
@@ -153,14 +156,10 @@ namespace TAO_PEGTL_NAMESPACE::parse_tree
    namespace internal
    {
       template< typename >
-      struct is_try_catch_type
-         : std::false_type
-      {};
+      inline constexpr bool is_try_catch_type = false;
 
       template< typename Exception, typename... Rules >
-      struct is_try_catch_type< TAO_PEGTL_NAMESPACE::internal::try_catch_type< Exception, Rules... > >
-         : std::true_type
-      {};
+      inline constexpr bool is_try_catch_type< TAO_PEGTL_NAMESPACE::internal::try_catch_type< Exception, Rules... > > = true;
 
       template< typename Node >
       struct state
@@ -194,150 +193,34 @@ namespace TAO_PEGTL_NAMESPACE::parse_tree
       void transform( Parameters&&... /*unused*/ ) noexcept
       {}
 
-      template< typename Selector, typename Input, typename Node, typename... States >
-      auto transform( const Input& in, std::unique_ptr< Node >& n, States&&... st ) noexcept( noexcept( Selector::transform( in, n, st... ) ) )
+      template< typename Selector, typename ParseInput, typename Node, typename... States >
+      auto transform( const ParseInput& in, std::unique_ptr< Node >& n, States&&... st ) noexcept( noexcept( Selector::transform( in, n, st... ) ) )
          -> decltype( Selector::transform( in, n, st... ), void() )
       {
          Selector::transform( in, n, st... );
       }
 
-      template< typename Selector, typename Input, typename Node, typename... States >
-      auto transform( const Input& /*unused*/, std::unique_ptr< Node >& n, States&&... st ) noexcept( noexcept( Selector::transform( n, st... ) ) )
+      template< typename Selector, typename ParseInput, typename Node, typename... States >
+      auto transform( const ParseInput& /*unused*/, std::unique_ptr< Node >& n, States&&... st ) noexcept( noexcept( Selector::transform( n, st... ) ) )
          -> decltype( Selector::transform( n, st... ), void() )
       {
          Selector::transform( n, st... );
       }
 
-      template< unsigned Level, typename Analyse, template< typename... > class Selector >
-      struct is_leaf
-         : std::false_type
-      {};
+      template< typename Rule, template< typename... > class Selector >
+      inline constexpr bool is_selected_node = ( TAO_PEGTL_NAMESPACE::internal::enable_control< Rule > && Selector< Rule >::value );
 
-      template< analysis::rule_type Type, template< typename... > class Selector >
-      struct is_leaf< 0, analysis::generic< Type >, Selector >
-         : std::true_type
-      {};
+      template< unsigned Level, typename Subs, template< typename... > class Selector >
+      inline constexpr bool is_leaf{};
 
-      template< analysis::rule_type Type, std::size_t Count, template< typename... > class Selector >
-      struct is_leaf< 0, analysis::counted< Type, Count >, Selector >
-         : std::true_type
-      {};
-
-      template< analysis::rule_type Type, typename... Rules, template< typename... > class Selector >
-      struct is_leaf< 0, analysis::generic< Type, Rules... >, Selector >
-         : std::false_type
-      {};
-
-      template< analysis::rule_type Type, std::size_t Count, typename... Rules, template< typename... > class Selector >
-      struct is_leaf< 0, analysis::counted< Type, Count, Rules... >, Selector >
-         : std::false_type
-      {};
+      template< typename... Rules, template< typename... > class Selector >
+      inline constexpr bool is_leaf< 0, type_list< Rules... >, Selector > = ( sizeof...( Rules ) == 0 );
 
       template< unsigned Level, typename Rule, template< typename... > class Selector >
-      inline constexpr bool is_unselected_leaf = ( TAO_PEGTL_NAMESPACE::internal::skip_control< Rule > || !Selector< Rule >::value ) && is_leaf< Level, typename Rule::analyze_t, Selector >::value;
-
-      template< unsigned Level, analysis::rule_type Type, typename... Rules, template< typename... > class Selector >
-      struct is_leaf< Level, analysis::generic< Type, Rules... >, Selector >
-         : std::bool_constant< ( is_unselected_leaf< Level - 1, Rules, Selector > && ... ) >
-      {};
-
-      template< unsigned Level, analysis::rule_type Type, std::size_t Count, typename... Rules, template< typename... > class Selector >
-      struct is_leaf< Level, analysis::counted< Type, Count, Rules... >, Selector >
-         : std::bool_constant< ( is_unselected_leaf< Level - 1, Rules, Selector > && ... ) >
-      {};
-
-      template< typename T >
-      struct control
-      {
-         template< typename Input, typename Tuple, std::size_t... Is >
-         static void start_impl( const Input& in, const Tuple& t, std::index_sequence< Is... > /*unused*/ ) noexcept( noexcept( T::start( in, std::get< sizeof...( Is ) >( t ), std::get< Is >( t )... ) ) )
-         {
-            T::start( in, std::get< sizeof...( Is ) >( t ), std::get< Is >( t )... );
-         }
-
-         template< typename Input, typename... States >
-         static void start( const Input& in, States&&... st ) noexcept( noexcept( start_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - 1 >() ) ) )
-         {
-            start_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - 1 >() );
-         }
+      inline constexpr bool is_unselected_branch = ( !is_selected_node< Rule, Selector > && is_leaf< Level, typename Rule::subs_t, Selector > );
 
-         template< typename Input, typename Tuple, std::size_t... Is >
-         static void success_impl( const Input& in, const Tuple& t, std::index_sequence< Is... > /*unused*/ ) noexcept( noexcept( T::success( in, std::get< sizeof...( Is ) >( t ), std::get< Is >( t )... ) ) )
-         {
-            T::success( in, std::get< sizeof...( Is ) >( t ), std::get< Is >( t )... );
-         }
-
-         template< typename Input, typename... States >
-         static void success( const Input& in, States&&... st ) noexcept( noexcept( success_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - 1 >() ) ) )
-         {
-            success_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - 1 >() );
-         }
-
-         template< typename Input, typename Tuple, std::size_t... Is >
-         static void failure_impl( const Input& in, const Tuple& t, std::index_sequence< Is... > /*unused*/ ) noexcept( noexcept( T::failure( in, std::get< sizeof...( Is ) >( t ), std::get< Is >( t )... ) ) )
-         {
-            T::failure( in, std::get< sizeof...( Is ) >( t ), std::get< Is >( t )... );
-         }
-
-         template< typename Input, typename... States >
-         static void failure( const Input& in, States&&... st ) noexcept( noexcept( failure_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - 1 >() ) ) )
-         {
-            failure_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - 1 >() );
-         }
-
-         template< typename Input, typename Tuple, std::size_t... Is >
-         static void raise_impl( const Input& in, const Tuple& t, std::index_sequence< Is... > /*unused*/ ) noexcept( noexcept( T::raise( in, std::get< Is >( t )... ) ) )
-         {
-            T::raise( in, std::get< Is >( t )... );
-         }
-
-         template< typename Input, typename... States >
-         static void raise( const Input& in, States&&... st ) noexcept( noexcept( raise_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - 1 >() ) ) )
-         {
-            raise_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - 1 >() );
-         }
-
-         template< template< typename... > class Action, typename Iterator, typename Input, typename Tuple, std::size_t... Is >
-         static auto apply_impl( const Iterator& begin, const Input& in, const Tuple& t, std::index_sequence< Is... > /*unused*/ ) noexcept( noexcept( T::template apply< Action >( begin, in, std::get< Is >( t )... ) ) )
-            -> decltype( T::template apply< Action >( begin, in, std::get< Is >( t )... ) )
-         {
-            return T::template apply< Action >( begin, in, std::get< Is >( t )... );
-         }
-
-         template< template< typename... > class Action, typename Iterator, typename Input, typename... States >
-         static auto apply( const Iterator& begin, const Input& in, States&&... st ) noexcept( noexcept( apply_impl< Action >( begin, in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - 1 >() ) ) )
-            -> decltype( apply_impl< Action >( begin, in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - 1 >() ) )
-         {
-            return apply_impl< Action >( begin, in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - 1 >() );
-         }
-
-         template< template< typename... > class Action, typename Input, typename Tuple, std::size_t... Is >
-         static auto apply0_impl( const Input& in, const Tuple& t, std::index_sequence< Is... > /*unused*/ ) noexcept( noexcept( T::template apply0< Action >( in, std::get< Is >( t )... ) ) )
-            -> decltype( T::template apply0< Action >( in, std::get< Is >( t )... ) )
-         {
-            return T::template apply0< Action >( in, std::get< Is >( t )... );
-         }
-
-         template< template< typename... > class Action, typename Input, typename... States >
-         static auto apply0( const Input& in, States&&... st ) noexcept( noexcept( apply0_impl< Action >( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - 1 >() ) ) )
-            -> decltype( apply0_impl< Action >( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - 1 >() ) )
-         {
-            return apply0_impl< Action >( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - 1 >() );
-         }
-
-         template< apply_mode A,
-                   rewind_mode M,
-                   template< typename... >
-                   class Action,
-                   template< typename... >
-                   class Control,
-                   typename Input,
-                   typename... States >
-         [[nodiscard]] static bool match( Input& in, States&&... st )
-         {
-            return T::template match< A, M, Action, Control >( in, st... );
-         }
-      };
+      template< unsigned Level, typename... Rules, template< typename... > class Selector >
+      inline constexpr bool is_leaf< Level, type_list< Rules... >, Selector > = ( is_unselected_branch< Level - 1, Rules, Selector > && ... );
 
       template< typename Node, template< typename... > class Selector, template< typename... > class Control >
       struct make_control
@@ -346,68 +229,32 @@ namespace TAO_PEGTL_NAMESPACE::parse_tree
          struct state_handler;
 
          template< typename Rule >
-         using type = control< state_handler< Rule, !TAO_PEGTL_NAMESPACE::internal::skip_control< Rule > && Selector< Rule >::value, is_leaf< 8, typename Rule::analyze_t, Selector >::value > >;
+         using type = rotate_states_right< state_handler< Rule, is_selected_node< Rule, Selector >, is_leaf< 8, typename Rule::subs_t, Selector > > >;
       };
 
       template< typename Node, template< typename... > class Selector, template< typename... > class Control >
       template< typename Rule >
       struct make_control< Node, Selector, Control >::state_handler< Rule, false, true >
-         : Control< Rule >
-      {
-         template< typename Input, typename... States >
-         static void start( const Input& in, state< Node >& /*unused*/, States&&... st ) noexcept( noexcept( Control< Rule >::start( in, st... ) ) )
-         {
-            Control< Rule >::start( in, st... );
-         }
-
-         template< typename Input, typename... States >
-         static void success( const Input& in, state< Node >& /*unused*/, States&&... st ) noexcept( noexcept( Control< Rule >::success( in, st... ) ) )
-         {
-            Control< Rule >::success( in, st... );
-         }
-
-         template< typename Input, typename... States >
-         static void failure( const Input& in, state< Node >& /*unused*/, States&&... st ) noexcept( noexcept( Control< Rule >::failure( in, st... ) ) )
-         {
-            Control< Rule >::failure( in, st... );
-         }
-      };
+         : remove_first_state< Control< Rule > >
+      {};
 
       template< typename Node, template< typename... > class Selector, template< typename... > class Control >
       template< typename Rule >
       struct make_control< Node, Selector, Control >::state_handler< Rule, false, false >
-         : Control< Rule >
+         : remove_first_state< Control< Rule > >
       {
-         template< typename Input, typename... States >
-         static void start( const Input& in, state< Node >& /*unused*/, States&&... st ) noexcept( noexcept( Control< Rule >::start( in, st... ) ) )
-         {
-            Control< Rule >::start( in, st... );
-         }
-
-         template< typename Input, typename... States >
-         static void success( const Input& in, state< Node >& /*unused*/, States&&... st ) noexcept( noexcept( Control< Rule >::success( in, st... ) ) )
-         {
-            Control< Rule >::success( in, st... );
-         }
-
-         template< typename Input, typename... States >
-         static void failure( const Input& in, state< Node >& /*unused*/, States&&... st ) noexcept( noexcept( Control< Rule >::failure( in, st... ) ) )
-         {
-            Control< Rule >::failure( in, st... );
-         }
-
          template< apply_mode A,
                    rewind_mode M,
                    template< typename... >
                    class Action,
                    template< typename... >
                    class Control2,
-                   typename Input,
+                   typename ParseInput,
                    typename... States >
-         [[nodiscard]] static bool match( Input& in, States&&... st )
+         [[nodiscard]] static bool match( ParseInput& in, States&&... st )
          {
             auto& state = std::get< sizeof...( st ) - 1 >( std::tie( st... ) );
-            if constexpr( is_try_catch_type< Rule >::value ) {
+            if constexpr( is_try_catch_type< Rule > ) {
                internal::state< Node > tmp;
                tmp.emplace_back();
                tmp.stack.swap( state.stack );
@@ -441,18 +288,18 @@ namespace TAO_PEGTL_NAMESPACE::parse_tree
       template< typename Node, template< typename... > class Selector, template< typename... > class Control >
       template< typename Rule, bool B >
       struct make_control< Node, Selector, Control >::state_handler< Rule, true, B >
-         : Control< Rule >
+         : remove_first_state< Control< Rule > >
       {
-         template< typename Input, typename... States >
-         static void start( const Input& in, state< Node >& state, States&&... st )
+         template< typename ParseInput, typename... States >
+         static void start( const ParseInput& in, state< Node >& state, States&&... st )
          {
             Control< Rule >::start( in, st... );
             state.emplace_back();
             state.back()->template start< Rule >( in, st... );
          }
 
-         template< typename Input, typename... States >
-         static void success( const Input& in, state< Node >& state, States&&... st )
+         template< typename ParseInput, typename... States >
+         static void success( const ParseInput& in, state< Node >& state, States&&... st )
          {
             Control< Rule >::success( in, st... );
             auto n = std::move( state.back() );
@@ -464,8 +311,8 @@ namespace TAO_PEGTL_NAMESPACE::parse_tree
             }
          }
 
-         template< typename Input, typename... States >
-         static void failure( const Input& in, state< Node >& state, States&&... st ) noexcept( noexcept( Control< Rule >::failure( in, st... ) ) && noexcept( std::declval< Node& >().template failure< Rule >( in, st... ) ) )
+         template< typename ParseInput, typename... States >
+         static void failure( const ParseInput& in, state< Node >& state, States&&... st ) noexcept( noexcept( Control< Rule >::failure( in, st... ) ) && noexcept( std::declval< Node& >().template failure< Rule >( in, st... ) ) )
          {
             Control< Rule >::failure( in, st... );
             state.back()->template failure< Rule >( in, st... );
@@ -569,9 +416,9 @@ namespace TAO_PEGTL_NAMESPACE::parse_tree
              template< typename... > class Selector = internal::store_all,
              template< typename... > class Action = nothing,
              template< typename... > class Control = normal,
-             typename Input,
+             typename ParseInput,
              typename... States >
-   [[nodiscard]] std::unique_ptr< Node > parse( Input&& in, States&&... st )
+   [[nodiscard]] std::unique_ptr< Node > parse( ParseInput&& in, States&&... st )
    {
       internal::state< Node > state;
       if( !TAO_PEGTL_NAMESPACE::parse< Rule, Action, internal::make_control< Node, Selector, Control >::template type >( in, st..., state ) ) {
@@ -585,9 +432,9 @@ namespace TAO_PEGTL_NAMESPACE::parse_tree
              template< typename... > class Selector = internal::store_all,
              template< typename... > class Action = nothing,
              template< typename... > class Control = normal,
-             typename Input,
+             typename ParseInput,
              typename... States >
-   [[nodiscard]] std::unique_ptr< node > parse( Input&& in, States&&... st )
+   [[nodiscard]] std::unique_ptr< node > parse( ParseInput&& in, States&&... st )
    {
       return parse< Rule, node, Selector, Action, Control >( in, st... );
    }
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/parse_tree_to_dot.hpp b/packages/PEGTL/include/tao/pegtl/contrib/parse_tree_to_dot.hpp
index 46abc9e0ef356b54200a09a948d680a2b063f419..a16b171d5eedbee9d38f918ee3c9d8c2209c91ab 100644
--- a/packages/PEGTL/include/tao/pegtl/contrib/parse_tree_to_dot.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/parse_tree_to_dot.hpp
@@ -26,40 +26,40 @@ namespace TAO_PEGTL_NAMESPACE::parse_tree
             if( c == '\\' ) {
                os.write( l, p - l );
                l = ++p;
-               os << "\\\\";
+               os << "\\\\\\\\";
             }
             else if( c == '"' ) {
                os.write( l, p - l );
                l = ++p;
-               os << "\\\"";
+               os << "\\\\\\\"";
             }
             else if( c < 32 ) {
                os.write( l, p - l );
                l = ++p;
                switch( c ) {
                   case '\b':
-                     os << "\\b";
+                     os << "\\\\b";
                      break;
                   case '\f':
-                     os << "\\f";
+                     os << "\\\\f";
                      break;
                   case '\n':
-                     os << "\\n";
+                     os << "\\\\n";
                      break;
                   case '\r':
-                     os << "\\r";
+                     os << "\\\\r";
                      break;
                   case '\t':
-                     os << "\\t";
+                     os << "\\\\t";
                      break;
                   default:
-                     os << "\\u00" << h[ ( c & 0xf0 ) >> 4 ] << h[ c & 0x0f ];
+                     os << "\\\\u00" << h[ ( c & 0xf0 ) >> 4 ] << h[ c & 0x0f ];
                }
             }
             else if( c == 127 ) {
                os.write( l, p - l );
                l = ++p;
-               os << "\\u007f";
+               os << "\\\\u007f";
             }
             else {
                ++p;
@@ -74,8 +74,9 @@ namespace TAO_PEGTL_NAMESPACE::parse_tree
          os << "  x" << &n << " [ label=\"";
          escape( os, s );
          if( n.has_content() ) {
-            os << "\\n";
+            os << "\\n\\\"";
             escape( os, n.string_view() );
+            os << "\\\"";
          }
          os << "\" ]\n";
          if( !n.children.empty() ) {
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/print.hpp b/packages/PEGTL/include/tao/pegtl/contrib/print.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..96c1792fe91d6798ea9b2ed267c3ccdc33c7d57c
--- /dev/null
+++ b/packages/PEGTL/include/tao/pegtl/contrib/print.hpp
@@ -0,0 +1,75 @@
+// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#ifndef TAO_PEGTL_CONTRIB_PRINT_HPP
+#define TAO_PEGTL_CONTRIB_PRINT_HPP
+
+#include <ostream>
+
+#include "../config.hpp"
+#include "../visit.hpp"
+
+#include "../internal/demangle.hpp"
+
+namespace TAO_PEGTL_NAMESPACE
+{
+   namespace internal
+   {
+      template< typename Name >
+      struct print_rules
+      {
+         static void visit( std::ostream& os )
+         {
+            os << demangle< Name >() << '\n';
+         }
+      };
+
+      template< typename Name >
+      struct print_sub_rules
+      {
+         static void visit( std::ostream& os )
+         {
+            const auto first = demangle< Name >();
+            os << first << '\n';
+
+            const auto second = demangle< typename Name::rule_t >();
+            if( first != second ) {
+               os << " (aka) " << second << '\n';
+            }
+
+            print_subs( os, typename Name::subs_t() );
+
+            os << '\n';
+         }
+
+      private:
+         template< typename... Rules >
+         static void print_subs( std::ostream& os, type_list< Rules... > /*unused*/ )
+         {
+            ( print_sub< Rules >( os ), ... );
+         }
+
+         template< typename Rule >
+         static void print_sub( std::ostream& os )
+         {
+            os << " (sub) " << demangle< Rule >() << '\n';
+         }
+      };
+
+   }  // namespace internal
+
+   template< typename Grammar >
+   void print_rules( std::ostream& os )
+   {
+      visit< Grammar, internal::print_rules >( os );
+   }
+
+   template< typename Grammar >
+   void print_sub_rules( std::ostream& os )
+   {
+      visit< Grammar, internal::print_sub_rules >( os );
+   }
+
+}  // namespace TAO_PEGTL_NAMESPACE
+
+#endif
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/print_coverage.hpp b/packages/PEGTL/include/tao/pegtl/contrib/print_coverage.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..0c49af45e70214c29d2fd7d1b48f489d96d3e9c7
--- /dev/null
+++ b/packages/PEGTL/include/tao/pegtl/contrib/print_coverage.hpp
@@ -0,0 +1,59 @@
+// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#ifndef TAO_PEGTL_CONTRIB_PRINT_COVERAGE_HPP
+#define TAO_PEGTL_CONTRIB_PRINT_COVERAGE_HPP
+
+#include <ostream>
+
+#include "coverage.hpp"
+
+namespace TAO_PEGTL_NAMESPACE
+{
+   // output is JSON
+   inline void print_coverage( std::ostream& os, const coverage_state& state )
+   {
+      os << "{\n"
+         << "  \"grammar\": \"" << state.grammar << "\",\n"
+         << "  \"source\": \"" << state.source << "\",\n"
+         << "  \"result\": " << ( state.result ? "true" : "false" ) << ",\n"
+         << "  \"coverage\":\n"
+         << "  [\n";
+      bool f = true;
+      for( const auto& [ k, v ] : state.map ) {
+         if( f ) {
+            f = false;
+         }
+         else {
+            os << ",\n";
+         }
+         os << "    {\n"
+            << "      \"rule\": \"" << k << "\",\n"
+            << "      \"start\": " << v.start << ", \"success\": " << v.success << ", \"local_failure\": " << v.local_failure << ", \"global_failure\": " << v.global_failure << ", \"raise\": " << v.raise << ",\n";
+         if( v.branches.empty() ) {
+            os << "      \"branches\": []\n";
+         }
+         else {
+            os << "      \"branches\": [\n";
+            bool f2 = true;
+            for( const auto& [ k2, v2 ] : v.branches ) {
+               if( f2 ) {
+                  f2 = false;
+               }
+               else {
+                  os << ",\n";
+               }
+               os << "        { \"branch\": \"" << k2 << "\", \"start\": " << v2.start << ", \"success\": " << v2.success << ", \"local_failure\": " << v2.local_failure << ", \"global_failure\": " << v2.global_failure << ", \"raise\": " << v2.raise << " }";
+            }
+            os << "\n      ]\n";
+         }
+         os << "    }";
+      }
+      os << "\n"
+         << "  ]\n"
+         << "}\n";
+   }
+
+}  // namespace TAO_PEGTL_NAMESPACE
+
+#endif
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/raw_string.hpp b/packages/PEGTL/include/tao/pegtl/contrib/raw_string.hpp
index 7c3c8eefb179b038468a6d1b50791ee5868805cf..7fc2e049bd994aa7ceb44a2e7bccb775c3d48331 100644
--- a/packages/PEGTL/include/tao/pegtl/contrib/raw_string.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/raw_string.hpp
@@ -8,19 +8,20 @@
 #include <type_traits>
 
 #include "../apply_mode.hpp"
+#include "../ascii.hpp"
 #include "../config.hpp"
 #include "../rewind_mode.hpp"
 
 #include "../internal/bytes.hpp"
+#include "../internal/enable_control.hpp"
 #include "../internal/eof.hpp"
 #include "../internal/eol.hpp"
 #include "../internal/must.hpp"
 #include "../internal/not_at.hpp"
 #include "../internal/seq.hpp"
-#include "../internal/skip_control.hpp"
 #include "../internal/star.hpp"
 
-#include "../analysis/generic.hpp"
+#include "analyze_traits.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
 {
@@ -29,7 +30,8 @@ namespace TAO_PEGTL_NAMESPACE
       template< char Open, char Marker >
       struct raw_string_open
       {
-         using analyze_t = analysis::generic< analysis::rule_type::any >;
+         using rule_t = raw_string_open;
+         using subs_t = empty_list;
 
          template< apply_mode A,
                    rewind_mode,
@@ -37,9 +39,9 @@ namespace TAO_PEGTL_NAMESPACE
                    class Action,
                    template< typename... >
                    class Control,
-                   typename Input,
+                   typename ParseInput,
                    typename... States >
-         [[nodiscard]] static bool match( Input& in, std::size_t& marker_size, States&&... /*unused*/ ) noexcept( noexcept( in.size( 0 ) ) )
+         [[nodiscard]] static bool match( ParseInput& in, std::size_t& marker_size, States&&... /*unused*/ ) noexcept( noexcept( in.size( 0 ) ) )
          {
             if( in.empty() || ( in.peek_char( 0 ) != Open ) ) {
                return false;
@@ -62,12 +64,13 @@ namespace TAO_PEGTL_NAMESPACE
       };
 
       template< char Open, char Marker >
-      inline constexpr bool skip_control< raw_string_open< Open, Marker > > = true;
+      inline constexpr bool enable_control< raw_string_open< Open, Marker > > = false;
 
       template< char Marker, char Close >
       struct at_raw_string_close
       {
-         using analyze_t = analysis::generic< analysis::rule_type::opt >;
+         using rule_t = at_raw_string_close;
+         using subs_t = empty_list;
 
          template< apply_mode A,
                    rewind_mode,
@@ -75,9 +78,9 @@ namespace TAO_PEGTL_NAMESPACE
                    class Action,
                    template< typename... >
                    class Control,
-                   typename Input,
+                   typename ParseInput,
                    typename... States >
-         [[nodiscard]] static bool match( Input& in, const std::size_t& marker_size, States&&... /*unused*/ ) noexcept( noexcept( in.size( 0 ) ) )
+         [[nodiscard]] static bool match( ParseInput& in, const std::size_t& marker_size, States&&... /*unused*/ ) noexcept( noexcept( in.size( 0 ) ) )
          {
             if( in.size( marker_size ) < marker_size ) {
                return false;
@@ -98,7 +101,7 @@ namespace TAO_PEGTL_NAMESPACE
       };
 
       template< char Marker, char Close >
-      inline constexpr bool skip_control< at_raw_string_close< Marker, Close > > = true;
+      inline constexpr bool enable_control< at_raw_string_close< Marker, Close > > = false;
 
       template< typename Cond, typename... Rules >
       struct raw_string_until
@@ -108,7 +111,8 @@ namespace TAO_PEGTL_NAMESPACE
       template< typename Cond >
       struct raw_string_until< Cond >
       {
-         using analyze_t = analysis::generic< analysis::rule_type::seq, star< not_at< Cond >, not_at< eof >, bytes< 1 > >, Cond >;
+         using rule_t = raw_string_until;
+         using subs_t = type_list< Cond >;
 
          template< apply_mode A,
                    rewind_mode M,
@@ -116,9 +120,9 @@ namespace TAO_PEGTL_NAMESPACE
                    class Action,
                    template< typename... >
                    class Control,
-                   typename Input,
+                   typename ParseInput,
                    typename... States >
-         [[nodiscard]] static bool match( Input& in, const std::size_t& marker_size, States&&... st )
+         [[nodiscard]] static bool match( ParseInput& in, const std::size_t& marker_size, States&&... st )
          {
             auto m = in.template mark< M >();
 
@@ -135,7 +139,8 @@ namespace TAO_PEGTL_NAMESPACE
       template< typename Cond, typename Rule >
       struct raw_string_until< Cond, Rule >
       {
-         using analyze_t = analysis::generic< analysis::rule_type::seq, star< not_at< Cond >, not_at< eof >, Rule >, Cond >;
+         using rule_t = raw_string_until;
+         using subs_t = type_list< Cond, Rule >;
 
          template< apply_mode A,
                    rewind_mode M,
@@ -143,15 +148,15 @@ namespace TAO_PEGTL_NAMESPACE
                    class Action,
                    template< typename... >
                    class Control,
-                   typename Input,
+                   typename ParseInput,
                    typename... States >
-         [[nodiscard]] static bool match( Input& in, const std::size_t& marker_size, States&&... st )
+         [[nodiscard]] static bool match( ParseInput& in, const std::size_t& marker_size, States&&... st )
          {
             auto m = in.template mark< M >();
             using m_t = decltype( m );
 
             while( !Control< Cond >::template match< A, rewind_mode::required, Action, Control >( in, marker_size, st... ) ) {
-               if( in.empty() || !Control< Rule >::template match< A, m_t::next_rewind_mode, Action, Control >( in, st... ) ) {
+               if( !Control< Rule >::template match< A, m_t::next_rewind_mode, Action, Control >( in, st... ) ) {
                   return false;
                }
             }
@@ -160,7 +165,7 @@ namespace TAO_PEGTL_NAMESPACE
       };
 
       template< typename Cond, typename... Rules >
-      inline constexpr bool skip_control< raw_string_until< Cond, Rules... > > = true;
+      inline constexpr bool enable_control< raw_string_until< Cond, Rules... > > = false;
 
    }  // namespace internal
 
@@ -198,7 +203,8 @@ namespace TAO_PEGTL_NAMESPACE
          : internal::raw_string_until< internal::at_raw_string_close< Marker, Close >, Contents... >
       {};
 
-      using analyze_t = typename internal::seq< internal::bytes< 1 >, content, internal::bytes< 1 > >::analyze_t;
+      using rule_t = raw_string;
+      using subs_t = type_list< internal::raw_string_open< Open, Marker >, internal::must< content > >;
 
       template< apply_mode A,
                 rewind_mode M,
@@ -206,14 +212,14 @@ namespace TAO_PEGTL_NAMESPACE
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
       {
          std::size_t marker_size;
-         if( internal::raw_string_open< Open, Marker >::template match< A, M, Action, Control >( in, marker_size, st... ) ) {
+         if( Control< internal::raw_string_open< Open, Marker > >::template match< A, M, Action, Control >( in, marker_size, st... ) ) {
             // TODO: Do not rely on must<>
-            (void)internal::must< content >::template match< A, M, Action, Control >( in, marker_size, st... );
+            (void)Control< internal::must< content > >::template match< A, M, Action, Control >( in, marker_size, st... );
             in.bump_in_this_line( marker_size );
             return true;
          }
@@ -221,6 +227,16 @@ namespace TAO_PEGTL_NAMESPACE
       }
    };
 
+   template< typename Name, char Open, char Marker, char Close >
+   struct analyze_traits< Name, raw_string< Open, Marker, Close > >
+      : analyze_any_traits<>
+   {};
+
+   template< typename Name, char Open, char Marker, char Close, typename... Contents >
+   struct analyze_traits< Name, raw_string< Open, Marker, Close, Contents... > >
+      : analyze_traits< Name, typename seq< any, star< Contents... >, any >::rule_t >
+   {};
+
 }  // namespace TAO_PEGTL_NAMESPACE
 
 #endif
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/remove_first_state.hpp b/packages/PEGTL/include/tao/pegtl/contrib/remove_first_state.hpp
index 4933a735e51585435b3585f5bf174b076964404d..48030def2e9bb687e86783ce0558029fd43ad96c 100644
--- a/packages/PEGTL/include/tao/pegtl/contrib/remove_first_state.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/remove_first_state.hpp
@@ -4,80 +4,52 @@
 #ifndef TAO_PEGTL_CONTRIB_REMOVE_FIRST_STATE_HPP
 #define TAO_PEGTL_CONTRIB_REMOVE_FIRST_STATE_HPP
 
-#include "../apply_mode.hpp"
 #include "../config.hpp"
-#include "../rewind_mode.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
 {
-   // NOTE: The naming of the following classes might still change.
-
-   template< typename Rule, template< typename... > class Control >
-   struct remove_first_state_after_match
-      : Control< Rule >
+   // Applies to start(), success(), failure(), raise(), apply(), and apply0():
+   // The first state is removed when the call is forwarded to Base.
+   template< typename Base >
+   struct remove_first_state
+      : Base
    {
-      template< typename Input, typename State, typename... States >
-      static void start( const Input& in, State&& /*unused*/, States&&... st ) noexcept( noexcept( Control< Rule >::start( in, st... ) ) )
-      {
-         Control< Rule >::start( in, st... );
-      }
-
-      template< typename Input, typename State, typename... States >
-      static void success( const Input& in, State&& /*unused*/, States&&... st ) noexcept( noexcept( Control< Rule >::success( in, st... ) ) )
+      template< typename ParseInput, typename State, typename... States >
+      static void start( const ParseInput& in, State&& /*unused*/, States&&... st ) noexcept( noexcept( Base::start( in, st... ) ) )
       {
-         Control< Rule >::success( in, st... );
+         Base::start( in, st... );
       }
 
-      template< typename Input, typename State, typename... States >
-      static void failure( const Input& in, State&& /*unused*/, States&&... st ) noexcept( noexcept( Control< Rule >::failure( in, st... ) ) )
+      template< typename ParseInput, typename State, typename... States >
+      static void success( const ParseInput& in, State&& /*unused*/, States&&... st ) noexcept( noexcept( Base::success( in, st... ) ) )
       {
-         Control< Rule >::failure( in, st... );
+         Base::success( in, st... );
       }
 
-      template< typename Input, typename State, typename... States >
-      static void raise( const Input& in, State&& /*unused*/, States&&... st )
+      template< typename ParseInput, typename State, typename... States >
+      static void failure( const ParseInput& in, State&& /*unused*/, States&&... st ) noexcept( noexcept( Base::failure( in, st... ) ) )
       {
-         Control< Rule >::raise( in, st... );
+         Base::failure( in, st... );
       }
 
-      template< template< typename... > class Action,
-                typename Iterator,
-                typename Input,
-                typename State,
-                typename... States >
-      static auto apply( const Iterator& begin, const Input& in, State&& /*unused*/, States&&... st ) noexcept( noexcept( Control< Rule >::template apply< Action >( begin, in, st... ) ) )
-         -> decltype( Control< Rule >::template apply< Action >( begin, in, st... ) )
+      template< typename ParseInput, typename State, typename... States >
+      [[noreturn]] static void raise( const ParseInput& in, State&& /*unused*/, States&&... st )
       {
-         return Control< Rule >::template apply< Action >( begin, in, st... );
+         Base::raise( in, st... );
       }
 
-      template< template< typename... > class Action,
-                typename Input,
-                typename State,
-                typename... States >
-      static auto apply0( const Input& in, State&& /*unused*/, States&&... st ) noexcept( noexcept( Control< Rule >::template apply0< Action >( in, st... ) ) )
-         -> decltype( Control< Rule >::template apply0< Action >( in, st... ) )
+      template< template< typename... > class Action, typename Iterator, typename ParseInput, typename State, typename... States >
+      static auto apply( const Iterator& begin, const ParseInput& in, State&& /*unused*/, States&&... st ) noexcept( noexcept( Base::template apply< Action >( begin, in, st... ) ) )
+         -> decltype( Base::template apply< Action >( begin, in, st... ) )
       {
-         return Control< Rule >::template apply0< Action >( in, st... );
+         return Base::template apply< Action >( begin, in, st... );
       }
-   };
 
-   template< typename Rule, template< typename... > class Control >
-   struct remove_self_and_first_state
-      : Control< Rule >
-   {
-      template< apply_mode A,
-                rewind_mode M,
-                template< typename... >
-                class Action,
-                template< typename... >
-                class,
-                typename Input,
-                typename State,
-                typename... States >
-      [[nodiscard]] static bool match( Input& in, State&& /*unused*/, States&&... st )
+      template< template< typename... > class Action, typename ParseInput, typename State, typename... States >
+      static auto apply0( const ParseInput& in, State&& /*unused*/, States&&... st ) noexcept( noexcept( Base::template apply0< Action >( in, st... ) ) )
+         -> decltype( Base::template apply0< Action >( in, st... ) )
       {
-         return Control< Rule >::template match< A, M, Action, Control >( in, st... );
+         return Base::template apply0< Action >( in, st... );
       }
    };
 
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/remove_last_states.hpp b/packages/PEGTL/include/tao/pegtl/contrib/remove_last_states.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..5fb778b7dbb4d45c29107e987697bc5393b75658
--- /dev/null
+++ b/packages/PEGTL/include/tao/pegtl/contrib/remove_last_states.hpp
@@ -0,0 +1,101 @@
+// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#ifndef TAO_PEGTL_CONTRIB_REMOVE_LAST_STATES_HPP
+#define TAO_PEGTL_CONTRIB_REMOVE_LAST_STATES_HPP
+
+#include <tuple>
+#include <utility>
+
+#include "../config.hpp"
+
+namespace TAO_PEGTL_NAMESPACE
+{
+   // Remove the last N states of start(), success(), failure(), raise(), apply(), and apply0()
+   template< typename Base, std::size_t N >
+   struct remove_last_states
+      : Base
+   {
+      template< typename ParseInput, typename Tuple, std::size_t... Is >
+      static void start_impl( const ParseInput& in, const Tuple& t, std::index_sequence< Is... > /*unused*/ ) noexcept( noexcept( Base::start( in, std::get< Is >( t )... ) ) )
+      {
+         Base::start( in, std::get< Is >( t )... );
+      }
+
+      template< typename ParseInput, typename... States >
+      static void start( const ParseInput& in, States&&... st ) noexcept( noexcept( start_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - N >() ) ) )
+      {
+         start_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - N >() );
+      }
+
+      template< typename ParseInput, typename Tuple, std::size_t... Is >
+      static void success_impl( const ParseInput& in, const Tuple& t, std::index_sequence< Is... > /*unused*/ ) noexcept( noexcept( Base::success( in, std::get< Is >( t )... ) ) )
+      {
+         Base::success( in, std::get< Is >( t )... );
+      }
+
+      template< typename ParseInput, typename... States >
+      static void success( const ParseInput& in, States&&... st ) noexcept( noexcept( success_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - N >() ) ) )
+      {
+         success_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - N >() );
+      }
+
+      template< typename ParseInput, typename Tuple, std::size_t... Is >
+      static void failure_impl( const ParseInput& in, const Tuple& t, std::index_sequence< Is... > /*unused*/ ) noexcept( noexcept( Base::failure( in, std::get< Is >( t )... ) ) )
+      {
+         Base::failure( in, std::get< Is >( t )... );
+      }
+
+      template< typename ParseInput, typename... States >
+      static void failure( const ParseInput& in, States&&... st ) noexcept( noexcept( failure_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - N >() ) ) )
+      {
+         failure_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - N >() );
+      }
+
+      template< typename ParseInput, typename Tuple, std::size_t... Is >
+      [[noreturn]] static void raise_impl( const ParseInput& in, const Tuple& t, std::index_sequence< Is... > /*unused*/ )
+      {
+         Base::raise( in, std::get< Is >( t )... );
+      }
+
+      template< typename ParseInput, typename... States >
+      [[noreturn]] static void raise( const ParseInput& in, States&&... st )
+      {
+         raise_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - N >() );
+      }
+
+      template< template< typename... > class Action, typename Iterator, typename ParseInput, typename Tuple, std::size_t... Is >
+      static auto apply_impl( const Iterator& begin, const ParseInput& in, const Tuple& t, std::index_sequence< Is... > /*unused*/ ) noexcept( noexcept( Base::template apply< Action >( begin, in, std::get< Is >( t )... ) ) )
+         -> decltype( Base::template apply< Action >( begin, in, std::get< Is >( t )... ) )
+      {
+         return Base::template apply< Action >( begin, in, std::get< Is >( t )... );
+      }
+
+      template< template< typename... > class Action, typename Iterator, typename ParseInput, typename... States >
+      static auto apply( const Iterator& begin, const ParseInput& in, States&&... st ) noexcept( noexcept( apply_impl< Action >( begin, in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - N >() ) ) )
+         -> decltype( apply_impl< Action >( begin, in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - N >() ) )
+      {
+         return apply_impl< Action >( begin, in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - N >() );
+      }
+
+      template< template< typename... > class Action, typename ParseInput, typename Tuple, std::size_t... Is >
+      static auto apply0_impl( const ParseInput& in, const Tuple& t, std::index_sequence< Is... > /*unused*/ ) noexcept( noexcept( Base::template apply0< Action >( in, std::get< Is >( t )... ) ) )
+         -> decltype( Base::template apply0< Action >( in, std::get< Is >( t )... ) )
+      {
+         return Base::template apply0< Action >( in, std::get< Is >( t )... );
+      }
+
+      template< template< typename... > class Action, typename ParseInput, typename... States >
+      static auto apply0( const ParseInput& in, States&&... st ) noexcept( noexcept( apply0_impl< Action >( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - N >() ) ) )
+         -> decltype( apply0_impl< Action >( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - N >() ) )
+      {
+         return apply0_impl< Action >( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) - N >() );
+      }
+   };
+
+   template< typename Base >
+   using remove_last_state = remove_last_states< Base, 1 >;
+
+}  // namespace TAO_PEGTL_NAMESPACE
+
+#endif
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/rep_one_min_max.hpp b/packages/PEGTL/include/tao/pegtl/contrib/rep_one_min_max.hpp
index f190edaabca38bc5bb7cff3d5eca856595996b1d..7ec4639ef68c435f13d585b87a41fa8a5c7784e1 100644
--- a/packages/PEGTL/include/tao/pegtl/contrib/rep_one_min_max.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/rep_one_min_max.hpp
@@ -5,13 +5,17 @@
 #define TAO_PEGTL_CONTRIB_REP_ONE_MIN_MAX_HPP
 
 #include <algorithm>
+#include <type_traits>
 
 #include "../config.hpp"
-
-#include "../analysis/counted.hpp"
+#include "../type_list.hpp"
 
 #include "../internal/bump_help.hpp"
-#include "../internal/skip_control.hpp"
+#include "../internal/bytes.hpp"
+#include "../internal/enable_control.hpp"
+#include "../internal/opt.hpp"
+
+#include "analyze_traits.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
 {
@@ -20,12 +24,13 @@ namespace TAO_PEGTL_NAMESPACE
       template< unsigned Min, unsigned Max, char C >
       struct rep_one_min_max
       {
-         using analyze_t = analysis::counted< analysis::rule_type::any, Min >;
+         using rule_t = rep_one_min_max;
+         using subs_t = empty_list;
 
          static_assert( Min <= Max );
 
-         template< typename Input >
-         [[nodiscard]] static bool match( Input& in )
+         template< typename ParseInput >
+         [[nodiscard]] static bool match( ParseInput& in )
          {
             const auto size = in.size( Max + 1 );
             if( size < Min ) {
@@ -36,7 +41,7 @@ namespace TAO_PEGTL_NAMESPACE
                ++i;
             }
             if( ( Min <= i ) && ( i <= Max ) ) {
-               bump_help< result_on_found::success, Input, char, C >( in, i );
+               bump_help< result_on_found::success, ParseInput, char, C >( in, i );
                return true;
             }
             return false;
@@ -44,7 +49,7 @@ namespace TAO_PEGTL_NAMESPACE
       };
 
       template< unsigned Min, unsigned Max, char C >
-      inline constexpr bool skip_control< rep_one_min_max< Min, Max, C > > = true;
+      inline constexpr bool enable_control< rep_one_min_max< Min, Max, C > > = false;
 
    }  // namespace internal
 
@@ -57,6 +62,11 @@ namespace TAO_PEGTL_NAMESPACE
 
    }  // namespace ascii
 
+   template< typename Name, unsigned Min, unsigned Max, char C >
+   struct analyze_traits< Name, internal::rep_one_min_max< Min, Max, C > >
+      : std::conditional_t< ( Min != 0 ), analyze_any_traits<>, analyze_opt_traits<> >
+   {};
+
 }  // namespace TAO_PEGTL_NAMESPACE
 
 #endif
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/shuffle_states.hpp b/packages/PEGTL/include/tao/pegtl/contrib/shuffle_states.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..e081051405ad231b944c5b2a14e5ddbfb25bef04
--- /dev/null
+++ b/packages/PEGTL/include/tao/pegtl/contrib/shuffle_states.hpp
@@ -0,0 +1,169 @@
+// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#ifndef TAO_PEGTL_CONTRIB_SHUFFLE_STATES_HPP
+#define TAO_PEGTL_CONTRIB_SHUFFLE_STATES_HPP
+
+#include <tuple>
+#include <utility>
+
+#include "../config.hpp"
+
+namespace TAO_PEGTL_NAMESPACE
+{
+   namespace internal
+   {
+      template< std::size_t N >
+      struct rotate_left
+      {
+         template< std::size_t I, std::size_t S >
+         static constexpr std::size_t value = ( I + N ) % S;
+      };
+
+      template< std::size_t N >
+      struct rotate_right
+      {
+         template< std::size_t I, std::size_t S >
+         static constexpr std::size_t value = ( I + S - N ) % S;
+      };
+
+      struct reverse
+      {
+         template< std::size_t I, std::size_t S >
+         static constexpr std::size_t value = ( S - 1 ) - I;
+      };
+
+   }  // namespace internal
+
+   // Applies 'Shuffle' to the states of start(), success(), failure(), raise(), apply(), and apply0()
+   template< typename Base, typename Shuffle >
+   struct shuffle_states
+      : Base
+   {
+      template< typename ParseInput, typename Tuple, std::size_t... Is >
+      static void start_impl( const ParseInput& in, const Tuple& t, std::index_sequence< Is... > /*unused*/ ) noexcept( noexcept( Base::start( in, std::get< Shuffle::template value< Is, sizeof...( Is ) > >( t )... ) ) )
+      {
+         Base::start( in, std::get< Shuffle::template value< Is, sizeof...( Is ) > >( t )... );
+      }
+
+      template< typename ParseInput, typename... States >
+      static void start( const ParseInput& in, States&&... st ) noexcept( noexcept( start_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) >() ) ) )
+      {
+         start_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) >() );
+      }
+
+      template< typename ParseInput, typename State >
+      static void start( const ParseInput& in, State&& st ) noexcept( noexcept( Base::start( in, st ) ) )
+      {
+         Base::start( in, st );
+      }
+
+      template< typename ParseInput, typename Tuple, std::size_t... Is >
+      static void success_impl( const ParseInput& in, const Tuple& t, std::index_sequence< Is... > /*unused*/ ) noexcept( noexcept( Base::success( in, std::get< Shuffle::template value< Is, sizeof...( Is ) > >( t )... ) ) )
+      {
+         Base::success( in, std::get< Shuffle::template value< Is, sizeof...( Is ) > >( t )... );
+      }
+
+      template< typename ParseInput, typename... States >
+      static void success( const ParseInput& in, States&&... st ) noexcept( noexcept( success_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) >() ) ) )
+      {
+         success_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) >() );
+      }
+
+      template< typename ParseInput, typename State >
+      static void success( const ParseInput& in, State&& st ) noexcept( noexcept( Base::success( in, st ) ) )
+      {
+         Base::success( in, st );
+      }
+
+      template< typename ParseInput, typename Tuple, std::size_t... Is >
+      static void failure_impl( const ParseInput& in, const Tuple& t, std::index_sequence< Is... > /*unused*/ ) noexcept( noexcept( Base::failure( in, std::get< Shuffle::template value< Is, sizeof...( Is ) > >( t )... ) ) )
+      {
+         Base::failure( in, std::get< Shuffle::template value< Is, sizeof...( Is ) > >( t )... );
+      }
+
+      template< typename ParseInput, typename... States >
+      static void failure( const ParseInput& in, States&&... st ) noexcept( noexcept( failure_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) >() ) ) )
+      {
+         failure_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) >() );
+      }
+
+      template< typename ParseInput, typename State >
+      static void failure( const ParseInput& in, State&& st ) noexcept( noexcept( Base::failure( in, st ) ) )
+      {
+         Base::failure( in, st );
+      }
+
+      template< typename ParseInput, typename Tuple, std::size_t... Is >
+      [[noreturn]] static void raise_impl( const ParseInput& in, const Tuple& t, std::index_sequence< Is... > /*unused*/ )
+      {
+         Base::raise( in, std::get< Shuffle::template value< Is, sizeof...( Is ) > >( t )... );
+      }
+
+      template< typename ParseInput, typename... States >
+      [[noreturn]] static void raise( const ParseInput& in, States&&... st )
+      {
+         raise_impl( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) >() );
+      }
+
+      template< typename ParseInput, typename State >
+      [[noreturn]] static void raise( const ParseInput& in, State&& st )
+      {
+         Base::raise( in, st );
+      }
+
+      template< template< typename... > class Action, typename Iterator, typename ParseInput, typename Tuple, std::size_t... Is >
+      static auto apply_impl( const Iterator& begin, const ParseInput& in, const Tuple& t, std::index_sequence< Is... > /*unused*/ ) noexcept( noexcept( Base::template apply< Action >( begin, in, std::get< Shuffle::template value< Is, sizeof...( Is ) > >( t )... ) ) )
+         -> decltype( Base::template apply< Action >( begin, in, std::get< Shuffle::template value< Is, sizeof...( Is ) > >( t )... ) )
+      {
+         return Base::template apply< Action >( begin, in, std::get< Shuffle::template value< Is, sizeof...( Is ) > >( t )... );
+      }
+
+      template< template< typename... > class Action, typename Iterator, typename ParseInput, typename... States >
+      static auto apply( const Iterator& begin, const ParseInput& in, States&&... st ) noexcept( noexcept( apply_impl< Action >( begin, in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) >() ) ) )
+         -> decltype( apply_impl< Action >( begin, in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) >() ) )
+      {
+         return apply_impl< Action >( begin, in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) >() );
+      }
+
+      template< template< typename... > class Action, typename Iterator, typename ParseInput, typename State >
+      static auto apply( const Iterator& begin, const ParseInput& in, State&& st ) noexcept( noexcept( Base::template apply< Action >( begin, in, st ) ) )
+         -> decltype( Base::template apply< Action >( begin, in, st ) )
+      {
+         return Base::template apply< Action >( begin, in, st );
+      }
+
+      template< template< typename... > class Action, typename ParseInput, typename Tuple, std::size_t... Is >
+      static auto apply0_impl( const ParseInput& in, const Tuple& t, std::index_sequence< Is... > /*unused*/ ) noexcept( noexcept( Base::template apply0< Action >( in, std::get< Shuffle::template value< Is, sizeof...( Is ) > >( t )... ) ) )
+         -> decltype( Base::template apply0< Action >( in, std::get< Shuffle::template value< Is, sizeof...( Is ) > >( t )... ) )
+      {
+         return Base::template apply0< Action >( in, std::get< Shuffle::template value< Is, sizeof...( Is ) > >( t )... );
+      }
+
+      template< template< typename... > class Action, typename ParseInput, typename... States >
+      static auto apply0( const ParseInput& in, States&&... st ) noexcept( noexcept( apply0_impl< Action >( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) >() ) ) )
+         -> decltype( apply0_impl< Action >( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) >() ) )
+      {
+         return apply0_impl< Action >( in, std::tie( st... ), std::make_index_sequence< sizeof...( st ) >() );
+      }
+
+      template< template< typename... > class Action, typename ParseInput, typename State >
+      static auto apply0( const ParseInput& in, State&& st ) noexcept( noexcept( Base::template apply0< Action >( in, st ) ) )
+         -> decltype( Base::template apply0< Action >( in, st ) )
+      {
+         return Base::template apply0< Action >( in, st );
+      }
+   };
+
+   template< typename Base, std::size_t N = 1 >
+   using rotate_states_left = shuffle_states< Base, internal::rotate_left< N > >;
+
+   template< typename Base, std::size_t N = 1 >
+   using rotate_states_right = shuffle_states< Base, internal::rotate_right< N > >;
+
+   template< typename Base >
+   using reverse_states = shuffle_states< Base, internal::reverse >;
+
+}  // namespace TAO_PEGTL_NAMESPACE
+
+#endif
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/trace.hpp b/packages/PEGTL/include/tao/pegtl/contrib/trace.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..798c951e6ab9cb518ab10622b2c4482ca326e537
--- /dev/null
+++ b/packages/PEGTL/include/tao/pegtl/contrib/trace.hpp
@@ -0,0 +1,154 @@
+// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#ifndef TAO_PEGTL_CONTRIB_TRACE_HPP
+#define TAO_PEGTL_CONTRIB_TRACE_HPP
+
+#include <cassert>
+#include <iomanip>
+#include <iostream>
+#include <utility>
+#include <vector>
+
+#include "../config.hpp"
+#include "../normal.hpp"
+
+#include "../internal/demangle.hpp"
+
+namespace TAO_PEGTL_NAMESPACE
+{
+   namespace internal
+   {
+      template< typename ParseInput >
+      void print_current( const ParseInput& in )
+      {
+         if( in.empty() ) {
+            std::cerr << "<eof>";
+         }
+         else {
+            const auto c = in.peek_uint8();
+            switch( c ) {
+               case 0:
+                  std::cerr << "<nul> = ";
+                  break;
+               case 9:
+                  std::cerr << "<ht> = ";
+                  break;
+               case 10:
+                  std::cerr << "<lf> = ";
+                  break;
+               case 13:
+                  std::cerr << "<cr> = ";
+                  break;
+               default:
+                  if( isprint( c ) ) {
+                     std::cerr << '\'' << c << "' = ";
+                  }
+            }
+            std::cerr << "(char)" << unsigned( c );
+         }
+      }
+
+   }  // namespace internal
+
+   struct trace_state
+   {
+      unsigned rule = 0;
+      unsigned line = 0;
+      std::vector< unsigned > stack;
+   };
+
+   template< typename Rule, template< typename... > class Control >
+   struct basic_trace_control
+      : Control< Rule >
+   {
+      template< typename ParseInput, typename... States >
+      static void start( const ParseInput& in, States&&... st )
+      {
+         std::cerr << in.position() << "  start  " << internal::demangle< Rule >() << "; current ";
+         print_current( in );
+         std::cerr << std::endl;
+         Control< Rule >::start( in, st... );
+      }
+
+      template< typename ParseInput, typename... States >
+      static void start( const ParseInput& in, trace_state& ts, States&&... st )
+      {
+         std::cerr << std::setw( 6 ) << ++ts.line << " " << std::setw( 6 ) << ++ts.rule << " ";
+         start( in, st... );
+         ts.stack.push_back( ts.rule );
+      }
+
+      template< typename ParseInput, typename... States >
+      static void success( const ParseInput& in, States&&... st )
+      {
+         std::cerr << in.position() << " success " << internal::demangle< Rule >() << "; next ";
+         print_current( in );
+         std::cerr << std::endl;
+         Control< Rule >::success( in, st... );
+      }
+
+      template< typename ParseInput, typename... States >
+      static void success( const ParseInput& in, trace_state& ts, States&&... st )
+      {
+         assert( !ts.stack.empty() );
+         std::cerr << std::setw( 6 ) << ++ts.line << " " << std::setw( 6 ) << ts.stack.back() << " ";
+         success( in, st... );
+         ts.stack.pop_back();
+      }
+
+      template< typename ParseInput, typename... States >
+      static void failure( const ParseInput& in, States&&... st )
+      {
+         std::cerr << in.position() << " failure " << internal::demangle< Rule >() << std::endl;
+         Control< Rule >::failure( in, st... );
+      }
+
+      template< typename ParseInput, typename... States >
+      static void failure( const ParseInput& in, trace_state& ts, States&&... st )
+      {
+         assert( !ts.stack.empty() );
+         std::cerr << std::setw( 6 ) << ++ts.line << " " << std::setw( 6 ) << ts.stack.back() << " ";
+         failure( in, st... );
+         ts.stack.pop_back();
+      }
+
+      template< template< typename... > class Action, typename Iterator, typename ParseInput, typename... States >
+      static auto apply( const Iterator& begin, const ParseInput& in, States&&... st )
+         -> decltype( Control< Rule >::template apply< Action >( begin, in, st... ) )
+      {
+         std::cerr << in.position() << "  apply  " << internal::demangle< Rule >() << std::endl;
+         return Control< Rule >::template apply< Action >( begin, in, st... );
+      }
+
+      template< template< typename... > class Action, typename Iterator, typename ParseInput, typename... States >
+      static auto apply( const Iterator& begin, const ParseInput& in, trace_state& ts, States&&... st )
+         -> decltype( apply< Action >( begin, in, st... ) )
+      {
+         std::cerr << std::setw( 6 ) << ++ts.line << "        ";
+         return apply< Action >( begin, in, st... );
+      }
+
+      template< template< typename... > class Action, typename ParseInput, typename... States >
+      static auto apply0( const ParseInput& in, States&&... st )
+         -> decltype( Control< Rule >::template apply0< Action >( in, st... ) )
+      {
+         std::cerr << in.position() << "  apply0 " << internal::demangle< Rule >() << std::endl;
+         return Control< Rule >::template apply0< Action >( in, st... );
+      }
+
+      template< template< typename... > class Action, typename ParseInput, typename... States >
+      static auto apply0( const ParseInput& in, trace_state& ts, States&&... st )
+         -> decltype( apply0< Action >( in, st... ) )
+      {
+         std::cerr << std::setw( 6 ) << ++ts.line << "        ";
+         return apply0< Action >( in, st... );
+      }
+   };
+
+   template< typename Rule >
+   using trace_control = basic_trace_control< Rule, normal >;
+
+}  // namespace TAO_PEGTL_NAMESPACE
+
+#endif
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/tracer.hpp b/packages/PEGTL/include/tao/pegtl/contrib/tracer.hpp
deleted file mode 100644
index c06968f764f3b8b06c2e13128d3619e17b444da3..0000000000000000000000000000000000000000
--- a/packages/PEGTL/include/tao/pegtl/contrib/tracer.hpp
+++ /dev/null
@@ -1,158 +0,0 @@
-// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey
-// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
-
-#ifndef TAO_PEGTL_CONTRIB_TRACER_HPP
-#define TAO_PEGTL_CONTRIB_TRACER_HPP
-
-#include <cassert>
-#include <iomanip>
-#include <iostream>
-#include <utility>
-#include <vector>
-
-#include "../config.hpp"
-#include "../normal.hpp"
-
-#include "../internal/demangle.hpp"
-
-namespace TAO_PEGTL_NAMESPACE
-{
-   namespace internal
-   {
-      template< typename Input >
-      void print_current( const Input& in )
-      {
-         if( in.empty() ) {
-            std::cerr << "<eof>";
-         }
-         else {
-            const auto c = in.peek_uint8();
-            switch( c ) {
-               case 0:
-                  std::cerr << "<nul> = ";
-                  break;
-               case 9:
-                  std::cerr << "<ht> = ";
-                  break;
-               case 10:
-                  std::cerr << "<lf> = ";
-                  break;
-               case 13:
-                  std::cerr << "<cr> = ";
-                  break;
-               default:
-                  if( isprint( c ) ) {
-                     std::cerr << '\'' << c << "' = ";
-                  }
-            }
-            std::cerr << "(char)" << unsigned( c );
-         }
-      }
-
-   }  // namespace internal
-
-   struct trace_state
-   {
-      unsigned rule = 0;
-      unsigned line = 0;
-      std::vector< unsigned > stack;
-   };
-
-   template< template< typename... > class Base >
-   struct trace
-   {
-      template< typename Rule >
-      struct control
-         : Base< Rule >
-      {
-         template< typename Input, typename... States >
-         static void start( const Input& in, States&&... st )
-         {
-            std::cerr << in.position() << "  start  " << internal::demangle< Rule >() << "; current ";
-            print_current( in );
-            std::cerr << std::endl;
-            Base< Rule >::start( in, st... );
-         }
-
-         template< typename Input, typename... States >
-         static void start( const Input& in, trace_state& ts, States&&... st )
-         {
-            std::cerr << std::setw( 6 ) << ++ts.line << " " << std::setw( 6 ) << ++ts.rule << " ";
-            start( in, st... );
-            ts.stack.push_back( ts.rule );
-         }
-
-         template< typename Input, typename... States >
-         static void success( const Input& in, States&&... st )
-         {
-            std::cerr << in.position() << " success " << internal::demangle< Rule >() << "; next ";
-            print_current( in );
-            std::cerr << std::endl;
-            Base< Rule >::success( in, st... );
-         }
-
-         template< typename Input, typename... States >
-         static void success( const Input& in, trace_state& ts, States&&... st )
-         {
-            assert( !ts.stack.empty() );
-            std::cerr << std::setw( 6 ) << ++ts.line << " " << std::setw( 6 ) << ts.stack.back() << " ";
-            success( in, st... );
-            ts.stack.pop_back();
-         }
-
-         template< typename Input, typename... States >
-         static void failure( const Input& in, States&&... st )
-         {
-            std::cerr << in.position() << " failure " << internal::demangle< Rule >() << std::endl;
-            Base< Rule >::failure( in, st... );
-         }
-
-         template< typename Input, typename... States >
-         static void failure( const Input& in, trace_state& ts, States&&... st )
-         {
-            assert( !ts.stack.empty() );
-            std::cerr << std::setw( 6 ) << ++ts.line << " " << std::setw( 6 ) << ts.stack.back() << " ";
-            failure( in, st... );
-            ts.stack.pop_back();
-         }
-
-         template< template< typename... > class Action, typename Iterator, typename Input, typename... States >
-         static auto apply( const Iterator& begin, const Input& in, States&&... st )
-            -> decltype( Base< Rule >::template apply< Action >( begin, in, st... ) )
-         {
-            std::cerr << in.position() << "  apply  " << internal::demangle< Rule >() << std::endl;
-            return Base< Rule >::template apply< Action >( begin, in, st... );
-         }
-
-         template< template< typename... > class Action, typename Iterator, typename Input, typename... States >
-         static auto apply( const Iterator& begin, const Input& in, trace_state& ts, States&&... st )
-            -> decltype( apply< Action >( begin, in, st... ) )
-         {
-            std::cerr << std::setw( 6 ) << ++ts.line << "        ";
-            return apply< Action >( begin, in, st... );
-         }
-
-         template< template< typename... > class Action, typename Input, typename... States >
-         static auto apply0( const Input& in, States&&... st )
-            -> decltype( Base< Rule >::template apply0< Action >( in, st... ) )
-         {
-            std::cerr << in.position() << "  apply0 " << internal::demangle< Rule >() << std::endl;
-            return Base< Rule >::template apply0< Action >( in, st... );
-         }
-
-         template< template< typename... > class Action, typename Input, typename... States >
-         static auto apply0( const Input& in, trace_state& ts, States&&... st )
-            -> decltype( apply0< Action >( in, st... ) )
-         {
-            std::cerr << std::setw( 6 ) << ++ts.line << "        ";
-            return apply0< Action >( in, st... );
-         }
-      };
-   };
-
-   template< typename Rule >
-   using tracer = trace< normal >::control< Rule >;
-
-}  // namespace TAO_PEGTL_NAMESPACE
-
-#endif
diff --git a/packages/PEGTL/include/tao/pegtl/uint16.hpp b/packages/PEGTL/include/tao/pegtl/contrib/uint16.hpp
similarity index 96%
rename from packages/PEGTL/include/tao/pegtl/uint16.hpp
rename to packages/PEGTL/include/tao/pegtl/contrib/uint16.hpp
index cda189d49d08f7de82172cdedb1f0abb4edce689..54fe468fb71a75b1f60df1795ed03347aa33c5e4 100644
--- a/packages/PEGTL/include/tao/pegtl/uint16.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/uint16.hpp
@@ -1,15 +1,15 @@
 // Copyright (c) 2018-2020 Dr. Colin Hirsch and Daniel Frey
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
-#ifndef TAO_PEGTL_UINT16_HPP
-#define TAO_PEGTL_UINT16_HPP
+#ifndef TAO_PEGTL_CONTRIB_UINT16_HPP
+#define TAO_PEGTL_CONTRIB_UINT16_HPP
 
-#include "config.hpp"
+#include "../config.hpp"
+#include "../internal/result_on_found.hpp"
+#include "../internal/rules.hpp"
 
 #include "internal/peek_mask_uint.hpp"
 #include "internal/peek_uint.hpp"
-#include "internal/result_on_found.hpp"
-#include "internal/rules.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
 {
diff --git a/packages/PEGTL/include/tao/pegtl/uint32.hpp b/packages/PEGTL/include/tao/pegtl/contrib/uint32.hpp
similarity index 96%
rename from packages/PEGTL/include/tao/pegtl/uint32.hpp
rename to packages/PEGTL/include/tao/pegtl/contrib/uint32.hpp
index ce0778299a0a0a295b4a8edbc9483b2bf6a6610c..31bc321c5b6b639696fee50cce07dba455c7f7f7 100644
--- a/packages/PEGTL/include/tao/pegtl/uint32.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/uint32.hpp
@@ -1,15 +1,15 @@
 // Copyright (c) 2018-2020 Dr. Colin Hirsch and Daniel Frey
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
-#ifndef TAO_PEGTL_UINT32_HPP
-#define TAO_PEGTL_UINT32_HPP
+#ifndef TAO_PEGTL_CONTRIB_UINT32_HPP
+#define TAO_PEGTL_CONTRIB_UINT32_HPP
 
-#include "config.hpp"
+#include "../config.hpp"
+#include "../internal/result_on_found.hpp"
+#include "../internal/rules.hpp"
 
 #include "internal/peek_mask_uint.hpp"
 #include "internal/peek_uint.hpp"
-#include "internal/result_on_found.hpp"
-#include "internal/rules.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
 {
diff --git a/packages/PEGTL/include/tao/pegtl/uint64.hpp b/packages/PEGTL/include/tao/pegtl/contrib/uint64.hpp
similarity index 96%
rename from packages/PEGTL/include/tao/pegtl/uint64.hpp
rename to packages/PEGTL/include/tao/pegtl/contrib/uint64.hpp
index c83182018143139b2ca7fedd4d66e9b16a786b30..027a3968c7fbe697c627371b84f0f417388f046b 100644
--- a/packages/PEGTL/include/tao/pegtl/uint64.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/uint64.hpp
@@ -1,15 +1,15 @@
 // Copyright (c) 2018-2020 Dr. Colin Hirsch and Daniel Frey
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
-#ifndef TAO_PEGTL_UINT64_HPP
-#define TAO_PEGTL_UINT64_HPP
+#ifndef TAO_PEGTL_CONTRIB_UINT64_HPP
+#define TAO_PEGTL_CONTRIB_UINT64_HPP
 
-#include "config.hpp"
+#include "../config.hpp"
+#include "../internal/result_on_found.hpp"
+#include "../internal/rules.hpp"
 
 #include "internal/peek_mask_uint.hpp"
 #include "internal/peek_uint.hpp"
-#include "internal/result_on_found.hpp"
-#include "internal/rules.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
 {
diff --git a/packages/PEGTL/include/tao/pegtl/uint8.hpp b/packages/PEGTL/include/tao/pegtl/contrib/uint8.hpp
similarity index 92%
rename from packages/PEGTL/include/tao/pegtl/uint8.hpp
rename to packages/PEGTL/include/tao/pegtl/contrib/uint8.hpp
index eec09683d24a5757d2b7cf49ec31eb3bb2c07243..fb094bec80b47d1ff5a12e4c8312e793320fe785 100644
--- a/packages/PEGTL/include/tao/pegtl/uint8.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/uint8.hpp
@@ -1,15 +1,15 @@
 // Copyright (c) 2018-2020 Dr. Colin Hirsch and Daniel Frey
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
-#ifndef TAO_PEGTL_UINT8_HPP
-#define TAO_PEGTL_UINT8_HPP
+#ifndef TAO_PEGTL_CONTRIB_UINT8_HPP
+#define TAO_PEGTL_CONTRIB_UINT8_HPP
 
-#include "config.hpp"
+#include "../config.hpp"
+#include "../internal/result_on_found.hpp"
+#include "../internal/rules.hpp"
 
 #include "internal/peek_mask_uint8.hpp"
 #include "internal/peek_uint8.hpp"
-#include "internal/result_on_found.hpp"
-#include "internal/rules.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::uint8
 {
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/unescape.hpp b/packages/PEGTL/include/tao/pegtl/contrib/unescape.hpp
index 3d185983c76e8ef79ff9c8cd6d7e92a775314d60..9aca033e8989c92d6b5f910af0cb04e902c14a6c 100644
--- a/packages/PEGTL/include/tao/pegtl/contrib/unescape.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/unescape.hpp
@@ -99,8 +99,8 @@ namespace TAO_PEGTL_NAMESPACE::unescape
 
    struct append_all
    {
-      template< typename Input >
-      static void apply( const Input& in, std::string& s )
+      template< typename ActionInput >
+      static void apply( const ActionInput& in, std::string& s )
       {
          s.append( in.begin(), in.size() );
       }
@@ -110,22 +110,22 @@ namespace TAO_PEGTL_NAMESPACE::unescape
    template< typename T, char... Rs >
    struct unescape_c
    {
-      template< typename Input >
-      static void apply( const Input& in, std::string& s )
+      template< typename ActionInput >
+      static void apply( const ActionInput& in, std::string& s )
       {
          assert( in.size() == 1 );
          s += apply_one( in, static_cast< const T* >( nullptr ) );
       }
 
-      template< typename Input, char... Qs >
-      [[nodiscard]] static char apply_one( const Input& in, const one< Qs... >* /*unused*/ )
+      template< typename ActionInput, char... Qs >
+      [[nodiscard]] static char apply_one( const ActionInput& in, const one< Qs... >* /*unused*/ )
       {
          static_assert( sizeof...( Qs ) == sizeof...( Rs ), "size mismatch between escaped characters and their mappings" );
          return apply_two( in, { Qs... }, { Rs... } );
       }
 
-      template< typename Input >
-      [[nodiscard]] static char apply_two( const Input& in, const std::initializer_list< char >& q, const std::initializer_list< char >& r )
+      template< typename ActionInput >
+      [[nodiscard]] static char apply_two( const ActionInput& in, const std::initializer_list< char >& q, const std::initializer_list< char >& r )
       {
          const char c = *in.begin();
          for( std::size_t i = 0; i < q.size(); ++i ) {
@@ -143,8 +143,8 @@ namespace TAO_PEGTL_NAMESPACE::unescape
 
    struct unescape_u
    {
-      template< typename Input >
-      static void apply( const Input& in, std::string& s )
+      template< typename ActionInput >
+      static void apply( const ActionInput& in, std::string& s )
       {
          assert( !in.empty() );  // First character MUST be present, usually 'u' or 'U'.
          if( !utf8_append_utf32( s, unhex_string< unsigned >( in.begin() + 1, in.end() ) ) ) {
@@ -155,8 +155,8 @@ namespace TAO_PEGTL_NAMESPACE::unescape
 
    struct unescape_x
    {
-      template< typename Input >
-      static void apply( const Input& in, std::string& s )
+      template< typename ActionInput >
+      static void apply( const ActionInput& in, std::string& s )
       {
          assert( !in.empty() );  // First character MUST be present, usually 'x'.
          s += unhex_string< char >( in.begin() + 1, in.end() );
@@ -173,8 +173,8 @@ namespace TAO_PEGTL_NAMESPACE::unescape
 
    struct unescape_j
    {
-      template< typename Input >
-      static void apply( const Input& in, std::string& s )
+      template< typename ActionInput >
+      static void apply( const ActionInput& in, std::string& s )
       {
          assert( ( ( in.size() + 1 ) % 6 ) == 0 );  // Expects multiple "\\u1234", starting with the first "u".
          for( const char* b = in.begin() + 1; b < in.end(); b += 6 ) {
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/uri.hpp b/packages/PEGTL/include/tao/pegtl/contrib/uri.hpp
index a15836f5824097e5e0a77fefc53a5abd5878aeb0..90e0a6d911d56af12dd61ead62d731849d3b090b 100644
--- a/packages/PEGTL/include/tao/pegtl/contrib/uri.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/uri.hpp
@@ -28,7 +28,7 @@ namespace TAO_PEGTL_NAMESPACE::uri
    using colon = one< ':' >;
 
    // clang-format off
-   struct dec_octet : integer::maximum_rule< std::uint8_t > {};
+   struct dec_octet : maximum_rule< std::uint8_t > {};
 
    struct IPv4address : seq< dec_octet, dot, dec_octet, dot, dec_octet, dot, dec_octet > {};
 
diff --git a/packages/PEGTL/include/tao/pegtl/utf16.hpp b/packages/PEGTL/include/tao/pegtl/contrib/utf16.hpp
similarity index 93%
rename from packages/PEGTL/include/tao/pegtl/utf16.hpp
rename to packages/PEGTL/include/tao/pegtl/contrib/utf16.hpp
index dee6e2e656b838aae54edab436801b0bfedcb846..499041408e5f3c501c798ac9afd7bfb7da728e51 100644
--- a/packages/PEGTL/include/tao/pegtl/utf16.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/utf16.hpp
@@ -1,14 +1,14 @@
 // Copyright (c) 2015-2020 Dr. Colin Hirsch and Daniel Frey
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
-#ifndef TAO_PEGTL_UTF16_HPP
-#define TAO_PEGTL_UTF16_HPP
+#ifndef TAO_PEGTL_CONTRIB_UTF16_HPP
+#define TAO_PEGTL_CONTRIB_UTF16_HPP
 
-#include "config.hpp"
+#include "../config.hpp"
+#include "../internal/result_on_found.hpp"
+#include "../internal/rules.hpp"
 
 #include "internal/peek_utf16.hpp"
-#include "internal/result_on_found.hpp"
-#include "internal/rules.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
 {
diff --git a/packages/PEGTL/include/tao/pegtl/utf32.hpp b/packages/PEGTL/include/tao/pegtl/contrib/utf32.hpp
similarity index 93%
rename from packages/PEGTL/include/tao/pegtl/utf32.hpp
rename to packages/PEGTL/include/tao/pegtl/contrib/utf32.hpp
index 1862ea625bb9260b477fefc262ba309f895a8a37..ce820fe2080169f4351bacf0c799cf47040d33f8 100644
--- a/packages/PEGTL/include/tao/pegtl/utf32.hpp
+++ b/packages/PEGTL/include/tao/pegtl/contrib/utf32.hpp
@@ -1,14 +1,14 @@
 // Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
-#ifndef TAO_PEGTL_UTF32_HPP
-#define TAO_PEGTL_UTF32_HPP
+#ifndef TAO_PEGTL_CONTRIB_UTF32_HPP
+#define TAO_PEGTL_CONTRIB_UTF32_HPP
 
-#include "config.hpp"
+#include "../config.hpp"
+#include "../internal/result_on_found.hpp"
+#include "../internal/rules.hpp"
 
 #include "internal/peek_utf32.hpp"
-#include "internal/result_on_found.hpp"
-#include "internal/rules.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
 {
diff --git a/packages/PEGTL/include/tao/pegtl/contrib/visit_rt.hpp b/packages/PEGTL/include/tao/pegtl/contrib/visit_rt.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..b4958e84399f2af15b0da7b940a2472fe52b16e2
--- /dev/null
+++ b/packages/PEGTL/include/tao/pegtl/contrib/visit_rt.hpp
@@ -0,0 +1,51 @@
+// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#ifndef TAO_PEGTL_CONTRIB_VISIT_RT_HPP
+#define TAO_PEGTL_CONTRIB_VISIT_RT_HPP
+
+#include <set>
+#include <string_view>
+
+#include "../config.hpp"
+#include "../type_list.hpp"
+
+#include "../internal/demangle.hpp"
+
+namespace TAO_PEGTL_NAMESPACE
+{
+   namespace internal
+   {
+      template< template< typename... > class Func, typename... Rules >
+      struct visitor_rt
+      {
+         template< typename... Args >
+         static void visit( std::set< std::string_view >& done, Args&&... args )
+         {
+            ( visit_rule< Rules >( typename Rules::subs_t(), done, args... ), ... );
+         }
+
+      private:
+         template< typename Rule, typename... Subs, typename... Args >
+         static void visit_rule( type_list< Subs... > /*unused*/, std::set< std::string_view >& done, Args&&... args )
+         {
+            if( done.emplace( demangle< Rule >() ).second ) {
+               Func< Rule >::visit( args... );
+               visitor_rt< Func, Subs... >::visit( done, args... );
+            }
+         }
+      };
+
+   }  // namespace internal
+
+   template< typename Rule, template< typename... > class Func, typename... Args >
+   std::size_t visit_rt( Args&&... args )
+   {
+      std::set< std::string_view > done;
+      internal::visitor_rt< Func, Rule >::visit( done, args... );
+      return done.size();
+   }
+
+}  // namespace TAO_PEGTL_NAMESPACE
+
+#endif
diff --git a/packages/PEGTL/include/tao/pegtl/disable_action.hpp b/packages/PEGTL/include/tao/pegtl/disable_action.hpp
index b3b1bb0614de436ac03ab9f4a486aecc196dc326..55872ff8b84902b4e75ea1927b821dedcaae232f 100644
--- a/packages/PEGTL/include/tao/pegtl/disable_action.hpp
+++ b/packages/PEGTL/include/tao/pegtl/disable_action.hpp
@@ -22,9 +22,9 @@ namespace TAO_PEGTL_NAMESPACE
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
       {
          return TAO_PEGTL_NAMESPACE::match< Rule, apply_mode::nothing, M, Action, Control >( in, st... );
       }
diff --git a/packages/PEGTL/include/tao/pegtl/discard_input.hpp b/packages/PEGTL/include/tao/pegtl/discard_input.hpp
index 9f9c23c7c71a912d4c4e3352f419315d4cef0dca..abf65fee56abe269d691123cc1bd3815dd05f83c 100644
--- a/packages/PEGTL/include/tao/pegtl/discard_input.hpp
+++ b/packages/PEGTL/include/tao/pegtl/discard_input.hpp
@@ -22,9 +22,9 @@ namespace TAO_PEGTL_NAMESPACE
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
       {
          const bool result = TAO_PEGTL_NAMESPACE::match< Rule, A, M, Action, Control >( in, st... );
          in.discard();
diff --git a/packages/PEGTL/include/tao/pegtl/discard_input_on_failure.hpp b/packages/PEGTL/include/tao/pegtl/discard_input_on_failure.hpp
index da7af0a7d4dd893546046504ea6d6c0e5e805455..d3596095e606c3ab0732d5642591cf62d668b204 100644
--- a/packages/PEGTL/include/tao/pegtl/discard_input_on_failure.hpp
+++ b/packages/PEGTL/include/tao/pegtl/discard_input_on_failure.hpp
@@ -22,9 +22,9 @@ namespace TAO_PEGTL_NAMESPACE
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
       {
          const bool result = TAO_PEGTL_NAMESPACE::match< Rule, A, M, Action, Control >( in, st... );
          if( !result ) {
diff --git a/packages/PEGTL/include/tao/pegtl/discard_input_on_success.hpp b/packages/PEGTL/include/tao/pegtl/discard_input_on_success.hpp
index 201b095542f74128be8120298d6a484b7adc8562..5c1ee85a3a5a1d7f6b577a8ee888ee43ef8ee85e 100644
--- a/packages/PEGTL/include/tao/pegtl/discard_input_on_success.hpp
+++ b/packages/PEGTL/include/tao/pegtl/discard_input_on_success.hpp
@@ -22,9 +22,9 @@ namespace TAO_PEGTL_NAMESPACE
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
       {
          const bool result = TAO_PEGTL_NAMESPACE::match< Rule, A, M, Action, Control >( in, st... );
          if( result ) {
diff --git a/packages/PEGTL/include/tao/pegtl/enable_action.hpp b/packages/PEGTL/include/tao/pegtl/enable_action.hpp
index f51a39bb743314f78b775a3347f328690c73416e..8492df7a46da0e4c802cdc64e4f05c972fb22035 100644
--- a/packages/PEGTL/include/tao/pegtl/enable_action.hpp
+++ b/packages/PEGTL/include/tao/pegtl/enable_action.hpp
@@ -22,9 +22,9 @@ namespace TAO_PEGTL_NAMESPACE
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
       {
          return TAO_PEGTL_NAMESPACE::match< Rule, apply_mode::action, M, Action, Control >( in, st... );
       }
diff --git a/packages/PEGTL/include/tao/pegtl/internal/action.hpp b/packages/PEGTL/include/tao/pegtl/internal/action.hpp
index 7dc03e47f26c4ee11f4e08051e08425bbd58bdfe..74e2f418b4efc4927a254b140c5f35819d8ddfeb 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/action.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/action.hpp
@@ -6,13 +6,13 @@
 
 #include "../config.hpp"
 
+#include "enable_control.hpp"
 #include "seq.hpp"
-#include "skip_control.hpp"
+#include "success.hpp"
 
 #include "../apply_mode.hpp"
 #include "../rewind_mode.hpp"
-
-#include "../analysis/generic.hpp"
+#include "../type_list.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
@@ -21,10 +21,16 @@ namespace TAO_PEGTL_NAMESPACE::internal
       : action< Action, seq< Rules... > >
    {};
 
+   template< template< typename... > class Action >
+   struct action< Action >
+      : success
+   {};
+
    template< template< typename... > class Action, typename Rule >
    struct action< Action, Rule >
    {
-      using analyze_t = analysis::generic< analysis::rule_type::seq, Rule >;
+      using rule_t = action;
+      using subs_t = type_list< Rule >;
 
       template< apply_mode A,
                 rewind_mode M,
@@ -32,16 +38,16 @@ namespace TAO_PEGTL_NAMESPACE::internal
                 class,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
       {
          return Control< Rule >::template match< A, M, Action, Control >( in, st... );
       }
    };
 
    template< template< typename... > class Action, typename... Rules >
-   inline constexpr bool skip_control< action< Action, Rules... > > = true;
+   inline constexpr bool enable_control< action< Action, Rules... > > = false;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/action_input.hpp b/packages/PEGTL/include/tao/pegtl/internal/action_input.hpp
index 051b1753be03654730f0a41685dd18a02563237c..3fff69687738b60a96f4b607a77d0a686929673b 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/action_input.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/action_input.hpp
@@ -16,14 +16,14 @@
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
-   template< typename Input >
+   template< typename ParseInput >
    class action_input
    {
    public:
-      using input_t = Input;
-      using iterator_t = typename Input::iterator_t;
+      using input_t = ParseInput;
+      using iterator_t = typename ParseInput::iterator_t;
 
-      action_input( const iterator_t& in_begin, const Input& in_input ) noexcept
+      action_input( const iterator_t& in_begin, const ParseInput& in_input ) noexcept
          : m_begin( in_begin ),
            m_input( in_input )
       {}
@@ -41,7 +41,7 @@ namespace TAO_PEGTL_NAMESPACE::internal
          return m_begin;
       }
 
-      [[nodiscard]] const Input& input() const noexcept
+      [[nodiscard]] const ParseInput& input() const noexcept
       {
          return m_input;
       }
@@ -98,7 +98,7 @@ namespace TAO_PEGTL_NAMESPACE::internal
 
    protected:
       const iterator_t m_begin;
-      const Input& m_input;
+      const ParseInput& m_input;
    };
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
diff --git a/packages/PEGTL/include/tao/pegtl/internal/any.hpp b/packages/PEGTL/include/tao/pegtl/internal/any.hpp
index d3f4d887cc359f2d01dc7d62950225fe9fd503dc..927f257ca931cdf411f04e0328fc3ec051df3aa1 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/any.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/any.hpp
@@ -6,10 +6,10 @@
 
 #include "../config.hpp"
 
+#include "enable_control.hpp"
 #include "peek_char.hpp"
-#include "skip_control.hpp"
 
-#include "../analysis/generic.hpp"
+#include "../type_list.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
@@ -19,10 +19,11 @@ namespace TAO_PEGTL_NAMESPACE::internal
    template<>
    struct any< peek_char >
    {
-      using analyze_t = analysis::generic< analysis::rule_type::any >;
+      using rule_t = any;
+      using subs_t = empty_list;
 
-      template< typename Input >
-      [[nodiscard]] static bool match( Input& in ) noexcept( noexcept( in.empty() ) )
+      template< typename ParseInput >
+      [[nodiscard]] static bool match( ParseInput& in ) noexcept( noexcept( in.empty() ) )
       {
          if( !in.empty() ) {
             in.bump();
@@ -35,23 +36,22 @@ namespace TAO_PEGTL_NAMESPACE::internal
    template< typename Peek >
    struct any
    {
-      using analyze_t = analysis::generic< analysis::rule_type::any >;
+      using rule_t = any;
+      using subs_t = empty_list;
 
-      template< typename Input >
-      [[nodiscard]] static bool match( Input& in ) noexcept( noexcept( in.size( Peek::max_input_size ) ) )
+      template< typename ParseInput >
+      [[nodiscard]] static bool match( ParseInput& in ) noexcept( noexcept( Peek::peek( in ) ) )
       {
-         if( const std::size_t s = in.size( Peek::max_input_size ); s >= Peek::min_input_size ) {
-            if( const auto t = Peek::peek( in, s ) ) {
-               in.bump( t.size );
-               return true;
-            }
+         if( const auto t = Peek::peek( in ) ) {
+            in.bump( t.size );
+            return true;
          }
          return false;
       }
    };
 
    template< typename Peek >
-   inline constexpr bool skip_control< any< Peek > > = true;
+   inline constexpr bool enable_control< any< Peek > > = false;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/apply.hpp b/packages/PEGTL/include/tao/pegtl/internal/apply.hpp
index 0b8b51f666f92c6c29309583a846afba7f46b2d5..92e24ef26b528eb3a8370ff88ff577b45529e461 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/apply.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/apply.hpp
@@ -7,18 +7,19 @@
 #include "../config.hpp"
 
 #include "apply_single.hpp"
-#include "skip_control.hpp"
+#include "enable_control.hpp"
 
-#include "../analysis/counted.hpp"
 #include "../apply_mode.hpp"
 #include "../rewind_mode.hpp"
+#include "../type_list.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
    template< typename... Actions >
    struct apply
    {
-      using analyze_t = analysis::counted< analysis::rule_type::any, 0 >;
+      using rule_t = apply;
+      using subs_t = empty_list;
 
       template< apply_mode A,
                 rewind_mode M,
@@ -26,12 +27,12 @@ namespace TAO_PEGTL_NAMESPACE::internal
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
       {
          if constexpr( ( A == apply_mode::action ) && ( sizeof...( Actions ) > 0 ) ) {
-            using action_t = typename Input::action_t;
+            using action_t = typename ParseInput::action_t;
             const action_t i2( in.iterator(), in );  // No data -- range is from begin to begin.
             return ( apply_single< Actions >::match( i2, st... ) && ... );
          }
@@ -46,7 +47,7 @@ namespace TAO_PEGTL_NAMESPACE::internal
    };
 
    template< typename... Actions >
-   inline constexpr bool skip_control< apply< Actions... > > = true;
+   inline constexpr bool enable_control< apply< Actions... > > = false;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/apply0.hpp b/packages/PEGTL/include/tao/pegtl/internal/apply0.hpp
index 70b1df947916116ec1a6ae291791b9f7402e3566..3ad4b3c2a2800ca4d5e5cc047dc7fcfb469ae417 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/apply0.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/apply0.hpp
@@ -7,18 +7,19 @@
 #include "../config.hpp"
 
 #include "apply0_single.hpp"
-#include "skip_control.hpp"
+#include "enable_control.hpp"
 
-#include "../analysis/counted.hpp"
 #include "../apply_mode.hpp"
 #include "../rewind_mode.hpp"
+#include "../type_list.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
    template< typename... Actions >
    struct apply0
    {
-      using analyze_t = analysis::counted< analysis::rule_type::any, 0 >;
+      using rule_t = apply0;
+      using subs_t = empty_list;
 
       template< apply_mode A,
                 rewind_mode M,
@@ -26,9 +27,9 @@ namespace TAO_PEGTL_NAMESPACE::internal
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( Input& /*unused*/, States&&... st )
+      [[nodiscard]] static bool match( ParseInput& /*unused*/, States&&... st )
       {
          if constexpr( A == apply_mode::action ) {
             return ( apply0_single< Actions >::match( st... ) && ... );
@@ -43,7 +44,7 @@ namespace TAO_PEGTL_NAMESPACE::internal
    };
 
    template< typename... Actions >
-   inline constexpr bool skip_control< apply0< Actions... > > = true;
+   inline constexpr bool enable_control< apply0< Actions... > > = false;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/apply_single.hpp b/packages/PEGTL/include/tao/pegtl/internal/apply_single.hpp
index 8a1b54f08295d0d753b161f1dc3f6e253e0cc3da..7120cd0ac2952271b8f1aace7c22a9cbae01d9b7 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/apply_single.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/apply_single.hpp
@@ -13,16 +13,16 @@ namespace TAO_PEGTL_NAMESPACE::internal
    template< typename Action >
    struct apply_single
    {
-      template< typename Input, typename... States >
-      [[nodiscard]] static auto match( const Input& in, States&&... st ) noexcept( noexcept( Action::apply( in, st... ) ) )
+      template< typename ActionInput, typename... States >
+      [[nodiscard]] static auto match( const ActionInput& in, States&&... st ) noexcept( noexcept( Action::apply( in, st... ) ) )
          -> std::enable_if_t< std::is_same_v< decltype( Action::apply( in, st... ) ), void >, bool >
       {
          Action::apply( in, st... );
          return true;
       }
 
-      template< typename Input, typename... States >
-      [[nodiscard]] static auto match( const Input& in, States&&... st ) noexcept( noexcept( Action::apply( in, st... ) ) )
+      template< typename ActionInput, typename... States >
+      [[nodiscard]] static auto match( const ActionInput& in, States&&... st ) noexcept( noexcept( Action::apply( in, st... ) ) )
          -> std::enable_if_t< std::is_same_v< decltype( Action::apply( in, st... ) ), bool >, bool >
       {
          return Action::apply( in, st... );
diff --git a/packages/PEGTL/include/tao/pegtl/internal/at.hpp b/packages/PEGTL/include/tao/pegtl/internal/at.hpp
index 8e360c8a1d200f9b676c5375fb113ab49bf78364..df853f71ef7c070f66ab69ad8d0a3f253e07382e 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/at.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/at.hpp
@@ -6,14 +6,13 @@
 
 #include "../config.hpp"
 
+#include "enable_control.hpp"
 #include "seq.hpp"
-#include "skip_control.hpp"
-#include "trivial.hpp"
+#include "success.hpp"
 
 #include "../apply_mode.hpp"
 #include "../rewind_mode.hpp"
-
-#include "../analysis/generic.hpp"
+#include "../type_list.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
@@ -24,13 +23,14 @@ namespace TAO_PEGTL_NAMESPACE::internal
 
    template<>
    struct at<>
-      : trivial< true >
+      : success
    {};
 
    template< typename Rule >
    struct at< Rule >
    {
-      using analyze_t = analysis::generic< analysis::rule_type::opt, Rule >;
+      using rule_t = at;
+      using subs_t = type_list< Rule >;
 
       template< apply_mode,
                 rewind_mode,
@@ -38,9 +38,9 @@ namespace TAO_PEGTL_NAMESPACE::internal
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
       {
          const auto m = in.template mark< rewind_mode::required >();
          return Control< Rule >::template match< apply_mode::nothing, rewind_mode::active, Action, Control >( in, st... );
@@ -48,7 +48,7 @@ namespace TAO_PEGTL_NAMESPACE::internal
    };
 
    template< typename... Rules >
-   inline constexpr bool skip_control< at< Rules... > > = true;
+   inline constexpr bool enable_control< at< Rules... > > = false;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/bof.hpp b/packages/PEGTL/include/tao/pegtl/internal/bof.hpp
index de82db37599c2344b4545b7735d6c1723a39fa4a..19367f5091cac287d85fa95c4a138ba0d81784e5 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/bof.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/bof.hpp
@@ -6,25 +6,26 @@
 
 #include "../config.hpp"
 
-#include "skip_control.hpp"
+#include "enable_control.hpp"
 
-#include "../analysis/generic.hpp"
+#include "../type_list.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
    struct bof
    {
-      using analyze_t = analysis::generic< analysis::rule_type::opt >;
+      using rule_t = bof;
+      using subs_t = empty_list;
 
-      template< typename Input >
-      [[nodiscard]] static bool match( Input& in ) noexcept
+      template< typename ParseInput >
+      [[nodiscard]] static bool match( ParseInput& in ) noexcept
       {
          return in.byte() == 0;
       }
    };
 
    template<>
-   inline constexpr bool skip_control< bof > = true;
+   inline constexpr bool enable_control< bof > = false;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/bol.hpp b/packages/PEGTL/include/tao/pegtl/internal/bol.hpp
index 691908fd355ac965aacf00003fa2892b17ca8638..3304cc5d4ff47005570e420c66ed86cc1bb3ce52 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/bol.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/bol.hpp
@@ -6,25 +6,26 @@
 
 #include "../config.hpp"
 
-#include "skip_control.hpp"
+#include "enable_control.hpp"
 
-#include "../analysis/generic.hpp"
+#include "../type_list.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
    struct bol
    {
-      using analyze_t = analysis::generic< analysis::rule_type::opt >;
+      using rule_t = bol;
+      using subs_t = empty_list;
 
-      template< typename Input >
-      [[nodiscard]] static bool match( Input& in ) noexcept
+      template< typename ParseInput >
+      [[nodiscard]] static bool match( ParseInput& in ) noexcept
       {
          return in.byte_in_line() == 0;
       }
    };
 
    template<>
-   inline constexpr bool skip_control< bol > = true;
+   inline constexpr bool enable_control< bol > = false;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/bump_help.hpp b/packages/PEGTL/include/tao/pegtl/internal/bump_help.hpp
index f6420c3ce22e13df27964401d7467675253556bc..dc9a1779d8834e5f1117e8c72890bcf5b5fd84a1 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/bump_help.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/bump_help.hpp
@@ -13,10 +13,10 @@
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
-   template< result_on_found R, typename Input, typename Char, Char... Cs >
-   void bump_help( Input& in, const std::size_t count ) noexcept
+   template< result_on_found R, typename ParseInput, typename Char, Char... Cs >
+   void bump_help( ParseInput& in, const std::size_t count ) noexcept
    {
-      if constexpr( ( ( Cs != Input::eol_t::ch ) && ... ) != bool( R ) ) {
+      if constexpr( ( ( Cs != ParseInput::eol_t::ch ) && ... ) != bool( R ) ) {
          in.bump( count );
       }
       else {
diff --git a/packages/PEGTL/include/tao/pegtl/internal/bytes.hpp b/packages/PEGTL/include/tao/pegtl/internal/bytes.hpp
index 7d6a4e630adc6fe651032c1bf8c7e789c05d048f..7bd29960effd86c508a82d95dea7a1697526a89c 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/bytes.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/bytes.hpp
@@ -6,30 +6,37 @@
 
 #include "../config.hpp"
 
-#include "skip_control.hpp"
+#include "enable_control.hpp"
+#include "success.hpp"
 
-#include "../analysis/counted.hpp"
+#include "../type_list.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
-   template< unsigned Num >
+   template< unsigned Cnt >
    struct bytes
    {
-      using analyze_t = analysis::counted< analysis::rule_type::any, Num >;
+      using rule_t = bytes;
+      using subs_t = empty_list;
 
-      template< typename Input >
-      [[nodiscard]] static bool match( Input& in ) noexcept( noexcept( in.size( 0 ) ) )
+      template< typename ParseInput >
+      [[nodiscard]] static bool match( ParseInput& in ) noexcept( noexcept( in.size( 0 ) ) )
       {
-         if( in.size( Num ) >= Num ) {
-            in.bump( Num );
+         if( in.size( Cnt ) >= Cnt ) {
+            in.bump( Cnt );
             return true;
          }
          return false;
       }
    };
 
-   template< unsigned Num >
-   inline constexpr bool skip_control< bytes< Num > > = true;
+   template<>
+   struct bytes< 0 >
+      : success
+   {};
+
+   template< unsigned Cnt >
+   inline constexpr bool enable_control< bytes< Cnt > > = false;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/control.hpp b/packages/PEGTL/include/tao/pegtl/internal/control.hpp
index 8197becd7d69d329e1ba52696782d9551c1d9540..119c98a99f98fae6383d0a2b5c400de5b75c84b3 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/control.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/control.hpp
@@ -6,13 +6,13 @@
 
 #include "../config.hpp"
 
+#include "enable_control.hpp"
 #include "seq.hpp"
-#include "skip_control.hpp"
+#include "success.hpp"
 
 #include "../apply_mode.hpp"
 #include "../rewind_mode.hpp"
-
-#include "../analysis/generic.hpp"
+#include "../type_list.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
@@ -21,10 +21,16 @@ namespace TAO_PEGTL_NAMESPACE::internal
       : control< Control, seq< Rules... > >
    {};
 
+   template< template< typename... > class Control >
+   struct control< Control >
+      : success
+   {};
+
    template< template< typename... > class Control, typename Rule >
    struct control< Control, Rule >
    {
-      using analyze_t = analysis::generic< analysis::rule_type::seq, Rule >;
+      using rule_t = control;
+      using subs_t = type_list< Rule >;
 
       template< apply_mode A,
                 rewind_mode M,
@@ -32,16 +38,16 @@ namespace TAO_PEGTL_NAMESPACE::internal
                 class Action,
                 template< typename... >
                 class,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
       {
          return Control< Rule >::template match< A, M, Action, Control >( in, st... );
       }
    };
 
    template< template< typename... > class Control, typename... Rules >
-   inline constexpr bool skip_control< control< Control, Rules... > > = true;
+   inline constexpr bool enable_control< control< Control, Rules... > > = false;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/cr_crlf_eol.hpp b/packages/PEGTL/include/tao/pegtl/internal/cr_crlf_eol.hpp
index 0b143178895bb75cb26e590678bd919f4b2e3ffc..201842bbd1ec4aa80848b46c2d76b3f72980ff27 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/cr_crlf_eol.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/cr_crlf_eol.hpp
@@ -13,8 +13,8 @@ namespace TAO_PEGTL_NAMESPACE::internal
    {
       static constexpr int ch = '\r';
 
-      template< typename Input >
-      [[nodiscard]] static eol_pair match( Input& in ) noexcept( noexcept( in.size( 2 ) ) )
+      template< typename ParseInput >
+      [[nodiscard]] static eol_pair match( ParseInput& in ) noexcept( noexcept( in.size( 2 ) ) )
       {
          eol_pair p = { false, in.size( 2 ) };
          if( p.second ) {
diff --git a/packages/PEGTL/include/tao/pegtl/internal/cr_eol.hpp b/packages/PEGTL/include/tao/pegtl/internal/cr_eol.hpp
index e9ed68492ddd245b5f4b4883d1a5ffbdc0da3c1a..859dd7f30ba2d17260aaefcdd601c40af664db06 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/cr_eol.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/cr_eol.hpp
@@ -13,8 +13,8 @@ namespace TAO_PEGTL_NAMESPACE::internal
    {
       static constexpr int ch = '\r';
 
-      template< typename Input >
-      [[nodiscard]] static eol_pair match( Input& in ) noexcept( noexcept( in.size( 1 ) ) )
+      template< typename ParseInput >
+      [[nodiscard]] static eol_pair match( ParseInput& in ) noexcept( noexcept( in.size( 1 ) ) )
       {
          eol_pair p = { false, in.size( 1 ) };
          if( p.second ) {
diff --git a/packages/PEGTL/include/tao/pegtl/internal/crlf_eol.hpp b/packages/PEGTL/include/tao/pegtl/internal/crlf_eol.hpp
index b9104d998cf7771952b6ae3f4493ebf430bdcb37..7a9ad5aa77d9beb238045c67f0a5e57d4e40436c 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/crlf_eol.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/crlf_eol.hpp
@@ -13,8 +13,8 @@ namespace TAO_PEGTL_NAMESPACE::internal
    {
       static constexpr int ch = '\n';
 
-      template< typename Input >
-      [[nodiscard]] static eol_pair match( Input& in ) noexcept( noexcept( in.size( 2 ) ) )
+      template< typename ParseInput >
+      [[nodiscard]] static eol_pair match( ParseInput& in ) noexcept( noexcept( in.size( 2 ) ) )
       {
          eol_pair p = { false, in.size( 2 ) };
          if( p.second > 1 ) {
diff --git a/packages/PEGTL/include/tao/pegtl/internal/always_false.hpp b/packages/PEGTL/include/tao/pegtl/internal/dependent_false.hpp
similarity index 63%
rename from packages/PEGTL/include/tao/pegtl/internal/always_false.hpp
rename to packages/PEGTL/include/tao/pegtl/internal/dependent_false.hpp
index cfeb7d1c9f0e2cace5ebfd0e93161dcba3f14725..421dc496c32bfb0feec765db76617f9a38fd0a01 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/always_false.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/dependent_false.hpp
@@ -1,19 +1,15 @@
 // Copyright (c) 2018-2020 Dr. Colin Hirsch and Daniel Frey
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
-#ifndef TAO_PEGTL_INTERNAL_ALWAYS_FALSE_HPP
-#define TAO_PEGTL_INTERNAL_ALWAYS_FALSE_HPP
+#ifndef TAO_PEGTL_INTERNAL_DEPENDENT_FALSE_HPP
+#define TAO_PEGTL_INTERNAL_DEPENDENT_FALSE_HPP
 
 #include "../config.hpp"
 
-#include <type_traits>
-
 namespace TAO_PEGTL_NAMESPACE::internal
 {
    template< typename... >
-   struct always_false
-      : std::false_type
-   {};
+   inline constexpr bool dependent_false = false;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/disable.hpp b/packages/PEGTL/include/tao/pegtl/internal/disable.hpp
index 556220d350dafe72c52f869ab6bda0a2ac3f026f..727f5eafd2b5839909b5c42a930d41e1577a8dab 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/disable.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/disable.hpp
@@ -6,13 +6,13 @@
 
 #include "../config.hpp"
 
+#include "enable_control.hpp"
 #include "seq.hpp"
-#include "skip_control.hpp"
+#include "success.hpp"
 
 #include "../apply_mode.hpp"
 #include "../rewind_mode.hpp"
-
-#include "../analysis/generic.hpp"
+#include "../type_list.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
@@ -21,10 +21,16 @@ namespace TAO_PEGTL_NAMESPACE::internal
       : disable< seq< Rules... > >
    {};
 
+   template<>
+   struct disable<>
+      : success
+   {};
+
    template< typename Rule >
    struct disable< Rule >
    {
-      using analyze_t = analysis::generic< analysis::rule_type::seq, Rule >;
+      using rule_t = disable;
+      using subs_t = type_list< Rule >;
 
       template< apply_mode,
                 rewind_mode M,
@@ -32,16 +38,16 @@ namespace TAO_PEGTL_NAMESPACE::internal
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
       {
          return Control< Rule >::template match< apply_mode::nothing, M, Action, Control >( in, st... );
       }
    };
 
    template< typename... Rules >
-   inline constexpr bool skip_control< disable< Rules... > > = true;
+   inline constexpr bool enable_control< disable< Rules... > > = false;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/discard.hpp b/packages/PEGTL/include/tao/pegtl/internal/discard.hpp
index 410cfb6839b792c79a21e443a5e0e3b0951dbb80..2b0b55af1ae691acbc0d390e7ff0892d6cd1bbe7 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/discard.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/discard.hpp
@@ -6,18 +6,19 @@
 
 #include "../config.hpp"
 
-#include "skip_control.hpp"
+#include "enable_control.hpp"
 
-#include "../analysis/generic.hpp"
+#include "../type_list.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
    struct discard
    {
-      using analyze_t = analysis::generic< analysis::rule_type::opt >;
+      using rule_t = discard;
+      using subs_t = empty_list;
 
-      template< typename Input >
-      [[nodiscard]] static bool match( Input& in ) noexcept
+      template< typename ParseInput >
+      [[nodiscard]] static bool match( ParseInput& in ) noexcept
       {
          static_assert( noexcept( in.discard() ) );
          in.discard();
@@ -26,7 +27,7 @@ namespace TAO_PEGTL_NAMESPACE::internal
    };
 
    template<>
-   inline constexpr bool skip_control< discard > = true;
+   inline constexpr bool enable_control< discard > = false;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/duseltronik.hpp b/packages/PEGTL/include/tao/pegtl/internal/duseltronik.hpp
index d6bb64bd507f15a48416f5d2911dd10c26c1589b..53555e9faf04b63311c39eb15234fb35a9518db2 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/duseltronik.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/duseltronik.hpp
@@ -36,15 +36,15 @@ namespace TAO_PEGTL_NAMESPACE::internal
              class Control >
    struct duseltronik< Rule, A, M, Action, Control, dusel_mode::nothing >
    {
-      template< typename Input, typename... States >
-      [[nodiscard]] static auto match( Input& in, States&&... st )
+      template< typename ParseInput, typename... States >
+      [[nodiscard]] static auto match( 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 Input, typename... States, int = 1 >
-      [[nodiscard]] static auto match( Input& in, States&&... /*unused*/ )
+      template< typename ParseInput, typename... States, int = 1 >
+      [[nodiscard]] static auto match( ParseInput& in, States&&... /*unused*/ )
          -> decltype( Rule::match( in ) )
       {
          return Rule::match( in );
@@ -60,16 +60,16 @@ namespace TAO_PEGTL_NAMESPACE::internal
              class Control >
    struct duseltronik< Rule, A, M, Action, Control, dusel_mode::control >
    {
-      template< typename Input, typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      template< typename ParseInput, typename... States >
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
       {
-         Control< Rule >::start( static_cast< const Input& >( in ), st... );
+         Control< Rule >::start( static_cast< const ParseInput& >( in ), st... );
 
          if( duseltronik< Rule, A, M, Action, Control, dusel_mode::nothing >::match( in, st... ) ) {
-            Control< Rule >::success( static_cast< const Input& >( in ), st... );
+            Control< Rule >::success( static_cast< const ParseInput& >( in ), st... );
             return true;
          }
-         Control< Rule >::failure( static_cast< const Input& >( in ), st... );
+         Control< Rule >::failure( static_cast< const ParseInput& >( in ), st... );
          return false;
       }
    };
@@ -83,19 +83,19 @@ namespace TAO_PEGTL_NAMESPACE::internal
              class Control >
    struct duseltronik< Rule, A, M, Action, Control, dusel_mode::control_and_apply_void >
    {
-      template< typename Input, typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      template< typename ParseInput, typename... States >
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
       {
          auto m = in.template mark< rewind_mode::required >();
 
-         Control< Rule >::start( static_cast< const Input& >( in ), st... );
+         Control< Rule >::start( static_cast< const ParseInput& >( in ), st... );
 
          if( duseltronik< Rule, A, rewind_mode::active, Action, Control, dusel_mode::nothing >::match( in, st... ) ) {
-            Control< Rule >::template apply< Action >( m.iterator(), static_cast< const Input& >( in ), st... );
-            Control< Rule >::success( static_cast< const Input& >( in ), st... );
+            Control< Rule >::template apply< Action >( m.iterator(), static_cast< const ParseInput& >( in ), st... );
+            Control< Rule >::success( static_cast< const ParseInput& >( in ), st... );
             return m( true );
          }
-         Control< Rule >::failure( static_cast< const Input& >( in ), st... );
+         Control< Rule >::failure( static_cast< const ParseInput& >( in ), st... );
          return false;
       }
    };
@@ -109,20 +109,20 @@ namespace TAO_PEGTL_NAMESPACE::internal
              class Control >
    struct duseltronik< Rule, A, M, Action, Control, dusel_mode::control_and_apply_bool >
    {
-      template< typename Input, typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      template< typename ParseInput, typename... States >
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
       {
          auto m = in.template mark< rewind_mode::required >();
 
-         Control< Rule >::start( static_cast< const Input& >( in ), st... );
+         Control< Rule >::start( static_cast< const ParseInput& >( in ), st... );
 
          if( duseltronik< Rule, A, rewind_mode::active, Action, Control, dusel_mode::nothing >::match( in, st... ) ) {
-            if( Control< Rule >::template apply< Action >( m.iterator(), static_cast< const Input& >( in ), st... ) ) {
-               Control< Rule >::success( static_cast< const Input& >( in ), st... );
+            if( Control< Rule >::template apply< Action >( m.iterator(), static_cast< const ParseInput& >( in ), st... ) ) {
+               Control< Rule >::success( static_cast< const ParseInput& >( in ), st... );
                return m( true );
             }
          }
-         Control< Rule >::failure( static_cast< const Input& >( in ), st... );
+         Control< Rule >::failure( static_cast< const ParseInput& >( in ), st... );
          return false;
       }
    };
@@ -136,17 +136,17 @@ namespace TAO_PEGTL_NAMESPACE::internal
              class Control >
    struct duseltronik< Rule, A, M, Action, Control, dusel_mode::control_and_apply0_void >
    {
-      template< typename Input, typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      template< typename ParseInput, typename... States >
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
       {
-         Control< Rule >::start( static_cast< const Input& >( in ), st... );
+         Control< Rule >::start( static_cast< const ParseInput& >( in ), st... );
 
          if( duseltronik< Rule, A, M, Action, Control, dusel_mode::nothing >::match( in, st... ) ) {
-            Control< Rule >::template apply0< Action >( static_cast< const Input& >( in ), st... );
-            Control< Rule >::success( static_cast< const Input& >( in ), st... );
+            Control< Rule >::template apply0< Action >( static_cast< const ParseInput& >( in ), st... );
+            Control< Rule >::success( static_cast< const ParseInput& >( in ), st... );
             return true;
          }
-         Control< Rule >::failure( static_cast< const Input& >( in ), st... );
+         Control< Rule >::failure( static_cast< const ParseInput& >( in ), st... );
          return false;
       }
    };
@@ -160,20 +160,20 @@ namespace TAO_PEGTL_NAMESPACE::internal
              class Control >
    struct duseltronik< Rule, A, M, Action, Control, dusel_mode::control_and_apply0_bool >
    {
-      template< typename Input, typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      template< typename ParseInput, typename... States >
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
       {
          auto m = in.template mark< rewind_mode::required >();
 
-         Control< Rule >::start( static_cast< const Input& >( in ), st... );
+         Control< Rule >::start( static_cast< const ParseInput& >( in ), st... );
 
          if( duseltronik< Rule, A, rewind_mode::active, Action, Control, dusel_mode::nothing >::match( in, st... ) ) {
-            if( Control< Rule >::template apply0< Action >( static_cast< const Input& >( in ), st... ) ) {
-               Control< Rule >::success( static_cast< const Input& >( in ), st... );
+            if( Control< Rule >::template apply0< Action >( static_cast< const ParseInput& >( in ), st... ) ) {
+               Control< Rule >::success( static_cast< const ParseInput& >( in ), st... );
                return m( true );
             }
          }
-         Control< Rule >::failure( static_cast< const Input& >( in ), st... );
+         Control< Rule >::failure( static_cast< const ParseInput& >( in ), st... );
          return false;
       }
    };
diff --git a/packages/PEGTL/include/tao/pegtl/internal/enable.hpp b/packages/PEGTL/include/tao/pegtl/internal/enable.hpp
index 88e3ee1767cee22d61bd5e67ff297edcaf3ac84e..e30e97b8a3bc92b886870feb23b43725dfb4e4dc 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/enable.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/enable.hpp
@@ -6,13 +6,13 @@
 
 #include "../config.hpp"
 
+#include "enable_control.hpp"
 #include "seq.hpp"
-#include "skip_control.hpp"
+#include "success.hpp"
 
 #include "../apply_mode.hpp"
 #include "../rewind_mode.hpp"
-
-#include "../analysis/generic.hpp"
+#include "../type_list.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
@@ -21,10 +21,16 @@ namespace TAO_PEGTL_NAMESPACE::internal
       : enable< seq< Rules... > >
    {};
 
+   template<>
+   struct enable<>
+      : success
+   {};
+
    template< typename Rule >
    struct enable< Rule >
    {
-      using analyze_t = analysis::generic< analysis::rule_type::seq, Rule >;
+      using rule_t = enable;
+      using subs_t = type_list< Rule >;
 
       template< apply_mode,
                 rewind_mode M,
@@ -32,16 +38,16 @@ namespace TAO_PEGTL_NAMESPACE::internal
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
       {
          return Control< Rule >::template match< apply_mode::action, M, Action, Control >( in, st... );
       }
    };
 
    template< typename... Rules >
-   inline constexpr bool skip_control< enable< Rules... > > = true;
+   inline constexpr bool enable_control< enable< Rules... > > = false;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/skip_control.hpp b/packages/PEGTL/include/tao/pegtl/internal/enable_control.hpp
similarity index 67%
rename from packages/PEGTL/include/tao/pegtl/internal/skip_control.hpp
rename to packages/PEGTL/include/tao/pegtl/internal/enable_control.hpp
index d2a37ad624df63a9be00ede1158c523b0bd66148..d424b5d79e460a4bdc2f6d3f8a187a8fa6259650 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/skip_control.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/enable_control.hpp
@@ -1,8 +1,8 @@
 // Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
-#ifndef TAO_PEGTL_INTERNAL_SKIP_CONTROL_HPP
-#define TAO_PEGTL_INTERNAL_SKIP_CONTROL_HPP
+#ifndef TAO_PEGTL_INTERNAL_ENABLE_CONTROL_HPP
+#define TAO_PEGTL_INTERNAL_ENABLE_CONTROL_HPP
 
 #include <type_traits>
 
@@ -11,14 +11,14 @@
 namespace TAO_PEGTL_NAMESPACE::internal
 {
    // This class is a simple tagging mechanism.
-   // By default, skip_control< Rule > is  'false'.
+   // By default, enable_control< Rule > is  'true'.
    // Each internal (!) rule that should be hidden
    // from the control and action class' callbacks
-   // simply specializes skip_control<> to return
+   // simply specializes enable_control<> to return
    // 'true' for the above expression.
 
    template< typename Rule >
-   inline constexpr bool skip_control = false;
+   inline constexpr bool enable_control = true;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/eof.hpp b/packages/PEGTL/include/tao/pegtl/internal/eof.hpp
index 30f053ef4154811882e1268690b02e4d744fa042..7dddc14456129c29a1913029911160aa44e6dd32 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/eof.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/eof.hpp
@@ -6,25 +6,26 @@
 
 #include "../config.hpp"
 
-#include "skip_control.hpp"
+#include "enable_control.hpp"
 
-#include "../analysis/generic.hpp"
+#include "../type_list.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
    struct eof
    {
-      using analyze_t = analysis::generic< analysis::rule_type::opt >;
+      using rule_t = eof;
+      using subs_t = empty_list;
 
-      template< typename Input >
-      [[nodiscard]] static bool match( Input& in ) noexcept( noexcept( in.empty() ) )
+      template< typename ParseInput >
+      [[nodiscard]] static bool match( ParseInput& in ) noexcept( noexcept( in.empty() ) )
       {
          return in.empty();
       }
    };
 
    template<>
-   inline constexpr bool skip_control< eof > = true;
+   inline constexpr bool enable_control< eof > = false;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/eol.hpp b/packages/PEGTL/include/tao/pegtl/internal/eol.hpp
index e6b22dcca564fc0cfd4d1cdbd040925db74a8ece..38f5fb7e5ab9229559b7a36aa1500f6081803125 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/eol.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/eol.hpp
@@ -6,25 +6,26 @@
 
 #include "../config.hpp"
 
-#include "skip_control.hpp"
+#include "enable_control.hpp"
 
-#include "../analysis/generic.hpp"
+#include "../type_list.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
    struct eol
    {
-      using analyze_t = analysis::generic< analysis::rule_type::any >;
+      using rule_t = eol;
+      using subs_t = empty_list;
 
-      template< typename Input >
-      [[nodiscard]] static bool match( Input& in ) noexcept( noexcept( Input::eol_t::match( in ) ) )
+      template< typename ParseInput >
+      [[nodiscard]] static bool match( ParseInput& in ) noexcept( noexcept( ParseInput::eol_t::match( in ) ) )
       {
-         return Input::eol_t::match( in ).first;
+         return ParseInput::eol_t::match( in ).first;
       }
    };
 
    template<>
-   inline constexpr bool skip_control< eol > = true;
+   inline constexpr bool enable_control< eol > = false;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/eolf.hpp b/packages/PEGTL/include/tao/pegtl/internal/eolf.hpp
index 231a7ab4020c297d93ba2d1acb56bc51a131615f..eb03141fbd67c5bdd1dc9a87d61ea362f2b492f1 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/eolf.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/eolf.hpp
@@ -6,26 +6,27 @@
 
 #include "../config.hpp"
 
-#include "skip_control.hpp"
+#include "enable_control.hpp"
 
-#include "../analysis/generic.hpp"
+#include "../type_list.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
    struct eolf
    {
-      using analyze_t = analysis::generic< analysis::rule_type::opt >;
+      using rule_t = eolf;
+      using subs_t = empty_list;
 
-      template< typename Input >
-      [[nodiscard]] static bool match( Input& in ) noexcept( noexcept( Input::eol_t::match( in ) ) )
+      template< typename ParseInput >
+      [[nodiscard]] static bool match( ParseInput& in ) noexcept( noexcept( ParseInput::eol_t::match( in ) ) )
       {
-         const auto p = Input::eol_t::match( in );
+         const auto p = ParseInput::eol_t::match( in );
          return p.first || ( !p.second );
       }
    };
 
    template<>
-   inline constexpr bool skip_control< eolf > = true;
+   inline constexpr bool enable_control< eolf > = false;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/failure.hpp b/packages/PEGTL/include/tao/pegtl/internal/failure.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..e8cfaa4ef8bf4e7d5d662e14d945978eafa1a75d
--- /dev/null
+++ b/packages/PEGTL/include/tao/pegtl/internal/failure.hpp
@@ -0,0 +1,32 @@
+// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#ifndef TAO_PEGTL_INTERNAL_FAILURE_HPP
+#define TAO_PEGTL_INTERNAL_FAILURE_HPP
+
+#include "../config.hpp"
+
+#include "enable_control.hpp"
+
+#include "../type_list.hpp"
+
+namespace TAO_PEGTL_NAMESPACE::internal
+{
+   struct failure
+   {
+      using rule_t = failure;
+      using subs_t = empty_list;
+
+      template< typename ParseInput >
+      [[nodiscard]] static bool match( ParseInput& /*unused*/ ) noexcept
+      {
+         return false;
+      }
+   };
+
+   template<>
+   inline constexpr bool enable_control< failure > = false;
+
+}  // namespace TAO_PEGTL_NAMESPACE::internal
+
+#endif
diff --git a/packages/PEGTL/include/tao/pegtl/internal/has_apply.hpp b/packages/PEGTL/include/tao/pegtl/internal/has_apply.hpp
index 20a8c603d3e9e70a2c6d2624661d2967dd26e0ec..8c9414aac85760ea1befd6bd810f5726c88a506a 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/has_apply.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/has_apply.hpp
@@ -4,21 +4,17 @@
 #ifndef TAO_PEGTL_INTERNAL_HAS_APPLY_HPP
 #define TAO_PEGTL_INTERNAL_HAS_APPLY_HPP
 
-#include <type_traits>
+#include <utility>
 
 #include "../config.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
    template< typename, typename, template< typename... > class, typename... >
-   struct has_apply
-      : std::false_type
-   {};
+   inline constexpr bool has_apply = false;
 
    template< typename C, template< typename... > class Action, typename... S >
-   struct has_apply< C, decltype( C::template apply< Action >( std::declval< S >()... ) ), Action, S... >
-      : std::true_type
-   {};
+   inline constexpr bool has_apply< C, decltype( C::template apply< Action >( std::declval< S >()... ) ), Action, S... > = true;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/has_apply0.hpp b/packages/PEGTL/include/tao/pegtl/internal/has_apply0.hpp
index deaa1373213b1e0925166a7b0cb91f3f91a5e27a..db49981a3b61df20a9c9e13e706e6270e9334b61 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/has_apply0.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/has_apply0.hpp
@@ -4,21 +4,17 @@
 #ifndef TAO_PEGTL_INTERNAL_HAS_APPLY0_HPP
 #define TAO_PEGTL_INTERNAL_HAS_APPLY0_HPP
 
-#include <type_traits>
+#include <utility>
 
 #include "../config.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
    template< typename, typename, template< typename... > class, typename... >
-   struct has_apply0
-      : std::false_type
-   {};
+   inline constexpr bool has_apply0 = false;
 
    template< typename C, template< typename... > class Action, typename... S >
-   struct has_apply0< C, decltype( C::template apply0< Action >( std::declval< S >()... ) ), Action, S... >
-      : std::true_type
-   {};
+   inline constexpr bool has_apply0< C, decltype( C::template apply0< Action >( std::declval< S >()... ) ), Action, S... > = true;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/has_match.hpp b/packages/PEGTL/include/tao/pegtl/internal/has_match.hpp
index 6b02244a6946d01e5595d685a526d01344a923bb..5b2892d959ee8c75167073e23c6a6cde9b5c82f6 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/has_match.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/has_match.hpp
@@ -4,7 +4,6 @@
 #ifndef TAO_PEGTL_INTERNAL_HAS_MATCH_HPP
 #define TAO_PEGTL_INTERNAL_HAS_MATCH_HPP
 
-#include <type_traits>
 #include <utility>
 
 #include "../apply_mode.hpp"
@@ -21,11 +20,9 @@ namespace TAO_PEGTL_NAMESPACE::internal
              class Action,
              template< typename... >
              class Control,
-             typename Input,
+             typename ParseInput,
              typename... States >
-   struct has_match
-      : std::false_type
-   {};
+   inline constexpr bool has_match = false;
 
    template< typename Rule,
              apply_mode A,
@@ -34,22 +31,9 @@ namespace TAO_PEGTL_NAMESPACE::internal
              class Action,
              template< typename... >
              class Control,
-             typename Input,
+             typename ParseInput,
              typename... States >
-   struct has_match< decltype( (void)Action< Rule >::template match< Rule, A, M, Action, Control >( std::declval< Input& >(), std::declval< States&& >()... ), void() ), Rule, A, M, Action, Control, Input, States... >
-      : std::true_type
-   {};
-
-   template< typename Rule,
-             apply_mode A,
-             rewind_mode M,
-             template< typename... >
-             class Action,
-             template< typename... >
-             class Control,
-             typename Input,
-             typename... States >
-   inline constexpr bool has_match_v = has_match< void, Rule, A, M, Action, Control, Input, States... >::value;
+   inline constexpr bool has_match< decltype( (void)Action< Rule >::template match< Rule, A, M, Action, Control >( std::declval< ParseInput& >(), std::declval< States&& >()... ), bool() ), Rule, A, M, Action, Control, ParseInput, States... > = true;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/if_apply.hpp b/packages/PEGTL/include/tao/pegtl/internal/if_apply.hpp
index 5c1e4ea603ca54218c1696eb5c35843c1b307860..4ccfb9c1ff19645d130f0d63c70349c41e79172d 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/if_apply.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/if_apply.hpp
@@ -7,18 +7,19 @@
 #include "../config.hpp"
 
 #include "apply_single.hpp"
-#include "skip_control.hpp"
+#include "enable_control.hpp"
 
-#include "../analysis/counted.hpp"
 #include "../apply_mode.hpp"
 #include "../rewind_mode.hpp"
+#include "../type_list.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
    template< typename Rule, typename... Actions >
    struct if_apply
    {
-      using analyze_t = typename Rule::analyze_t;
+      using rule_t = if_apply;
+      using subs_t = type_list< Rule >;
 
       template< apply_mode A,
                 rewind_mode M,
@@ -26,12 +27,12 @@ namespace TAO_PEGTL_NAMESPACE::internal
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
       {
          if constexpr( ( A == apply_mode::action ) && ( sizeof...( Actions ) != 0 ) ) {
-            using action_t = typename Input::action_t;
+            using action_t = typename ParseInput::action_t;
             auto m = in.template mark< rewind_mode::required >();
             if( Control< Rule >::template match< apply_mode::action, rewind_mode::active, Action, Control >( in, st... ) ) {
                const action_t i2( m.iterator(), in );
@@ -46,7 +47,7 @@ namespace TAO_PEGTL_NAMESPACE::internal
    };
 
    template< typename Rule, typename... Actions >
-   inline constexpr bool skip_control< if_apply< Rule, Actions... > > = true;
+   inline constexpr bool enable_control< if_apply< Rule, Actions... > > = false;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/if_must.hpp b/packages/PEGTL/include/tao/pegtl/internal/if_must.hpp
index 7786f614e87ff8cdc901b4e8b05b0f943bf4d647..68689f32338e7b94d8e0c739f021dff31319e914 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/if_must.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/if_must.hpp
@@ -6,21 +6,20 @@
 
 #include "../config.hpp"
 
+#include "enable_control.hpp"
 #include "must.hpp"
-#include "skip_control.hpp"
-#include "trivial.hpp"
 
 #include "../apply_mode.hpp"
 #include "../rewind_mode.hpp"
-
-#include "../analysis/counted.hpp"
+#include "../type_list.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
    template< bool Default, typename Cond, typename... Rules >
    struct if_must
    {
-      using analyze_t = analysis::counted< analysis::rule_type::seq, Default ? 0 : 1, Cond, must< Rules... > >;
+      using rule_t = if_must;
+      using subs_t = type_list< Cond, must< Rules... > >;
 
       template< apply_mode A,
                 rewind_mode M,
@@ -28,9 +27,9 @@ namespace TAO_PEGTL_NAMESPACE::internal
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
       {
          if( Control< Cond >::template match< A, M, Action, Control >( in, st... ) ) {
             (void)Control< must< Rules... > >::template match< A, M, Action, Control >( in, st... );
@@ -41,7 +40,7 @@ namespace TAO_PEGTL_NAMESPACE::internal
    };
 
    template< bool Default, typename Cond, typename... Rules >
-   inline constexpr bool skip_control< if_must< Default, Cond, Rules... > > = true;
+   inline constexpr bool enable_control< if_must< Default, Cond, Rules... > > = false;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/if_must_else.hpp b/packages/PEGTL/include/tao/pegtl/internal/if_must_else.hpp
index ab68991b7945418f80e07cc39e924ef77dd6cf2b..bad4358d6e5ff19d71b529527c1f7fe0e03f97f4 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/if_must_else.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/if_must_else.hpp
@@ -9,6 +9,8 @@
 #include "if_then_else.hpp"
 #include "must.hpp"
 
+#include "../type_list.hpp"
+
 namespace TAO_PEGTL_NAMESPACE::internal
 {
    template< typename Cond, typename Then, typename Else >
diff --git a/packages/PEGTL/include/tao/pegtl/internal/if_then_else.hpp b/packages/PEGTL/include/tao/pegtl/internal/if_then_else.hpp
index 114300ef20038246121cfb6c5e869c2326a5e1b6..ea0bf8a31954e8055c72e630d6f3f1231fda8280 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/if_then_else.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/if_then_else.hpp
@@ -6,22 +6,22 @@
 
 #include "../config.hpp"
 
+#include "enable_control.hpp"
 #include "not_at.hpp"
 #include "seq.hpp"
-#include "skip_control.hpp"
 #include "sor.hpp"
 
 #include "../apply_mode.hpp"
 #include "../rewind_mode.hpp"
-
-#include "../analysis/generic.hpp"
+#include "../type_list.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
    template< typename Cond, typename Then, typename Else >
    struct if_then_else
    {
-      using analyze_t = analysis::generic< analysis::rule_type::sor, seq< Cond, Then >, seq< not_at< Cond >, Else > >;
+      using rule_t = if_then_else;
+      using subs_t = type_list< Cond, Then, Else >;
 
       template< apply_mode A,
                 rewind_mode M,
@@ -29,9 +29,9 @@ namespace TAO_PEGTL_NAMESPACE::internal
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
       {
          auto m = in.template mark< M >();
          using m_t = decltype( m );
@@ -44,7 +44,7 @@ namespace TAO_PEGTL_NAMESPACE::internal
    };
 
    template< typename Cond, typename Then, typename Else >
-   inline constexpr bool skip_control< if_then_else< Cond, Then, Else > > = true;
+   inline constexpr bool enable_control< if_then_else< Cond, Then, Else > > = false;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/istring.hpp b/packages/PEGTL/include/tao/pegtl/internal/istring.hpp
index bc0f765885ba2fe3ad079a8673c12c5cde7625fc..60e6a2fe2025f50b0086a8110f8e363e3dba84dc 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/istring.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/istring.hpp
@@ -9,11 +9,11 @@
 #include "../config.hpp"
 
 #include "bump_help.hpp"
+#include "enable_control.hpp"
 #include "result_on_found.hpp"
-#include "skip_control.hpp"
-#include "trivial.hpp"
+#include "success.hpp"
 
-#include "../analysis/counted.hpp"
+#include "../type_list.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
@@ -42,20 +42,21 @@ namespace TAO_PEGTL_NAMESPACE::internal
 
    template<>
    struct istring<>
-      : trivial< true >
+      : success
    {};
 
    template< char... Cs >
    struct istring
    {
-      using analyze_t = analysis::counted< analysis::rule_type::any, sizeof...( Cs ) >;
+      using rule_t = istring;
+      using subs_t = empty_list;
 
-      template< typename Input >
-      [[nodiscard]] static bool match( Input& in ) noexcept( noexcept( in.size( 0 ) ) )
+      template< typename ParseInput >
+      [[nodiscard]] static bool match( ParseInput& in ) noexcept( noexcept( in.size( 0 ) ) )
       {
          if( in.size( sizeof...( Cs ) ) >= sizeof...( Cs ) ) {
             if( istring_equal< Cs... >( in.current() ) ) {
-               bump_help< result_on_found::success, Input, char, Cs... >( in, sizeof...( Cs ) );
+               bump_help< result_on_found::success, ParseInput, char, Cs... >( in, sizeof...( Cs ) );
                return true;
             }
          }
@@ -64,7 +65,7 @@ namespace TAO_PEGTL_NAMESPACE::internal
    };
 
    template< char... Cs >
-   inline constexpr bool skip_control< istring< Cs... > > = true;
+   inline constexpr bool enable_control< istring< Cs... > > = false;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/lf_crlf_eol.hpp b/packages/PEGTL/include/tao/pegtl/internal/lf_crlf_eol.hpp
index 42b138d155984d43d73a0accf70ee02d56756488..2c08186e570ddef4a01f394fc549e17ff81e548b 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/lf_crlf_eol.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/lf_crlf_eol.hpp
@@ -13,8 +13,8 @@ namespace TAO_PEGTL_NAMESPACE::internal
    {
       static constexpr int ch = '\n';
 
-      template< typename Input >
-      [[nodiscard]] static eol_pair match( Input& in ) noexcept( noexcept( in.size( 2 ) ) )
+      template< typename ParseInput >
+      [[nodiscard]] static eol_pair match( ParseInput& in ) noexcept( noexcept( in.size( 2 ) ) )
       {
          eol_pair p = { false, in.size( 2 ) };
          if( p.second ) {
diff --git a/packages/PEGTL/include/tao/pegtl/internal/lf_eol.hpp b/packages/PEGTL/include/tao/pegtl/internal/lf_eol.hpp
index 38ecc785c045c05b17c17a457d04f018375cab3a..9eee34ebf0777cd1ba25e82ec82c9bfcddb4cab3 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/lf_eol.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/lf_eol.hpp
@@ -13,8 +13,8 @@ namespace TAO_PEGTL_NAMESPACE::internal
    {
       static constexpr int ch = '\n';
 
-      template< typename Input >
-      [[nodiscard]] static eol_pair match( Input& in ) noexcept( noexcept( in.size( 1 ) ) )
+      template< typename ParseInput >
+      [[nodiscard]] static eol_pair match( ParseInput& in ) noexcept( noexcept( in.size( 1 ) ) )
       {
          eol_pair p = { false, in.size( 1 ) };
          if( p.second ) {
diff --git a/packages/PEGTL/include/tao/pegtl/internal/list_tail.hpp b/packages/PEGTL/include/tao/pegtl/internal/list_tail.hpp
index c620d0ff51a89d351400fbc56bd1911d2e6b82b4..05d4ade59e940bbd03fa18d47f81eb22890d80f4 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/list_tail.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/list_tail.hpp
@@ -6,14 +6,16 @@
 
 #include "../config.hpp"
 
-#include "list.hpp"
 #include "opt.hpp"
 #include "seq.hpp"
+#include "star.hpp"
+
+#include "../type_list.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
    template< typename Rule, typename Sep >
-   using list_tail = seq< list< Rule, Sep >, opt< Sep > >;
+   using list_tail = seq< Rule, star< Sep, Rule >, opt< Sep > >;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/list_tail_pad.hpp b/packages/PEGTL/include/tao/pegtl/internal/list_tail_pad.hpp
index fb6113d7f50a7ca2176e98c3e98ea5d9245a82d6..e6a43294cdd03707830c5e07fd36f605c1ba4322 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/list_tail_pad.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/list_tail_pad.hpp
@@ -15,7 +15,7 @@
 namespace TAO_PEGTL_NAMESPACE::internal
 {
    template< typename Rule, typename Sep, typename Pad >
-   using list_tail_pad = seq< list< Rule, pad< Sep, Pad > >, opt< star< Pad >, Sep > >;
+   using list_tail_pad = seq< Rule, star< pad< Sep, Pad >, Rule >, opt< star< Pad >, Sep > >;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/minus.hpp b/packages/PEGTL/include/tao/pegtl/internal/minus.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..f928371623e96a086bc5b49eb30df3da9be47bde
--- /dev/null
+++ b/packages/PEGTL/include/tao/pegtl/internal/minus.hpp
@@ -0,0 +1,21 @@
+// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#ifndef TAO_PEGTL_INTERNAL_MINUS_HPP
+#define TAO_PEGTL_INTERNAL_MINUS_HPP
+
+#include "../config.hpp"
+
+#include "eof.hpp"
+#include "not_at.hpp"
+#include "rematch.hpp"
+#include "seq.hpp"
+
+namespace TAO_PEGTL_NAMESPACE::internal
+{
+   template< typename M, typename S >
+   using minus = rematch< M, not_at< S, eof > >;
+
+}  // namespace TAO_PEGTL_NAMESPACE::internal
+
+#endif
diff --git a/packages/PEGTL/include/tao/pegtl/internal/missing_apply.hpp b/packages/PEGTL/include/tao/pegtl/internal/missing_apply.hpp
index 349042135fd3631e0f4a79c03bd85e16c76a6cd6..0e3e51127f48a7ef7e6162b3bcb9ed2ec051193a 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/missing_apply.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/missing_apply.hpp
@@ -12,9 +12,9 @@ namespace TAO_PEGTL_NAMESPACE::internal
    template< typename Control,
              template< typename... >
              class Action,
-             typename Input,
+             typename ParseInput,
              typename... States >
-   void missing_apply( Input& in, States&&... st )
+   void missing_apply( ParseInput& in, States&&... st )
    {
       auto m = in.template mark< rewind_mode::required >();
       (void)Control::template apply< Action >( m.iterator(), in, st... );
diff --git a/packages/PEGTL/include/tao/pegtl/internal/missing_apply0.hpp b/packages/PEGTL/include/tao/pegtl/internal/missing_apply0.hpp
index 3ad5a42d9a908ffc9e847699300c7669c994e060..345e50f6e9ec3dce59f0fec4fc0340c48d9aeb86 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/missing_apply0.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/missing_apply0.hpp
@@ -11,9 +11,9 @@ namespace TAO_PEGTL_NAMESPACE::internal
    template< typename Control,
              template< typename... >
              class Action,
-             typename Input,
+             typename ParseInput,
              typename... States >
-   void missing_apply0( Input& in, States&&... st )
+   void missing_apply0( ParseInput& in, States&&... st )
    {
       (void)Control::template apply0< Action >( in, st... );
    }
diff --git a/packages/PEGTL/include/tao/pegtl/internal/must.hpp b/packages/PEGTL/include/tao/pegtl/internal/must.hpp
index e0f015c011da37ba7824552a6559690e75774bd7..4cb6454be7c60efd48e115a95de44ed07e770051 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/must.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/must.hpp
@@ -6,14 +6,13 @@
 
 #include "../config.hpp"
 
-#include "raise.hpp"
+#include "enable_control.hpp"
 #include "seq.hpp"
-#include "skip_control.hpp"
+#include "success.hpp"
 
 #include "../apply_mode.hpp"
 #include "../rewind_mode.hpp"
-
-#include "../analysis/generic.hpp"
+#include "../type_list.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
@@ -25,6 +24,11 @@ namespace TAO_PEGTL_NAMESPACE::internal
       : seq< must< Rules >... >
    {};
 
+   template<>
+   struct must<>
+      : success
+   {};
+
    // While in theory the implementation for a single rule could
    // be simplified to must< Rule > = sor< Rule, raise< Rule > >, this
    // would result in some unnecessary run-time overhead.
@@ -32,7 +36,8 @@ namespace TAO_PEGTL_NAMESPACE::internal
    template< typename Rule >
    struct must< Rule >
    {
-      using analyze_t = typename Rule::analyze_t;
+      using rule_t = must;
+      using subs_t = type_list< Rule >;
 
       template< apply_mode A,
                 rewind_mode,
@@ -40,19 +45,19 @@ namespace TAO_PEGTL_NAMESPACE::internal
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
       {
          if( !Control< Rule >::template match< A, rewind_mode::dontcare, Action, Control >( in, st... ) ) {
-            (void)raise< Rule >::template match< A, rewind_mode::dontcare, Action, Control >( in, st... );
+            Control< Rule >::raise( static_cast< const ParseInput& >( in ), st... );
          }
          return true;
       }
    };
 
    template< typename... Rules >
-   inline constexpr bool skip_control< must< Rules... > > = true;
+   inline constexpr bool enable_control< must< Rules... > > = false;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/not_at.hpp b/packages/PEGTL/include/tao/pegtl/internal/not_at.hpp
index 774a2eaccf23d08f059671f0ace1dc6509b3ca7a..09ba3c5eb089c61d27171cace08444b4e6b9a53e 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/not_at.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/not_at.hpp
@@ -6,14 +6,13 @@
 
 #include "../config.hpp"
 
+#include "enable_control.hpp"
+#include "failure.hpp"
 #include "seq.hpp"
-#include "skip_control.hpp"
-#include "trivial.hpp"
 
 #include "../apply_mode.hpp"
 #include "../rewind_mode.hpp"
-
-#include "../analysis/generic.hpp"
+#include "../type_list.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
@@ -24,13 +23,14 @@ namespace TAO_PEGTL_NAMESPACE::internal
 
    template<>
    struct not_at<>
-      : trivial< false >
+      : failure
    {};
 
    template< typename Rule >
    struct not_at< Rule >
    {
-      using analyze_t = analysis::generic< analysis::rule_type::opt, Rule >;
+      using rule_t = not_at;
+      using subs_t = type_list< Rule >;
 
       template< apply_mode,
                 rewind_mode,
@@ -38,9 +38,9 @@ namespace TAO_PEGTL_NAMESPACE::internal
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
       {
          const auto m = in.template mark< rewind_mode::required >();
          return !Control< Rule >::template match< apply_mode::nothing, rewind_mode::active, Action, Control >( in, st... );
@@ -48,7 +48,7 @@ namespace TAO_PEGTL_NAMESPACE::internal
    };
 
    template< typename... Rules >
-   inline constexpr bool skip_control< not_at< Rules... > > = true;
+   inline constexpr bool enable_control< not_at< Rules... > > = false;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/one.hpp b/packages/PEGTL/include/tao/pegtl/internal/one.hpp
index b8918f1fd270b9fb27fe832e2576ba901bf2ca3f..65bc2e1236d109bcf4637f95f5c8e4c81dea8b75 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/one.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/one.hpp
@@ -8,36 +8,47 @@
 
 #include "../config.hpp"
 
+#include "any.hpp"
 #include "bump_help.hpp"
+#include "enable_control.hpp"
+#include "failure.hpp"
 #include "result_on_found.hpp"
-#include "skip_control.hpp"
 
-#include "../analysis/generic.hpp"
+#include "../type_list.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
    template< result_on_found R, typename Peek, typename Peek::data_t... Cs >
    struct one
    {
-      using analyze_t = analysis::generic< analysis::rule_type::any >;
+      using rule_t = one;
+      using subs_t = empty_list;
 
-      template< typename Input >
-      [[nodiscard]] static bool match( Input& in ) noexcept( noexcept( in.size( Peek::max_input_size ) ) )
+      template< typename ParseInput >
+      [[nodiscard]] static bool match( ParseInput& in ) noexcept( noexcept( Peek::peek( in ) ) )
       {
-         if( const std::size_t s = in.size( Peek::max_input_size ); s >= Peek::min_input_size ) {
-            if( const auto t = Peek::peek( in, s ) ) {
-               if( ( ( t.data == Cs ) || ... ) == bool( R ) ) {
-                  bump_help< R, Input, typename Peek::data_t, Cs... >( in, t.size );
-                  return true;
-               }
+         if( const auto t = Peek::peek( in ) ) {
+            if( ( ( t.data == Cs ) || ... ) == bool( R ) ) {
+               bump_help< R, ParseInput, typename Peek::data_t, Cs... >( in, t.size );
+               return true;
             }
          }
          return false;
       }
    };
 
+   template< typename Peek >
+   struct one< result_on_found::success, Peek >
+      : failure
+   {};
+
+   template< typename Peek >
+   struct one< result_on_found::failure, Peek >
+      : any< Peek >
+   {};
+
    template< result_on_found R, typename Peek, typename Peek::data_t... Cs >
-   inline constexpr bool skip_control< one< R, Peek, Cs... > > = true;
+   inline constexpr bool enable_control< one< R, Peek, Cs... > > = false;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/opt.hpp b/packages/PEGTL/include/tao/pegtl/internal/opt.hpp
index 1c3f48fea8333383c26e4e068c8533628ebf53b9..9f25c5038ef7e87894398c778186fdf18f04e758 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/opt.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/opt.hpp
@@ -8,14 +8,13 @@
 
 #include "../config.hpp"
 
+#include "enable_control.hpp"
 #include "seq.hpp"
-#include "skip_control.hpp"
-#include "trivial.hpp"
+#include "success.hpp"
 
 #include "../apply_mode.hpp"
 #include "../rewind_mode.hpp"
-
-#include "../analysis/generic.hpp"
+#include "../type_list.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
@@ -26,13 +25,14 @@ namespace TAO_PEGTL_NAMESPACE::internal
 
    template<>
    struct opt<>
-      : trivial< true >
+      : success
    {};
 
    template< typename Rule >
    struct opt< Rule >
    {
-      using analyze_t = analysis::generic< analysis::rule_type::opt, Rule >;
+      using rule_t = opt;
+      using subs_t = type_list< Rule >;
 
       template< apply_mode A,
                 rewind_mode,
@@ -40,9 +40,9 @@ namespace TAO_PEGTL_NAMESPACE::internal
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
       {
          (void)Control< Rule >::template match< A, rewind_mode::required, Action, Control >( in, st... );
          return true;
@@ -50,7 +50,7 @@ namespace TAO_PEGTL_NAMESPACE::internal
    };
 
    template< typename... Rules >
-   inline constexpr bool skip_control< opt< Rules... > > = true;
+   inline constexpr bool enable_control< opt< Rules... > > = false;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/peek_char.hpp b/packages/PEGTL/include/tao/pegtl/internal/peek_char.hpp
index db4655e562468389caafafff1fb364b36dac492f..85f1b4dbe022986634404ab6e353fccb6f86d34b 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/peek_char.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/peek_char.hpp
@@ -17,12 +17,12 @@ namespace TAO_PEGTL_NAMESPACE::internal
       using data_t = char;
       using pair_t = input_pair< char >;
 
-      static constexpr std::size_t min_input_size = 1;
-      static constexpr std::size_t max_input_size = 1;
-
-      template< typename Input >
-      [[nodiscard]] static pair_t peek( const Input& in, const std::size_t /*unused*/ = 1 ) noexcept
+      template< typename ParseInput >
+      [[nodiscard]] static pair_t peek( ParseInput& in ) noexcept( noexcept( in.empty() ) )
       {
+         if( in.empty() ) {
+            return { 0, 0 };
+         }
          return { in.peek_char(), 1 };
       }
    };
diff --git a/packages/PEGTL/include/tao/pegtl/internal/peek_utf8.hpp b/packages/PEGTL/include/tao/pegtl/internal/peek_utf8.hpp
index 3df1b373d73e6f9c8217b5a4d0feef9d9990e078..8f1e5a991ddb42d07494c821fe5d504856d56ade 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/peek_utf8.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/peek_utf8.hpp
@@ -15,26 +15,25 @@ namespace TAO_PEGTL_NAMESPACE::internal
       using data_t = char32_t;
       using pair_t = input_pair< char32_t >;
 
-      static constexpr std::size_t min_input_size = 1;
-      static constexpr std::size_t max_input_size = 4;
-
-      template< typename Input >
-      [[nodiscard]] static pair_t peek( const Input& in, const std::size_t s ) noexcept
+      template< typename ParseInput >
+      [[nodiscard]] static pair_t peek( ParseInput& in ) noexcept( noexcept( in.empty() ) )
       {
-         char32_t c0 = in.peek_uint8();
-
+         if( in.empty() ) {
+            return { 0, 0 };
+         }
+         const char32_t c0 = in.peek_uint8();
          if( ( c0 & 0x80 ) == 0 ) {
             return { c0, 1 };
          }
-         return peek_impl( in, c0, s );
+         return peek_impl( in, c0 );
       }
 
    private:
-      template< typename Input >
-      [[nodiscard]] static pair_t peek_impl( const Input& in, char32_t c0, const std::size_t s ) noexcept
+      template< typename ParseInput >
+      [[nodiscard]] static pair_t peek_impl( ParseInput& in, char32_t c0 ) noexcept( noexcept( in.size( 4 ) ) )
       {
          if( ( c0 & 0xE0 ) == 0xC0 ) {
-            if( s >= 2 ) {
+            if( in.size( 2 ) >= 2 ) {
                const char32_t c1 = in.peek_uint8( 1 );
                if( ( c1 & 0xC0 ) == 0x80 ) {
                   c0 &= 0x1F;
@@ -47,7 +46,7 @@ namespace TAO_PEGTL_NAMESPACE::internal
             }
          }
          else if( ( c0 & 0xF0 ) == 0xE0 ) {
-            if( s >= 3 ) {
+            if( in.size( 3 ) >= 3 ) {
                const char32_t c1 = in.peek_uint8( 1 );
                const char32_t c2 = in.peek_uint8( 2 );
                if( ( ( c1 & 0xC0 ) == 0x80 ) && ( ( c2 & 0xC0 ) == 0x80 ) ) {
@@ -63,7 +62,7 @@ namespace TAO_PEGTL_NAMESPACE::internal
             }
          }
          else if( ( c0 & 0xF8 ) == 0xF0 ) {
-            if( s >= 4 ) {
+            if( in.size( 4 ) >= 4 ) {
                const char32_t c1 = in.peek_uint8( 1 );
                const char32_t c2 = in.peek_uint8( 2 );
                const char32_t c3 = in.peek_uint8( 3 );
diff --git a/packages/PEGTL/include/tao/pegtl/internal/plus.hpp b/packages/PEGTL/include/tao/pegtl/internal/plus.hpp
index 1570d80cafc759bb18cb634a2644806ecf24939d..82e191d8b755f07b22d7bf1841030eadad6f6a66 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/plus.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/plus.hpp
@@ -8,15 +8,12 @@
 
 #include "../config.hpp"
 
-#include "opt.hpp"
+#include "enable_control.hpp"
 #include "seq.hpp"
-#include "skip_control.hpp"
-#include "star.hpp"
 
 #include "../apply_mode.hpp"
 #include "../rewind_mode.hpp"
-
-#include "../analysis/generic.hpp"
+#include "../type_list.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
@@ -33,7 +30,8 @@ namespace TAO_PEGTL_NAMESPACE::internal
    template< typename Rule >
    struct plus< Rule >
    {
-      using analyze_t = analysis::generic< analysis::rule_type::seq, Rule, opt< plus > >;
+      using rule_t = plus;
+      using subs_t = type_list< Rule >;
 
       template< apply_mode A,
                 rewind_mode M,
@@ -41,16 +39,21 @@ namespace TAO_PEGTL_NAMESPACE::internal
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
       {
-         return Control< Rule >::template match< A, M, Action, Control >( in, st... ) && Control< star< Rule > >::template match< A, M, Action, Control >( in, st... );
+         if( Control< Rule >::template match< A, M, Action, Control >( in, st... ) ) {
+            while( Control< Rule >::template match< A, rewind_mode::required, Action, Control >( in, st... ) ) {
+            }
+            return true;
+         }
+         return false;
       }
    };
 
    template< typename Rule, typename... Rules >
-   inline constexpr bool skip_control< plus< Rule, Rules... > > = true;
+   inline constexpr bool enable_control< plus< Rule, Rules... > > = false;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/raise.hpp b/packages/PEGTL/include/tao/pegtl/internal/raise.hpp
index cd1528e7c3451b0c04aedf8f96d27917b61ba42d..a84c92a894c2a6cdcdecf319548a8f979dc2cc8e 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/raise.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/raise.hpp
@@ -4,49 +4,40 @@
 #ifndef TAO_PEGTL_INTERNAL_RAISE_HPP
 #define TAO_PEGTL_INTERNAL_RAISE_HPP
 
-#include <cstdlib>
 #include <stdexcept>
-#include <type_traits>
 
 #include "../config.hpp"
 
-#include "skip_control.hpp"
+#include "enable_control.hpp"
 
-#include "../analysis/generic.hpp"
 #include "../apply_mode.hpp"
 #include "../rewind_mode.hpp"
+#include "../type_list.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
    template< typename T >
    struct raise
    {
-      using analyze_t = analysis::generic< analysis::rule_type::any >;
+      using rule_t = raise;
+      using subs_t = empty_list;
 
-#if defined( _MSC_VER )
-#pragma warning( push )
-#pragma warning( disable : 4702 )
-#endif
       template< apply_mode,
                 rewind_mode,
                 template< typename... >
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      [[noreturn]] static bool match( ParseInput& in, States&&... st )
       {
-         Control< T >::raise( static_cast< const Input& >( in ), st... );
-         throw std::logic_error( "code should be unreachable: Control< T >::raise() did not throw an exception" );  // LCOV_EXCL_LINE
-#if defined( _MSC_VER )
-#pragma warning( pop )
-#endif
+         Control< T >::raise( static_cast< const ParseInput& >( in ), st... );
       }
    };
 
    template< typename T >
-   inline constexpr bool skip_control< raise< T > > = true;
+   inline constexpr bool enable_control< raise< T > > = false;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/range.hpp b/packages/PEGTL/include/tao/pegtl/internal/range.hpp
index 9720fa900ecc576041a317a7afb6c2767f82e898..e956b709ca2557018ac8258753d2dd2a9f06f9d8 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/range.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/range.hpp
@@ -6,45 +6,50 @@
 
 #include "../config.hpp"
 
+#include "enable_control.hpp"
+#include "one.hpp"
 #include "result_on_found.hpp"
-#include "skip_control.hpp"
 
-#include "../analysis/generic.hpp"
+#include "../type_list.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
    template< result_on_found R, typename Peek, typename Peek::data_t Lo, typename Peek::data_t Hi >
    struct range
    {
-      static_assert( Lo <= Hi, "invalid range detected" );
+      using rule_t = range;
+      using subs_t = empty_list;
 
-      using analyze_t = analysis::generic< analysis::rule_type::any >;
+      static_assert( Lo < Hi, "invalid range" );
 
       template< int Eol >
       static constexpr bool can_match_eol = ( ( ( Lo <= Eol ) && ( Eol <= Hi ) ) == bool( R ) );
 
-      template< typename Input >
-      [[nodiscard]] static bool match( Input& in ) noexcept( noexcept( in.size( Peek::max_input_size ) ) )
+      template< typename ParseInput >
+      [[nodiscard]] static bool match( ParseInput& in ) noexcept( noexcept( Peek::peek( in ) ) )
       {
-         if( const std::size_t s = in.size( Peek::max_input_size ); s >= Peek::min_input_size ) {
-            if( const auto t = Peek::peek( in, s ) ) {
-               if( ( ( Lo <= t.data ) && ( t.data <= Hi ) ) == bool( R ) ) {
-                  if constexpr( can_match_eol< Input::eol_t::ch > ) {
-                     in.bump( t.size );
-                  }
-                  else {
-                     in.bump_in_this_line( t.size );
-                  }
-                  return true;
+         if( const auto t = Peek::peek( in ) ) {
+            if( ( ( Lo <= t.data ) && ( t.data <= Hi ) ) == bool( R ) ) {
+               if constexpr( can_match_eol< ParseInput::eol_t::ch > ) {
+                  in.bump( t.size );
                }
+               else {
+                  in.bump_in_this_line( t.size );
+               }
+               return true;
             }
          }
          return false;
       }
    };
 
+   template< result_on_found R, typename Peek, typename Peek::data_t C >
+   struct range< R, Peek, C, C >
+      : one< R, Peek, C >
+   {};
+
    template< result_on_found R, typename Peek, typename Peek::data_t Lo, typename Peek::data_t Hi >
-   inline constexpr bool skip_control< range< R, Peek, Lo, Hi > > = true;
+   inline constexpr bool enable_control< range< R, Peek, Lo, Hi > > = false;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/ranges.hpp b/packages/PEGTL/include/tao/pegtl/internal/ranges.hpp
index 8aa01e70c18fb8bfab7c438ad494d1d30bab6f0e..a26b45539ef196493b1aa01887fe87153afc581e 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/ranges.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/ranges.hpp
@@ -6,10 +6,12 @@
 
 #include "../config.hpp"
 
+#include "enable_control.hpp"
+#include "failure.hpp"
+#include "one.hpp"
 #include "range.hpp"
-#include "skip_control.hpp"
 
-#include "../analysis/generic.hpp"
+#include "../type_list.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
@@ -54,25 +56,24 @@ namespace TAO_PEGTL_NAMESPACE::internal
    template< typename Peek, typename Peek::data_t... Cs >
    struct ranges
    {
-      using analyze_t = analysis::generic< analysis::rule_type::any >;
+      using rule_t = ranges;
+      using subs_t = empty_list;
 
       template< int Eol >
       static constexpr bool can_match_eol = ranges_impl< Eol, typename Peek::data_t, Cs... >::can_match_eol;
 
-      template< typename Input >
-      [[nodiscard]] static bool match( Input& in ) noexcept( noexcept( in.size( Peek::max_input_size ) ) )
+      template< typename ParseInput >
+      [[nodiscard]] static bool match( ParseInput& in ) noexcept( noexcept( Peek::peek( in ) ) )
       {
-         if( const std::size_t s = in.size( Peek::max_input_size ); s >= Peek::min_input_size ) {
-            if( const auto t = Peek::peek( in, s ) ) {
-               if( ranges_impl< Input::eol_t::ch, typename Peek::data_t, Cs... >::match( t.data ) ) {
-                  if constexpr( can_match_eol< Input::eol_t::ch > ) {
-                     in.bump( t.size );
-                  }
-                  else {
-                     in.bump_in_this_line( t.size );
-                  }
-                  return true;
+         if( const auto t = Peek::peek( in ) ) {
+            if( ranges_impl< ParseInput::eol_t::ch, typename Peek::data_t, Cs... >::match( t.data ) ) {
+               if constexpr( can_match_eol< ParseInput::eol_t::ch > ) {
+                  in.bump( t.size );
                }
+               else {
+                  in.bump_in_this_line( t.size );
+               }
+               return true;
             }
          }
          return false;
@@ -84,8 +85,18 @@ namespace TAO_PEGTL_NAMESPACE::internal
       : range< result_on_found::success, Peek, Lo, Hi >
    {};
 
+   template< typename Peek, typename Peek::data_t C >
+   struct ranges< Peek, C >
+      : one< result_on_found::success, Peek, C >
+   {};
+
+   template< typename Peek >
+   struct ranges< Peek >
+      : failure
+   {};
+
    template< typename Peek, typename Peek::data_t... Cs >
-   inline constexpr bool skip_control< ranges< Peek, Cs... > > = true;
+   inline constexpr bool enable_control< ranges< Peek, Cs... > > = false;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/rematch.hpp b/packages/PEGTL/include/tao/pegtl/internal/rematch.hpp
index c6897f457bd224079cd57cc422064171937c342e..eefe9283b0a6b34514d6955576d1e73951a44656 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/rematch.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/rematch.hpp
@@ -6,11 +6,12 @@
 
 #include "../config.hpp"
 
-#include "skip_control.hpp"
+#include "enable_control.hpp"
 
 #include "../apply_mode.hpp"
 #include "../memory_input.hpp"
 #include "../rewind_mode.hpp"
+#include "../type_list.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
@@ -20,7 +21,8 @@ namespace TAO_PEGTL_NAMESPACE::internal
    template< typename Head >
    struct rematch< Head >
    {
-      using analyze_t = typename Head::analyze_t;
+      using rule_t = rematch;
+      using subs_t = type_list< Head >;
 
       template< apply_mode A,
                 rewind_mode M,
@@ -28,9 +30,9 @@ namespace TAO_PEGTL_NAMESPACE::internal
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
       {
          return Control< Head >::template match< A, M, Action, Control >( in, st... );
       }
@@ -39,7 +41,8 @@ namespace TAO_PEGTL_NAMESPACE::internal
    template< typename Head, typename Rule, typename... Rules >
    struct rematch< Head, Rule, Rules... >
    {
-      using analyze_t = typename Head::analyze_t;  // NOTE: Rule and Rules are ignored for analyze().
+      using rule_t = rematch;
+      using subs_t = type_list< Head, Rule, Rules... >;
 
       template< apply_mode A,
                 rewind_mode,
@@ -47,14 +50,14 @@ namespace TAO_PEGTL_NAMESPACE::internal
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
       {
          auto m = in.template mark< rewind_mode::required >();
 
          if( Control< Head >::template match< A, rewind_mode::active, Action, Control >( in, st... ) ) {
-            memory_input< Input::tracking_mode_v, typename Input::eol_t, typename Input::source_t > i2( m.iterator(), in.current(), in.source() );
+            memory_input< ParseInput::tracking_mode_v, typename ParseInput::eol_t, typename ParseInput::source_t > i2( m.iterator(), in.current(), in.source() );
             return m( ( Control< Rule >::template match< A, rewind_mode::active, Action, Control >( i2, st... ) && ... && ( i2.restart( m ), Control< Rules >::template match< A, rewind_mode::active, Action, Control >( i2, st... ) ) ) );
          }
          return false;
@@ -62,7 +65,7 @@ namespace TAO_PEGTL_NAMESPACE::internal
    };
 
    template< typename Head, typename... Rules >
-   inline constexpr bool skip_control< rematch< Head, Rules... > > = true;
+   inline constexpr bool enable_control< rematch< Head, Rules... > > = false;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/rep.hpp b/packages/PEGTL/include/tao/pegtl/internal/rep.hpp
index 199f46ee0eaa83eb8bbcf3f34c37256a22fbc195..1b7bc8649b21128a031bd9c092931fed2086e04f 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/rep.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/rep.hpp
@@ -6,36 +6,36 @@
 
 #include "../config.hpp"
 
+#include "enable_control.hpp"
 #include "seq.hpp"
-#include "skip_control.hpp"
-#include "trivial.hpp"
+#include "success.hpp"
 
 #include "../apply_mode.hpp"
 #include "../rewind_mode.hpp"
-
-#include "../analysis/counted.hpp"
+#include "../type_list.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
-   template< unsigned Num, typename... Rules >
+   template< unsigned Cnt, typename... Rules >
    struct rep
-      : rep< Num, seq< Rules... > >
+      : rep< Cnt, seq< Rules... > >
    {};
 
-   template< unsigned Num >
-   struct rep< Num >
-      : trivial< true >
+   template< unsigned Cnt >
+   struct rep< Cnt >
+      : success
    {};
 
    template< typename Rule >
    struct rep< 0, Rule >
-      : trivial< true >
+      : success
    {};
 
-   template< unsigned Num, typename Rule >
-   struct rep< Num, Rule >
+   template< unsigned Cnt, typename Rule >
+   struct rep< Cnt, Rule >
    {
-      using analyze_t = analysis::counted< analysis::rule_type::seq, Num, Rule >;
+      using rule_t = rep;
+      using subs_t = type_list< Rule >;
 
       template< apply_mode A,
                 rewind_mode M,
@@ -43,14 +43,14 @@ namespace TAO_PEGTL_NAMESPACE::internal
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
       {
          auto m = in.template mark< M >();
          using m_t = decltype( m );
 
-         for( unsigned i = 0; i != Num; ++i ) {
+         for( unsigned i = 0; i != Cnt; ++i ) {
             if( !Control< Rule >::template match< A, m_t::next_rewind_mode, Action, Control >( in, st... ) ) {
                return false;
             }
@@ -59,8 +59,8 @@ namespace TAO_PEGTL_NAMESPACE::internal
       }
    };
 
-   template< unsigned Num, typename... Rules >
-   inline constexpr bool skip_control< rep< Num, Rules... > > = true;
+   template< unsigned Cnt, typename... Rules >
+   inline constexpr bool enable_control< rep< Cnt, Rules... > > = false;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/rep_min_max.hpp b/packages/PEGTL/include/tao/pegtl/internal/rep_min_max.hpp
index a82dc83ff601a001d5f5b28f62ee271e327db55e..f153cd10a37e5c39f28d5c91ef689dbd42e381d6 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/rep_min_max.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/rep_min_max.hpp
@@ -8,26 +8,27 @@
 
 #include "../config.hpp"
 
+#include "enable_control.hpp"
+#include "failure.hpp"
 #include "not_at.hpp"
 #include "seq.hpp"
-#include "skip_control.hpp"
-#include "trivial.hpp"
 
 #include "../apply_mode.hpp"
 #include "../rewind_mode.hpp"
-
-#include "../analysis/counted.hpp"
+#include "../type_list.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
    template< unsigned Min, unsigned Max, typename... Rules >
    struct rep_min_max
       : rep_min_max< Min, Max, seq< Rules... > >
-   {};
+   {
+      static_assert( Min <= Max );
+   };
 
    template< unsigned Min, unsigned Max >
    struct rep_min_max< Min, Max >
-      : trivial< false >
+      : failure
    {
       static_assert( Min <= Max );
    };
@@ -40,7 +41,8 @@ namespace TAO_PEGTL_NAMESPACE::internal
    template< unsigned Min, unsigned Max, typename Rule >
    struct rep_min_max< Min, Max, Rule >
    {
-      using analyze_t = analysis::counted< analysis::rule_type::seq, Min, Rule >;
+      using rule_t = rep_min_max;
+      using subs_t = type_list< Rule >;
 
       static_assert( Min <= Max );
 
@@ -50,9 +52,9 @@ namespace TAO_PEGTL_NAMESPACE::internal
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
       {
          auto m = in.template mark< M >();
          using m_t = decltype( m );
@@ -72,7 +74,7 @@ namespace TAO_PEGTL_NAMESPACE::internal
    };
 
    template< unsigned Min, unsigned Max, typename... Rules >
-   inline constexpr bool skip_control< rep_min_max< Min, Max, Rules... > > = true;
+   inline constexpr bool enable_control< rep_min_max< Min, Max, Rules... > > = false;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/rep_opt.hpp b/packages/PEGTL/include/tao/pegtl/internal/rep_opt.hpp
index dd2d63413d57604c86205844320a1d2e9d92b392..ea69ee5636c07ca7554e44e382bd23359f7d7fa2 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/rep_opt.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/rep_opt.hpp
@@ -6,13 +6,13 @@
 
 #include "../config.hpp"
 
+#include "enable_control.hpp"
 #include "seq.hpp"
-#include "skip_control.hpp"
+#include "success.hpp"
 
 #include "../apply_mode.hpp"
 #include "../rewind_mode.hpp"
-
-#include "../analysis/generic.hpp"
+#include "../type_list.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
@@ -21,10 +21,21 @@ namespace TAO_PEGTL_NAMESPACE::internal
       : rep_opt< Max, seq< Rules... > >
    {};
 
+   template< unsigned Max >
+   struct rep_opt< Max >
+      : success
+   {};
+
+   template< typename... Rules >
+   struct rep_opt< 0, Rules... >
+      : success
+   {};
+
    template< unsigned Max, typename Rule >
    struct rep_opt< Max, Rule >
    {
-      using analyze_t = analysis::generic< analysis::rule_type::opt, Rule >;
+      using rule_t = rep_opt;
+      using subs_t = type_list< Rule >;
 
       template< apply_mode A,
                 rewind_mode,
@@ -32,9 +43,9 @@ namespace TAO_PEGTL_NAMESPACE::internal
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
       {
          for( unsigned i = 0; ( i != Max ) && Control< Rule >::template match< A, rewind_mode::required, Action, Control >( in, st... ); ++i ) {
          }
@@ -43,7 +54,7 @@ namespace TAO_PEGTL_NAMESPACE::internal
    };
 
    template< unsigned Max, typename... Rules >
-   inline constexpr bool skip_control< rep_opt< Max, Rules... > > = true;
+   inline constexpr bool enable_control< rep_opt< Max, Rules... > > = false;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/require.hpp b/packages/PEGTL/include/tao/pegtl/internal/require.hpp
index 94e299a231f533c22e6ca140ed8e0174baab97c4..e6d6b0c9f8fe3ec545d69b43a2d666bce4cf405e 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/require.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/require.hpp
@@ -6,10 +6,10 @@
 
 #include "../config.hpp"
 
-#include "skip_control.hpp"
-#include "trivial.hpp"
+#include "enable_control.hpp"
+#include "success.hpp"
 
-#include "../analysis/generic.hpp"
+#include "../type_list.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
@@ -18,23 +18,24 @@ namespace TAO_PEGTL_NAMESPACE::internal
 
    template<>
    struct require< 0 >
-      : trivial< true >
+      : success
    {};
 
    template< unsigned Amount >
    struct require
    {
-      using analyze_t = analysis::generic< analysis::rule_type::opt >;
+      using rule_t = require;
+      using subs_t = empty_list;
 
-      template< typename Input >
-      [[nodiscard]] static bool match( Input& in ) noexcept( noexcept( in.size( 0 ) ) )
+      template< typename ParseInput >
+      [[nodiscard]] static bool match( ParseInput& in ) noexcept( noexcept( in.size( 0 ) ) )
       {
          return in.size( Amount ) >= Amount;
       }
    };
 
    template< unsigned Amount >
-   inline constexpr bool skip_control< require< Amount > > = true;
+   inline constexpr bool enable_control< require< Amount > > = false;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/rules.hpp b/packages/PEGTL/include/tao/pegtl/internal/rules.hpp
index fc56a6e8590fb3577ee7ce448f3c22bc58ac08c6..2e9554a70ff1b1818043035f29e944f695ddcb6d 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/rules.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/rules.hpp
@@ -18,9 +18,11 @@
 #include "disable.hpp"
 #include "discard.hpp"
 #include "enable.hpp"
+#include "enable_control.hpp"
 #include "eof.hpp"
 #include "eol.hpp"
 #include "eolf.hpp"
+#include "failure.hpp"
 #include "identifier.hpp"
 #include "if_apply.hpp"
 #include "if_must.hpp"
@@ -31,6 +33,7 @@
 #include "list_must.hpp"
 #include "list_tail.hpp"
 #include "list_tail_pad.hpp"
+#include "minus.hpp"
 #include "must.hpp"
 #include "not_at.hpp"
 #include "one.hpp"
@@ -48,13 +51,12 @@
 #include "rep_opt.hpp"
 #include "require.hpp"
 #include "seq.hpp"
-#include "skip_control.hpp"
 #include "sor.hpp"
 #include "star.hpp"
 #include "star_must.hpp"
 #include "state.hpp"
 #include "string.hpp"
-#include "trivial.hpp"
+#include "success.hpp"
 #include "try_catch_type.hpp"
 #include "until.hpp"
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/seq.hpp b/packages/PEGTL/include/tao/pegtl/internal/seq.hpp
index 3779635b2d87955c611ae169464ec3fa5bcf3294..aa45dbe3163dff044a805cefa94cf8085155b93c 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/seq.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/seq.hpp
@@ -6,13 +6,12 @@
 
 #include "../config.hpp"
 
-#include "skip_control.hpp"
-#include "trivial.hpp"
+#include "enable_control.hpp"
+#include "success.hpp"
 
 #include "../apply_mode.hpp"
 #include "../rewind_mode.hpp"
-
-#include "../analysis/generic.hpp"
+#include "../type_list.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
@@ -21,32 +20,14 @@ namespace TAO_PEGTL_NAMESPACE::internal
 
    template<>
    struct seq<>
-      : trivial< true >
+      : success
    {};
 
-   template< typename Rule >
-   struct seq< Rule >
-   {
-      using analyze_t = typename Rule::analyze_t;
-
-      template< apply_mode A,
-                rewind_mode M,
-                template< typename... >
-                class Action,
-                template< typename... >
-                class Control,
-                typename Input,
-                typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
-      {
-         return Control< Rule >::template match< A, M, Action, Control >( in, st... );
-      }
-   };
-
    template< typename... Rules >
    struct seq
    {
-      using analyze_t = analysis::generic< analysis::rule_type::seq, Rules... >;
+      using rule_t = seq;
+      using subs_t = type_list< Rules... >;
 
       template< apply_mode A,
                 rewind_mode M,
@@ -54,18 +35,23 @@ namespace TAO_PEGTL_NAMESPACE::internal
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
       {
-         auto m = in.template mark< M >();
-         using m_t = decltype( m );
-         return m( ( Control< Rules >::template match< A, m_t::next_rewind_mode, Action, Control >( in, st... ) && ... ) );
+         if constexpr( sizeof...( Rules ) == 1 ) {
+            return Control< Rules... >::template match< A, M, Action, Control >( in, st... );
+         }
+         else {
+            auto m = in.template mark< M >();
+            using m_t = decltype( m );
+            return m( ( Control< Rules >::template match< A, m_t::next_rewind_mode, Action, Control >( in, st... ) && ... ) );
+         }
       }
    };
 
    template< typename... Rules >
-   inline constexpr bool skip_control< seq< Rules... > > = true;
+   inline constexpr bool enable_control< seq< Rules... > > = false;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/sor.hpp b/packages/PEGTL/include/tao/pegtl/internal/sor.hpp
index a26d466b64c923ea4d42b8a25de16e26a3955e67..c56bcc2da7a45a08603fd312be5edcc6ba4864c7 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/sor.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/sor.hpp
@@ -8,13 +8,12 @@
 
 #include "../config.hpp"
 
-#include "skip_control.hpp"
-#include "trivial.hpp"
+#include "enable_control.hpp"
+#include "failure.hpp"
 
 #include "../apply_mode.hpp"
 #include "../rewind_mode.hpp"
-
-#include "../analysis/generic.hpp"
+#include "../type_list.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
@@ -23,18 +22,14 @@ namespace TAO_PEGTL_NAMESPACE::internal
 
    template<>
    struct sor<>
-      : trivial< false >
+      : failure
    {};
 
    template< typename... Rules >
    struct sor
-      : sor< std::index_sequence_for< Rules... >, Rules... >
-   {};
-
-   template< std::size_t... Indices, typename... Rules >
-   struct sor< std::index_sequence< Indices... >, Rules... >
    {
-      using analyze_t = analysis::generic< analysis::rule_type::sor, Rules... >;
+      using rule_t = sor;
+      using subs_t = type_list< Rules... >;
 
       template< apply_mode A,
                 rewind_mode M,
@@ -42,16 +37,30 @@ namespace TAO_PEGTL_NAMESPACE::internal
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                std::size_t... Indices,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      [[nodiscard]] static bool match( std::index_sequence< Indices... > /*unused*/, ParseInput& in, States&&... st )
       {
          return ( Control< Rules >::template match< A, ( ( Indices == ( sizeof...( Rules ) - 1 ) ) ? M : rewind_mode::required ), Action, Control >( in, st... ) || ... );
       }
+
+      template< apply_mode A,
+                rewind_mode M,
+                template< typename... >
+                class Action,
+                template< typename... >
+                class Control,
+                typename ParseInput,
+                typename... States >
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
+      {
+         return match< A, M, Action, Control >( std::index_sequence_for< Rules... >(), in, st... );
+      }
    };
 
    template< typename... Rules >
-   inline constexpr bool skip_control< sor< Rules... > > = true;
+   inline constexpr bool enable_control< sor< Rules... > > = false;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/star.hpp b/packages/PEGTL/include/tao/pegtl/internal/star.hpp
index dfa425b250ce62b533f712a568339a72f15ab586..f1353ba238f2d6ac0c74ffa89aae834fcdd22db8 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/star.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/star.hpp
@@ -8,13 +8,12 @@
 
 #include "../config.hpp"
 
+#include "enable_control.hpp"
 #include "seq.hpp"
-#include "skip_control.hpp"
 
 #include "../apply_mode.hpp"
 #include "../rewind_mode.hpp"
-
-#include "../analysis/generic.hpp"
+#include "../type_list.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
@@ -26,7 +25,8 @@ namespace TAO_PEGTL_NAMESPACE::internal
    template< typename Rule >
    struct star< Rule >
    {
-      using analyze_t = analysis::generic< analysis::rule_type::opt, Rule, star >;
+      using rule_t = star;
+      using subs_t = type_list< Rule >;
 
       template< apply_mode A,
                 rewind_mode,
@@ -34,9 +34,9 @@ namespace TAO_PEGTL_NAMESPACE::internal
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
       {
          while( Control< Rule >::template match< A, rewind_mode::required, Action, Control >( in, st... ) ) {
          }
@@ -45,7 +45,7 @@ namespace TAO_PEGTL_NAMESPACE::internal
    };
 
    template< typename Rule, typename... Rules >
-   inline constexpr bool skip_control< star< Rule, Rules... > > = true;
+   inline constexpr bool enable_control< star< Rule, Rules... > > = false;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/state.hpp b/packages/PEGTL/include/tao/pegtl/internal/state.hpp
index 08f6c07b25a41e88b0ef37bad633d7ce35100250..0fc6cfc0a8e5ccc3ce851bd6fd4f1c017931feed 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/state.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/state.hpp
@@ -6,13 +6,13 @@
 
 #include "../config.hpp"
 
+#include "enable_control.hpp"
 #include "seq.hpp"
-#include "skip_control.hpp"
+#include "success.hpp"
 
 #include "../apply_mode.hpp"
 #include "../rewind_mode.hpp"
-
-#include "../analysis/generic.hpp"
+#include "../type_list.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
@@ -21,10 +21,16 @@ namespace TAO_PEGTL_NAMESPACE::internal
       : state< State, seq< Rules... > >
    {};
 
+   template< typename State >
+   struct state< State >
+      : success
+   {};
+
    template< typename State, typename Rule >
    struct state< State, Rule >
    {
-      using analyze_t = analysis::generic< analysis::rule_type::seq, Rule >;
+      using rule_t = state;
+      using subs_t = type_list< Rule >;
 
       template< apply_mode A,
                 rewind_mode M,
@@ -32,13 +38,13 @@ namespace TAO_PEGTL_NAMESPACE::internal
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
       {
-         State s( static_cast< const Input& >( in ), st... );
+         State s( static_cast< const ParseInput& >( in ), st... );
          if( Control< Rule >::template match< A, M, Action, Control >( in, s ) ) {
-            s.success( static_cast< const Input& >( in ), st... );
+            s.success( static_cast< const ParseInput& >( in ), st... );
             return true;
          }
          return false;
@@ -46,7 +52,7 @@ namespace TAO_PEGTL_NAMESPACE::internal
    };
 
    template< typename State, typename... Rules >
-   inline constexpr bool skip_control< state< State, Rules... > > = true;
+   inline constexpr bool enable_control< state< State, Rules... > > = false;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/string.hpp b/packages/PEGTL/include/tao/pegtl/internal/string.hpp
index b8ed2eedb594e4aa93ae56db9f703bee80fd2f3f..3d2f2c433236af5d1bdb8bd299a3592c74ac0cf3 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/string.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/string.hpp
@@ -10,11 +10,11 @@
 #include "../config.hpp"
 
 #include "bump_help.hpp"
+#include "enable_control.hpp"
 #include "result_on_found.hpp"
-#include "skip_control.hpp"
-#include "trivial.hpp"
+#include "success.hpp"
 
-#include "../analysis/counted.hpp"
+#include "../type_list.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
@@ -28,20 +28,21 @@ namespace TAO_PEGTL_NAMESPACE::internal
 
    template<>
    struct string<>
-      : trivial< true >
+      : success
    {};
 
    template< char... Cs >
    struct string
    {
-      using analyze_t = analysis::counted< analysis::rule_type::any, sizeof...( Cs ) >;
+      using rule_t = string;
+      using subs_t = empty_list;
 
-      template< typename Input >
-      [[nodiscard]] static bool match( Input& in ) noexcept( noexcept( in.size( 0 ) ) )
+      template< typename ParseInput >
+      [[nodiscard]] static bool match( ParseInput& in ) noexcept( noexcept( in.size( 0 ) ) )
       {
          if( in.size( sizeof...( Cs ) ) >= sizeof...( Cs ) ) {
             if( unsafe_equals( in.current(), { Cs... } ) ) {
-               bump_help< result_on_found::success, Input, char, Cs... >( in, sizeof...( Cs ) );
+               bump_help< result_on_found::success, ParseInput, char, Cs... >( in, sizeof...( Cs ) );
                return true;
             }
          }
@@ -50,7 +51,7 @@ namespace TAO_PEGTL_NAMESPACE::internal
    };
 
    template< char... Cs >
-   inline constexpr bool skip_control< string< Cs... > > = true;
+   inline constexpr bool enable_control< string< Cs... > > = false;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/success.hpp b/packages/PEGTL/include/tao/pegtl/internal/success.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..e93caff15a4c6c8d356f9a3357e5e8494da98f6e
--- /dev/null
+++ b/packages/PEGTL/include/tao/pegtl/internal/success.hpp
@@ -0,0 +1,32 @@
+// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#ifndef TAO_PEGTL_INTERNAL_SUCCESS_HPP
+#define TAO_PEGTL_INTERNAL_SUCCESS_HPP
+
+#include "../config.hpp"
+
+#include "enable_control.hpp"
+
+#include "../type_list.hpp"
+
+namespace TAO_PEGTL_NAMESPACE::internal
+{
+   struct success
+   {
+      using rule_t = success;
+      using subs_t = empty_list;
+
+      template< typename ParseInput >
+      [[nodiscard]] static bool match( ParseInput& /*unused*/ ) noexcept
+      {
+         return true;
+      }
+   };
+
+   template<>
+   inline constexpr bool enable_control< success > = false;
+
+}  // namespace TAO_PEGTL_NAMESPACE::internal
+
+#endif
diff --git a/packages/PEGTL/include/tao/pegtl/internal/trivial.hpp b/packages/PEGTL/include/tao/pegtl/internal/trivial.hpp
deleted file mode 100644
index 9d66cd82283bff7638790411f663ac6312009502..0000000000000000000000000000000000000000
--- a/packages/PEGTL/include/tao/pegtl/internal/trivial.hpp
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey
-// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
-
-#ifndef TAO_PEGTL_INTERNAL_TRIVIAL_HPP
-#define TAO_PEGTL_INTERNAL_TRIVIAL_HPP
-
-#include "../config.hpp"
-
-#include "skip_control.hpp"
-
-#include "../analysis/counted.hpp"
-
-namespace TAO_PEGTL_NAMESPACE::internal
-{
-   template< bool Result >
-   struct trivial
-   {
-      using analyze_t = analysis::counted< analysis::rule_type::any, unsigned( !Result ) >;
-
-      template< typename Input >
-      [[nodiscard]] static bool match( Input& /*unused*/ ) noexcept
-      {
-         return Result;
-      }
-   };
-
-   template< bool Result >
-   inline constexpr bool skip_control< trivial< Result > > = true;
-
-}  // namespace TAO_PEGTL_NAMESPACE::internal
-
-#endif
diff --git a/packages/PEGTL/include/tao/pegtl/internal/try_catch_type.hpp b/packages/PEGTL/include/tao/pegtl/internal/try_catch_type.hpp
index fdd74b6dbb1802b8d54b5251b2e7d6b69ff11850..630f3d89e1872e48647fa2e2921a72bb8b0a84e4 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/try_catch_type.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/try_catch_type.hpp
@@ -8,14 +8,13 @@
 
 #include "../config.hpp"
 
+#include "enable_control.hpp"
 #include "seq.hpp"
-#include "skip_control.hpp"
-#include "trivial.hpp"
+#include "success.hpp"
 
 #include "../apply_mode.hpp"
 #include "../rewind_mode.hpp"
-
-#include "../analysis/generic.hpp"
+#include "../type_list.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
@@ -26,13 +25,14 @@ namespace TAO_PEGTL_NAMESPACE::internal
 
    template< typename Exception >
    struct try_catch_type< Exception >
-      : trivial< true >
+      : success
    {};
 
    template< typename Exception, typename Rule >
    struct try_catch_type< Exception, Rule >
    {
-      using analyze_t = analysis::generic< analysis::rule_type::seq, Rule >;
+      using rule_t = try_catch_type;
+      using subs_t = type_list< Rule >;
 
       template< apply_mode A,
                 rewind_mode M,
@@ -40,9 +40,9 @@ namespace TAO_PEGTL_NAMESPACE::internal
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
       {
          auto m = in.template mark< M >();
          using m_t = decltype( m );
@@ -57,7 +57,7 @@ namespace TAO_PEGTL_NAMESPACE::internal
    };
 
    template< typename Exception, typename... Rules >
-   inline constexpr bool skip_control< try_catch_type< Exception, Rules... > > = true;
+   inline constexpr bool enable_control< try_catch_type< Exception, Rules... > > = false;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/internal/until.hpp b/packages/PEGTL/include/tao/pegtl/internal/until.hpp
index 9042a942e5db22d799fb3d53ca8a40f97b62cfa1..f32e23fb38776731f32427c898a81509783dd785 100644
--- a/packages/PEGTL/include/tao/pegtl/internal/until.hpp
+++ b/packages/PEGTL/include/tao/pegtl/internal/until.hpp
@@ -7,16 +7,15 @@
 #include "../config.hpp"
 
 #include "bytes.hpp"
+#include "enable_control.hpp"
 #include "eof.hpp"
 #include "not_at.hpp"
 #include "seq.hpp"
-#include "skip_control.hpp"
 #include "star.hpp"
 
 #include "../apply_mode.hpp"
 #include "../rewind_mode.hpp"
-
-#include "../analysis/generic.hpp"
+#include "../type_list.hpp"
 
 namespace TAO_PEGTL_NAMESPACE::internal
 {
@@ -28,7 +27,8 @@ namespace TAO_PEGTL_NAMESPACE::internal
    template< typename Cond >
    struct until< Cond >
    {
-      using analyze_t = analysis::generic< analysis::rule_type::seq, star< not_at< Cond >, not_at< eof >, bytes< 1 > >, Cond >;
+      using rule_t = until;
+      using subs_t = type_list< Cond >;
 
       template< apply_mode A,
                 rewind_mode M,
@@ -36,9 +36,9 @@ namespace TAO_PEGTL_NAMESPACE::internal
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
       {
          auto m = in.template mark< M >();
 
@@ -55,7 +55,8 @@ namespace TAO_PEGTL_NAMESPACE::internal
    template< typename Cond, typename Rule >
    struct until< Cond, Rule >
    {
-      using analyze_t = analysis::generic< analysis::rule_type::seq, star< not_at< Cond >, not_at< eof >, Rule >, Cond >;
+      using rule_t = until;
+      using subs_t = type_list< Cond, Rule >;
 
       template< apply_mode A,
                 rewind_mode M,
@@ -63,9 +64,9 @@ namespace TAO_PEGTL_NAMESPACE::internal
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
       {
          auto m = in.template mark< M >();
          using m_t = decltype( m );
@@ -80,7 +81,7 @@ namespace TAO_PEGTL_NAMESPACE::internal
    };
 
    template< typename Cond, typename... Rules >
-   inline constexpr bool skip_control< until< Cond, Rules... > > = true;
+   inline constexpr bool enable_control< until< Cond, Rules... > > = false;
 
 }  // namespace TAO_PEGTL_NAMESPACE::internal
 
diff --git a/packages/PEGTL/include/tao/pegtl/match.hpp b/packages/PEGTL/include/tao/pegtl/match.hpp
index f74ba057396c1551111e8a16ce3d85cb6c322192..77f596b94c23954b5eb294bfe103686d0aae3434 100644
--- a/packages/PEGTL/include/tao/pegtl/match.hpp
+++ b/packages/PEGTL/include/tao/pegtl/match.hpp
@@ -19,7 +19,6 @@
 #include "internal/has_apply0.hpp"
 #include "internal/missing_apply.hpp"
 #include "internal/missing_apply0.hpp"
-#include "internal/skip_control.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
 {
@@ -30,20 +29,20 @@ namespace TAO_PEGTL_NAMESPACE
              class Action,
              template< typename... >
              class Control,
-             typename Input,
+             typename ParseInput,
              typename... States >
-   [[nodiscard]] bool match( Input& in, States&&... st )
+   [[nodiscard]] bool match( ParseInput& in, States&&... st )
    {
-      constexpr bool enable_control = !internal::skip_control< Rule >;
+      constexpr bool enable_control = Control< Rule >::enable;
       constexpr bool enable_action = enable_control && ( A == apply_mode::action );
 
-      using iterator_t = typename Input::iterator_t;
-      constexpr bool has_apply_void = enable_action && internal::has_apply< Control< Rule >, void, Action, const iterator_t&, const Input&, States... >::value;
-      constexpr bool has_apply_bool = enable_action && internal::has_apply< Control< Rule >, bool, Action, const iterator_t&, const Input&, States... >::value;
+      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 Input&, States... >::value;
-      constexpr bool has_apply0_bool = enable_action && internal::has_apply0< Control< Rule >, bool, Action, const Input&, States... >::value;
+      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" );
diff --git a/packages/PEGTL/include/tao/pegtl/must_if.hpp b/packages/PEGTL/include/tao/pegtl/must_if.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..ab15cb6b6c71fbd0f287b3e5edda55c9ded4313e
--- /dev/null
+++ b/packages/PEGTL/include/tao/pegtl/must_if.hpp
@@ -0,0 +1,62 @@
+// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#ifndef TAO_PEGTL_MUST_IF_HPP
+#define TAO_PEGTL_MUST_IF_HPP
+
+#include "config.hpp"
+#include "normal.hpp"
+
+namespace TAO_PEGTL_NAMESPACE
+{
+   namespace internal
+   {
+      template< typename T, typename Rule, typename = void >
+      inline constexpr bool raise_on_failure = ( T::template message< Rule > != nullptr );
+
+      template< typename T, typename Rule >
+      inline constexpr bool raise_on_failure< T, Rule, decltype( T::template raise_on_failure< Rule >, void() ) > = T::template raise_on_failure< Rule >;
+
+   }  // namespace internal
+
+   template< typename T, template< typename... > class Base = normal, bool RequireMessage = true >
+   struct must_if
+   {
+      template< typename Rule >
+      struct control
+         : Base< Rule >
+      {
+         template< typename ParseInput, typename... States >
+         static void failure( const ParseInput& in, States&&... st ) noexcept( !internal::raise_on_failure< T, Rule > && noexcept( Base< Rule >::failure( in, st... ) ) )
+         {
+            if constexpr( internal::raise_on_failure< T, Rule > ) {
+               raise( in, st... );
+            }
+            else {
+               Base< Rule >::failure( in, st... );
+            }
+         }
+
+         template< typename ParseInput, typename... States >
+         [[noreturn]] static void raise( const ParseInput& in, States&&... st )
+         {
+            if constexpr( RequireMessage ) {
+               static_assert( T::template message< Rule > != nullptr );
+            }
+            if constexpr( T::template message< Rule > != nullptr ) {
+               constexpr const char* p = T::template message< Rule >;
+               throw parse_error( p, in );
+#if defined( _MSC_VER )
+               (void)( (void)st, ... );
+#endif
+            }
+            else {
+               Base< Rule >::raise( in, st... );
+            }
+         }
+      };
+   };
+
+}  // namespace TAO_PEGTL_NAMESPACE
+
+#endif
diff --git a/packages/PEGTL/include/tao/pegtl/normal.hpp b/packages/PEGTL/include/tao/pegtl/normal.hpp
index a96d0d0d36ad3df447ef6020fdaf655d1e1ef8da..5d7845b99433dd041d51ef05b1740d392f12dab7 100644
--- a/packages/PEGTL/include/tao/pegtl/normal.hpp
+++ b/packages/PEGTL/include/tao/pegtl/normal.hpp
@@ -15,58 +15,49 @@
 #include "rewind_mode.hpp"
 
 #include "internal/demangle.hpp"
+#include "internal/enable_control.hpp"
 #include "internal/has_match.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
 {
-   template< typename Rule >
-   inline constexpr const char* error_message = nullptr;
-
    template< typename Rule >
    struct normal
    {
-      template< typename Input, typename... States >
-      static void start( const Input& /*unused*/, States&&... /*unused*/ ) noexcept
+      static constexpr bool enable = internal::enable_control< Rule >;
+
+      template< typename ParseInput, typename... States >
+      static void start( const ParseInput& /*unused*/, States&&... /*unused*/ ) noexcept
       {}
 
-      template< typename Input, typename... States >
-      static void success( const Input& /*unused*/, States&&... /*unused*/ ) noexcept
+      template< typename ParseInput, typename... States >
+      static void success( const ParseInput& /*unused*/, States&&... /*unused*/ ) noexcept
       {}
 
-      template< typename Input, typename... States >
-      static void failure( const Input& in, States&&... /*unused*/ ) noexcept( error_message< Rule > == nullptr )
-      {
-         if constexpr( error_message< Rule > != nullptr ) {
-            throw parse_error( error_message< Rule >, in );
-         }
-#if defined( _MSC_VER )
-         else {
-            (void)in;
-         }
-#endif
-      }
+      template< typename ParseInput, typename... States >
+      static void failure( const ParseInput& /*unused*/, States&&... /*unused*/ ) noexcept
+      {}
 
-      template< typename Input, typename... States >
-      static void raise( const Input& in, States&&... /*unused*/ )
+      template< typename ParseInput, typename... States >
+      [[noreturn]] static void raise( const ParseInput& in, States&&... /*unused*/ )
       {
          throw parse_error( "parse error matching " + std::string( internal::demangle< Rule >() ), in );
       }
 
       template< template< typename... > class Action,
                 typename Iterator,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      static auto apply( const Iterator& begin, const Input& in, States&&... st ) noexcept( noexcept( Action< Rule >::apply( std::declval< const typename Input::action_t& >(), st... ) ) )
-         -> decltype( Action< Rule >::apply( std::declval< const typename Input::action_t& >(), st... ) )
+      static auto apply( const Iterator& begin, const ParseInput& in, States&&... st ) noexcept( noexcept( Action< Rule >::apply( std::declval< const typename ParseInput::action_t& >(), st... ) ) )
+         -> decltype( Action< Rule >::apply( std::declval< const typename ParseInput::action_t& >(), st... ) )
       {
-         const typename Input::action_t action_input( begin, in );
+         const typename ParseInput::action_t action_input( begin, in );
          return Action< Rule >::apply( action_input, st... );
       }
 
       template< template< typename... > class Action,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      static auto apply0( const Input& /*unused*/, States&&... st ) noexcept( noexcept( Action< Rule >::apply0( st... ) ) )
+      static auto apply0( const ParseInput& /*unused*/, States&&... st ) noexcept( noexcept( Action< Rule >::apply0( st... ) ) )
          -> decltype( Action< Rule >::apply0( st... ) )
       {
          return Action< Rule >::apply0( st... );
@@ -78,11 +69,11 @@ namespace TAO_PEGTL_NAMESPACE
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... st )
+      [[nodiscard]] static bool match( ParseInput& in, States&&... st )
       {
-         if constexpr( internal::has_match_v< Rule, A, M, Action, Control, Input, States... > ) {
+         if constexpr( internal::has_match< bool, Rule, A, M, Action, Control, ParseInput, States... > ) {
             return Action< Rule >::template match< Rule, A, M, Action, Control >( in, st... );
          }
          else {
diff --git a/packages/PEGTL/include/tao/pegtl/parse.hpp b/packages/PEGTL/include/tao/pegtl/parse.hpp
index 2cc622dac0034919cc317bbe378c341a67342ab9..7d435708a06209082cca146350cd993c218acf70 100644
--- a/packages/PEGTL/include/tao/pegtl/parse.hpp
+++ b/packages/PEGTL/include/tao/pegtl/parse.hpp
@@ -13,8 +13,6 @@
 #include "parse_error.hpp"
 #include "rewind_mode.hpp"
 
-#include "internal/action_input.hpp"
-
 namespace TAO_PEGTL_NAMESPACE
 {
    template< typename Rule,
@@ -22,9 +20,9 @@ namespace TAO_PEGTL_NAMESPACE
              template< typename... > class Control = normal,
              apply_mode A = apply_mode::action,
              rewind_mode M = rewind_mode::required,
-             typename Input,
+             typename ParseInput,
              typename... States >
-   bool parse( Input&& in, States&&... st )
+   bool parse( ParseInput&& in, States&&... st )
    {
       return Control< Rule >::template match< A, M, Action, Control >( in, st... );
    }
@@ -34,10 +32,10 @@ namespace TAO_PEGTL_NAMESPACE
              template< typename... > class Control = normal,
              apply_mode A = apply_mode::action,
              rewind_mode M = rewind_mode::required,
-             typename Outer,
-             typename Input,
+             typename OuterInput,
+             typename ParseInput,
              typename... States >
-   bool parse_nested( const Outer& oi, Input&& in, States&&... st )
+   bool parse_nested( const OuterInput& oi, ParseInput&& in, States&&... st )
    {
       try {
          return parse< Rule, Action, Control, A, M >( in, st... );
diff --git a/packages/PEGTL/include/tao/pegtl/parse_error.hpp b/packages/PEGTL/include/tao/pegtl/parse_error.hpp
index 277d4cc2de7189b17f2b8782375665d9906a9b00..d48f95b830048929c62fbaba1348be9be915b721 100644
--- a/packages/PEGTL/include/tao/pegtl/parse_error.hpp
+++ b/packages/PEGTL/include/tao/pegtl/parse_error.hpp
@@ -38,8 +38,8 @@ namespace TAO_PEGTL_NAMESPACE
          positions.emplace_back( std::move( pos ) );
       }
 
-      template< typename Msg, typename Input >
-      parse_error( Msg&& msg, const Input& in )
+      template< typename Msg, typename ParseInput >
+      parse_error( Msg&& msg, const ParseInput& in )
          : parse_error( std::forward< Msg >( msg ), in.position() )
       {}
 
diff --git a/packages/PEGTL/include/tao/pegtl/rules.hpp b/packages/PEGTL/include/tao/pegtl/rules.hpp
index d1ced0a7972b292ab14cd49f74e76dab7f5d167f..659619c0eda2725b8bf3d6d67ae1fb912ba17249 100644
--- a/packages/PEGTL/include/tao/pegtl/rules.hpp
+++ b/packages/PEGTL/include/tao/pegtl/rules.hpp
@@ -24,7 +24,8 @@ namespace TAO_PEGTL_NAMESPACE
    struct discard : internal::discard {};
    template< typename... Rules > struct enable : internal::enable< Rules... > {};
    struct eof : internal::eof {};
-   struct failure : internal::trivial< false > {};
+   struct eolf : internal::eolf {};
+   struct failure : internal::failure {};
    template< typename Rule, typename... Actions > struct if_apply : internal::if_apply< Rule, Actions... > {};
    template< typename Cond, typename... Thens > struct if_must : internal::if_must< false, Cond, Thens... > {};
    template< typename Cond, typename Then, typename Else > struct if_must_else : internal::if_must_else< Cond, Then, Else > {};
@@ -35,7 +36,7 @@ namespace TAO_PEGTL_NAMESPACE
    template< typename Rule, typename Sep > struct list_must< Rule, Sep, void > : internal::list_must< Rule, Sep > {};
    template< typename Rule, typename Sep, typename Pad = void > struct list_tail : internal::list_tail_pad< Rule, Sep, Pad > {};
    template< typename Rule, typename Sep > struct list_tail< Rule, Sep, void > : internal::list_tail< Rule, Sep > {};
-   template< typename M, typename S > struct minus : internal::rematch< M, internal::not_at< S, internal::eof > > {};
+   template< typename M, typename S > struct minus : internal::minus< M, S > {};
    template< typename... Rules > struct must : internal::must< Rules... > {};
    template< typename... Rules > struct not_at : internal::not_at< Rules... > {};
    template< typename... Rules > struct opt : internal::opt< Rules... > {};
@@ -56,7 +57,7 @@ namespace TAO_PEGTL_NAMESPACE
    template< typename Rule, typename... Rules > struct star : internal::star< Rule, Rules... > {};
    template< typename Cond, typename... Rules > struct star_must : internal::star_must< Cond, Rules... > {};
    template< typename State, typename... Rules > struct state : internal::state< State, Rules... > {};
-   struct success : internal::trivial< true > {};
+   struct success : internal::success {};
    template< typename... Rules > struct try_catch : internal::seq< internal::try_catch_type< parse_error, Rules... > > {};
    template< typename Exception, typename... Rules > struct try_catch_type : internal::seq< internal::try_catch_type< Exception, Rules... > > {};
    template< typename Cond, typename... Rules > struct until : internal::until< Cond, Rules... > {};
diff --git a/packages/PEGTL/include/tao/pegtl/type_list.hpp b/packages/PEGTL/include/tao/pegtl/type_list.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..a6bfcdfd34baa871a891478e56cb8684b22030f5
--- /dev/null
+++ b/packages/PEGTL/include/tao/pegtl/type_list.hpp
@@ -0,0 +1,46 @@
+// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#ifndef TAO_PEGTL_TYPE_LIST_HPP
+#define TAO_PEGTL_TYPE_LIST_HPP
+
+#include <cstddef>
+
+#include "config.hpp"
+
+namespace TAO_PEGTL_NAMESPACE
+{
+   template< typename... Ts >
+   struct type_list
+   {
+      static constexpr std::size_t size = sizeof...( Ts );
+   };
+
+   using empty_list = type_list<>;
+
+   template< typename... >
+   struct type_list_concat;
+
+   template<>
+   struct type_list_concat<>
+   {
+      using type = empty_list;
+   };
+
+   template< typename... Ts >
+   struct type_list_concat< type_list< Ts... > >
+   {
+      using type = type_list< Ts... >;
+   };
+
+   template< typename... T0s, typename... T1s, typename... Ts >
+   struct type_list_concat< type_list< T0s... >, type_list< T1s... >, Ts... >
+      : type_list_concat< type_list< T0s..., T1s... >, Ts... >
+   {};
+
+   template< typename... Ts >
+   using type_list_concat_t = typename type_list_concat< Ts... >::type;
+
+}  // namespace TAO_PEGTL_NAMESPACE
+
+#endif
diff --git a/packages/PEGTL/include/tao/pegtl/visit.hpp b/packages/PEGTL/include/tao/pegtl/visit.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..ad575bd590e87883bae31a46c589321b560b3be3
--- /dev/null
+++ b/packages/PEGTL/include/tao/pegtl/visit.hpp
@@ -0,0 +1,66 @@
+// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#ifndef TAO_PEGTL_VISIT_HPP
+#define TAO_PEGTL_VISIT_HPP
+
+#include <type_traits>
+
+#include "config.hpp"
+#include "type_list.hpp"
+
+namespace TAO_PEGTL_NAMESPACE
+{
+   namespace internal
+   {
+      template< typename Type, typename... Types >
+      inline constexpr bool contains = ( std::is_same_v< Type, Types > || ... );
+
+      template< typename Rules, typename Todo, typename Done >
+      struct filter
+      {
+         using type = Todo;
+      };
+
+      template< typename Rule, typename... Rules, typename... Todo, typename... Done >
+      struct filter< type_list< Rule, Rules... >, type_list< Todo... >, type_list< Done... > >
+         : filter< type_list< Rules... >, std::conditional_t< contains< Rule, Todo..., Done... >, type_list< Todo... >, type_list< Rule, Todo... > >, type_list< Done... > >
+      {};
+
+      template< typename Rules, typename Todo, typename Done >
+      using filter_t = typename filter< Rules, Todo, Done >::type;
+
+      template< template< typename... > class Func, typename Done, typename... Rules >
+      struct visitor
+      {
+         template< typename... Args >
+         static void visit( Args&&... args )
+         {
+            ( Func< Rules >::visit( args... ), ... );
+            using NextDone = type_list_concat_t< type_list< Rules... >, Done >;
+            using NextSubs = type_list_concat_t< typename Rules::subs_t... >;
+            using NextTodo = filter_t< NextSubs, empty_list, NextDone >;
+            if constexpr( !std::is_same_v< NextTodo, empty_list > ) {
+               visit_next< NextDone >( NextTodo(), args... );
+            }
+         }
+
+      private:
+         template< typename NextDone, typename... NextTodo, typename... Args >
+         static void visit_next( type_list< NextTodo... > /*unused*/, Args&&... args )
+         {
+            visitor< Func, NextDone, NextTodo... >::visit( args... );
+         }
+      };
+
+   }  // namespace internal
+
+   template< typename Rule, template< typename... > class Func, typename... Args >
+   void visit( Args&&... args )
+   {
+      internal::visitor< Func, empty_list, Rule >::visit( args... );
+   }
+
+}  // namespace TAO_PEGTL_NAMESPACE
+
+#endif
diff --git a/packages/PEGTL/src/example/pegtl/CMakeLists.txt b/packages/PEGTL/src/example/pegtl/CMakeLists.txt
index 2fed9a883279bf46e9e6178ec8b5a1b5a24ba56a..60518785710ccf34241b761ef4dfef3d6d6c4a52 100644
--- a/packages/PEGTL/src/example/pegtl/CMakeLists.txt
+++ b/packages/PEGTL/src/example/pegtl/CMakeLists.txt
@@ -12,7 +12,10 @@ set(example_sources
   indent_aware.cpp
   json_build.cpp
   json_count.cpp
+  json_coverage.cpp
   json_parse.cpp
+  json_print_rules.cpp
+  json_print_sub_rules.cpp
   lua53_parse.cpp
   modulus_match.cpp
   parse_tree.cpp
diff --git a/packages/PEGTL/src/example/pegtl/abnf2pegtl.cpp b/packages/PEGTL/src/example/pegtl/abnf2pegtl.cpp
index 93d425ce35dd6e6ba206d0a050dff4ab9f076d34..5af83c55112402a143afa902ce883e6b5bf2ce49 100644
--- a/packages/PEGTL/src/example/pegtl/abnf2pegtl.cpp
+++ b/packages/PEGTL/src/example/pegtl/abnf2pegtl.cpp
@@ -24,8 +24,8 @@
 #endif
 
 #include <tao/pegtl.hpp>
-#include <tao/pegtl/analyze.hpp>
 #include <tao/pegtl/contrib/abnf.hpp>
+#include <tao/pegtl/contrib/analyze.hpp>
 #include <tao/pegtl/contrib/parse_tree.hpp>
 
 namespace TAO_PEGTL_NAMESPACE
@@ -208,18 +208,17 @@ namespace TAO_PEGTL_NAMESPACE
          // ABNF from somewhere might lead to surprising results as the
          // alternations are now sequential, using the sor<> rule.
          //
-         // PEG also require two extensions: the and-predicate and the
+         // PEGs also require two extensions: The and-predicate and the
          // not-predicate. They are expressed by '&' and '!' respectively,
          // being allowed (optionally, only one of them) before the
          // repetition. You can use braces for more complex expressions.
          //
          // Finally, instead of the pre-defined CRLF sequence, we accept
-         // any type of line ending as a convenience extension:
+         // any type of line ending as a convenience extension.
 
          // clang-format off
          struct CRLF : sor< abnf::CRLF, CR, LF > {};
 
-         // The rest is according to the RFC(s):
          struct comment_cont : until< CRLF, sor< WSP, VCHAR > > {};
          struct comment : seq< one< ';' >, comment_cont > {};
          struct c_nl : sor< comment, CRLF > {};
@@ -279,33 +278,51 @@ namespace TAO_PEGTL_NAMESPACE
 
       }  // namespace grammar
 
-   }  // namespace abnf
+      // Using must_if<> we define a control class which is used for
+      // the parsing run instead of the default control class.
+      //
+      // This improves the errors reported to the user.
+      //
+      // The following turns local errors into global errors, i.e.
+      // if one of the rules for which a custom error message is
+      // defined fails, it throws a parse_error exception (aka global
+      // failure) instead of returning false (aka local failure).
 
-   // clang-format off
-   template<> constexpr const char* error_message< abnf::grammar::comment_cont > = "unterminated comment";
+      // clang-format off
+      template< typename > inline constexpr const char* error_message = nullptr;
 
-   template<> constexpr const char* error_message< abnf::grammar::quoted_string_cont > = "unterminated string (missing '\"')";
-   template<> constexpr const char* error_message< abnf::grammar::prose_val_cont > = "unterminated prose description (missing '>')";
+      template<> inline constexpr auto error_message< abnf::grammar::comment_cont > = "unterminated comment";
 
-   template<> constexpr const char* error_message< abnf::grammar::hex_val::value > = "expected hexadecimal value";
-   template<> constexpr const char* error_message< abnf::grammar::dec_val::value > = "expected decimal value";
-   template<> constexpr const char* error_message< abnf::grammar::bin_val::value > = "expected binary value";
-   template<> constexpr const char* error_message< abnf::grammar::num_val_choice > = "expected base specifier (one of 'bBdDxX')";
+      template<> inline constexpr auto error_message< abnf::grammar::quoted_string_cont > = "unterminated string (missing '\"')";
+      template<> inline constexpr auto error_message< abnf::grammar::prose_val_cont > = "unterminated prose description (missing '>')";
 
-   template<> constexpr const char* error_message< abnf::grammar::option_close > = "unterminated option (missing ']')";
-   template<> constexpr const char* error_message< abnf::grammar::group_close > = "unterminated group (missing ')')";
+      template<> inline constexpr auto error_message< abnf::grammar::hex_val::value > = "expected hexadecimal value";
+      template<> inline constexpr auto error_message< abnf::grammar::dec_val::value > = "expected decimal value";
+      template<> inline constexpr auto error_message< abnf::grammar::bin_val::value > = "expected binary value";
+      template<> inline constexpr auto error_message< abnf::grammar::num_val_choice > = "expected base specifier (one of 'bBdDxX')";
 
-   template<> constexpr const char* error_message< abnf::grammar::req_repetition > = "expected element";
-   template<> constexpr const char* error_message< abnf::grammar::concatenation > = "expected element";
-   template<> constexpr const char* error_message< abnf::grammar::alternation > = "expected element";
+      template<> inline constexpr auto error_message< abnf::grammar::option_close > = "unterminated option (missing ']')";
+      template<> inline constexpr auto error_message< abnf::grammar::group_close > = "unterminated group (missing ')')";
 
-   template<> constexpr const char* error_message< abnf::grammar::defined_as > = "expected '=' or '=/'";
-   template<> constexpr const char* error_message< abnf::grammar::req_c_nl > = "unterminated rule";
-   template<> constexpr const char* error_message< abnf::grammar::rule > = "expected rule";
-   // clang-format on
+      template<> inline constexpr auto error_message< abnf::grammar::req_repetition > = "expected element";
+      template<> inline constexpr auto error_message< abnf::grammar::concatenation > = "expected element";
+      template<> inline constexpr auto error_message< abnf::grammar::alternation > = "expected element";
+
+      template<> inline constexpr auto error_message< abnf::grammar::defined_as > = "expected '=' or '=/'";
+      template<> inline constexpr auto error_message< abnf::grammar::req_c_nl > = "unterminated rule";
+      template<> inline constexpr auto error_message< abnf::grammar::rule > = "expected rule";
+
+      struct error { template< typename Rule > static constexpr auto message = error_message< Rule >; };
+      template< typename Rule > using control = must_if< error >::control< Rule >;
+      // clang-format on
+
+      // Since we are going to generate a parse tree, we define a
+      // selector that decides which rules will be included in our
+      // parse tree, which rules will be omitted from the parse tree,
+      // and which of the nodes will store the matched content.
+      // Additionally, some nodes will fold when they have exactly
+      // one child node. (see fold_one below)
 
-   namespace abnf
-   {
       template< typename Rule >
       struct selector
          : parse_tree::selector<
@@ -334,11 +351,17 @@ namespace TAO_PEGTL_NAMESPACE
                  grammar::group,
                  grammar::repetition,
                  grammar::concatenation > >
-      {
-      };
+      {};
+
+      // Besides the above "simple" list of selected rules,
+      // we also provide special handling to some nodes.
+      // When they are inserted into the parse tree, the
+      // transform method allows additional tree transformations
+      // in order to improve the generated tree.
 
       template<>
-      struct selector< grammar::quoted_string > : std::true_type
+      struct selector< grammar::quoted_string >
+         : std::true_type
       {
          template< typename... States >
          static void transform( node_ptr& n )
@@ -363,7 +386,8 @@ namespace TAO_PEGTL_NAMESPACE
       };
 
       template<>
-      struct selector< grammar::case_sensitive_string > : std::true_type
+      struct selector< grammar::case_sensitive_string >
+         : std::true_type
       {
          template< typename... States >
          static void transform( node_ptr& n )
@@ -443,7 +467,8 @@ namespace TAO_PEGTL_NAMESPACE
       }  // namespace
 
       template<>
-      struct selector< grammar::rule > : std::true_type
+      struct selector< grammar::rule >
+         : std::true_type
       {
          template< typename... States >
          static void transform( node_ptr& n )
@@ -497,6 +522,9 @@ namespace TAO_PEGTL_NAMESPACE
          }
       };
 
+      // Finally, the generated parse tree for each node is converted to
+      // a C++ source code string.
+
       struct stringifier
       {
          using function_t = std::string ( * )( const node_ptr& n );
@@ -699,7 +727,7 @@ int main( int argc, char** argv )  // NOLINT(bugprone-exception-escape)
 
    file_input in( argv[ 1 ] );
    try {
-      const auto root = parse_tree::parse< abnf::grammar::rulelist, abnf::selector >( in );
+      const auto root = parse_tree::parse< abnf::grammar::rulelist, abnf::selector, nothing, abnf::control >( in );
 
       for( const auto& rule : root->children ) {
          abnf::rules_defined.push_back( abnf::get_rulename( rule->children.front() ) );
diff --git a/packages/PEGTL/src/example/pegtl/analyze.cpp b/packages/PEGTL/src/example/pegtl/analyze.cpp
index 0e4e6416aac5eb3d43a127aa5328813dea9ca74b..1079686f185282854f767525c7ee295ec797ac9d 100644
--- a/packages/PEGTL/src/example/pegtl/analyze.cpp
+++ b/packages/PEGTL/src/example/pegtl/analyze.cpp
@@ -2,7 +2,8 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include <tao/pegtl.hpp>
-#include <tao/pegtl/analyze.hpp>
+
+#include <tao/pegtl/contrib/analyze.hpp>
 
 using namespace TAO_PEGTL_NAMESPACE;
 
diff --git a/packages/PEGTL/src/example/pegtl/calculator.cpp b/packages/PEGTL/src/example/pegtl/calculator.cpp
index bbc6751098b0abc3030713eeb508308a151db736..4612216f58fe47efd7d85273f141ea1202217fce 100644
--- a/packages/PEGTL/src/example/pegtl/calculator.cpp
+++ b/packages/PEGTL/src/example/pegtl/calculator.cpp
@@ -13,7 +13,7 @@
 // Include the analyze function that checks
 // a grammar for possible infinite cycles.
 
-#include <tao/pegtl/analyze.hpp>
+#include <tao/pegtl/contrib/analyze.hpp>
 
 namespace pegtl = TAO_PEGTL_NAMESPACE;
 
@@ -205,7 +205,7 @@ namespace calculator
 
    struct infix
    {
-      using analyze_t = analysis::generic< analysis::rule_type::any >;
+      using rule_t = ascii::any::rule_t;
 
       template< apply_mode,
                 rewind_mode,
@@ -213,9 +213,9 @@ namespace calculator
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      static bool match( Input& in, const operators& b, stacks& s, States&&... /*unused*/ )
+      static bool match( ParseInput& in, const operators& b, stacks& s, States&&... /*unused*/ )
       {
          // Look for the longest match of the input against the operators in the operator map.
 
@@ -223,8 +223,8 @@ namespace calculator
       }
 
    private:
-      template< typename Input >
-      static bool match( Input& in, const operators& b, stacks& s, std::string t )
+      template< typename ParseInput >
+      static bool match( ParseInput& in, const operators& b, stacks& s, std::string t )
       {
          if( in.size( t.size() + 1 ) > t.size() ) {
             t += in.peek_char( t.size() );
@@ -299,8 +299,8 @@ namespace calculator
    template<>
    struct action< number >
    {
-      template< typename Input >
-      static void apply( const Input& in, const operators& /*unused*/, stacks& s )
+      template< typename ActionInput >
+      static void apply( const ActionInput& in, const operators& /*unused*/, stacks& s )
       {
          std::stringstream ss( in.string() );
          long v;
diff --git a/packages/PEGTL/src/example/pegtl/chomsky_hierarchy.cpp b/packages/PEGTL/src/example/pegtl/chomsky_hierarchy.cpp
index 1099fcb2dc78d2a387af38a71892c4136ec22fb4..7624b26f79ec132ebaffecb82210433146e60c3f 100644
--- a/packages/PEGTL/src/example/pegtl/chomsky_hierarchy.cpp
+++ b/packages/PEGTL/src/example/pegtl/chomsky_hierarchy.cpp
@@ -44,9 +44,9 @@ namespace example
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      static bool match( Input& in, std::size_t& count, States&&... /*unused*/ )
+      static bool match( ParseInput& in, std::size_t& count, States&&... /*unused*/ )
       {
          if( in.size( count ) >= count ) {
             for( std::size_t i = 0; i < count; ++i ) {
@@ -72,8 +72,8 @@ namespace example
    template<>
    struct action_2_with_state< pegtl::star< pegtl::one< 'a' > > >
    {
-      template< typename Input >
-      static void apply( const Input& in, std::size_t& count )
+      template< typename ActionInput >
+      static void apply( const ActionInput& in, std::size_t& count )
       {
          count = in.size();
       }
diff --git a/packages/PEGTL/src/example/pegtl/csv1.cpp b/packages/PEGTL/src/example/pegtl/csv1.cpp
index 09aed9205bedf8e9a073538c8f225159237e55ef..b81eb638e402c52302e95a75919d40b0b37c70c4 100644
--- a/packages/PEGTL/src/example/pegtl/csv1.cpp
+++ b/packages/PEGTL/src/example/pegtl/csv1.cpp
@@ -50,8 +50,8 @@ namespace csv1
    template<>
    struct action< value >
    {
-      template< typename Input >
-      static void apply( const Input& in, result_data& data )
+      template< typename ActionInput >
+      static void apply( const ActionInput& in, result_data& data )
       {
          assert( !data.empty() );
          std::stringstream ss( in.string() );
@@ -70,14 +70,14 @@ namespace csv1
    struct control< value_line >
       : pegtl::normal< value_line >
    {
-      template< typename Input >
-      static void start( Input& /*unused*/, result_data& data )
+      template< typename ParseInput >
+      static void start( ParseInput& /*unused*/, result_data& data )
       {
          data.emplace_back();
       }
 
-      template< typename Input >
-      static void failure( Input& /*unused*/, result_data& data )
+      template< typename ParseInput >
+      static void failure( ParseInput& /*unused*/, result_data& data )
       {
          assert( !data.empty() );
          data.pop_back();
diff --git a/packages/PEGTL/src/example/pegtl/csv2.cpp b/packages/PEGTL/src/example/pegtl/csv2.cpp
index 2fb912f6c5d5d6273ad746c11ca724e2f3fa40b9..328744a0e9896590ac17ac14bd004d639f7fffef 100644
--- a/packages/PEGTL/src/example/pegtl/csv2.cpp
+++ b/packages/PEGTL/src/example/pegtl/csv2.cpp
@@ -91,8 +91,8 @@ namespace csv2
    template<>
    struct action< plain_value >
    {
-      template< typename Input, unsigned N >
-      static void apply( const Input& in, result_data< N >& data )
+      template< typename ActionInput, unsigned N >
+      static void apply( const ActionInput& in, result_data< N >& data )
       {
          data.temp.push_back( in.string() );
       }
@@ -108,8 +108,8 @@ namespace csv2
    {
       using tuple_t = typename tuple_help< N, std::tuple<> >::tuple_t;
 
-      template< typename Input >
-      static void apply( const Input& in, result_data< N >& data )
+      template< typename ActionInput >
+      static void apply( const ActionInput& in, result_data< N >& data )
       {
          if( data.temp.size() != N ) {
             throw pegtl::parse_error( "column count mismatch", in );
diff --git a/packages/PEGTL/src/example/pegtl/dynamic_match.cpp b/packages/PEGTL/src/example/pegtl/dynamic_match.cpp
index a0636b6d3c05ee7defd4ba6c678ead10c13b66b6..da9f2dc24623dc5ce150b1847d1347c994aecc1f 100644
--- a/packages/PEGTL/src/example/pegtl/dynamic_match.cpp
+++ b/packages/PEGTL/src/example/pegtl/dynamic_match.cpp
@@ -1,6 +1,7 @@
 // Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
+#include <cassert>
 #include <cstring>
 
 #include <iostream>
@@ -8,6 +9,8 @@
 
 #include <tao/pegtl.hpp>
 
+#include <tao/pegtl/contrib/analyze.hpp>
+
 namespace pegtl = TAO_PEGTL_NAMESPACE;
 
 namespace dynamic
@@ -22,15 +25,17 @@ namespace dynamic
 
    struct long_literal_mark
    {
+      using rule_t = long_literal_mark;
+
       template< pegtl::apply_mode,
                 pegtl::rewind_mode,
                 template< typename... >
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      static bool match( Input& in, const std::string& id, const std::string& /*unused*/, States&&... /*unused*/ )
+      static bool match( ParseInput& in, const std::string& id, const std::string& /*unused*/, States&&... /*unused*/ )
       {
          if( in.size( id.size() ) >= id.size() ) {
             if( std::memcmp( in.current(), id.data(), id.size() ) == 0 ) {
@@ -61,8 +66,8 @@ namespace dynamic
    template<>
    struct action< long_literal_id >
    {
-      template< typename Input >
-      static void apply( const Input& in, std::string& id, const std::string& /*unused*/ )
+      template< typename ActionInput >
+      static void apply( const ActionInput& in, std::string& id, const std::string& /*unused*/ )
       {
          id = in.string();
       }
@@ -71,8 +76,8 @@ namespace dynamic
    template<>
    struct action< long_literal_body >
    {
-      template< typename Input >
-      static void apply( const Input& in, const std::string& /*unused*/, std::string& body )
+      template< typename ActionInput >
+      static void apply( const ActionInput& in, const std::string& /*unused*/, std::string& body )
       {
          body += in.string();
       }
@@ -80,8 +85,20 @@ namespace dynamic
 
 }  // namespace dynamic
 
+namespace TAO_PEGTL_NAMESPACE
+{
+   template< typename Name >
+   struct analyze_traits< Name, dynamic::long_literal_mark >
+      : analyze_any_traits<>
+   {};
+
+}  // namespace TAO_PEGTL_NAMESPACE
+
 int main( int argc, char** argv )  // NOLINT(bugprone-exception-escape)
 {
+   const auto issues = pegtl::analyze< dynamic::grammar >();
+   assert( !issues );
+
    if( argc > 1 ) {
       std::string id;
       std::string body;
diff --git a/packages/PEGTL/src/example/pegtl/hello_world.cpp b/packages/PEGTL/src/example/pegtl/hello_world.cpp
index e6522777634a0ecd92f9863dfd58a522dd2810f4..4ff0cd258e0358cedf28edacf4d4a388f39ce624 100644
--- a/packages/PEGTL/src/example/pegtl/hello_world.cpp
+++ b/packages/PEGTL/src/example/pegtl/hello_world.cpp
@@ -23,8 +23,8 @@ namespace hello
    template<>
    struct action< name >
    {
-      template< typename Input >
-      static void apply( const Input& in, std::string& v )
+      template< typename ActionInput >
+      static void apply( const ActionInput& in, std::string& v )
       {
          v = in.string();
       }
diff --git a/packages/PEGTL/src/example/pegtl/indent_aware.cpp b/packages/PEGTL/src/example/pegtl/indent_aware.cpp
index 056ec661640099a1eca5c57c9c15a14ecbff9afc..27b484aac59b77077e23cd83c9bb6bec136b41b9 100644
--- a/packages/PEGTL/src/example/pegtl/indent_aware.cpp
+++ b/packages/PEGTL/src/example/pegtl/indent_aware.cpp
@@ -132,8 +132,8 @@ namespace example
    template<>
    struct action< else_line >
    {
-      template< typename Input >
-      static void apply( const Input& in, state& s )
+      template< typename ActionInput >
+      static void apply( const ActionInput& in, state& s )
       {
          assert( !s.stack.empty() );
          if( ( s.stack.back().type != type::if_ ) || ( s.stack.back().indent != s.current_indent ) ) {
@@ -155,8 +155,8 @@ namespace example
    template<>
    struct action< nothing >
    {
-      template< typename Input >
-      static void apply( const Input& in, state& s )
+      template< typename ActionInput >
+      static void apply( const ActionInput& in, state& s )
       {
          if( s.minimum_indent > 0 ) {
             throw pegtl::parse_error( "expected indented block instead of empty line", in );
@@ -168,8 +168,8 @@ namespace example
    template<>
    struct action< indent >
    {
-      template< typename Input >
-      static void apply( const Input& in, state& s )
+      template< typename ActionInput >
+      static void apply( const ActionInput& in, state& s )
       {
          s.current_indent = in.size();
          if( s.current_indent != 0 ) {
@@ -192,8 +192,8 @@ namespace example
    template<>
    struct action< grammar >
    {
-      template< typename Input >
-      static void apply( const Input& in, state& s )
+      template< typename ActionInput >
+      static void apply( const ActionInput& in, state& s )
       {
          if( s.minimum_indent > 0 ) {
             throw pegtl::parse_error( "expected indented block instead of eof", in );
diff --git a/packages/PEGTL/src/example/pegtl/json_build.cpp b/packages/PEGTL/src/example/pegtl/json_build.cpp
index f7ea3b9fe6393658698ebd1bf7aa6337ea5695b2..f4ec3dc9f61b476969531ea45647a23d609fb7f0 100644
--- a/packages/PEGTL/src/example/pegtl/json_build.cpp
+++ b/packages/PEGTL/src/example/pegtl/json_build.cpp
@@ -64,8 +64,8 @@ namespace examples
    template<>
    struct action< pegtl::json::number >
    {
-      template< typename Input >
-      static void apply( const Input& in, json_state& state )
+      template< typename ActionInput >
+      static void apply( const ActionInput& in, json_state& state )
       {
          std::stringstream ss( in.string() );
          long double v;
@@ -78,8 +78,8 @@ namespace examples
    struct action< pegtl::json::string::content >
       : json_unescape
    {
-      template< typename Input >
-      static void success( const Input& /*unused*/, std::string& s, json_state& state )
+      template< typename ParseInput >
+      static void success( const ParseInput& /*unused*/, std::string& s, json_state& state )
       {
          state.result = std::make_shared< string_json >( std::move( s ) );
       }
@@ -128,8 +128,8 @@ namespace examples
    struct action< pegtl::json::key::content >
       : json_unescape
    {
-      template< typename Input >
-      static void success( const Input& /*unused*/, std::string& s, json_state& state )
+      template< typename ParseInput >
+      static void success( const ParseInput& /*unused*/, std::string& s, json_state& state )
       {
          state.keys.push_back( std::move( s ) );
       }
@@ -167,7 +167,7 @@ int main( int argc, char** argv )  // NOLINT(bugprone-exception-escape)
    else {
       examples::json_state state;
       pegtl::file_input in( argv[ 1 ] );
-      pegtl::parse< examples::grammar, examples::action, examples::errors >( in, state );
+      pegtl::parse< examples::grammar, examples::action, examples::control >( in, state );
       assert( state.keys.empty() );
       assert( state.arrays.empty() );
       assert( state.objects.empty() );
diff --git a/packages/PEGTL/src/example/pegtl/json_count.cpp b/packages/PEGTL/src/example/pegtl/json_count.cpp
index 8ac72875c67de844f757b11943bce8fcb9a4949f..e0fb731afaf1c260f367d49dbc8adcb8b35a80a0 100644
--- a/packages/PEGTL/src/example/pegtl/json_count.cpp
+++ b/packages/PEGTL/src/example/pegtl/json_count.cpp
@@ -1,15 +1,57 @@
 // Copyright (c) 2017-2020 Dr. Colin Hirsch and Daniel Frey
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
+#include <cstddef>
 #include <iomanip>
 #include <iostream>
+#include <map>
+#include <string_view>
 
 #include <tao/pegtl.hpp>
-#include <tao/pegtl/contrib/counter.hpp>
+
 #include <tao/pegtl/contrib/json.hpp>
-#include <tao/pegtl/file_input.hpp>
+
+namespace TAO_PEGTL_NAMESPACE
+{
+   struct counter_data
+   {
+      std::size_t start = 0;
+      std::size_t success = 0;
+      std::size_t failure = 0;
+   };
+
+   struct counter_state
+   {
+      std::map< std::string_view, counter_data > counts;
+   };
+
+   template< typename Rule >
+   struct counter
+      : normal< Rule >
+   {
+      template< typename Input >
+      static void start( const Input& /*unused*/, counter_state& ts )
+      {
+         ++ts.counts[ internal::demangle< Rule >() ].start;
+      }
+
+      template< typename Input >
+      static void success( const Input& /*unused*/, counter_state& ts )
+      {
+         ++ts.counts[ internal::demangle< Rule >() ].success;
+      }
+
+      template< typename Input >
+      static void failure( const Input& /*unused*/, counter_state& ts )
+      {
+         ++ts.counts[ internal::demangle< Rule >() ].failure;
+      }
+   };
+
+}  // namespace TAO_PEGTL_NAMESPACE
 
 using namespace TAO_PEGTL_NAMESPACE;
+
 using grammar = must< json::text, eof >;
 
 int main( int argc, char** argv )  // NOLINT(bugprone-exception-escape)
diff --git a/packages/PEGTL/src/example/pegtl/json_coverage.cpp b/packages/PEGTL/src/example/pegtl/json_coverage.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b19c496929c3f5ce0cb3ad07c00599ed1b1b8c60
--- /dev/null
+++ b/packages/PEGTL/src/example/pegtl/json_coverage.cpp
@@ -0,0 +1,19 @@
+// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#include <iostream>
+
+#include <tao/pegtl.hpp>
+
+#include <tao/pegtl/contrib/coverage.hpp>
+#include <tao/pegtl/contrib/json.hpp>
+#include <tao/pegtl/contrib/print_coverage.hpp>
+
+int main( int argc, char** argv )  // NOLINT(bugprone-exception-escape)
+{
+   for( int i = 1; i < argc; ++i ) {
+      auto coverage = tao::pegtl::coverage< tao::pegtl::json::text >( tao::pegtl::file_input( argv[ i ] ) );
+      tao::pegtl::print_coverage( std::cout, coverage );
+   }
+   return 0;
+}
diff --git a/packages/PEGTL/src/example/pegtl/json_errors.hpp b/packages/PEGTL/src/example/pegtl/json_errors.hpp
index 2c0c2292c54d76731f6c2c45e55f7229f5f64c96..4f674f805188bfd015944c3dcd30f325e4e2a8d7 100644
--- a/packages/PEGTL/src/example/pegtl/json_errors.hpp
+++ b/packages/PEGTL/src/example/pegtl/json_errors.hpp
@@ -12,53 +12,38 @@ namespace pegtl = TAO_PEGTL_NAMESPACE;
 namespace examples
 {
    // This file shows how to throw exceptions with
-   // custom error messages for parse errors. A custom
-   // control class is created that delegates everything
-   // to the PEGTL default control class TAO_PEGTL_NAMESPACE::normal<>
-   // except for the throwing of exceptions:
+   // custom error messages for parse errors.
+   // As the grammar contains must<>-rules,
+   // the compiler will complain when a
+   // specialization is missing.
 
-   template< typename Rule >
-   struct errors
-      : public pegtl::normal< Rule >
-   {
-      static const std::string error_message;
+   // clang-format off
+   template< typename > inline constexpr const char* error_message = nullptr;
 
-      template< typename Input, typename... States >
-      static void raise( const Input& in, States&&... /*unused*/ )
-      {
-         throw pegtl::parse_error( error_message, in );
-      }
-   };
+   template<> inline constexpr auto error_message< pegtl::json::text > = "no valid JSON";
 
-   // The following specialisations of the static string
-   // member are then used in the exception messages:
+   template<> inline constexpr auto error_message< pegtl::json::end_array > = "incomplete array, expected ']'";
+   template<> inline constexpr auto error_message< pegtl::json::end_object > = "incomplete object, expected '}'";
+   template<> inline constexpr auto error_message< pegtl::json::member > = "expected member";
+   template<> inline constexpr auto error_message< pegtl::json::name_separator > = "expected ':'";
+   template<> inline constexpr auto error_message< pegtl::json::array_element > = "expected value";
+   template<> inline constexpr auto error_message< pegtl::json::value > = "expected value";
 
-   // clang-format off
-   template<> inline const std::string errors< pegtl::json::text >::error_message = "no valid JSON";
+   template<> inline constexpr auto error_message< pegtl::json::digits > = "expected at least one digit";
+   template<> inline constexpr auto error_message< pegtl::json::xdigit > = "incomplete universal character name";
+   template<> inline constexpr auto error_message< pegtl::json::escaped > = "unknown escape sequence";
+   template<> inline constexpr auto error_message< pegtl::json::char_ > = "invalid character in string";
+   template<> inline constexpr auto error_message< pegtl::json::string::content > = "unterminated string";
+   template<> inline constexpr auto error_message< pegtl::json::key::content > = "unterminated key";
 
-   template<> inline const std::string errors< pegtl::json::end_array >::error_message = "incomplete array, expected ']'";
-   template<> inline const std::string errors< pegtl::json::end_object >::error_message = "incomplete object, expected '}'";
-   template<> inline const std::string errors< pegtl::json::member >::error_message = "expected member";
-   template<> inline const std::string errors< pegtl::json::name_separator >::error_message = "expected ':'";
-   template<> inline const std::string errors< pegtl::json::array_element >::error_message = "expected value";
-   template<> inline const std::string errors< pegtl::json::value >::error_message = "expected value";
+   template<> inline constexpr auto error_message< pegtl::eof > = "unexpected character after JSON value";
 
-   template<> inline const std::string errors< pegtl::json::digits >::error_message = "expected at least one digit";
-   template<> inline const std::string errors< pegtl::json::xdigit >::error_message = "incomplete universal character name";
-   template<> inline const std::string errors< pegtl::json::escaped >::error_message = "unknown escape sequence";
-   template<> inline const std::string errors< pegtl::json::char_ >::error_message = "invalid character in string";
-   template<> inline const std::string errors< pegtl::json::string::content >::error_message = "unterminated string";
-   template<> inline const std::string errors< pegtl::json::key::content >::error_message = "unterminated key";
+   // As must_if can not take error_message as a template parameter directly, we need to wrap it:
+   struct error { template< typename Rule > static constexpr auto message = error_message< Rule >; };
 
-   template<> inline const std::string errors< pegtl::eof >::error_message = "unexpected character after JSON value";
+   template< typename Rule > using control = pegtl::must_if< error >::control< Rule >;
    // clang-format on
 
-   // The raise()-function-template is instantiated exactly
-   // for the specialisations of errors< Rule > for which a
-   // parse error can be generated, therefore the string
-   // error_message needs to be supplied only for these rules
-   // (and the compiler will complain if one is missing).
-
 }  // namespace examples
 
 #endif
diff --git a/packages/PEGTL/src/example/pegtl/json_parse.cpp b/packages/PEGTL/src/example/pegtl/json_parse.cpp
index db4e4cce447fb968a2bc38e9964d16bba78b7354..7db715bcc5314983cda4d7808c0bad1f6047e6b5 100644
--- a/packages/PEGTL/src/example/pegtl/json_parse.cpp
+++ b/packages/PEGTL/src/example/pegtl/json_parse.cpp
@@ -12,7 +12,7 @@ int main( int argc, char** argv )  // NOLINT(bugprone-exception-escape)
 {
    for( int i = 1; i < argc; ++i ) {
       argv_input in( argv, i );
-      parse< grammar, nothing, examples::errors >( in );
+      parse< grammar, nothing, examples::control >( in );
    }
    return 0;
 }
diff --git a/packages/PEGTL/src/example/pegtl/json_print_rules.cpp b/packages/PEGTL/src/example/pegtl/json_print_rules.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..87850508fe761c236314a356b174f8d617a54146
--- /dev/null
+++ b/packages/PEGTL/src/example/pegtl/json_print_rules.cpp
@@ -0,0 +1,13 @@
+// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#include <iostream>
+
+#include <tao/pegtl/contrib/json.hpp>
+#include <tao/pegtl/contrib/print.hpp>
+
+int main()  // NOLINT(bugprone-exception-escape)
+{
+   tao::pegtl::print_rules< tao::pegtl::json::text >( std::cout );
+   return 0;
+}
diff --git a/packages/PEGTL/src/example/pegtl/json_print_sub_rules.cpp b/packages/PEGTL/src/example/pegtl/json_print_sub_rules.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e28a04ef9fd3cd6ecd1fb0ca211be35401749f71
--- /dev/null
+++ b/packages/PEGTL/src/example/pegtl/json_print_sub_rules.cpp
@@ -0,0 +1,13 @@
+// Copyright (c) 2020 Dr. Colin Hirsch and Daniel Frey
+// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
+
+#include <iostream>
+
+#include <tao/pegtl/contrib/json.hpp>
+#include <tao/pegtl/contrib/print.hpp>
+
+int main()  // NOLINT(bugprone-exception-escape)
+{
+   tao::pegtl::print_sub_rules< tao::pegtl::json::text >( std::cout );
+   return 0;
+}
diff --git a/packages/PEGTL/src/example/pegtl/lua53_parse.cpp b/packages/PEGTL/src/example/pegtl/lua53_parse.cpp
index 535c892529e4f187f1d4d9fedb98fc2c6f4cf2e2..ddb1df06b2c75ac04874ec1fc074e49a0cb81469 100644
--- a/packages/PEGTL/src/example/pegtl/lua53_parse.cpp
+++ b/packages/PEGTL/src/example/pegtl/lua53_parse.cpp
@@ -2,7 +2,7 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include <tao/pegtl.hpp>
-#include <tao/pegtl/analyze.hpp>
+#include <tao/pegtl/contrib/analyze.hpp>
 #include <tao/pegtl/contrib/raw_string.hpp>
 
 namespace lua53
diff --git a/packages/PEGTL/src/example/pegtl/modulus_match.cpp b/packages/PEGTL/src/example/pegtl/modulus_match.cpp
index fb484cfd27d28afc335a430638c87d0b20462572..e748a1940eb8beb72af3392f44a860d8a0143301 100644
--- a/packages/PEGTL/src/example/pegtl/modulus_match.cpp
+++ b/packages/PEGTL/src/example/pegtl/modulus_match.cpp
@@ -10,13 +10,11 @@ namespace modulus
    template< unsigned M, unsigned R = 0 >
    struct my_rule
    {
-      using analyze_t = analysis::generic< analysis::rule_type::any >;
-
       static_assert( M > 1, "Modulus must be greater than 1" );
       static_assert( R < M, "Remainder must be less than modulus" );
 
-      template< typename Input >
-      static bool match( Input& in )
+      template< typename ParseInput >
+      static bool match( ParseInput& in )
       {
          if( !in.empty() ) {
             if( ( ( *in.current() ) % M ) == R ) {
diff --git a/packages/PEGTL/src/example/pegtl/parse_tree_user_state.cpp b/packages/PEGTL/src/example/pegtl/parse_tree_user_state.cpp
index f727e46cc7423aa718b619d58540d060e7d54431..e6baa01cdabbbc5813a3e1c769b4e8d182b8ccd2 100644
--- a/packages/PEGTL/src/example/pegtl/parse_tree_user_state.cpp
+++ b/packages/PEGTL/src/example/pegtl/parse_tree_user_state.cpp
@@ -21,8 +21,8 @@ struct work
 template<>
 struct work< success >
 {
-   template< typename Input >
-   static void apply( const Input& /*unused*/, user_state& /*unused*/ )
+   template< typename ActionInput >
+   static void apply( const ActionInput& /*unused*/, user_state& /*unused*/ )
    {}
 };
 
diff --git a/packages/PEGTL/src/example/pegtl/proto3.cpp b/packages/PEGTL/src/example/pegtl/proto3.cpp
index 9e9a8f56ad8e0d0bdf24264b7d32d7c530e33b7d..2797187882ecd123bab1c097fa74d572af0f3d5f 100644
--- a/packages/PEGTL/src/example/pegtl/proto3.cpp
+++ b/packages/PEGTL/src/example/pegtl/proto3.cpp
@@ -2,7 +2,7 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include <tao/pegtl.hpp>
-#include <tao/pegtl/analyze.hpp>
+#include <tao/pegtl/contrib/analyze.hpp>
 
 namespace TAO_PEGTL_NAMESPACE::proto3
 {
diff --git a/packages/PEGTL/src/example/pegtl/recover.cpp b/packages/PEGTL/src/example/pegtl/recover.cpp
index f2f9effc0bd2e81570649740e99ef85705a4c03f..6353a7442074a645a105e31999a2400bd3331adb 100644
--- a/packages/PEGTL/src/example/pegtl/recover.cpp
+++ b/packages/PEGTL/src/example/pegtl/recover.cpp
@@ -52,8 +52,8 @@ struct my_action
 template< typename T >
 struct my_action< skipping< T > >
 {
-   template< typename Input >
-   static void apply( const Input& in, bool& error )
+   template< typename ActionInput >
+   static void apply( const ActionInput& in, bool& error )
    {
       if( !error ) {
          std::cout << in.position() << ": Invalid expression \"" << in.string() << "\"" << std::endl;
@@ -65,8 +65,8 @@ struct my_action< skipping< T > >
 template< typename R >
 struct found
 {
-   template< typename Input >
-   static void apply( const Input& in, bool& error )
+   template< typename ActionInput >
+   static void apply( const ActionInput& in, bool& error )
    {
       if( !error ) {
          std::cout << in.position() << ": Found " << internal::demangle< R >() << ": \"" << in.string() << "\"" << std::endl;
@@ -88,8 +88,8 @@ template<> struct my_action< expr > : found< expr > {};
 template<>
 struct my_action< recoverable_expr >
 {
-   template< typename Input >
-   static void apply( const Input& /*unused*/, bool& error )
+   template< typename ActionInput >
+   static void apply( const ActionInput& /*unused*/, bool& error )
    {
       error = false;
       std::cout << std::string( 79, '-' ) << std::endl;
@@ -100,8 +100,8 @@ template< typename Rule >
 struct my_control
    : normal< Rule >
 {
-   template< typename Input, typename... States >
-   static void raise( const Input& in, States&&... /*unused*/ )
+   template< typename ParseInput, typename... States >
+   [[noreturn]] static void raise( const ParseInput& in, States&&... /*unused*/ )
    {
       std::cout << in.position() << ": Parse error matching " << internal::demangle< Rule >() << std::endl;
       throw parse_error( "parse error matching " + std::string( internal::demangle< Rule >() ), in );
diff --git a/packages/PEGTL/src/example/pegtl/s_expression.cpp b/packages/PEGTL/src/example/pegtl/s_expression.cpp
index 60670f40905e501dd7275c8c8d5670bcc163ce38..7c47f1c8b9b11217a070b5ac6d8355beca569f02 100644
--- a/packages/PEGTL/src/example/pegtl/s_expression.cpp
+++ b/packages/PEGTL/src/example/pegtl/s_expression.cpp
@@ -4,7 +4,7 @@
 #include <iostream>
 
 #include <tao/pegtl.hpp>
-#include <tao/pegtl/analyze.hpp>
+#include <tao/pegtl/contrib/analyze.hpp>
 
 using namespace TAO_PEGTL_NAMESPACE;
 
@@ -44,8 +44,8 @@ namespace sexpr
    template<>
    struct action< plus< not_one< '"' > > >
    {
-      template< typename Input >
-      static void apply( const Input& in, std::string& fn )
+      template< typename ActionInput >
+      static void apply( const ActionInput& in, std::string& fn )
       {
          fn = in.string();
       }
@@ -54,8 +54,8 @@ namespace sexpr
    template<>
    struct action< hash_include >
    {
-      template< typename Input >
-      static void apply( const Input& in, std::string& fn )
+      template< typename ActionInput >
+      static void apply( const ActionInput& in, std::string& fn )
       {
          std::string f2;
          // Here f2 is the state argument for the nested parsing
diff --git a/packages/PEGTL/src/example/pegtl/sum.cpp b/packages/PEGTL/src/example/pegtl/sum.cpp
index 8c6f267dfdfc976ff0b94a4a70a691b5af2479b8..196a2a87dd23370e0db1f3a8e82ba2dbdd897405 100644
--- a/packages/PEGTL/src/example/pegtl/sum.cpp
+++ b/packages/PEGTL/src/example/pegtl/sum.cpp
@@ -33,8 +33,8 @@ namespace sum
    template<>
    struct action< double_::grammar >
    {
-      template< typename Input >
-      static void apply( const Input& in, double& sum )
+      template< typename ActionInput >
+      static void apply( const ActionInput& in, double& sum )
       {
          // assume all values will fit into a C++ double
          std::stringstream ss( in.string() );
diff --git a/packages/PEGTL/src/example/pegtl/symbol_table.cpp b/packages/PEGTL/src/example/pegtl/symbol_table.cpp
index c18ae9fd4626c48cc4b2b99ecaf45d8fda17dc1e..5d0a7b51ab7a503008cc787c3ade45738dcf4af2 100644
--- a/packages/PEGTL/src/example/pegtl/symbol_table.cpp
+++ b/packages/PEGTL/src/example/pegtl/symbol_table.cpp
@@ -47,7 +47,7 @@ namespace example
 
    template<>
    struct action< value >
-      : public pegtl::integer::unsigned_action
+      : public pegtl::unsigned_action
    {
       // Sets st.converted to the integer value of the matched string.
    };
@@ -55,8 +55,8 @@ namespace example
    template<>
    struct action< name >
    {
-      template< typename Input >
-      static void apply( const Input& in, state& st )
+      template< typename ActionInput >
+      static void apply( const ActionInput& in, state& st )
       {
          st.temporary = in.string();
       }
@@ -65,8 +65,8 @@ namespace example
    template<>
    struct action< definition >
    {
-      template< typename Input >
-      static void apply( const Input& in, state& st )
+      template< typename ActionInput >
+      static void apply( const ActionInput& in, state& st )
       {
          if( !st.symbol_table.try_emplace( st.temporary, 0 ).second ) {
             throw pegtl::parse_error( "duplicate symbol " + st.temporary, in );
@@ -77,8 +77,8 @@ namespace example
    template<>
    struct action< assignment >
    {
-      template< typename Input >
-      static void apply( const Input& in, state& st )
+      template< typename ActionInput >
+      static void apply( const ActionInput& in, state& st )
       {
          const auto i = st.symbol_table.find( st.temporary );
          if( i == st.symbol_table.end() ) {
diff --git a/packages/PEGTL/src/example/pegtl/uri.cpp b/packages/PEGTL/src/example/pegtl/uri.cpp
index 571f2b1e49090d543254a0467ad9a8af517a637d..38559c574b1c0f928248b42786c05b5225731ca0 100644
--- a/packages/PEGTL/src/example/pegtl/uri.cpp
+++ b/packages/PEGTL/src/example/pegtl/uri.cpp
@@ -27,8 +27,8 @@ namespace uri
    template< std::string URI::*Field >
    struct bind
    {
-      template< typename Input >
-      static void apply( const Input& in, URI& uri )
+      template< typename ActionInput >
+      static void apply( const ActionInput& in, URI& uri )
       {
          uri.*Field = in.string();
       }
@@ -53,8 +53,8 @@ namespace uri
    template<>
    struct action< pegtl::uri::opt_userinfo >
    {
-      template< typename Input >
-      static void apply( const Input& in, URI& uri )
+      template< typename ActionInput >
+      static void apply( const ActionInput& in, URI& uri )
       {
          if( !in.empty() ) {
             uri.userinfo = std::string( in.begin(), in.size() - 1 );
diff --git a/packages/PEGTL/src/example/pegtl/uri_trace.cpp b/packages/PEGTL/src/example/pegtl/uri_trace.cpp
index d159950f6880a253bc12e3b9bfee487df8dcfe85..cbd354ef15277ed3d126633757fd0adcc9316bc3 100644
--- a/packages/PEGTL/src/example/pegtl/uri_trace.cpp
+++ b/packages/PEGTL/src/example/pegtl/uri_trace.cpp
@@ -4,7 +4,7 @@
 #include <iostream>
 
 #include <tao/pegtl.hpp>
-#include <tao/pegtl/contrib/tracer.hpp>
+#include <tao/pegtl/contrib/trace.hpp>
 #include <tao/pegtl/contrib/uri.hpp>
 
 namespace pegtl = TAO_PEGTL_NAMESPACE;
@@ -16,7 +16,7 @@ int main( int argc, char** argv )  // NOLINT(bugprone-exception-escape)
    for( int i = 1; i < argc; ++i ) {
       std::cout << "Parsing " << argv[ i ] << std::endl;
       pegtl::argv_input in( argv, i );
-      pegtl::parse< grammar, pegtl::nothing, pegtl::tracer >( in );
+      pegtl::parse< grammar, pegtl::nothing, pegtl::trace_control >( in );
    }
    return 0;
 }
diff --git a/packages/PEGTL/src/test/pegtl/CMakeLists.txt b/packages/PEGTL/src/test/pegtl/CMakeLists.txt
index 61819674d71d9b57245b123bb22fc9a3d90605b6..964d99432ce8e434ccc7e807aaec5aaeb376cf92 100644
--- a/packages/PEGTL/src/test/pegtl/CMakeLists.txt
+++ b/packages/PEGTL/src/test/pegtl/CMakeLists.txt
@@ -6,7 +6,6 @@ set(test_sources
   actions_one.cpp
   actions_three.cpp
   actions_two.cpp
-  analyze_cycles.cpp
   argv_input.cpp
   ascii_classes.cpp
   ascii_eol.cpp
@@ -25,6 +24,7 @@ set(test_sources
   change_state.cpp
   change_states.cpp
   contrib_alphabet.cpp
+  contrib_analyze.cpp
   contrib_http.cpp
   contrib_if_then.cpp
   contrib_integer.cpp
diff --git a/packages/PEGTL/src/test/pegtl/action_match.cpp b/packages/PEGTL/src/test/pegtl/action_match.cpp
index 30a4db52f5e6ad079e4ada427273a175d4713417..c6205367a777f8fd3e982f011a6641e8aa23aecf 100644
--- a/packages/PEGTL/src/test/pegtl/action_match.cpp
+++ b/packages/PEGTL/src/test/pegtl/action_match.cpp
@@ -14,9 +14,9 @@ namespace TAO_PEGTL_NAMESPACE
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      [[nodiscard]] static bool match( Input& in, States&&... /*unused*/ )
+      [[nodiscard]] static bool match( ParseInput& in, States&&... /*unused*/ )
       {
          return TAO_PEGTL_NAMESPACE::match< Rule, A, M, Action, Control >( in );
       }
@@ -67,15 +67,15 @@ namespace TAO_PEGTL_NAMESPACE
    struct action_one_b< grammar_inner >
    {
       // used inside of remove_state
-      template< typename Input >
-      static void apply( const Input& /*unused*/ )
+      template< typename ActionInput >
+      static void apply( const ActionInput& /*unused*/ )
       {
          ++global_state;
       }
 
       // used outside of remove_state
-      template< typename Input >
-      static void apply( const Input& in, state_one& state )
+      template< typename ActionInput >
+      static void apply( const ActionInput& in, state_one& state )
       {
          state.byte_in_line_b += in.input().byte();
       }
@@ -94,8 +94,8 @@ namespace TAO_PEGTL_NAMESPACE
    template<>
    struct action_one_a< grammar_inner >
    {
-      template< typename Input >
-      static void apply( const Input& in, state_one& state )
+      template< typename ActionInput >
+      static void apply( const ActionInput& in, state_one& state )
       {
          state.byte_in_line_a += in.input().byte();
       }
diff --git a/packages/PEGTL/src/test/pegtl/actions_one.cpp b/packages/PEGTL/src/test/pegtl/actions_one.cpp
index 8f370cea5f1c7db4b48943a2a5bd3fffdf396043..1e5c2f81312439714ad6cd5475cde7480431e370 100644
--- a/packages/PEGTL/src/test/pegtl/actions_one.cpp
+++ b/packages/PEGTL/src/test/pegtl/actions_one.cpp
@@ -57,8 +57,8 @@ namespace TAO_PEGTL_NAMESPACE
    template< typename Rule >
    struct test_action
    {
-      template< typename Input >
-      static void apply( const Input& in )
+      template< typename ActionInput >
+      static void apply( const ActionInput& in )
       {
          applied.emplace_back( internal::demangle< Rule >(), in.string() );
       }
diff --git a/packages/PEGTL/src/test/pegtl/actions_three.cpp b/packages/PEGTL/src/test/pegtl/actions_three.cpp
index c7de4cbec30a36576ff45d1d032cd6292dde4a6c..992d655b9dd01d36ee4a5e16325efe568ccdc0f5 100644
--- a/packages/PEGTL/src/test/pegtl/actions_three.cpp
+++ b/packages/PEGTL/src/test/pegtl/actions_three.cpp
@@ -5,6 +5,28 @@
 
 namespace TAO_PEGTL_NAMESPACE
 {
+   template< unsigned Size, apply_mode B, rewind_mode N, typename... Rules >
+   struct test_rule
+   {
+      template< apply_mode A,
+                rewind_mode M,
+                template< typename... >
+                class Action,
+                template< typename... >
+                class Control,
+                typename ParseInput,
+                typename... States >
+      static bool match( ParseInput& in, States&&... st )
+      {
+         static_assert( A == B, "unexpected apply mode" );
+         static_assert( M == N, "unexpected rewind mode" );
+
+         TAO_PEGTL_TEST_ASSERT( in.size() == Size );
+
+         return seq< Rules... >::template match< A, M, Action, Control >( in, st... );
+      }
+   };
+
    namespace test1
    {
       bool apply_result;
@@ -20,8 +42,8 @@ namespace TAO_PEGTL_NAMESPACE
       template<>
       struct apply_bool_action< grammar >
       {
-         template< typename Input >
-         static bool apply( const Input& /*unused*/ )
+         template< typename ActionInput >
+         static bool apply( const ActionInput& /*unused*/ )
          {
             return apply_result;
          }
diff --git a/packages/PEGTL/src/test/pegtl/actions_two.cpp b/packages/PEGTL/src/test/pegtl/actions_two.cpp
index b210c33bce4b42b9f382328b4a21a7a84e248049..a21d222ff32abb8014c7e0f9a6906298ccf8c2d3 100644
--- a/packages/PEGTL/src/test/pegtl/actions_two.cpp
+++ b/packages/PEGTL/src/test/pegtl/actions_two.cpp
@@ -11,14 +11,13 @@ namespace TAO_PEGTL_NAMESPACE
       {
          char c;
 
-         template< typename Input >
-         state1( const Input& /*unused*/, std::string& /*unused*/ )
+         template< typename ParseInput >
+         state1( const ParseInput& /*unused*/, std::string& /*unused*/ )
             : c()
-         {
-         }
+         {}
 
-         template< typename Input >
-         void success( const Input& /*unused*/, std::string& s ) const
+         template< typename ParseInput >
+         void success( const ParseInput& /*unused*/, std::string& s ) const
          {
             s += c;
          }
@@ -39,8 +38,8 @@ namespace TAO_PEGTL_NAMESPACE
       template<>
       struct action1< alpha >
       {
-         template< typename Input >
-         static void apply( const Input& in, state1& s )
+         template< typename ActionInput >
+         static void apply( const ActionInput& in, state1& s )
          {
             assert( in.size() == 1 );
             s.c = in.begin()[ 0 ];
@@ -99,8 +98,8 @@ namespace TAO_PEGTL_NAMESPACE
       template< typename Rule >
       struct count_action
       {
-         template< typename Input >
-         static void apply( const Input& in )
+         template< typename ActionInput >
+         static void apply( const ActionInput& in )
          {
             TAO_PEGTL_TEST_ASSERT( in.iterator().byte == count_byte );
             TAO_PEGTL_TEST_ASSERT( in.iterator().line == count_line );
diff --git a/packages/PEGTL/src/test/pegtl/change_action_and_state.cpp b/packages/PEGTL/src/test/pegtl/change_action_and_state.cpp
index ec023501315797a0baf98d5ca93e24cd5233d472..abbaaa5e1ae2622bf23e30a395188753e19d9cf9 100644
--- a/packages/PEGTL/src/test/pegtl/change_action_and_state.cpp
+++ b/packages/PEGTL/src/test/pegtl/change_action_and_state.cpp
@@ -35,8 +35,8 @@ namespace TAO_PEGTL_NAMESPACE
    {
       int v = 0;
 
-      template< typename Input >
-      explicit S( const Input& /*unused*/, int& c )
+      template< typename ParseInput >
+      explicit S( const ParseInput& /*unused*/, int& c )
       {
          if( c == 5 ) {
             v = 6;
@@ -49,8 +49,8 @@ namespace TAO_PEGTL_NAMESPACE
          }
       }
 
-      template< typename Input >
-      void success( const Input& /*unused*/, int& c )
+      template< typename ParseInput >
+      void success( const ParseInput& /*unused*/, int& c )
       {
          if( v != 3 ) {
             throw std::runtime_error( "fail3" );
diff --git a/packages/PEGTL/src/test/pegtl/change_action_and_states.cpp b/packages/PEGTL/src/test/pegtl/change_action_and_states.cpp
index 1e6636b44b557dde3d08b76bd5fdbf8833c71591..74cb0c976e20d710218c4b9e67a3ff44a94b7142 100644
--- a/packages/PEGTL/src/test/pegtl/change_action_and_states.cpp
+++ b/packages/PEGTL/src/test/pegtl/change_action_and_states.cpp
@@ -41,8 +41,8 @@ namespace TAO_PEGTL_NAMESPACE
          throw std::runtime_error( "fail2" );
       }
 
-      template< typename Input >
-      static void success( const Input& /*unused*/, int& v, int& c )
+      template< typename ParseInput >
+      static void success( const ParseInput& /*unused*/, int& v, int& c )
       {
          if( v != 2 ) {
             throw std::runtime_error( "fail3" );
diff --git a/packages/PEGTL/src/test/pegtl/change_state.cpp b/packages/PEGTL/src/test/pegtl/change_state.cpp
index ad06b149d9eee74c990548c8940efcd17a01c219..10a64f154e322778f5da2f32be148c72e520b0ca 100644
--- a/packages/PEGTL/src/test/pegtl/change_state.cpp
+++ b/packages/PEGTL/src/test/pegtl/change_state.cpp
@@ -31,8 +31,8 @@ namespace TAO_PEGTL_NAMESPACE
    {
       int v = 0;
 
-      template< typename Input >
-      explicit S( const Input& /*unused*/, int& c )
+      template< typename ParseInput >
+      explicit S( const ParseInput& /*unused*/, int& c )
       {
          if( c == 5 ) {
             v = 6;
@@ -45,8 +45,8 @@ namespace TAO_PEGTL_NAMESPACE
          }
       }
 
-      template< typename Input >
-      void success( const Input& /*unused*/, int& c )
+      template< typename ParseInput >
+      void success( const ParseInput& /*unused*/, int& c )
       {
          if( v != 3 ) {
             throw std::runtime_error( "fail3" );
diff --git a/packages/PEGTL/src/test/pegtl/change_states.cpp b/packages/PEGTL/src/test/pegtl/change_states.cpp
index 3241e3ec839703331684342079e0b35b5a6fd6d9..d6cdbd0a3a374df3dcba1461cb14523cbef6d256 100644
--- a/packages/PEGTL/src/test/pegtl/change_states.cpp
+++ b/packages/PEGTL/src/test/pegtl/change_states.cpp
@@ -39,8 +39,8 @@ namespace TAO_PEGTL_NAMESPACE
          v = 2;
       }
 
-      template< typename Input >
-      static void success( const Input& /*unused*/, int& v, int& c )
+      template< typename ParseInput >
+      static void success( const ParseInput& /*unused*/, int& v, int& c )
       {
          if( v != 2 ) {
             throw std::runtime_error( "fail3" );
diff --git a/packages/PEGTL/src/test/pegtl/analyze_cycles.cpp b/packages/PEGTL/src/test/pegtl/contrib_analyze.cpp
similarity index 58%
rename from packages/PEGTL/src/test/pegtl/analyze_cycles.cpp
rename to packages/PEGTL/src/test/pegtl/contrib_analyze.cpp
index cd1a01641b7154d44cdfe0e5373f28f5b0b81dfb..dee2d0408fa9d1188cb7cd556b53625e6092710a 100644
--- a/packages/PEGTL/src/test/pegtl/analyze_cycles.cpp
+++ b/packages/PEGTL/src/test/pegtl/contrib_analyze.cpp
@@ -6,125 +6,81 @@
 
 namespace TAO_PEGTL_NAMESPACE
 {
-   template< typename... Rules >
-   struct any_seq
-      : public seq< Rules... >
-   {
-      using analyze_t = analysis::generic< analysis::rule_type::any, Rules... >;
-   };
-
    void unit_test()
    {
       verify_analyze< eof >( __LINE__, __FILE__, false, false );
       verify_analyze< eolf >( __LINE__, __FILE__, false, false );
       verify_analyze< success >( __LINE__, __FILE__, false, false );
       verify_analyze< failure >( __LINE__, __FILE__, true, false );
+      // clang-format off
       {
-         struct tst : star< tst >
-         {
-         };
+         struct tst : star< tst > {};
          verify_analyze< tst >( __LINE__, __FILE__, false, true );
       }
       {
-         struct tst : plus< tst >
-         {
-         };
+         struct tst : plus< tst > {};
          verify_analyze< tst >( __LINE__, __FILE__, false, true );
       }
       {
-         struct tst : seq< eof, at< digit >, tst >
-         {
-         };
+         struct tst : seq< eof, at< digit >, tst > {};
          verify_analyze< tst >( __LINE__, __FILE__, false, true );  // This is a false positive.
       }
       {
-         struct tst : sor< digit, seq< at< digit >, tst > >
-         {
-         };
+         struct tst : sor< digit, seq< at< digit >, tst > > {};
          verify_analyze< tst >( __LINE__, __FILE__, false, true );  // This is a false positive.
       }
       {
-         struct tst : sor< digit, seq< opt< digit >, tst > >
-         {
-         };
+         struct tst : sor< digit, seq< opt< digit >, tst > > {};
          verify_analyze< tst >( __LINE__, __FILE__, false, true );
       }
       {
-         struct tst : sor< digit, tst >
-         {
-         };
+         struct tst : sor< digit, tst > {};
          verify_analyze< tst >( __LINE__, __FILE__, false, true );
       }
       {
-         struct tst : at< any >
-         {
-         };
+         struct tst : at< any > {};
          verify_analyze< tst >( __LINE__, __FILE__, false, false );
       }
       {
-         struct tst : at< tst >
-         {
-         };
+         struct tst : at< tst > {};
          verify_analyze< tst >( __LINE__, __FILE__, false, true );
       }
       {
-         struct tst : at< any, tst >
-         {
-         };
+         struct tst : at< any, tst > {};
          verify_analyze< tst >( __LINE__, __FILE__, false, false );
       }
       {
-         struct tst : not_at< any >
-         {
-         };
+         struct tst : not_at< any > {};
          verify_analyze< tst >( __LINE__, __FILE__, false, false );
       }
       {
-         struct tst : opt< tst >
-         {
-         };
+         struct tst : opt< tst > {};
          verify_analyze< tst >( __LINE__, __FILE__, false, true );
       }
       {
-         struct tst : opt< any, tst >
-         {
-         };
+         struct tst : opt< any, tst > {};
          verify_analyze< tst >( __LINE__, __FILE__, false, false );
       }
       {
-         struct rec : sor< seq< rec, alpha >, alpha >
-         {
-         };
+         struct rec : sor< seq< rec, alpha >, alpha > {};
          verify_analyze< rec >( __LINE__, __FILE__, true, true );
       }
       {
          struct bar;
-         struct foo : seq< digit, bar >
-         {
-         };
-         struct bar : plus< foo >
-         {
-         };
+         struct foo : seq< digit, bar > {};
+         struct bar : plus< foo > {};
          verify_analyze< seq< any, bar > >( __LINE__, __FILE__, true, false );
       }
       {
          struct bar;
-         struct foo : seq< bar, digit >
-         {
-         };
-         struct bar : plus< foo >
-         {
-         };
+         struct foo : seq< bar, digit > {};
+         struct bar : plus< foo > {};
          verify_analyze< seq< bar, any > >( __LINE__, __FILE__, true, true );
       }
       {
          struct bar;
-         struct foo : sor< digit, bar >
-         {
-         };
-         struct bar : plus< foo >
-         {
-         };
+         struct foo : sor< digit, bar > {};
+         struct bar : plus< foo > {};
          verify_analyze< bar >( __LINE__, __FILE__, false, true );
          verify_analyze< foo >( __LINE__, __FILE__, false, true );
          verify_analyze< sor< any, bar > >( __LINE__, __FILE__, false, true );
@@ -137,169 +93,110 @@ namespace TAO_PEGTL_NAMESPACE
          // Simplified version, equivalent regarding consumption of input:
          struct var;
          struct fun;
-         struct exp : sor< var, fun, seq< any, exp, any > >
-         {
-         };
-         struct fun : seq< exp, any >
-         {
-         };
-         struct var : sor< any, seq< exp, any, exp >, seq< exp, any > >
-         {
-         };
+         struct exp : sor< var, fun, seq< any, exp, any > > {};
+         struct fun : seq< exp, any > {};
+         struct var : sor< any, seq< exp, any, exp >, seq< exp, any > > {};
          verify_analyze< exp >( __LINE__, __FILE__, true, true );
          verify_analyze< fun >( __LINE__, __FILE__, true, true );
          verify_analyze< var >( __LINE__, __FILE__, true, true );
       }
       {
-         struct exp : sor< exp, seq< any, exp > >
-         {
-         };
+         struct exp : sor< exp, seq< any, exp > > {};
          verify_analyze< exp >( __LINE__, __FILE__, false, true );
       }
       {
-         struct tst : until< any >
-         {
-         };
+         struct tst : until< any > {};
          verify_analyze< tst >( __LINE__, __FILE__, true, false );
       }
       {
-         struct tst : until< star< any > >
-         {
-         };
+         struct tst : until< star< any > > {};
          verify_analyze< tst >( __LINE__, __FILE__, false, false );
       }
       {
-         struct tst : until< any, star< any > >
-         {
-         };
+         struct tst : until< any, star< any > > {};
          verify_analyze< tst >( __LINE__, __FILE__, true, true );
       }
       {
-         struct tst : until< star< any >, star< any > >
-         {
-         };
+         struct tst : until< star< any >, star< any > > {};
          verify_analyze< tst >( __LINE__, __FILE__, false, true );
       }
       {
-         struct tst : until< star< any >, star< any > >
-         {
-         };
-         verify_analyze< any_seq< tst > >( __LINE__, __FILE__, true, true );
-      }
-      {
-         struct tst : until< any, any >
-         {
-         };
+         struct tst : until< any, any > {};
          verify_analyze< tst >( __LINE__, __FILE__, true, false );
       }
       {
-         struct tst : until< star< any >, any >
-         {
-         };
+         struct tst : until< star< any >, any > {};
          verify_analyze< tst >( __LINE__, __FILE__, false, false );
       }
       {
-         struct tst : plus< plus< any > >
-         {
-         };
+         struct tst : plus< plus< any > > {};
          verify_analyze< tst >( __LINE__, __FILE__, true, false );
       }
       {
-         struct tst : star< star< any > >
-         {
-         };
+         struct tst : star< star< any > > {};
          verify_analyze< tst >( __LINE__, __FILE__, false, true );
       }
       {
-         struct tst : plus< star< any > >
-         {
-         };
+         struct tst : plus< star< any > > {};
          verify_analyze< tst >( __LINE__, __FILE__, false, true );
       }
       {
-         struct tst : plus< opt< any > >
-         {
-         };
+         struct tst : plus< opt< any > > {};
          verify_analyze< tst >( __LINE__, __FILE__, false, true );
       }
       {
-         struct tst : star< opt< any > >
-         {
-         };
+         struct tst : star< opt< any > > {};
          verify_analyze< tst >( __LINE__, __FILE__, false, true );
       }
       {
-         struct tst : star< plus< opt< any > > >
-         {
-         };
+         struct tst : star< plus< opt< any > > > {};
          verify_analyze< tst >( __LINE__, __FILE__, false, true );
       }
       {
-         struct tst : list< any, any >
-         {
-         };
+         struct tst : list< any, any > {};
          verify_analyze< tst >( __LINE__, __FILE__, true, false );
       }
       {
-         struct tst : list< star< any >, any >
-         {
-         };
+         struct tst : list< star< any >, any > {};
          verify_analyze< tst >( __LINE__, __FILE__, false, false );
       }
       {
-         struct tst : list< any, opt< any > >
-         {
-         };
+         struct tst : list< any, opt< any > > {};
          verify_analyze< tst >( __LINE__, __FILE__, true, false );
       }
       {
-         struct tst : list< star< any >, opt< any > >
-         {
-         };
+         struct tst : list< star< any >, opt< any > > {};
          verify_analyze< tst >( __LINE__, __FILE__, false, true );
       }
       {
-         struct tst : list_must< any, any >
-         {
-         };
+         struct tst : list_must< any, any > {};
          verify_analyze< tst >( __LINE__, __FILE__, true, false );
       }
       {
-         struct tst : list_must< star< any >, any >
-         {
-         };
+         struct tst : list_must< star< any >, any > {};
          verify_analyze< tst >( __LINE__, __FILE__, false, false );
       }
       {
-         struct tst : list_must< any, opt< any > >
-         {
-         };
+         struct tst : list_must< any, opt< any > > {};
          verify_analyze< tst >( __LINE__, __FILE__, true, false );
       }
       {
-         struct tst : list_must< star< any >, opt< any > >
-         {
-         };
+         struct tst : list_must< star< any >, opt< any > > {};
          verify_analyze< tst >( __LINE__, __FILE__, false, true );
       }
       {
-         struct tst : plus< pad_opt< alpha, digit > >
-         {
-         };
+         struct tst : plus< pad_opt< alpha, digit > > {};
          verify_analyze< tst >( __LINE__, __FILE__, false, true );
       }
       {
-         struct tst : rep< 42, opt< alpha > >
-         {
-         };
+         struct tst : rep< 42, opt< alpha > > {};
          verify_analyze< tst >( __LINE__, __FILE__, false, false );
       }
       {
-         struct tst : rep_min< 42, opt< alpha > >
-         {
-         };
+         struct tst : rep_min< 42, opt< alpha > > {};
          verify_analyze< tst >( __LINE__, __FILE__, false, true );
       }
+      // clang-format on
    }
 
 }  // namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/contrib_integer.cpp b/packages/PEGTL/src/test/pegtl/contrib_integer.cpp
index b9a2b0f0fc505c46db11c6b6590725d26c24d801..9290f670de8575ba55f0feacaeaaee80912ac2c2 100644
--- a/packages/PEGTL/src/test/pegtl/contrib_integer.cpp
+++ b/packages/PEGTL/src/test/pegtl/contrib_integer.cpp
@@ -6,6 +6,7 @@
 
 #include "test.hpp"
 
+#include "verify_analyze.hpp"
 #include "verify_rule.hpp"
 
 #include <tao/pegtl/contrib/integer.hpp>
@@ -24,13 +25,13 @@ namespace TAO_PEGTL_NAMESPACE
    {};
 
    template<>
-   struct int_action< integer::signed_rule >
-      : integer::signed_action
+   struct int_action< signed_rule >
+      : signed_action
    {};
 
    template<>
-   struct int_action< integer::unsigned_rule >
-      : integer::unsigned_action
+   struct int_action< unsigned_rule >
+      : unsigned_action
    {};
 
    template< typename S >
@@ -39,19 +40,19 @@ namespace TAO_PEGTL_NAMESPACE
       {
          S st = -123;
          memory_input in( i, __FUNCTION__ );
-         parse< must< integer::signed_rule, eof >, int_action >( in, st );
+         parse< must< signed_rule, eof >, int_action >( in, st );
          TAO_PEGTL_TEST_ASSERT( st == s );
       }
       {
          int_state< S > st;
          memory_input in( i, __FUNCTION__ );
-         parse< must< integer::signed_rule, eof >, int_action >( in, st );
+         parse< must< signed_rule, eof >, int_action >( in, st );
          TAO_PEGTL_TEST_ASSERT( st.converted == s );
       }
       {
          S st = -123;
          memory_input in( i, __FUNCTION__ );
-         parse< must< integer::signed_rule_with_action, eof > >( in, st );
+         parse< must< signed_rule_with_action, eof > >( in, st );
          TAO_PEGTL_TEST_ASSERT( st == s );
       }
    }
@@ -61,7 +62,7 @@ namespace TAO_PEGTL_NAMESPACE
    {
       int_state< S > st;
       memory_input in( i, __FUNCTION__ );
-      TAO_PEGTL_TEST_THROWS( parse< must< integer::signed_rule, eof >, int_action >( in, st ) );
+      TAO_PEGTL_TEST_THROWS( parse< must< signed_rule, eof >, int_action >( in, st ) );
    }
 
    template< typename S >
@@ -78,7 +79,7 @@ namespace TAO_PEGTL_NAMESPACE
       int_state< S > st;
       const auto i = lexical_cast( s );
       memory_input in( i, __FUNCTION__ );
-      parse< must< integer::signed_rule, eof >, int_action >( in, st );
+      parse< must< signed_rule, eof >, int_action >( in, st );
       TAO_PEGTL_TEST_ASSERT( st.converted == s );
    }
 
@@ -88,19 +89,19 @@ namespace TAO_PEGTL_NAMESPACE
       {
          S st = 123;
          memory_input in( i, __FUNCTION__ );
-         parse< must< integer::unsigned_rule, eof >, int_action >( in, st );
+         parse< must< unsigned_rule, eof >, int_action >( in, st );
          TAO_PEGTL_TEST_ASSERT( st == s );
       }
       {
          int_state< S > st;
          memory_input in( i, __FUNCTION__ );
-         parse< must< integer::unsigned_rule, eof >, int_action >( in, st );
+         parse< must< unsigned_rule, eof >, int_action >( in, st );
          TAO_PEGTL_TEST_ASSERT( st.converted == s );
       }
       {
          S st = 123;
          memory_input in( i, __FUNCTION__ );
-         parse< must< integer::unsigned_rule_with_action, eof > >( in, st );
+         parse< must< unsigned_rule_with_action, eof > >( in, st );
          TAO_PEGTL_TEST_ASSERT( st == s );
       }
    }
@@ -110,7 +111,7 @@ namespace TAO_PEGTL_NAMESPACE
    {
       S st = 123;
       memory_input in( i, __FUNCTION__ );
-      TAO_PEGTL_TEST_THROWS( parse< must< integer::unsigned_rule, eof >, int_action >( in, st ) );
+      TAO_PEGTL_TEST_THROWS( parse< must< unsigned_rule, eof >, int_action >( in, st ) );
    }
 
    template< typename S >
@@ -119,12 +120,12 @@ namespace TAO_PEGTL_NAMESPACE
       S st = 123;
       const auto i = lexical_cast( s );
       memory_input in( i, __FUNCTION__ );
-      parse< must< integer::unsigned_rule, eof >, int_action >( in, st );
+      parse< must< unsigned_rule, eof >, int_action >( in, st );
       TAO_PEGTL_TEST_ASSERT( st == s );
    }
 
    template< auto M >
-   using max_seq_rule = seq< one< 'a' >, integer::maximum_rule< std::uint64_t, M >, one< 'b' >, eof >;
+   using max_seq_rule = seq< one< 'a' >, maximum_rule< std::uint64_t, M >, one< 'b' >, eof >;
 
    void unit_test()
    {
@@ -256,6 +257,12 @@ namespace TAO_PEGTL_NAMESPACE
       verify_rule< max_seq_rule< 18446744073709551615ULL > >( __LINE__, __FILE__, "a18446744073709551615b", result_type::success );
       verify_rule< max_seq_rule< 18446744073709551615ULL > >( __LINE__, __FILE__, "a18446744073709551616b", result_type::global_failure );
       verify_rule< max_seq_rule< 18446744073709551615ULL > >( __LINE__, __FILE__, "a98446744073709551614b", result_type::global_failure );
+
+      verify_analyze< unsigned_rule >( __LINE__, __FILE__, true, false );
+      verify_analyze< unsigned_rule_with_action >( __LINE__, __FILE__, true, false );
+
+      verify_analyze< signed_rule >( __LINE__, __FILE__, true, false );
+      verify_analyze< signed_rule_with_action >( __LINE__, __FILE__, true, false );
    }
 
 }  // namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/contrib_json.cpp b/packages/PEGTL/src/test/pegtl/contrib_json.cpp
index 21cef36375412c9f20019e93e33b838036588c3a..67abd1d1d9083abeb67e8d68ed0a5080fa6312b3 100644
--- a/packages/PEGTL/src/test/pegtl/contrib_json.cpp
+++ b/packages/PEGTL/src/test/pegtl/contrib_json.cpp
@@ -6,7 +6,6 @@
 #include "verify_fail.hpp"
 #include "verify_rule.hpp"
 
-#include <tao/pegtl/analyze.hpp>
 #include <tao/pegtl/contrib/json.hpp>
 
 namespace TAO_PEGTL_NAMESPACE
diff --git a/packages/PEGTL/src/test/pegtl/contrib_partial_trace.cpp b/packages/PEGTL/src/test/pegtl/contrib_partial_trace.cpp
index 323012aaaf1c5004711d12448c39cf30812c13d5..b8ac7a168bbedd7c66f3020e04e4b35793febec5 100644
--- a/packages/PEGTL/src/test/pegtl/contrib_partial_trace.cpp
+++ b/packages/PEGTL/src/test/pegtl/contrib_partial_trace.cpp
@@ -3,7 +3,7 @@
 
 #include "test.hpp"
 
-#include <tao/pegtl/contrib/tracer.hpp>
+#include <tao/pegtl/contrib/trace.hpp>
 
 namespace TAO_PEGTL_NAMESPACE
 {
@@ -13,7 +13,7 @@ namespace TAO_PEGTL_NAMESPACE
 
    // how to run a tracer on a *part* of the grammar:
    template< typename > struct partial_action {};
-   template<> struct partial_action< inner > : change_control< tracer > {};
+   template<> struct partial_action< inner > : change_control< trace_control > {};
    // clang-format on
 
    void unit_test()
diff --git a/packages/PEGTL/src/test/pegtl/contrib_raw_string.cpp b/packages/PEGTL/src/test/pegtl/contrib_raw_string.cpp
index 872251b1a50dcf6374e5e04779a9e0cc1c29e9e6..95d2737e72d37b5bea2ffce010c4e3e822503b72 100644
--- a/packages/PEGTL/src/test/pegtl/contrib_raw_string.cpp
+++ b/packages/PEGTL/src/test/pegtl/contrib_raw_string.cpp
@@ -2,6 +2,7 @@
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
 #include "test.hpp"
+#include "verify_analyze.hpp"
 #include "verify_fail.hpp"
 
 #include <tao/pegtl/contrib/raw_string.hpp>
@@ -20,8 +21,8 @@ namespace TAO_PEGTL_NAMESPACE
    template<>
    struct raction< rstring::content >
    {
-      template< typename Input, typename... States >
-      static void apply( const Input& in, const States&... /*unused*/ )
+      template< typename ActionInput, typename... States >
+      static void apply( const ActionInput& in, const States&... /*unused*/ )
       {
          content.assign( in.begin(), in.end() );
       }
@@ -34,8 +35,8 @@ namespace TAO_PEGTL_NAMESPACE
    template<>
    struct qaction< qstring::content >
    {
-      template< typename Input, typename... States >
-      static void apply( const Input& in, const States&... /*unused*/ )
+      template< typename ActionInput, typename... States >
+      static void apply( const ActionInput& in, const States&... /*unused*/ )
       {
          content.assign( in.begin(), in.end() );
       }
@@ -68,6 +69,11 @@ namespace TAO_PEGTL_NAMESPACE
 
    void unit_test()
    {
+      verify_analyze< rstring >( __LINE__, __FILE__, true, false );
+      verify_analyze< qstring >( __LINE__, __FILE__, true, false );
+
+      verify_analyze< raw_string< 'a', 'b', 'c', star< star< any > > > >( __LINE__, __FILE__, true, true );
+
       verify_data< rgrammar, raction >( __LINE__, __FILE__, "[[]]", "" );
       verify_data< rgrammar, raction >( __LINE__, __FILE__, "[[foo]]", "foo" );
       verify_data< rgrammar, raction >( __LINE__, __FILE__, "[===[foo]===]", "foo" );
diff --git a/packages/PEGTL/src/test/pegtl/contrib_tracer.cpp b/packages/PEGTL/src/test/pegtl/contrib_tracer.cpp
index 022a10d8c509625810eb4e055f6fb926707d0ef7..074c701f71d2eed0486754949762ede23348fd3b 100644
--- a/packages/PEGTL/src/test/pegtl/contrib_tracer.cpp
+++ b/packages/PEGTL/src/test/pegtl/contrib_tracer.cpp
@@ -3,7 +3,7 @@
 
 #include "test.hpp"
 
-#include <tao/pegtl/contrib/tracer.hpp>
+#include <tao/pegtl/contrib/trace.hpp>
 
 namespace TAO_PEGTL_NAMESPACE
 {
@@ -11,14 +11,14 @@ namespace TAO_PEGTL_NAMESPACE
    using GRAMMAR2 = seq< one< 'a' >, any, any, any, any, one< 'b' >, eof >;
 
    template< typename Rule >
-   struct tracer_action
+   struct trace_action
    {};
 
    unsigned a0 = 0;
    unsigned a = 0;
 
    template<>
-   struct tracer_action< one< 'a' > >
+   struct trace_action< one< 'a' > >
    {
       template< typename... Ts >
       static void apply0( Ts&&... /*unused*/ )
@@ -28,7 +28,7 @@ namespace TAO_PEGTL_NAMESPACE
    };
 
    template<>
-   struct tracer_action< GRAMMAR >
+   struct trace_action< GRAMMAR >
    {
       template< typename... Ts >
       static void apply( Ts&&... /*unused*/ )
@@ -41,14 +41,14 @@ namespace TAO_PEGTL_NAMESPACE
    {
       {
          memory_input in( "ab", "trace test please ignore" );
-         const auto result = parse< GRAMMAR, nothing, tracer >( in );
+         const auto result = parse< GRAMMAR, nothing, trace_control >( in );
          TAO_PEGTL_TEST_ASSERT( result );
          TAO_PEGTL_TEST_ASSERT( a0 == 0 );
          TAO_PEGTL_TEST_ASSERT( a == 0 );
       }
       {
          memory_input in( "ab", "trace test please ignore" );
-         const auto result = parse< GRAMMAR, tracer_action, tracer >( in );
+         const auto result = parse< GRAMMAR, trace_action, trace_control >( in );
          TAO_PEGTL_TEST_ASSERT( result );
          TAO_PEGTL_TEST_ASSERT( a0 == 1 );
          TAO_PEGTL_TEST_ASSERT( a == 1 );
@@ -56,7 +56,7 @@ namespace TAO_PEGTL_NAMESPACE
       {
          trace_state ts;
          memory_input in( "ab", "trace test please ignore" );
-         const auto result = parse< GRAMMAR, nothing, tracer >( in, ts );
+         const auto result = parse< GRAMMAR, nothing, trace_control >( in, ts );
          TAO_PEGTL_TEST_ASSERT( result );
          TAO_PEGTL_TEST_ASSERT( a0 == 1 );
          TAO_PEGTL_TEST_ASSERT( a == 1 );
@@ -64,7 +64,7 @@ namespace TAO_PEGTL_NAMESPACE
       {
          trace_state ts;
          memory_input in( "ab", "trace test please ignore" );
-         const auto result = parse< GRAMMAR, tracer_action, tracer >( in, ts );
+         const auto result = parse< GRAMMAR, trace_action, trace_control >( in, ts );
          TAO_PEGTL_TEST_ASSERT( result );
          TAO_PEGTL_TEST_ASSERT( a0 == 2 );
          TAO_PEGTL_TEST_ASSERT( a == 2 );
@@ -72,7 +72,7 @@ namespace TAO_PEGTL_NAMESPACE
       {
          trace_state ts;
          memory_input in( "a\r\n\t\0b", 6, "trace test please ignore" );
-         const auto result = parse< GRAMMAR2, nothing, tracer >( in, ts );
+         const auto result = parse< GRAMMAR2, nothing, trace_control >( in, ts );
          TAO_PEGTL_TEST_ASSERT( result );
          TAO_PEGTL_TEST_ASSERT( a0 == 2 );
          TAO_PEGTL_TEST_ASSERT( a == 2 );
@@ -80,7 +80,7 @@ namespace TAO_PEGTL_NAMESPACE
       {
          trace_state ts;
          memory_input in( "a\r\n\t\0b", 6, "trace test please ignore" );
-         const auto result = parse< GRAMMAR2, tracer_action, tracer >( in, ts );
+         const auto result = parse< GRAMMAR2, trace_action, trace_control >( in, ts );
          TAO_PEGTL_TEST_ASSERT( result );
       }
    }
diff --git a/packages/PEGTL/src/test/pegtl/error_message.cpp b/packages/PEGTL/src/test/pegtl/error_message.cpp
index bfc6fd30a057327d46b6058f979637521626f81a..05870afbaf6e2ff595f9eefec1e27fdd6f8543c1 100644
--- a/packages/PEGTL/src/test/pegtl/error_message.cpp
+++ b/packages/PEGTL/src/test/pegtl/error_message.cpp
@@ -3,28 +3,30 @@
 
 #include "test.hpp"
 
-#include <string>
-
-namespace TAO_PEGTL_NAMESPACE
+namespace test1
 {
-   namespace test1
-   {
-      // clang-format off
-      struct a : one< 'a' > {};
-      struct b : one< 'b' > {};
-      struct foo : sor< a, b > {};
-      // clang-format on
-
-   }  // namespace test1
+   using namespace TAO_PEGTL_NAMESPACE;
 
    // clang-format off
-   template<> constexpr const char* error_message< test1::a > = "test123";
+   struct a : one< 'a' > {};
+   struct b : one< 'b' > {};
+   struct grammar : sor< a, b > {};
+
+   template< typename > inline constexpr const char* error_message = nullptr;
+   template<> inline constexpr auto error_message< test1::a > = "test123";
+
+   struct error { template< typename Rule > static constexpr auto message = error_message< Rule >; };
+   template< typename Rule > using control = must_if< error >::control< Rule >;
    // clang-format on
 
+}  // namespace test1
+
+namespace TAO_PEGTL_NAMESPACE
+{
    void unit_test()
    {
       try {
-         parse< test1::foo >( memory_input( "b", __FUNCTION__ ) );
+         parse< test1::grammar, nothing, test1::control >( memory_input( "b", __FUNCTION__ ) );
          TAO_PEGTL_TEST_ASSERT( false );
       }
       catch( const parse_error& e ) {
diff --git a/packages/PEGTL/src/test/pegtl/file_mmap.cpp b/packages/PEGTL/src/test/pegtl/file_mmap.cpp
index cd8d7ab715d201800a1899cd5fdf2e8a6c62f81b..478b3b1f0181452324829c63011734b753da7e15 100644
--- a/packages/PEGTL/src/test/pegtl/file_mmap.cpp
+++ b/packages/PEGTL/src/test/pegtl/file_mmap.cpp
@@ -22,7 +22,7 @@ namespace TAO_PEGTL_NAMESPACE
 
 #else
 
-int main( int, char** )
+int main()
 {
    return 0;
 }
diff --git a/packages/PEGTL/src/test/pegtl/internal_endian.cpp b/packages/PEGTL/src/test/pegtl/internal_endian.cpp
index 6a8ab73e20cc41777526d5d385edc2ae383e31c8..6319a70cec05a650de1f4f89684c09a31dd83eb6 100644
--- a/packages/PEGTL/src/test/pegtl/internal_endian.cpp
+++ b/packages/PEGTL/src/test/pegtl/internal_endian.cpp
@@ -1,7 +1,7 @@
 // Copyright (c) 2018-2020 Dr. Colin Hirsch and Daniel Frey
 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
 
-#include <tao/pegtl/internal/endian.hpp>
+#include <tao/pegtl/contrib/internal/endian.hpp>
 
 #include "test.hpp"
 
diff --git a/packages/PEGTL/src/test/pegtl/internal_file_mapper.cpp b/packages/PEGTL/src/test/pegtl/internal_file_mapper.cpp
index 74d8a765345e5a02b737abbbca355d8e903ee833..567ed28a6e1a1acd846e5831f00eba31cfb008e1 100644
--- a/packages/PEGTL/src/test/pegtl/internal_file_mapper.cpp
+++ b/packages/PEGTL/src/test/pegtl/internal_file_mapper.cpp
@@ -30,7 +30,7 @@ namespace TAO_PEGTL_NAMESPACE
 
 #else
 
-int main( int, char** )
+int main()
 {
    return 0;
 }
diff --git a/packages/PEGTL/src/test/pegtl/internal_file_opener.cpp b/packages/PEGTL/src/test/pegtl/internal_file_opener.cpp
index cb21dca72d42f021d59dc853cab95a033c9d9391..3a3dc3c2c8a6ab40678c4563bba8112f6aa9a1e7 100644
--- a/packages/PEGTL/src/test/pegtl/internal_file_opener.cpp
+++ b/packages/PEGTL/src/test/pegtl/internal_file_opener.cpp
@@ -29,7 +29,7 @@ namespace TAO_PEGTL_NAMESPACE
 
 #else
 
-int main( int, char** )
+int main()
 {
    return 0;
 }
diff --git a/packages/PEGTL/src/test/pegtl/position.cpp b/packages/PEGTL/src/test/pegtl/position.cpp
index ff5426d0fa209dde3ae65f958de978afbbe6cc08..92e8e45a0d64692e4bc42ab02c1ca54df1667749 100644
--- a/packages/PEGTL/src/test/pegtl/position.cpp
+++ b/packages/PEGTL/src/test/pegtl/position.cpp
@@ -15,36 +15,36 @@ namespace TAO_PEGTL_NAMESPACE
       {}
    };
 
-   template< typename Rule, typename Input = memory_input<> >
+   template< typename Rule, typename ParseInput = memory_input<> >
    void test_matches_lf()
    {
       static const std::string s1 = "\n";
 
-      Input i1( s1, __FUNCTION__ );
+      ParseInput i1( s1, __FUNCTION__ );
 
       TAO_PEGTL_TEST_ASSERT( parse< Rule >( i1 ) );
       TAO_PEGTL_TEST_ASSERT( i1.line() == 2 );
       TAO_PEGTL_TEST_ASSERT( i1.byte_in_line() == 0 );
    }
 
-   template< typename Rule, typename Input = memory_input<> >
+   template< typename Rule, typename ParseInput = memory_input<> >
    void test_matches_other( const std::string& s2 )
    {
       TAO_PEGTL_TEST_ASSERT( s2.size() == 1 );
 
-      Input i2( s2, __FUNCTION__ );
+      ParseInput i2( s2, __FUNCTION__ );
 
       TAO_PEGTL_TEST_ASSERT( parse< Rule >( i2 ) );
       TAO_PEGTL_TEST_ASSERT( i2.line() == 1 );
       TAO_PEGTL_TEST_ASSERT( i2.byte_in_line() == 1 );
    }
 
-   template< typename Rule, typename Input = memory_input<> >
+   template< typename Rule, typename ParseInput = memory_input<> >
    void test_mismatch( const std::string& s3 )
    {
       TAO_PEGTL_TEST_ASSERT( s3.size() == 1 );
 
-      Input i3( s3, __FUNCTION__ );
+      ParseInput i3( s3, __FUNCTION__ );
 
       TAO_PEGTL_TEST_ASSERT( !parse< Rule >( i3 ) );
       TAO_PEGTL_TEST_ASSERT( i3.line() == 1 );
@@ -66,8 +66,8 @@ namespace TAO_PEGTL_NAMESPACE
    template<>
    struct outer_action< two< 'b' > >
    {
-      template< typename Input >
-      static void apply( const Input& oi )
+      template< typename ActionInput >
+      static void apply( const ActionInput& oi )
       {
          const auto p = oi.position();
          TAO_PEGTL_TEST_ASSERT( p.source == "outer" );
@@ -79,7 +79,7 @@ namespace TAO_PEGTL_NAMESPACE
       }
    };
 
-   template< typename Input = memory_input<> >
+   template< typename ParseInput = memory_input<> >
    void test_nested()
    {
       try {
diff --git a/packages/PEGTL/src/test/pegtl/rule_action.cpp b/packages/PEGTL/src/test/pegtl/rule_action.cpp
index 5273e2d24cb92526875b824083d350e8a12fa648..6b0c1c0dc0f11c0eefc7d50b512d49837ee42ee0 100644
--- a/packages/PEGTL/src/test/pegtl/rule_action.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_action.cpp
@@ -11,6 +11,10 @@ namespace TAO_PEGTL_NAMESPACE
 
    void unit_test()
    {
+      verify_meta< action< nothing >, internal::success >();
+      verify_meta< action< nothing, eof >, internal::action< nothing, eof >, eof >();
+      verify_meta< action< nothing, eof, any >, internal::action< nothing, internal::seq< eof, any > >, internal::seq< eof, any > >();
+
       verify_seqs< test_action_rule >();
    }
 
diff --git a/packages/PEGTL/src/test/pegtl/rule_apply.cpp b/packages/PEGTL/src/test/pegtl/rule_apply.cpp
index 21d9c20c7b84d592a4be02b11c579634ae188123..92bf49220e739f065c782161800b5156ed46a9a6 100644
--- a/packages/PEGTL/src/test/pegtl/rule_apply.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_apply.cpp
@@ -11,8 +11,8 @@ namespace TAO_PEGTL_NAMESPACE
    {
       struct action_a
       {
-         template< typename Input >
-         static void apply( const Input& /*unused*/, int& r, int& s )
+         template< typename ActionInput >
+         static void apply( const ActionInput& /*unused*/, int& r, int& s )
          {
             TAO_PEGTL_TEST_ASSERT( !r );
             TAO_PEGTL_TEST_ASSERT( !s );
@@ -22,8 +22,8 @@ namespace TAO_PEGTL_NAMESPACE
 
       struct action_b
       {
-         template< typename Input >
-         static bool apply( const Input& /*unused*/, int& r, int& s )
+         template< typename ActionInput >
+         static bool apply( const ActionInput& /*unused*/, int& r, int& s )
          {
             TAO_PEGTL_TEST_ASSERT( !s );
             TAO_PEGTL_TEST_ASSERT( r == 1 );
@@ -34,8 +34,8 @@ namespace TAO_PEGTL_NAMESPACE
 
       struct action2_a
       {
-         template< typename Input >
-         static void apply( const Input& /*unused*/, bool& state_b )
+         template< typename ActionInput >
+         static void apply( const ActionInput& /*unused*/, bool& state_b )
          {
             TAO_PEGTL_TEST_ASSERT( !state_b );
          }
@@ -43,8 +43,8 @@ namespace TAO_PEGTL_NAMESPACE
 
       struct action2_b
       {
-         template< typename Input >
-         static bool apply( const Input& /*unused*/, bool& state_b )
+         template< typename ActionInput >
+         static bool apply( const ActionInput& /*unused*/, bool& state_b )
          {
             TAO_PEGTL_TEST_ASSERT( !state_b );
             state_b = true;
@@ -54,8 +54,8 @@ namespace TAO_PEGTL_NAMESPACE
 
       struct action2_c
       {
-         template< typename Input >
-         static void apply( const Input& /*unused*/, bool& /*unused*/ )
+         template< typename ActionInput >
+         static void apply( const ActionInput& /*unused*/, bool& /*unused*/ )
          {
             TAO_PEGTL_TEST_ASSERT( false );
          }
@@ -79,6 +79,8 @@ namespace TAO_PEGTL_NAMESPACE
       TAO_PEGTL_TEST_ASSERT( !result );
       TAO_PEGTL_TEST_ASSERT( state_b );
 
+      verify_meta< apply< test1::action_a, test1::action_b >, internal::apply< test1::action_a, test1::action_b > >();
+
       verify_analyze< apply<> >( __LINE__, __FILE__, false, false );
 
       verify_rule< apply<> >( __LINE__, __FILE__, "", result_type::success, 0 );
diff --git a/packages/PEGTL/src/test/pegtl/rule_apply0.cpp b/packages/PEGTL/src/test/pegtl/rule_apply0.cpp
index a55fe68bb687d1c8a7bc9a9f2d250c21212114a3..4a25a5b3922409bcaa610d1b4fd7e019a1fbe094 100644
--- a/packages/PEGTL/src/test/pegtl/rule_apply0.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_apply0.cpp
@@ -74,6 +74,8 @@ namespace TAO_PEGTL_NAMESPACE
       TAO_PEGTL_TEST_ASSERT( !result );
       TAO_PEGTL_TEST_ASSERT( state_b );
 
+      verify_meta< apply0< test1::action_a, test1::action_b >, internal::apply0< test1::action_a, test1::action_b > >();
+
       verify_analyze< apply0<> >( __LINE__, __FILE__, false, false );
 
       verify_rule< apply0<> >( __LINE__, __FILE__, "", result_type::success, 0 );
diff --git a/packages/PEGTL/src/test/pegtl/rule_at.cpp b/packages/PEGTL/src/test/pegtl/rule_at.cpp
index c411cc6adc585e7b70b8ecefd5f9a71c5c1d215d..3d7f6dd484ed45ca35161a6476779f30f2c61c95 100644
--- a/packages/PEGTL/src/test/pegtl/rule_at.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_at.cpp
@@ -16,8 +16,7 @@ namespace TAO_PEGTL_NAMESPACE
    template<>
    struct at_action< any >
    {
-      template< typename Input >
-      static void apply( const Input& /*unused*/ )
+      static void apply0()
       {
          ++at_counter;
       }
@@ -27,6 +26,10 @@ namespace TAO_PEGTL_NAMESPACE
    {
       TAO_PEGTL_TEST_ASSERT( at_counter == 0 );
 
+      verify_meta< at<>, internal::success >();
+      verify_meta< at< eof >, internal::at< eof >, eof >();
+      verify_meta< at< eof, any >, internal::at< internal::seq< eof, any > >, internal::seq< eof, any > >();
+
       verify_analyze< at< eof > >( __LINE__, __FILE__, false, false );
       verify_analyze< at< any > >( __LINE__, __FILE__, false, false );
 
diff --git a/packages/PEGTL/src/test/pegtl/rule_bof.cpp b/packages/PEGTL/src/test/pegtl/rule_bof.cpp
index 4ed27590d46200be971765d2746142e5fc526540..ee02311678a3825ed5eafe01ad55a3ebe8f1ecc6 100644
--- a/packages/PEGTL/src/test/pegtl/rule_bof.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_bof.cpp
@@ -9,6 +9,8 @@ namespace TAO_PEGTL_NAMESPACE
 {
    void unit_test()
    {
+      verify_meta< bof, internal::bof >();
+
       verify_analyze< bof >( __LINE__, __FILE__, false, false );
 
       verify_rule< bof >( __LINE__, __FILE__, "", result_type::success, 0 );
diff --git a/packages/PEGTL/src/test/pegtl/rule_bol.cpp b/packages/PEGTL/src/test/pegtl/rule_bol.cpp
index ac6932c70620abef6287f558a78357c29a34a975..d50a41bbedba9aa926a55784b3019fe599bd2f46 100644
--- a/packages/PEGTL/src/test/pegtl/rule_bol.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_bol.cpp
@@ -9,6 +9,8 @@ namespace TAO_PEGTL_NAMESPACE
 {
    void unit_test()
    {
+      verify_meta< bol, internal::bol >();
+
       verify_analyze< bol >( __LINE__, __FILE__, false, false );
 
       verify_only< bol >( __LINE__, __FILE__, "", result_type::success, 0 );
diff --git a/packages/PEGTL/src/test/pegtl/rule_bytes.cpp b/packages/PEGTL/src/test/pegtl/rule_bytes.cpp
index 4ee77bb6ace659640dbf34f70c1af7717d13c0a9..9485df93ff904fbc19338ed999d033c1ee8716c0 100644
--- a/packages/PEGTL/src/test/pegtl/rule_bytes.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_bytes.cpp
@@ -10,6 +10,10 @@ namespace TAO_PEGTL_NAMESPACE
 {
    void unit_test()
    {
+      verify_meta< bytes< 0 >, internal::success >();
+      verify_meta< bytes< 1 >, internal::bytes< 1 > >();
+      verify_meta< bytes< 42 >, internal::bytes< 42 > >();
+
       verify_analyze< bytes< 0 > >( __LINE__, __FILE__, false, false );
 
       verify_rule< bytes< 0 > >( __LINE__, __FILE__, "", result_type::success, 0 );
diff --git a/packages/PEGTL/src/test/pegtl/rule_control.cpp b/packages/PEGTL/src/test/pegtl/rule_control.cpp
index 251d6b6a53c2817c2031b9f5aef762b39b139e80..7153086e24c9e34bdcbd0d5ddc56fec1e54a6fee 100644
--- a/packages/PEGTL/src/test/pegtl/rule_control.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_control.cpp
@@ -11,6 +11,10 @@ namespace TAO_PEGTL_NAMESPACE
 
    void unit_test()
    {
+      verify_meta< control< normal >, internal::success >();
+      verify_meta< control< normal, eof >, internal::control< normal, eof >, eof >();
+      verify_meta< control< normal, eof, any >, internal::control< normal, internal::seq< eof, any > >, internal::seq< eof, any > >();
+
       verify_seqs< test_control_rule >();
    }
 
diff --git a/packages/PEGTL/src/test/pegtl/rule_disable.cpp b/packages/PEGTL/src/test/pegtl/rule_disable.cpp
index d0503fc6bffeac652a44046ae3145f2ce4b2fab1..f48626d9e5be265c60b4a988cd5e66e8f7b2b9b6 100644
--- a/packages/PEGTL/src/test/pegtl/rule_disable.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_disable.cpp
@@ -8,6 +8,10 @@ namespace TAO_PEGTL_NAMESPACE
 {
    void unit_test()
    {
+      verify_meta< disable<>, internal::success >();
+      verify_meta< disable< eof >, internal::disable< eof >, eof >();
+      verify_meta< disable< eof, any >, internal::disable< internal::seq< eof, any > >, internal::seq< eof, any > >();
+
       verify_seqs< disable >();
    }
 
diff --git a/packages/PEGTL/src/test/pegtl/rule_enable.cpp b/packages/PEGTL/src/test/pegtl/rule_enable.cpp
index 4cf0131404e346384ac1fe41feeff0326cbb4b42..121b18ce458da1c145df3f132f74fbb8ee3975e0 100644
--- a/packages/PEGTL/src/test/pegtl/rule_enable.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_enable.cpp
@@ -8,6 +8,10 @@ namespace TAO_PEGTL_NAMESPACE
 {
    void unit_test()
    {
+      verify_meta< enable<>, internal::success >();
+      verify_meta< enable< eof >, internal::enable< eof >, eof >();
+      verify_meta< enable< eof, any >, internal::enable< internal::seq< eof, any > >, internal::seq< eof, any > >();
+
       verify_seqs< enable >();
    }
 
diff --git a/packages/PEGTL/src/test/pegtl/rule_eof.cpp b/packages/PEGTL/src/test/pegtl/rule_eof.cpp
index 8c841de5cedfe746430b40082b3e547b02d393f1..2d200d564fc3b920ebe9cf120e0550fe5bd0f725 100644
--- a/packages/PEGTL/src/test/pegtl/rule_eof.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_eof.cpp
@@ -10,6 +10,8 @@ namespace TAO_PEGTL_NAMESPACE
 {
    void unit_test()
    {
+      verify_meta< eof, internal::eof >();
+
       verify_analyze< eof >( __LINE__, __FILE__, false, false );
 
       verify_rule< eof >( __LINE__, __FILE__, "", result_type::success, 0 );
diff --git a/packages/PEGTL/src/test/pegtl/rule_failure.cpp b/packages/PEGTL/src/test/pegtl/rule_failure.cpp
index 989c77d7fbf8da82221cf1632eeee9bc6a9ba151..2f116fa201fccec496bdf9a7d9deaf6a2db7288a 100644
--- a/packages/PEGTL/src/test/pegtl/rule_failure.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_failure.cpp
@@ -10,6 +10,8 @@ namespace TAO_PEGTL_NAMESPACE
 {
    void unit_test()
    {
+      verify_meta< failure, internal::failure >();
+
       verify_analyze< failure >( __LINE__, __FILE__, true, false );  // "Success implies consumption" is true because "success" never happens.
 
       verify_rule< failure >( __LINE__, __FILE__, "", result_type::local_failure, 0 );
diff --git a/packages/PEGTL/src/test/pegtl/rule_if_apply.cpp b/packages/PEGTL/src/test/pegtl/rule_if_apply.cpp
index 8b6dcb506429b3644a206e0478e7e330389caf5f..82d3cb7bfe7d7e49acc1b60815bc3cc1c47b1c94 100644
--- a/packages/PEGTL/src/test/pegtl/rule_if_apply.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_if_apply.cpp
@@ -10,8 +10,8 @@ namespace TAO_PEGTL_NAMESPACE
    {
       struct action_a
       {
-         template< typename Input >
-         static void apply( const Input& in, std::string& r, std::string& s )
+         template< typename ActionInput >
+         static void apply( const ActionInput& in, std::string& r, std::string& s )
          {
             TAO_PEGTL_TEST_ASSERT( r.empty() );
             TAO_PEGTL_TEST_ASSERT( s.empty() );
@@ -21,8 +21,8 @@ namespace TAO_PEGTL_NAMESPACE
 
       struct action_b
       {
-         template< typename Input >
-         static void apply( const Input& in, std::string& r, std::string& s )
+         template< typename ActionInput >
+         static void apply( const ActionInput& in, std::string& r, std::string& s )
          {
             TAO_PEGTL_TEST_ASSERT( s.empty() );
             s += in.string();
@@ -33,8 +33,8 @@ namespace TAO_PEGTL_NAMESPACE
 
       struct action2_a
       {
-         template< typename Input >
-         static void apply( const Input& in, bool& state_b )
+         template< typename ActionInput >
+         static void apply( const ActionInput& in, bool& state_b )
          {
             TAO_PEGTL_TEST_ASSERT( in.string_view() == "foo" );
             TAO_PEGTL_TEST_ASSERT( !state_b );
@@ -43,8 +43,8 @@ namespace TAO_PEGTL_NAMESPACE
 
       struct action2_b
       {
-         template< typename Input >
-         static bool apply( const Input& in, bool& state_b )
+         template< typename ActionInput >
+         static bool apply( const ActionInput& in, bool& state_b )
          {
             TAO_PEGTL_TEST_ASSERT( in.string_view() == "foo" );
             TAO_PEGTL_TEST_ASSERT( !state_b );
@@ -55,8 +55,8 @@ namespace TAO_PEGTL_NAMESPACE
 
       struct action2_c
       {
-         template< typename Input >
-         static void apply( const Input& /*unused*/, bool& /*unused*/ )
+         template< typename ActionInput >
+         static void apply( const ActionInput& /*unused*/, bool& /*unused*/ )
          {
             TAO_PEGTL_TEST_ASSERT( false );
          }
@@ -114,6 +114,8 @@ namespace TAO_PEGTL_NAMESPACE
          TAO_PEGTL_TEST_ASSERT( !result );
          TAO_PEGTL_TEST_ASSERT( !state_b );
       }
+      verify_meta< if_apply< any >, internal::if_apply< any >, any >();
+      verify_meta< if_apply< any, test1::action_a >, internal::if_apply< any, test1::action_a >, any >();
 
       verify_seqs< if_apply_seq >();
       verify_seqs< if_apply_disable >();
diff --git a/packages/PEGTL/src/test/pegtl/rule_if_must.cpp b/packages/PEGTL/src/test/pegtl/rule_if_must.cpp
index 8b89ab7bead1274d8b8e89776f68d41a87bb5035..51ef74024c5e9bc45e83701b1f4c8fde7e5a10c2 100644
--- a/packages/PEGTL/src/test/pegtl/rule_if_must.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_if_must.cpp
@@ -9,6 +9,10 @@ namespace TAO_PEGTL_NAMESPACE
 {
    void unit_test()
    {
+      verify_meta< if_must< any >, internal::if_must< false, any >, any, internal::must<> >();
+      verify_meta< if_must< any, eof >, internal::if_must< false, any, eof >, any, internal::must< eof > >();
+      verify_meta< if_must< any, eof, one< 0 > >, internal::if_must< false, any, eof, one< 0 > >, any, internal::must< eof, one< 0 > > >();
+
       verify_analyze< if_must< any, any > >( __LINE__, __FILE__, true, false );
       verify_analyze< if_must< eof, any > >( __LINE__, __FILE__, true, false );
       verify_analyze< if_must< opt< any >, any > >( __LINE__, __FILE__, true, false );
diff --git a/packages/PEGTL/src/test/pegtl/rule_if_then_else.cpp b/packages/PEGTL/src/test/pegtl/rule_if_then_else.cpp
index 0b4f21917b4f6e151801de70907ed50cbcb1aae4..c31c540349ce1daa7a593a724b979a07b79b4f3d 100644
--- a/packages/PEGTL/src/test/pegtl/rule_if_then_else.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_if_then_else.cpp
@@ -8,6 +8,8 @@ namespace TAO_PEGTL_NAMESPACE
 {
    void unit_test()
    {
+      verify_meta< if_then_else< digit, alpha, print >, internal::if_then_else< digit, alpha, print >, digit, alpha, print >();
+
       verify_ifmt< if_then_else >();
    }
 
diff --git a/packages/PEGTL/src/test/pegtl/rule_must.cpp b/packages/PEGTL/src/test/pegtl/rule_must.cpp
index 4140b33856e63da223db7d7219c03693922a6983..b93354ff07427b227ffc3e01a2ab01ae11d9d80a 100644
--- a/packages/PEGTL/src/test/pegtl/rule_must.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_must.cpp
@@ -8,6 +8,10 @@ namespace TAO_PEGTL_NAMESPACE
 {
    void unit_test()
    {
+      verify_meta< must<>, internal::success >();
+      verify_meta< must< alpha >, internal::must< alpha >, alpha >();
+      verify_meta< must< alpha, digit >, internal::seq< internal::must< alpha >, internal::must< digit > >, internal::must< alpha >, internal::must< digit > >();
+
       verify_seqs< must >( result_type::global_failure );
    }
 
diff --git a/packages/PEGTL/src/test/pegtl/rule_not_at.cpp b/packages/PEGTL/src/test/pegtl/rule_not_at.cpp
index a09bdca39749762bb294003db389c53c99980ee5..7fe69a528d45ab2e6501c1d0f4abee690c685ff7 100644
--- a/packages/PEGTL/src/test/pegtl/rule_not_at.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_not_at.cpp
@@ -16,8 +16,7 @@ namespace TAO_PEGTL_NAMESPACE
    template<>
    struct at_action< alpha >
    {
-      template< typename Input >
-      static void apply( const Input& /*unused*/ )
+      static void apply0()
       {
          ++at_counter;
       }
@@ -27,6 +26,10 @@ namespace TAO_PEGTL_NAMESPACE
    {
       TAO_PEGTL_TEST_ASSERT( at_counter == 0 );
 
+      verify_meta< not_at<>, internal::failure >();
+      verify_meta< not_at< eof >, internal::not_at< eof >, eof >();
+      verify_meta< not_at< eof, any >, internal::not_at< internal::seq< eof, any > >, internal::seq< eof, any > >();
+
       verify_analyze< not_at< eof > >( __LINE__, __FILE__, false, false );
       verify_analyze< not_at< any > >( __LINE__, __FILE__, false, false );
 
diff --git a/packages/PEGTL/src/test/pegtl/rule_opt.cpp b/packages/PEGTL/src/test/pegtl/rule_opt.cpp
index 72fe74551767fc17bae22669be69abb3ee194838..05507c8c559c188671408d4dd3fdb7cbc71af81c 100644
--- a/packages/PEGTL/src/test/pegtl/rule_opt.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_opt.cpp
@@ -22,6 +22,10 @@ namespace TAO_PEGTL_NAMESPACE
 
    void unit_test()
    {
+      verify_meta< opt<>, internal::success >();
+      verify_meta< opt< eof >, internal::opt< eof >, eof >();
+      verify_meta< opt< eof, any >, internal::opt< internal::seq< eof, any > >, internal::seq< eof, any > >();
+
       verify_analyze< opt< any > >( __LINE__, __FILE__, false, false );
       verify_analyze< opt< eof > >( __LINE__, __FILE__, false, false );
 
diff --git a/packages/PEGTL/src/test/pegtl/rule_rematch.cpp b/packages/PEGTL/src/test/pegtl/rule_rematch.cpp
index 90367d37f5037b082b597442bb6a8cafba819981..6eec3dba03df0aa960660d090371929d39e2845e 100644
--- a/packages/PEGTL/src/test/pegtl/rule_rematch.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_rematch.cpp
@@ -17,7 +17,25 @@ namespace TAO_PEGTL_NAMESPACE
 
       verify_analyze< rematch< alpha, digit > >( __LINE__, __FILE__, true, false );
       verify_analyze< rematch< opt< alpha >, digit > >( __LINE__, __FILE__, false, false );
-
+      verify_analyze< rematch< alnum, opt< alpha > > >( __LINE__, __FILE__, true, false );
+      {
+         struct foo
+            : rematch< foo, alnum >
+         {};
+         verify_analyze< foo >( __LINE__, __FILE__, false, true );
+      }
+      {
+         struct foo
+            : rematch< alnum, foo >
+         {};
+         verify_analyze< foo >( __LINE__, __FILE__, true, true );
+      }
+      {
+         struct foo
+            : rematch< alnum, alpha, foo >
+         {};
+         verify_analyze< foo >( __LINE__, __FILE__, true, true );
+      }
       verify_rule< rematch< alnum, digit > >( __LINE__, __FILE__, "", result_type::local_failure, 0 );
       verify_rule< rematch< alnum, digit > >( __LINE__, __FILE__, "1", result_type::success, 0 );
       verify_rule< rematch< alnum, digit > >( __LINE__, __FILE__, "a", result_type::local_failure, 1 );
diff --git a/packages/PEGTL/src/test/pegtl/rule_state.cpp b/packages/PEGTL/src/test/pegtl/rule_state.cpp
index 456f5481ce2b24cd03d70d4604f1a8322c24e186..77ed17f01bb18186b64b8f6a6b2dd2ffa7647d0b 100644
--- a/packages/PEGTL/src/test/pegtl/rule_state.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_state.cpp
@@ -8,12 +8,12 @@ namespace TAO_PEGTL_NAMESPACE
 {
    struct test_state_state
    {
-      template< typename Input >
-      explicit test_state_state( const Input& /*unused*/ )
+      template< typename ParseInput >
+      explicit test_state_state( const ParseInput& /*unused*/ )
       {}
 
-      template< typename Input >
-      void success( const Input& /*unused*/ ) const
+      template< typename ParseInput >
+      void success( const ParseInput& /*unused*/ ) const
       {}
    };
 
diff --git a/packages/PEGTL/src/test/pegtl/rule_until.cpp b/packages/PEGTL/src/test/pegtl/rule_until.cpp
index a6c288fa198c53519e882abc86fba7283d52293a..f1e49d3946460dcf36194298c3a3b4f07ea7128d 100644
--- a/packages/PEGTL/src/test/pegtl/rule_until.cpp
+++ b/packages/PEGTL/src/test/pegtl/rule_until.cpp
@@ -15,9 +15,9 @@ namespace TAO_PEGTL_NAMESPACE
                 class Action,
                 template< typename... >
                 class Control,
-                typename Input,
+                typename ParseInput,
                 typename... States >
-      static bool match( Input& /*unused*/, bool& v, States... /*unused*/ )
+      static bool match( ParseInput& /*unused*/, bool& v, States... /*unused*/ )
       {
          return v;
       }
diff --git a/packages/PEGTL/src/test/pegtl/test.hpp b/packages/PEGTL/src/test/pegtl/test.hpp
index b1b4de434c5111b4c4de4e528224c25e7875e979..18868e018cd60583c214a4073059bb9aaa193f71 100644
--- a/packages/PEGTL/src/test/pegtl/test.hpp
+++ b/packages/PEGTL/src/test/pegtl/test.hpp
@@ -67,32 +67,4 @@ namespace TAO_PEGTL_NAMESPACE
       }                                             \
    } while( false )
 
-namespace TAO_PEGTL_NAMESPACE
-{
-   template< unsigned Size, apply_mode B, rewind_mode N, typename... Rules >
-   struct test_rule
-   {
-      using analyze_t = typename seq< Rules... >::analyze_t;
-
-      template< apply_mode A,
-                rewind_mode M,
-                template< typename... >
-                class Action,
-                template< typename... >
-                class Control,
-                typename Input,
-                typename... States >
-      static bool match( Input& in, States&&... st )
-      {
-         static_assert( A == B, "unexpected apply mode" );
-         static_assert( M == N, "unexpected rewind mode" );
-
-         TAO_PEGTL_TEST_ASSERT( in.size() == Size );
-
-         return seq< Rules... >::template match< A, M, Action, Control >( in, st... );
-      }
-   };
-
-}  // namespace TAO_PEGTL_NAMESPACE
-
 #endif
diff --git a/packages/PEGTL/src/test/pegtl/uint16_general.cpp b/packages/PEGTL/src/test/pegtl/uint16_general.cpp
index adff4f078e1538b6d602fc0de1ef6490ddb8a094..c43aa51563bb0bd4359fe7184a15e100b740b4c0 100644
--- a/packages/PEGTL/src/test/pegtl/uint16_general.cpp
+++ b/packages/PEGTL/src/test/pegtl/uint16_general.cpp
@@ -5,6 +5,8 @@
 #include "verify_char.hpp"
 #include "verify_rule.hpp"
 
+#include <tao/pegtl/contrib/uint16.hpp>
+
 namespace TAO_PEGTL_NAMESPACE
 {
    void unit_test()
diff --git a/packages/PEGTL/src/test/pegtl/uint32_general.cpp b/packages/PEGTL/src/test/pegtl/uint32_general.cpp
index 688973b70ccffc78e2a215db67ed1944bd86e162..97430a5a8bd831199f514f75060d7d39b5a56172 100644
--- a/packages/PEGTL/src/test/pegtl/uint32_general.cpp
+++ b/packages/PEGTL/src/test/pegtl/uint32_general.cpp
@@ -5,6 +5,8 @@
 #include "verify_char.hpp"
 #include "verify_rule.hpp"
 
+#include <tao/pegtl/contrib/uint32.hpp>
+
 namespace TAO_PEGTL_NAMESPACE
 {
    void unit_test()
diff --git a/packages/PEGTL/src/test/pegtl/uint64_general.cpp b/packages/PEGTL/src/test/pegtl/uint64_general.cpp
index f10dd76b23dcde06994d98269d459158e8363cf9..2b5ef5e218d2aa46d6a45d014156ced41b690d49 100644
--- a/packages/PEGTL/src/test/pegtl/uint64_general.cpp
+++ b/packages/PEGTL/src/test/pegtl/uint64_general.cpp
@@ -5,6 +5,8 @@
 #include "verify_char.hpp"
 #include "verify_rule.hpp"
 
+#include <tao/pegtl/contrib/uint64.hpp>
+
 namespace TAO_PEGTL_NAMESPACE
 {
    void unit_test()
diff --git a/packages/PEGTL/src/test/pegtl/uint8_general.cpp b/packages/PEGTL/src/test/pegtl/uint8_general.cpp
index bb9d6471b6e42237add11f4f85939f3b6864ee9f..20ad2a951e3f279b695c349764bcfe12e1abd85d 100644
--- a/packages/PEGTL/src/test/pegtl/uint8_general.cpp
+++ b/packages/PEGTL/src/test/pegtl/uint8_general.cpp
@@ -5,6 +5,8 @@
 #include "verify_char.hpp"
 #include "verify_rule.hpp"
 
+#include <tao/pegtl/contrib/uint8.hpp>
+
 namespace TAO_PEGTL_NAMESPACE
 {
    void unit_test()
diff --git a/packages/PEGTL/src/test/pegtl/utf16_general.cpp b/packages/PEGTL/src/test/pegtl/utf16_general.cpp
index 9ca27052cd4910e8cb3d87e63c5767ef76fa9d82..57c7ba3bb9bf7d590277df5cbb2ca6e13c8a2134 100644
--- a/packages/PEGTL/src/test/pegtl/utf16_general.cpp
+++ b/packages/PEGTL/src/test/pegtl/utf16_general.cpp
@@ -4,6 +4,8 @@
 #include "test.hpp"
 #include "verify_rule.hpp"
 
+#include <tao/pegtl/contrib/utf16.hpp>
+
 namespace TAO_PEGTL_NAMESPACE
 {
    namespace
diff --git a/packages/PEGTL/src/test/pegtl/utf32_general.cpp b/packages/PEGTL/src/test/pegtl/utf32_general.cpp
index cdc38efee230708d34aa8096edf80ee479a3fad8..d9a435a2448923d5865fa64cda81d6965de7c31e 100644
--- a/packages/PEGTL/src/test/pegtl/utf32_general.cpp
+++ b/packages/PEGTL/src/test/pegtl/utf32_general.cpp
@@ -4,6 +4,8 @@
 #include "test.hpp"
 #include "verify_rule.hpp"
 
+#include <tao/pegtl/contrib/utf32.hpp>
+
 namespace TAO_PEGTL_NAMESPACE
 {
    namespace
diff --git a/packages/PEGTL/src/test/pegtl/verify_analyze.hpp b/packages/PEGTL/src/test/pegtl/verify_analyze.hpp
index 5441287cb08f9e82329ad866e29626c38c1b4941..befefba5b6d8eaf5046aaf672db2719719507718 100644
--- a/packages/PEGTL/src/test/pegtl/verify_analyze.hpp
+++ b/packages/PEGTL/src/test/pegtl/verify_analyze.hpp
@@ -4,7 +4,7 @@
 #ifndef TAO_PEGTL_SRC_TEST_PEGTL_VERIFY_ANALYZE_HPP
 #define TAO_PEGTL_SRC_TEST_PEGTL_VERIFY_ANALYZE_HPP
 
-#include <tao/pegtl/analyze.hpp>
+#include <tao/pegtl/contrib/analyze.hpp>
 
 #include "test.hpp"
 
@@ -13,7 +13,7 @@ namespace TAO_PEGTL_NAMESPACE
    template< typename Rule >
    void verify_analyze( const unsigned line, const char* file, const bool expect_consume, const bool expect_problems )
    {
-      analysis::analyze_cycles< Rule > a( false );
+      internal::analyze_cycles< Rule > a( false );
 
       const bool has_problems = ( a.problems() != 0 );
       const bool does_consume = a.template consumes< Rule >();
diff --git a/packages/PEGTL/src/test/pegtl/verify_file.hpp b/packages/PEGTL/src/test/pegtl/verify_file.hpp
index 9e7df26f783ffd06741ec5bad8b6241bc6cc323d..7ac5683c4444ece26b41c569e5f6c831d09bbb94 100644
--- a/packages/PEGTL/src/test/pegtl/verify_file.hpp
+++ b/packages/PEGTL/src/test/pegtl/verify_file.hpp
@@ -40,8 +40,8 @@ namespace TAO_PEGTL_NAMESPACE
    struct file_control< eof >
       : normal< eof >
    {
-      template< typename Input >
-      static void success( const Input& /*unused*/, bool& flag )
+      template< typename ParseInput >
+      static void success( const ParseInput& /*unused*/, bool& flag )
       {
          flag = true;
       }
diff --git a/packages/PEGTL/src/test/pegtl/verify_impl.hpp b/packages/PEGTL/src/test/pegtl/verify_impl.hpp
index b09aec0a0fc7b058ef53643feacd0b2539457283..83ad2977ca4f4d6abc0e540f594d7bbfbe026ff6 100644
--- a/packages/PEGTL/src/test/pegtl/verify_impl.hpp
+++ b/packages/PEGTL/src/test/pegtl/verify_impl.hpp
@@ -18,8 +18,8 @@
 
 namespace TAO_PEGTL_NAMESPACE
 {
-   template< typename Rule, template< typename... > class Action, typename Input >
-   result_type verify_impl_two( Input& in )
+   template< typename Rule, template< typename... > class Action, typename ParseInput >
+   result_type verify_impl_two( ParseInput& in )
    {
       try {
          if( normal< Rule >::template match< apply_mode::action, rewind_mode::required, Action, normal >( in ) ) {
@@ -36,8 +36,8 @@ namespace TAO_PEGTL_NAMESPACE
       }
    }
 
-   template< typename Rule, template< typename... > class Action, typename Input >
-   void verify_impl_one( const std::size_t line, const char* file, const std::string& data, Input& in, const result_type expected, const std::size_t remain )
+   template< typename Rule, template< typename... > class Action, typename ParseInput >
+   void verify_impl_one( const std::size_t line, const char* file, const std::string& data, ParseInput& in, const result_type expected, const std::size_t remain )
    {
       const result_type received = verify_impl_two< Rule, Action >( in );
 
diff --git a/packages/PEGTL/src/test/pegtl/verify_rule.hpp b/packages/PEGTL/src/test/pegtl/verify_rule.hpp
index 3efef51c9b16b06add8e2eb856f223994b00d4f4..fc614e06da2d5a0711f804544a245833de4cd1d3 100644
--- a/packages/PEGTL/src/test/pegtl/verify_rule.hpp
+++ b/packages/PEGTL/src/test/pegtl/verify_rule.hpp
@@ -10,17 +10,25 @@
 #include <tao/pegtl/eol.hpp>
 #include <tao/pegtl/memory_input.hpp>
 #include <tao/pegtl/tracking_mode.hpp>
+#include <tao/pegtl/type_list.hpp>
 
 #include "result_type.hpp"
 #include "verify_impl.hpp"
 
 namespace TAO_PEGTL_NAMESPACE
 {
+   template< typename Name, typename Rule, typename... Rules >
+   void verify_meta()
+   {
+      static_assert( std::is_same_v< typename Name::rule_t, Rule > );
+      static_assert( std::is_same_v< typename Name::subs_t, type_list< Rules... > > );
+   }
+
    template< typename Rule >
    struct verify_action_impl
    {
-      template< typename Input, typename... States >
-      static void apply( const Input& /*unused*/, States&&... /*unused*/ )
+      template< typename ActionInput, typename... States >
+      static void apply( const ActionInput& /*unused*/, States&&... /*unused*/ )
       {}
    };
 
diff --git a/src/language/PugsParser.cpp b/src/language/PugsParser.cpp
index 8226db8316b2f45f20fff9850077f3728ad6f6df..1998ccb83ede7394f81e1d94791755fed1bfc6e5 100644
--- a/src/language/PugsParser.cpp
+++ b/src/language/PugsParser.cpp
@@ -9,7 +9,7 @@
 
 #include <rang.hpp>
 
-#include <pegtl/analyze.hpp>
+#include <pegtl/contrib/analyze.hpp>
 #include <pegtl/contrib/parse_tree.hpp>
 #include <pegtl/contrib/parse_tree_to_dot.hpp>