Header-only library for compile-time DSL.
Library provides macro_rules
macro that allows to describe own DSL.
Syntax of macro_rules
was inspired by Rust, but with some limitations.
DSL can be implemented directly using templates, for more flexibility.
This project is currently under development and not well tested and not documented.
#include "meta/meta_rules.hpp"
/** This would be equivalent to macro_rules(sum $(args:number)*) **/
struct Example : meta::parse::group<
meta::parse::ident<"sum">,
meta::parse::list<
meta::parse::with_name<
"args",
meta::parse::token<TokenType::Number>
>
>
> {
consteval static auto transform(auto ctx) {
auto args = meta::parse::get<"args">(ctx.value);
int32_t result = 0;
std::__for_each_index_sequence(
std::make_index_sequence<std::tuple_size_v<decltype(args)>>(),
[&]<size_t I>{
int32_t number;
std::from_chars(std::get<I>(args).str.begin(), std::get<I>(args).str.end(), number);
result += number;
}
);
return result;
}
};
static_assert(apply_rules(Example, sum 1 2 3 4) == 10);
#include "meta/meta_rules.hpp"
template<auto params>
struct FunctionContext {
constexpr static auto get_argument_index(std::string_view name) -> size_t {
for (size_t i = 0; i < params.value.size(); ++i) {
if (params.value[i] == name) {
return i;
}
}
return -1;
}
};
struct Function : macro_rules(
($($param:ident)*) -> $body:expr
) {
consteval static auto transform(auto ctx) {
constexpr auto params = meta::parse::Wrapper<[] {
return std::apply(
[](auto... args) {
return std::array{ args.str... };
},
meta::parse::get<"param">(decltype(ctx){}.value)
);
}>();
return wrap<FunctionContext<params>{}, std::get<0>(meta::parse::get<"body">(ctx.value))>();
}
template<FunctionContext ctx, auto body>
consteval static auto wrap() {
return [](auto&&... args) {
return body(ctx, std::forward_as_tuple(std::forward<decltype(args)>(args)...));
};
}
};
#define $fn(...) apply_rules(Function, __VA_ARGS__)
auto main() -> int {
constexpr auto fn1 = $fn((a b c d) -> ((a + b) * (c - d)) * 10);
constexpr auto fn2 = [](int a, int b, int c, int d) {
return (a + b) * (c - d) * 10;
};
static_assert(fn1(1, 2, 3, 4) == fn2(1, 2, 3, 4));
return 0;
}