10 Comments

Here is my previous post a nice markdown view if you want (the code is more readable) : https://hackmd.io/@Mewily/HyLyk_wla

Expand full comment

Thank for this post, I just discover the blog !

I personally use an different form similar to X macro, but I can add any number of parameter without the need of changing everything. And the way I use them is a tiny bit more flexible.

Here is a short (modified for the example) portion of code for an interpreter I wrote in C,

My ways of making extensible enum (enum with more data attach to it) look like:

```c

#define category_int 'i'

#define category_float 'f'

// defining the enum named bi (build in) : (c type, type category)

#define i32_bi (int32_t , category_int)

#define i64_bi (int64_t , category_int)

#define f32_bi (float, category_float)

#define f64_bi (double, category_float)

// each member of the enum should have the same number of value

// you can do add more data attach to it like: (int32_t , category_int, "INT", 1)

```

Getting the info you need about an bi :

```c

#define get_1(a, b) a

#define get_2(a, b) b

#define bi_type(bi) get_1 bi

#define bi_category(bi) get_2 bi

```

so things like `bi_category(f64_bi)` -> `category_float` === `'f'` work

Mapping enum to stuff (function, macro...) :

```c

//build_in = (integer_type) Union (float_type)

// map the macro on all integer type inside bi :

#define map_on_bi_integer(macro)\

macro(i32_bi)\

macro(i64_bi)

#define map_on_bi_float(macro)\

macro(f32_bi)\

macro(f64_bi)

#define map_on_bi(macro)\

map_on_bi_integer(macro)\

map_on_bi_float(macro)

```

And then map it to whatever ! You can generate enum, switch case, custom function body and definition...

```c

// glue without evaluating the macro a and b

#define glue_instant(a,b) a ## b

// eval the macro FIRST, and then glue the result (other wise you will glue the unevaluated macro

#define glue(a,b) glue_instant(a, b)

enum bi_enum

{

// note : the ## glue macro don't directly work here, you need

#define declare_bi_enum_member(bi) glue(enum_,bi_type(bi)),

map_on_bi(declare_bi_enum_member)

/*

expend to :

enum_i32_bi, enum_i64_bi, enum_f32_bi, enum_f64_bi,

*/

#undef declare_bi_enum_member

}

Here is a switch case exemple :

```c

bool get_category(bi_enum b)

{

switch(b)

{

#define handle_case(bi)\

case glue(enum_, bi): return bi_category(bi); break;

/*break is not really helpful but anyways*/

map_on_bi(handle_case)

default: TODO; break; // (some macro to crash and tell the case was not implemented)

}

}

// or you can define a global array of bool if you want

```

the `map_on...` macro are great to map stuff, especially because you can create different family like :

```c

bool display(bi_enum b)

{

switch(b)

{

#define handle_int(bi)\

case glue(enum_, bi): printf("some integer!"); break;

#define handle_float(bi)\

case glue(enum_, bi): printf("some float!"); break;

/*break is not really helpful but anyways*/

map_on_bi_integer(handle_int)

map_on_bi_float(handle_float)

default: TODO; break;

}

}

```

I generally I put the enum number inside the define (`#define i32_bi (int32_t , category_int, 1)`), and add :

```

#define get_3(a, b, c) c

#define bi_id(bi) get_3 bi

```

so I don't declare an enum and the macro are a tiny bit easier to write.

But you can do it without it like in this example if you want.

(Fun fact, I'm a 21 years student in CS)

Expand full comment

It looks a lot like Coq (proof assistant) with its tactics. You can automate the writing of your own program and you need to do it in hope of getting anything done. But you can also write the program yourself.

Anyway in Coq, you have two levels of authorship and it seems to work fine.

Expand full comment
Jun 8·edited Jun 8

In case I missed something, aren't you just describing (E)DSLs? In this sense, wouldn't languages that facilitate the creation of (E)DSLs (e.g. Lisp-like languages) be the way to go?

Expand full comment