aboutsummaryrefslogtreecommitdiff
path: root/src/main.c
diff options
context:
space:
mode:
authorKimplul <kimi.h.kuparinen@gmail.com>2025-09-01 22:00:02 +0300
committerKimplul <kimi.h.kuparinen@gmail.com>2025-09-01 22:00:02 +0300
commite68480f2fc508ce73cad331ce4e8439e07d25702 (patch)
treebfa99b6f20402ba46230771a0d42172fc2169481 /src/main.c
parent20ce6fa81cd9f55dca3212699d5949f8ebe7d95b (diff)
downloadngc-e68480f2fc508ce73cad331ce4e8439e07d25702.tar.gz
ngc-e68480f2fc508ce73cad331ce4e8439e07d25702.zip
use <> as expansion charactersHEADmaster
+ I kind of like the 'symmetry' of <> being 'self' and <param> being some parameter, but having to type lots of extra <*> is a bit annoying, and might also be an issue for C++. Still, enough functionality for a hashmap example
Diffstat (limited to 'src/main.c')
-rw-r--r--src/main.c221
1 files changed, 204 insertions, 17 deletions
diff --git a/src/main.c b/src/main.c
index 38102fb..f3811c7 100644
--- a/src/main.c
+++ b/src/main.c
@@ -13,6 +13,8 @@ struct def {
char *args;
char *inst;
char *body;
+
+ struct def *tmpl;
};
#define MAP_NAME defs
@@ -24,6 +26,7 @@ struct def {
struct defs templates;
struct defs traits;
+struct defs impls;
static void usage(FILE *f)
{
@@ -368,10 +371,12 @@ static char *process_trait(char *id, struct tokens *tokens, char *grp, FILE *f)
}
struct def def = {
- .id = strdup(id),
+ .id = strdup(id),
.types = NULL,
- .args = NULL,
- .body = strdup(grp)
+ .args = NULL,
+ .inst = NULL,
+ .body = strdup(grp),
+ .tmpl = NULL
};
defs_insert(&traits, def.id, def);
@@ -412,7 +417,8 @@ static char *process_supertemplate(char *id, char *types, char *args, struct tok
.types = strdup(types),
.args = strdup(args),
.body = strdup(body),
- .inst = strdup(inst)
+ .inst = strdup(inst),
+ .tmpl = NULL
};
defs_insert(&templates, def.id, def);
@@ -485,6 +491,52 @@ static char *maybe_process_template(char *id, struct tokens *tokens, char *grp,
return grp;
}
+static char *replace_trait(char *body, char *replace, char *id)
+{
+ /** @todo check that trait exists */
+ assert(body);
+ assert(id);
+ size_t len = strlen(replace);
+ size_t idlen = strlen(id);
+
+ /* check that replacement is regular alphanumeric */
+ for (size_t i = 0; i < len; ++i) {
+ assert(isalnum(replace[i]) || replace[i] == '_');
+ }
+
+ char *new = malloc(1 * sizeof(char));
+ new[0] = '\0';
+
+ size_t idx = 0;
+ while (body[idx]) {
+ if (body[idx] != '<') {
+ new = append(new, body[idx++]);
+ continue;
+ }
+
+ if (strncmp(&body[idx + 1], replace, len) != 0) {
+ new = append(new, body[idx++]);
+ continue;
+ }
+
+ if (body[idx + len + 1] != '>') {
+ new = append(new, body[idx++]);
+ continue;
+ }
+
+ /* match */
+ /** @todo check that func exists (whatever is following this
+ * template instanciation */
+ for (size_t i = 0; i < idlen; ++i)
+ new = append(new, id[i]);
+
+ idx += len + 2;
+ }
+
+ free(body);
+ return new;
+}
+
static char *replace_id(char *body, char *replace, char *id)
{
assert(body);
@@ -545,15 +597,52 @@ static char *replace(char *body, char *replace, char *id)
continue;
}
- if (strncmp(&body[idx], replace, len) == 0) {
- for (size_t i = 0; i < idlen; ++i)
- new = append(new, id[i]);
+ if (strncmp(&body[idx], replace, len) != 0) {
+ new = append(new, body[idx++]);
+ continue;
+ }
+
+ for (size_t i = 0; i < idlen; ++i)
+ new = append(new, id[i]);
+
+ idx += len;
+ }
+
+ free(body);
+ return new;
+}
+
+static char *remove_traits(char *body)
+{
+ char *new = malloc(1 * sizeof(char));
+ new[0] = '\0';
+
+ size_t idx = 0;
+ while (body[idx]) {
+ if (body[idx] != '<') {
+ new = append(new, body[idx++]);
+ continue;
+ }
+
+ if (body[idx + 1] != '[') {
+ new = append(new, body[idx++]);
+ continue;
+ }
+
+ size_t start = idx;
+ while (body[idx] && body[idx] != ']')
+ idx++;
- idx += len;
+ /* found what we expected, remove from body by not appending to
+ * new body */
+ if (body[idx] && body[idx + 1] == '>') {
+ idx += 2;
continue;
}
- new = append(new, body[idx++]);
+ /* not what we expected, include everything */
+ for (size_t i = start; i < idx; ++i)
+ new = append(new, body[i]);
}
free(body);
@@ -680,6 +769,52 @@ static void collect_const_args(struct tokens *types, struct tokens *params, stru
free(grp);
}
+static bool check_implements(struct def *tmpl, char *trait)
+{
+ char *body = tmpl->body;
+ assert(body);
+
+ /** @todo more robust checking */
+ if (strcmp(trait, "any") == 0)
+ return true;
+
+ size_t len = strlen(trait);
+
+ size_t idx = 0;
+ while (body[idx]) {
+ if (body[idx] != '<') {
+ idx++;
+ continue;
+ }
+
+ if (body[idx + 1] != '[') {
+ idx++;
+ continue;
+ }
+
+ if (strncmp(&body[idx + 2], trait, len) != 0) {
+ idx++;
+ continue;
+ }
+
+ if (body[idx + len + 2] != ']') {
+ idx++;
+ continue;
+ }
+
+ if (body[idx + len + 3] != '>') {
+ idx++;
+ continue;
+ }
+
+ /* found! */
+ return true;
+ }
+
+ /** @todo check super */
+ return false;
+}
+
static void expand_instance(char *id, char *instance)
{
char *grp = NULL;
@@ -705,7 +840,7 @@ static void expand_instance(char *id, char *instance)
if (!def) {
/** @todo location info and so on */
fprintf(stderr, "no such template: %s\n", name);
- goto cleanup;
+ abort();
}
/* +1 to skip leading '{' */
@@ -713,7 +848,8 @@ static void expand_instance(char *id, char *instance)
/* overwrite trailing '}' */
body[strlen(body) - 1] = '\0';
- body = replace(body, "<>", id);
+ body = remove_traits(body);
+ body = replace(body, "<>", id);
if (def->inst)
super = replace(strdup(def->inst), "<>", id);
@@ -734,16 +870,31 @@ static void expand_instance(char *id, char *instance)
}
for (size_t i = 0; i < tokens_len(&type_params); ++i) {
- char *name = *tokens_at(&type_params, i);
- char *type = *tokens_at(&type_args, i);
+ char *trait = *tokens_at(&type_traits, i);
+ char *name = *tokens_at(&type_params, i);
+ char *type = *tokens_at(&type_args, i);
+
+ struct def *def = defs_find(&traits, trait);
+ if (!def) {
+ fprintf(stderr, "no trait '%s'\n", trait);
+ abort();
+ }
+
+ struct def *impl = defs_find(&impls, type);
+ /* no definition found presumably means raw struct or something,
+ * try optimistically continuing */
+ if (impl && !check_implements(impl->tmpl, trait)) {
+ fprintf(stderr, "'%s' does not implement '%s'\n", type, trait);
+ abort();
+ }
- body = replace_id(body, name, type);
+ body = replace_trait(body, name, type);
if (super)
- super = replace_id(super, name, type);
+ super = replace_trait(super, name, type);
if (args)
- args = replace_id(args, name, type);
+ args = replace_trait(args, name, type);
}
drop_tokens(&type_traits);
@@ -779,6 +930,20 @@ static void expand_instance(char *id, char *instance)
super = replace_id(super, name, arg);
}
+ if (tokens_len(&const_types) != tokens_len(&const_args)) {
+ fprintf(stderr, "mismatch const types vs args\n");
+ abort();
+ }
+
+ for (size_t i = 0; i < tokens_len(&const_types); ++i) {
+ char *type = *tokens_at(&const_types, i);
+ char *arg = *tokens_at(&const_args, i);
+
+ printf("_Static_assert(_Generic((%s), %s: 1, default: 0),"
+ "\"expected %s\");\n",
+ arg, type, type);
+ }
+
if (super)
expand_instance(id, super);
@@ -788,7 +953,6 @@ static void expand_instance(char *id, char *instance)
printf(body);
-cleanup:
free(body);
free(super);
@@ -811,6 +975,27 @@ static char *process_instance(char *id, struct tokens *tokens, char *grp, FILE *
expand_instance(id, instance);
+ /* I hate this, this is effectively the same as in expand_instance */
+ size_t instance_idx = 0;
+ optional_str_space(instance, &instance_idx);
+ grp = next_str_grp(grp, instance, &instance_idx);
+ assert(is_identifier(grp));
+ char *tmpl_name = strdup(grp);
+
+ struct def *tmpl = defs_find(&templates, tmpl_name);
+ if (tmpl) {
+ struct def inst = {
+ .id = strdup(id),
+ .types = NULL,
+ .args = NULL,
+ .inst = NULL,
+ .body = NULL,
+ .tmpl = tmpl
+ };
+
+ defs_insert(&impls, inst.id, inst);
+ }
+
/* ; can probably be ignored...?*/
drop_tokens(tokens);
return grp;
@@ -893,6 +1078,7 @@ int main(int argc, char *argv[])
templates = defs_create(0);
traits = defs_create(0);
+ impls = defs_create(0);
char *fname = argv[1];
@@ -908,6 +1094,7 @@ int main(int argc, char *argv[])
free_defs(&templates);
free_defs(&traits);
+ free_defs(&impls);
fclose(f);
return ret;
}