summaryrefslogtreecommitdiffhomepage
path: root/src/build/codegen.c
diff options
context:
space:
mode:
authorMichael Smith <mikesmiffy128@gmail.com>2022-09-13 21:46:21 +0100
committerMichael Smith <mikesmiffy128@gmail.com>2022-09-13 22:50:30 +0100
commit792463cb133f65645feb48743bbc03ef8eb96bdd (patch)
tree3879cd6895fe5c8f597f445af2410a41bcf00f73 /src/build/codegen.c
parent378892d089b6742a95b8d573af58535597f19d25 (diff)
Move towards C23, improve events and vcall macros
Another big one. Here's a list of things: - Since the upcoming C23 standardises typeof(), use it as an extension for the time being in order to allow passing arbitrary types as macro/codegen parameters. It wouldn't have been a big leap to do this even without standardisation since it's apparently an easy extension to implement - and also, to be honest, this project is essentially glued to Clang anyway so who cares. - Likewise, bool, true and false are becoming pre-defined, so pre-pre-define them now in order to get the benefit of not having to remember one header everywhere. - Really ungodly/amazing vcall macro stuff now allows us to call C++ virtual functions like regular C functions. It's pretty cool! - Events can now take arbitrary parameters and come in two types: regular events and predicates. All this makes the base code even uglier but makes the feature implementation nicer. In other words, it places more of the cognitive burden on myself and less on other people who might want to contribute. This is a good tradeoff, because I'm a genius.
Diffstat (limited to 'src/build/codegen.c')
-rw-r--r--src/build/codegen.c84
1 files changed, 70 insertions, 14 deletions
diff --git a/src/build/codegen.c b/src/build/codegen.c
index 04a9058..f5231c0 100644
--- a/src/build/codegen.c
+++ b/src/build/codegen.c
@@ -14,7 +14,6 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -139,12 +138,15 @@ push: if (!vec_push(vecp, param)) die("couldn't allocate memory");
DECL_SKIPLIST(static, event, struct event, const char *, 4)
struct event {
- const char *name;
+ usize name; // string, but tagged pointer - see below
+ const char *const *params;
+ int nparams;
+ //char pad[4];
struct vec_usize handlers; // strings, but with tagged pointers - see below
struct skiplist_hdr_event hdr;
};
static inline int cmp_event(struct event *e, const char *s) {
- return strcmp(e->name, s);
+ return strcmp((const char *)(e->name & ~1ull), s);
}
static inline struct skiplist_hdr_event *hdr_event(struct event *e) {
return &e->hdr;
@@ -152,12 +154,15 @@ static inline struct skiplist_hdr_event *hdr_event(struct event *e) {
DEF_SKIPLIST(static, event, cmp_event, hdr_event)
static struct skiplist_hdr_event events = {0};
-static void onevdef(const char *name) {
+static void onevdef(const char *name, const char *const *params, int nparams,
+ bool predicate) {
struct event *e = skiplist_get_event(&events, name);
if (!e) {
struct event *e = malloc(sizeof(*e));
if (!e) die("couldn't allocate memory");
- e->name = name;
+ // hack: using unused pointer bit to distinguish the two types of event
+ e->name = (usize)name | predicate;
+ e->params = params; e->nparams = nparams;
e->handlers = (struct vec_usize){0};
e->hdr = (struct skiplist_hdr_event){0};
skiplist_insert_event(&events, name, e);
@@ -445,19 +450,70 @@ _( "")
H_()
for (const struct event *e = events.x[0]; e; e = e->hdr.x[0]) {
_( "")
-F( "void _evemit_%s(void) {", e->name)
- for (usize *pp = e->handlers.data;
- pp - e->handlers.data < e->handlers.sz; ++pp) {
- const char *modname = (const char *)(*pp & ~1ull);
-F( " void _evhandler_%s_%s(void);", modname, e->name) // blegh.
- if (*pp & 1ull) {
- // note: has_* variables are already included by this point (above)
-F( " if (has_%s) _evhandler_%s_%s();", modname, modname, e->name)
+ // gotta break from the string emit macros for a sec in order to do the
+ // somewhat more complicated task sometimes referred to as a "for loop"
+ fprintf(out, "%s_%s(", e->name & 1 ? "bool CHECK" : "void EMIT",
+ (const char *)(e->name & ~1ull));
+ for (int n = 0; n < (int)e->nparams - 1; ++n) {
+ fprintf(out, "typeof(%s) a%d, ", e->params[n], n + 1);
+ }
+ if (e->nparams && strcmp(e->params[0], "void")) {
+ fprintf(out, "typeof(%s) a%d", e->params[e->nparams - 1],
+ e->nparams);
}
else {
-F( " _evhandler_%s_%s();", modname, e->name)
+ // just unilaterally doing void for now. when we're fully on C23
+ // eventually we can unilaterally do nothing instead
+ fputs("void", out);
}
+_( ") {")
+ for (usize *pp = e->handlers.data;
+ pp - e->handlers.data < e->handlers.sz; ++pp) {
+ const char *modname = (const char *)(*pp & ~1ull);
+ fprintf(out, "\t%s _evhandler_%s_%s(", e->name & 1 ? "bool" : "void",
+ modname, (const char *)(e->name & ~1ull));
+ for (int n = 0; n < (int)e->nparams - 1; ++n) {
+ fprintf(out, "typeof(%s) a%d, ", e->params[n], n + 1);
+ }
+ if (e->nparams && strcmp(e->params[0], "void")) {
+ fprintf(out, "typeof(%s) a%d", e->params[e->nparams - 1],
+ e->nparams);
+ }
+ else {
+ fputs("void", out);
+ }
+ fputs(");\n\t", out);
+ // conditional and non-conditional cases - in theory could be
+ // unified a bit but this is easier to make output relatively pretty
+ // note: has_* variables are already included by this point (above)
+ if (e->name & 1) {
+ if (*pp & 1) fprintf(out, "if (has_%s && !", modname);
+ else fprintf(out, "if (!");
+ fprintf(out, "_evhandler_%s_%s(", modname,
+ (const char *)(e->name & ~1ull));
+ // XXX: much repetitive drivel here
+ for (int n = 0; n < (int)e->nparams - 1; ++n) {
+ fprintf(out, "a%d,", n + 1);
+ }
+ if (e->nparams && strcmp(e->params[0], "void")) {
+ fprintf(out, "a%d", e->nparams);
+ }
+ fputs(")) return false;\n", out);
+ }
+ else {
+ if (*pp & 1) fprintf(out, "if (has_%s) ", modname);
+ fprintf(out, "_evhandler_%s_%s(", modname,
+ (const char *)(e->name & ~1ull));
+ for (int n = 0; n < (int)e->nparams - 1; ++n) {
+ fprintf(out, "a%d,", n + 1);
+ }
+ if (e->nparams && strcmp(e->params[0], "void")) {
+ fprintf(out, "a%d", e->nparams);
+ }
+ fputs(");\n", out);
+ }
}
+ if (e->name & 1) fputs("\treturn true;\n", out);
_( "}")
}
if (fclose(out) == EOF) die("couldn't fully write evglue.gen.h");