diff options
-rw-r--r-- | example_hashmap/new/main.c | 5 | ||||
-rw-r--r-- | example_hashmap/new/map.h | 22 | ||||
-rw-r--r-- | example_vec/new/main.c | 15 | ||||
-rw-r--r-- | example_vec/new/vec.h | 18 | ||||
-rw-r--r-- | src/main.c | 221 |
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--; } @@ -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; } |