aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main.c281
-rw-r--r--tests/xok/superval.c24
-rw-r--r--tests/xok/val.c17
3 files changed, 243 insertions, 79 deletions
diff --git a/src/main.c b/src/main.c
index bf4d06f..e801130 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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, &params_idx);
-
- grp = next_str_grp(grp, params, &params_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, &params_idx);
- grp = next_str_grp(grp, params, &params_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, &params_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");
+}