aboutsummaryrefslogtreecommitdiff
path: root/src/libexpr/parser/change_head.hh
diff options
context:
space:
mode:
Diffstat (limited to 'src/libexpr/parser/change_head.hh')
-rw-r--r--src/libexpr/parser/change_head.hh66
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...);
+ }
+};
+
+}