diff options
Diffstat (limited to 'src/libexpr/parser/change_head.hh')
-rw-r--r-- | src/libexpr/parser/change_head.hh | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/src/libexpr/parser/change_head.hh b/src/libexpr/parser/change_head.hh new file mode 100644 index 000000000..aab315553 --- /dev/null +++ b/src/libexpr/parser/change_head.hh @@ -0,0 +1,66 @@ +#pragma once +///@file + +#include <tao/pegtl.hpp> + +namespace nix::parser { + +// modified copy of change_state, as the manual suggest for more involved +// state manipulation. we want to change only the first state parameter, +// and we care about the *initial* position of a rule application (not the +// past-the-end position as pegtl change_state provides) +template<typename NewState> +struct change_head : tao::pegtl::maybe_nothing +{ + template< + typename Rule, + tao::pegtl::apply_mode A, + tao::pegtl::rewind_mode M, + template<typename...> class Action, + template<typename...> class Control, + typename ParseInput, + typename State, + typename... States + > + [[nodiscard]] static bool match(ParseInput & in, State && st, States &&... sts) + { + const auto begin = in.iterator(); + + if constexpr (std::is_constructible_v<NewState, State, States...>) { + NewState s(st, sts...); + if (tao::pegtl::match<Rule, A, M, Action, Control>(in, s, sts...)) { + if constexpr (A == tao::pegtl::apply_mode::action) { + _success<Action<Rule>>(0, begin, in, s, st, sts...); + } + return true; + } + return false; + } else if constexpr (std::is_default_constructible_v<NewState>) { + NewState s; + if (tao::pegtl::match<Rule, A, M, Action, Control>(in, s, sts...)) { + if constexpr (A == tao::pegtl::apply_mode::action) { + _success<Action<Rule>>(0, begin, in, s, st, sts...); + } + return true; + } + return false; + } else { + static_assert(decltype(sizeof(NewState))(), "unable to instantiate new state"); + } + } + + template<typename Target, typename ParseInput, typename... S> + static void _success(void *, auto & begin, ParseInput & in, S & ... sts) + { + const typename ParseInput::action_t at(begin, in); + Target::success(at, sts...); + } + + template<typename Target, typename... S> + static void _success(decltype(Target::success0(std::declval<S &>()...), 0), auto &, auto &, S & ... sts) + { + Target::success0(sts...); + } +}; + +} |