aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--example_hashmap/new/main.c5
-rw-r--r--example_hashmap/new/map.h22
-rw-r--r--example_vec/new/main.c15
-rw-r--r--example_vec/new/vec.h18
-rw-r--r--src/main.c221
5 files changed, 240 insertions, 41 deletions
diff --git a/example_hashmap/new/main.c b/example_hashmap/new/main.c
index 4846ab5..db575c6 100644
--- a/example_hashmap/new/main.c
+++ b/example_hashmap/new/main.c
@@ -1,6 +1,9 @@
#include <assert.h>
#include <stdio.h>
+/* provide generic any that matches anything/everything */
+typedef any {}
+
#include "map.h"
#define foreach(name, i, s) \
@@ -9,7 +12,7 @@
/* int wrapper, provides cmp/hash for a generic integer type
* (here a trait like is_integer would be ideal but oh well) */
typedef intw[any I]() {
- typedef I <>;
+ typedef <I> <>;
size_t <>_hash(<> *a)
{
diff --git a/example_hashmap/new/map.h b/example_hashmap/new/map.h
index e993139..e892011 100644
--- a/example_hashmap/new/map.h
+++ b/example_hashmap/new/map.h
@@ -17,8 +17,8 @@
* supported so just go with this for now */
typedef map[any K, any D]() {
struct <>_tuple {
- K key;
- D data;
+ <K> key;
+ <D> data;
};
typedef struct <>_tuple *<>_iter;
@@ -64,9 +64,9 @@ typedef map[any K, any D]() {
free(root->buckets);
}
- D *<>_insert(<>* root, K key, D data)
+ <D> *<>_insert(<>* root, <K> key, <D> data)
{
- size_t hash = <key>_hash(&key);
+ size_t hash = <K>_hash(&key);
/* look through buckets in order */
for (size_t b = 0; b < root->count; ++b) {
struct <>_bucket *bucket = root->buckets[b];
@@ -84,7 +84,7 @@ typedef map[any K, any D]() {
}
/* there already exists a node like this */
- if (node->hash == hash && <key>_cmp(&node->t.key, &key) == 0)
+ if (node->hash == hash && <K>_cmp(&node->t.key, &key) == 0)
return &node->t.data;
}
@@ -122,12 +122,12 @@ typedef map[any K, any D]() {
return &node->t.data;
}
- D *<>_find(<> *root, K key)
+ <D> *<>_find(<> *root, <K> key)
{
if (root->len == 0)
return NULL;
- size_t hash = <key>_hash(&key);
+ size_t hash = <K>_hash(&key);
for (size_t b = 0; b < root->count; ++b) {
struct <>_bucket *bucket = root->buckets[b];
size_t idx = NGC_BUCKET_IDX(hash, root->pow2, b);
@@ -136,7 +136,7 @@ typedef map[any K, any D]() {
if (node->hash != hash)
continue;
- if (<key>_cmp(&node->t.key, key) != 0)
+ if (<K>_cmp(&node->t.key, &key) != 0)
continue;
return &node->t.data;
@@ -145,7 +145,7 @@ typedef map[any K, any D]() {
return NULL;
}
- void <>_remove_found(<> *root, D *data)
+ void <>_remove_found(<> *root, <D> *data)
{
struct <>_tuple *tuple = NGC_CONTAINER_OF(data, struct <>_tuple, data);
struct <>_node *node = NGC_CONTAINER_OF(tuple, struct <>_node, t);
@@ -153,9 +153,9 @@ typedef map[any K, any D]() {
root->len--;
}
- void <>_remove(<> *root, K key)
+ void <>_remove(<> *root, <K> key)
{
- D *found = <>_find(root, key);
+ <D> *found = <>_find(root, key);
if (!found)
return;
diff --git a/example_vec/new/main.c b/example_vec/new/main.c
index 4849cb3..a756281 100644
--- a/example_vec/new/main.c
+++ b/example_vec/new/main.c
@@ -1,12 +1,21 @@
#include <stdio.h>
+
+/* an empty trait matches anything, this would presumably be defined in a
+ * library somewhere and then included everywhere */
+typedef any {}
+
#include "vec.h"
#define foreach(name, i, s) \
for (name##_iter i = name##_begin(s); !name##_end(s, i); i = name##_next(i))
-typedef summable_vec[summable type]() = vec[type](){
- type <>_sum(struct <> *v) {
- type sum = 0;
+/* traits aren't really implemented fully yet but this would check for a
+ * function like <>_add(<> a, <> b) or something along those lines */
+typedef summable {}
+
+typedef summable_vec[summable type]() = vec[<type>](){
+ <type> <>_sum(struct <> *v) {
+ <type> sum = 0;
for (size_t i = 0; i < v->n; ++i) {
sum += v->buf[i];
}
diff --git a/example_vec/new/vec.h b/example_vec/new/vec.h
index 613af51..6842a42 100644
--- a/example_vec/new/vec.h
+++ b/example_vec/new/vec.h
@@ -10,10 +10,10 @@ typedef vec[any type]() {
struct <> {
size_t n;
size_t s;
- type *buf;
+ <type> *buf;
};
- typedef type *<>_iter;
+ typedef <type> *<>_iter;
struct <> <>_create(size_t reserve)
{
@@ -23,7 +23,7 @@ typedef vec[any type]() {
return (struct <>){
.n = 0,
.s = reserve,
- .buf = malloc(reserve * sizeof(type))
+ .buf = malloc(reserve * sizeof(<type>))
};
}
@@ -38,25 +38,25 @@ typedef vec[any type]() {
}
- type *<>_at(struct <> *v, size_t i)
+ <type> *<>_at(struct <> *v, size_t i)
{
assert(i < v->n && "out of vector bounds");
return &v->buf[i];
}
- type *<>_pop(struct <> *v)
+ <type> *<>_pop(struct <> *v)
{
assert(v->n && "attempting to pop empty vector");
v->n--;
return &v->buf[v->n];
}
- type* <>_append(struct <> *v, type n)
+ <type>* <>_append(struct <> *v, <type> n)
{
v->n++;
if (v->n >= v->s) {
v->s = v->s == 0 ? 1 : 2 * v->s;
- v->buf = realloc(v->buf, v->s * sizeof(type));
+ v->buf = realloc(v->buf, v->s * sizeof(<type>));
}
v->buf[v->n - 1] = n;
@@ -80,7 +80,7 @@ typedef vec[any type]() {
while (v->s < v->n)
v->s = v->s == 0 ? 1 : 2 * v->s;
- v->buf = realloc(v->buf, v->s * sizeof(type));
+ v->buf = realloc(v->buf, v->s * sizeof(<type>));
}
void <>_shrink(struct <> *v, size_t n)
@@ -92,7 +92,7 @@ typedef vec[any type]() {
void <>_remove(struct <> *v, size_t i)
{
assert(v->n > i);
- size_t c = sizeof(type) * (v->n - i);
+ size_t c = sizeof(<type>) * (v->n - i);
memcpy(&v->buf[i], &v->buf[i + 1], c);
v->n--;
}
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;
}