1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
|
#include <datatype99.h>
#include <assert.h>
#include <string.h>
// Deriver implementation {
#define DATATYPE99_DERIVE_Metadata_IMPL(name, variants) \
ML99_TERMS(genVariantsMetadata(name, variants), genMetadata(name, variants))
#define genVariantsMetadata(name, variants) \
ML99_assignStmt( \
v(static const VariantMetadata name##_variants_metadata[]), \
genVariantsInitializerList(name, variants))
#define genVariantsInitializerList(name, variants) \
ML99_braced(ML99_listMapInPlace( \
ML99_compose(ML99_appl(v(genVariant), v(name)), v(ML99_untuple)), \
v(variants)))
#define genVariant_IMPL(name_, tag, sig) \
ML99_TERMS( \
ML99_braced( \
ML99_assign(v(.name), v(#tag)), \
ML99_assign(v(.arity), ML99_listLen(v(sig))), \
ML99_assign(v(.size), v(sizeof(name_##tag)))), \
v(, ))
#define genVariant_ARITY 2
#define genMetadata(name_, variants_) \
ML99_assignStmt( \
v(static const DatatypeMetadata name_##_metadata), \
ML99_braced( \
ML99_assign(v(.name), v(#name_)), \
ML99_assign(v(.variants), v((const VariantMetadata *)&name_##_variants_metadata)), \
ML99_assign(v(.variants_count), ML99_listLen(v(variants_)))))
// } (Deriver implementation)
typedef struct {
const char *name;
size_t arity;
size_t size;
} VariantMetadata;
typedef struct {
const char *name;
const VariantMetadata *variants;
size_t variants_count;
} DatatypeMetadata;
// clang-format off
datatype(
derive(Metadata),
Num,
(Char, char),
(Int, int),
(Double, double)
);
// clang-format on
/*
The generated metadata:
static const VariantMetadata Num_variants_metadata[] = {
{.name = "Char", .arity = 1, .size = sizeof(NumChar)},
{.name = "Int", .arity = 1, .size = sizeof(NumInt)},
{.name = "Double", .arity = 1, .size = sizeof(NumDouble)},
};
static const DatatypeMetadata Num_metadata = {
.name = "Num",
.variants = (const VariantMetadata *)&Num_variants_metadata,
.variants_count = 3,
};
*/
int main(void) {
#define CHECK(idx, name_, arity_, size_) \
do { \
assert(strcmp(Num_metadata.variants[idx].name, name_) == 0); \
assert(arity_ == Num_metadata.variants[idx].arity); \
assert(size_ == Num_metadata.variants[idx].size); \
} while (0)
CHECK(0, "Char", 1, sizeof(char));
CHECK(1, "Int", 1, sizeof(int));
CHECK(2, "Double", 1, sizeof(double));
#undef CHECK
assert(strcmp(Num_metadata.name, "Num") == 0);
assert(3 == Num_metadata.variants_count);
return 0;
}
|