diff options
-rw-r--r-- | src/main.c | 281 | ||||
-rw-r--r-- | tests/xok/superval.c | 24 | ||||
-rw-r--r-- | tests/xok/val.c | 17 |
3 files changed, 243 insertions, 79 deletions
@@ -59,6 +59,33 @@ static void optional_str_space(char *str, size_t *idx) } } +static char *reverse_strip(char *str) +{ + size_t len = strlen(str); + while (len) { + if (isspace(str[--len])) + continue; + + str[len + 1] = '\0'; + break; + } + + return str; +} + +static char *reverse_id(char *str) +{ + size_t len = strlen(str); + while (len) { + if (!isalnum(str[len - 1]) && str[len - 1] != '_') + break; + + len--; + } + + return &str[len]; +} + static char *next_str_grp(char *grp, char *str, size_t *idx) { grp = realloc(grp, sizeof(char)); @@ -84,19 +111,26 @@ static char *next_str_grp(char *grp, char *str, size_t *idx) return NULL; } -static char *next_str_until(char *grp, char *str, size_t *idx, char *until) +static char *next_special_str_until(char *grp, char *str, size_t *idx, char *until) { grp = realloc(grp, sizeof(char)); grp[0] = '\0'; + size_t depth = 0; while (1) { char c = str[*idx]; if (!c) return grp; + if (char_in(c, "[{(")) + depth++; + if (char_in(c, until)) return grp; + if (char_in(c, ")}]")) + depth--; + grp = append(grp, c); (*idx)++; } @@ -524,9 +558,131 @@ static char *replace(char *body, char *replace, char *id) return new; } +static void collect_type_args(struct tokens *traits, struct tokens *params, struct tokens *args, + char *type_params, char *type_args) +{ + char *grp = NULL; + + assert(type_params[0] == '['); + size_t type_params_idx = 1; + while (1) { + optional_str_space(type_params, &type_params_idx); + + grp = next_str_grp(grp, type_params, &type_params_idx); + assert(is_identifier(grp)); + char *trait = strdup(grp); + + optional_str_space(type_params, &type_params_idx); + grp = next_str_grp(grp, type_params, &type_params_idx); + assert(is_identifier(grp)); + char *param = strdup(grp); + + optional_str_space(type_params, &type_params_idx); + char delim = type_params[type_params_idx++]; + assert(delim == ',' || delim == ']'); + + if (trait[0] == '\0') + free(trait); + else + tokens_append(traits, trait); + + if (param[0] == '\0') + free(param); + else + tokens_append(params, param); + + if (delim == ']') + break; + } + + assert(type_args[0] == '['); + size_t type_args_idx = 1; + while (1) { + optional_str_space(type_args, &type_args_idx); + grp = next_special_str_until(grp, type_args, &type_args_idx, ",]"); + char *arg = strdup(grp); + + char delim = type_args[type_args_idx++]; + assert(delim == ',' || delim == ']'); + + if (arg[0] == '\0') + free(arg); + else + tokens_append(args, arg); + + if (delim == ']') + break; + } + + free(grp); +} + +static void collect_const_args(struct tokens *types, struct tokens *params, struct tokens *args, + char *const_params, char *const_args) +{ + char *grp = NULL; + + assert(const_params[0] == '('); + size_t const_params_idx = 1; + while (1) { + optional_str_space(const_params, &const_params_idx); + grp = next_special_str_until(grp, const_params, &const_params_idx, ",)"); + char *full_param = strdup(grp); + + char delim = const_params[const_params_idx++]; + assert(delim == ',' || delim == ')'); + + full_param = reverse_strip(full_param); + char *id = reverse_id(full_param); + char *name = strdup(id); + + /* split full_param */ + *id = '\0'; + + /* type takes ownership of full_param, no need to free */ + char *type = reverse_strip(full_param); + + if (type[0] == '\0') + free(type); + else + tokens_append(types, type); + + if (name[0] == '\0') + free(name); + else + tokens_append(params, name); + + if (delim == ')') + break; + } + + assert(const_args[0] == '('); + size_t const_args_idx = 1; + while (1) { + optional_str_space(const_args, &const_args_idx); + grp = next_special_str_until(grp, const_args, &const_args_idx, ",)"); + char *arg = strdup(grp); + + char delim = const_args[const_args_idx++]; + assert(delim == ',' || delim == ')'); + + if (arg[0] == '\0') + free(arg); + else + tokens_append(args, arg); + + if (delim == ')') + break; + } + + free(grp); +} + static void expand_instance(char *id, char *instance) { char *grp = NULL; + char *body = NULL; + char *super = NULL; size_t instance_idx = 0; optional_str_space(instance, &instance_idx); @@ -547,100 +703,66 @@ static void expand_instance(char *id, char *instance) if (!def) { /** @todo location info and so on */ fprintf(stderr, "no such template: %s\n", name); - free(name); - free(args); - free(types); - return; + goto cleanup; } - free(name); - - - /** @todo check traits */ - /* +1 to skip leading '{' */ - char *body = strdup(def->body + 1); + body = strdup(def->body + 1); /* overwrite trailing '}' */ body[strlen(body) - 1] = '\0'; - /* handle type args */ - char *params = def->types; - assert(params[0] == '['); - - /* skip '[' */ - size_t params_idx = 1; - - /* skip '(' in args */ - size_t types_idx = 1; + body = replace(body, "<>", id); + if (def->inst) + super = replace(strdup(def->inst), "<>", id); + struct tokens type_traits = tokens_create(0); struct tokens type_params = tokens_create(0); struct tokens type_args = tokens_create(0); - while (1) { - /* get type param */ - optional_str_space(params, ¶ms_idx); - - grp = next_str_grp(grp, params, ¶ms_idx); - assert(is_identifier(grp)); - char *trait = strdup(grp); + collect_type_args(&type_traits, &type_params, &type_args, def->types, types); - optional_str_space(params, ¶ms_idx); - grp = next_str_grp(grp, params, ¶ms_idx); - assert(is_identifier(grp)); - char *name = strdup(grp); + if (tokens_len(&type_params) != tokens_len(&type_args)) { + fprintf(stderr, "mismatch type params vs args\n"); + drop_tokens(&type_traits); + drop_tokens(&type_params); + drop_tokens(&type_args); + goto cleanup; + } - optional_str_space(params, ¶ms_idx); - char delim = params[params_idx++]; - assert(delim == ',' || delim == ']'); + 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); - /* get arg type */ - optional_str_space(types, &types_idx); - grp = next_str_until(grp, types, &types_idx, ",]"); - char *type = strdup(grp); + body = replace_id(body, name, type); - char last = types[types_idx++]; - assert(last == ',' || last == ']'); + if (super) + super = replace_id(super, name, type); - tokens_append(&type_params, name); - tokens_append(&type_args, type); + if (args) + args = replace_id(super, name, type); + } - free(trait); + drop_tokens(&type_traits); + drop_tokens(&type_params); + drop_tokens(&type_args); - if (delim == ']' && last == ']') - break; + struct tokens const_types = tokens_create(0); + struct tokens const_params = tokens_create(0); + struct tokens const_args = tokens_create(0); - if (delim == ']') { - fprintf(stderr, "more type args than params\n"); - free(body); - drop_tokens(&type_params); - drop_tokens(&type_args); - free(args); - free(types); - free(grp); - return; - } + collect_const_args(&const_types, &const_params, &const_args, def->args, args); - if (last == ']') { - fprintf(stderr, "more type params than args\n"); - free(body); - drop_tokens(&type_params); - drop_tokens(&type_args); - free(args); - free(types); - free(grp); - return; - } + if (tokens_len(&const_params) != tokens_len(&const_args)) { + fprintf(stderr, "mismatch const params vs args\n"); + drop_tokens(&const_types); + drop_tokens(&const_params); + drop_tokens(&const_args); + goto cleanup; } - char *super = NULL; - body = replace(body, "<>", id); - - if (def->inst) - super = replace(strdup(def->inst), "<>", id); - - 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); + for (size_t i = 0; i < tokens_len(&const_params); ++i) { + char *name = *tokens_at(&const_params, i); + char *type = *tokens_at(&const_args, i); body = replace_id(body, name, type); @@ -651,16 +773,17 @@ static void expand_instance(char *id, char *instance) if (super) expand_instance(id, super); - /** @todo regular params, probably much like above but parsing the type - * might be a bit annoying... */ - - drop_tokens(&type_params); - drop_tokens(&type_args); + drop_tokens(&const_types); + drop_tokens(&const_params); + drop_tokens(&const_args); printf(body); + +cleanup: free(body); free(super); + free(name); free(types); free(args); free(grp); diff --git a/tests/xok/superval.c b/tests/xok/superval.c new file mode 100644 index 0000000..f6903c2 --- /dev/null +++ b/tests/xok/superval.c @@ -0,0 +1,24 @@ +#include <stdio.h> + +typedef tmpl[](int v){ + int <>_ok() + { + return v; + } +}; + +typedef supertmpl[](int v) = tmpl[](v) { + int <>_superok() + { + return <>_ok(); + } +} + +typedef inst = supertmpl[](20); + +int main() +{ + int ok = inst_superok(); + if (ok == 20) + puts("OK"); +} diff --git a/tests/xok/val.c b/tests/xok/val.c new file mode 100644 index 0000000..9518d40 --- /dev/null +++ b/tests/xok/val.c @@ -0,0 +1,17 @@ +#include <stdio.h> + +typedef tmpl[](int v){ + int <>_ok() + { + return v; + } +}; + +typedef inst = tmpl[](20); + +int main() +{ + int ok = inst_ok(); + if (ok == 20) + puts("OK"); +} |