Skip to content

C++ compile-time Rust's like macro_rules implementation

Notifications You must be signed in to change notification settings

maksym-pasichnyk/macro_rules

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

16 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Introduction

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.

Code Example

#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;
}

About

C++ compile-time Rust's like macro_rules implementation

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published