-
Notifications
You must be signed in to change notification settings - Fork 23
/
Copy pathmetadata.c
96 lines (77 loc) · 3.8 KB
/
metadata.c
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;
}