Library: implement model-binding with generic-λ

Basically the implementation is already in place;
yet for better error messages we need to find out if the given functor
can handle the model present at this stage. Since generic-λ are not
functions by themselves (but rather templates), we need to ''probe''
with the expected argument and see if instantiation is possible.

⚠ NOTE: still a strange bug related to using the same Syntax several times
This commit is contained in:
Fischlurch 2025-01-25 03:40:41 +01:00
parent 860e2fa226
commit 57dc56f5c6
3 changed files with 54 additions and 39 deletions

View file

@ -168,23 +168,21 @@ namespace util {
// namespace {
// /** handle all regular "function-like" entities */
// template<typename SRC, typename F, typename SEL =void>
// struct FunDetector
// {
// using Sig = typename _Fun<F>::Sig;
// };
//
// /** handle a generic lambda, accepting a reference to the `SRC` iterator */
// template<typename SRC, typename F>
// struct FunDetector<SRC, F, lib::meta::disable_if<_Fun<F>> >
// {
// using Arg = std::add_lvalue_reference_t<SRC>;
// using Ret = decltype(std::declval<F>() (std::declval<Arg>()));
// using Sig = Ret(Arg);
// };
// }
namespace {
/** helper to detect return type of a possibly generic λ */
template<typename ARG, typename FUN, typename SEL =void>
struct _ProbeFunReturn
{
static_assert (!sizeof(ARG),
"Model binding must accept preceding model result.");
};
template<typename ARG, typename FUN>
struct _ProbeFunReturn<ARG,FUN, std::void_t<decltype(std::declval<FUN>() (std::declval<ARG>()))>>
{ // probe the λ with ARG to force template instantiation
using Ret = decltype(std::declval<FUN>() (std::declval<ARG>()));
};
}
/**
* Adapt by applying a result-transforming function after a successful parse.
@ -197,12 +195,8 @@ namespace util {
adaptConnex (CON&& connex, BIND&& modelBinding)
{
using RX = typename CON::Result;
// using Arg = lib::meta::_FunArg<BIND>;
// static_assert (std::is_constructible_v<Arg,RX>,
// "Model binding must accept preceding model result.");
// using AdaptedRes = typename _Fun<BIND>::Ret;
using Arg = std::add_lvalue_reference_t<RX>;
using AdaptedRes = decltype(modelBinding (std::declval<Arg>() ));
using Arg = std::add_rvalue_reference_t<RX>;
using AdaptedRes = typename _ProbeFunReturn<Arg,BIND>::Ret;
return Connex{[origConnex = forward<CON>(connex)
,binding = forward<BIND>(modelBinding)
]
@ -217,6 +211,7 @@ namespace util {
}
/* ===== building structured models ===== */
/**

View file

@ -573,7 +573,6 @@ namespace test {
auto syntax1 = accept(word).seq(word)
.bind([](Mod1 res)
{
// auto& [a,b] = res;
return res.get<0>().str() +"-"+ res.get<1>().str();
});
@ -582,10 +581,22 @@ namespace test {
syntax1.parse(s1);
CHECK (syntax1.success());
auto res1 = syntax1.getResult();
SHOW_TYPE(decltype(res1))
CHECK (showType<decltype(res1)>() == "string");
SHOW_EXPR(res1)
CHECK (res == "ham-actor"_expect);
CHECK (showType<decltype(res1)>() == "string"); // surprise! it is a simple string (as returned from λ)
CHECK (res1 == "ham-actor"_expect);
// 💡 shortcut for RegExp match groups...
auto syntax1b = accept("(\\w+) (\\w+)");
CHECK (accept(syntax1b).bindMatch( ).parse(s1).getResult() == "ham actor"_expect );
CHECK (accept(syntax1b).bindMatch(1).parse(s1).getResult() == "ham"_expect );
CHECK (accept(syntax1b).bindMatch(2).parse(s1).getResult() == "actor"_expect );
CHECK (accept(syntax1b).bindMatch(3).parse(s1).getResult() == ""_expect );