aboutsummaryrefslogtreecommitdiff
path: root/src/main.c
diff options
context:
space:
mode:
authorKimplul <kimi.h.kuparinen@gmail.com>2025-07-18 21:33:50 +0300
committerKimplul <kimi.h.kuparinen@gmail.com>2025-07-18 21:33:50 +0300
commit94b767679fc68c51aa0c80bdada35b9978989199 (patch)
tree711af40c89140a9add7db30cf6a81861a3df1013 /src/main.c
parent1564f79cfc7d790e15298d28f52b4c5c216ce9e5 (diff)
downloadngc-94b767679fc68c51aa0c80bdada35b9978989199.tar.gz
ngc-94b767679fc68c51aa0c80bdada35b9978989199.zip
add supertemplate handling
Diffstat (limited to 'src/main.c')
-rw-r--r--src/main.c334
1 files changed, 250 insertions, 84 deletions
diff --git a/src/main.c b/src/main.c
index 0c7f8cd..bf4d06f 100644
--- a/src/main.c
+++ b/src/main.c
@@ -11,6 +11,7 @@ struct def {
char *id;
char *types;
char *args;
+ char *inst;
char *body;
};
@@ -58,47 +59,49 @@ static void optional_str_space(char *str, size_t *idx)
}
}
-static char *next_str_grp(char *str, size_t *idx)
+static char *next_str_grp(char *grp, char *str, size_t *idx)
{
- char *next = malloc(1 * sizeof(char));
- next[0] = '\0';
+ grp = realloc(grp, sizeof(char));
+ grp[0] = '\0';
while (1) {
char c = str[*idx];
if (!c)
- return next;
+ return grp;
if (isspace(c))
- return next;
+ return grp;
/* special separators */
if (char_in(c, "{[()]},.;"))
- return next;
+ return grp;
- next = append(next, c);
+ grp = append(grp, c);
(*idx)++;
}
+ free(grp);
return NULL;
}
-static char *next_str_until(char *str, size_t *idx, char *until)
+static char *next_str_until(char *grp, char *str, size_t *idx, char *until)
{
- char *next = malloc(1 * sizeof(char));
- next[0] = '\0';
+ grp = realloc(grp, sizeof(char));
+ grp[0] = '\0';
while (1) {
char c = str[*idx];
if (!c)
- return next;
+ return grp;
if (char_in(c, until))
- return next;
+ return grp;
- next = append(next, c);
+ grp = append(grp, c);
(*idx)++;
}
+ free(grp);
return NULL;
}
@@ -204,6 +207,26 @@ static void drop_tokens(struct tokens *tokens)
tokens_destroy(tokens);
}
+static char *collect_until(char *grp, FILE *f, int until)
+{
+ grp = realloc(grp, sizeof(char));
+ grp[0] = '\0';
+
+ while (1) {
+ int c = fgetc(f);
+ assert(c != EOF);
+
+ if (c == until) {
+ ungetc(c, f);
+ return grp;
+ }
+
+ grp = append(grp, c);
+ }
+
+ return NULL;
+}
+
static char *collect_block(char *grp, FILE *f, int start, int end)
{
int c = fgetc(f);
@@ -232,6 +255,34 @@ static char *collect_block(char *grp, FILE *f, int start, int end)
return NULL;
}
+static char *collect_str_block(char *grp, char *str, size_t *idx, int start, int end)
+{
+ char c = str[(*idx)++];
+ assert(c == start);
+
+ grp = realloc(grp, 2 * sizeof(char));
+ grp[0] = start;
+ grp[1] = '\0';
+
+ size_t depth = 1;
+ while (1) {
+ c = str[(*idx)++];
+ grp = append(grp, c);
+
+ if (c == start)
+ depth++;
+
+ if (c == end)
+ depth--;
+
+ if (depth == 0)
+ return grp;
+
+ }
+
+ return NULL;
+}
+
static int is_identifier(char *id)
{
while (*id) {
@@ -259,6 +310,16 @@ static char *collect_curly_block(char *grp, FILE *f)
return collect_block(grp, f, '{', '}');
}
+static char *collect_str_square_block(char *grp, char *str, size_t *idx)
+{
+ return collect_str_block(grp, str, idx, '[', ']');
+}
+
+static char *collect_str_paren_block(char *grp, char *str, size_t *idx)
+{
+ return collect_str_block(grp, str, idx, '(', ')');
+}
+
static char *process_trait(char *id, struct tokens *tokens, char *grp, FILE *f)
{
printf("/* found trait %s*/", id);
@@ -287,7 +348,41 @@ static char *process_trait(char *id, struct tokens *tokens, char *grp, FILE *f)
static char *process_supertemplate(char *id, char *types, char *args, struct tokens *tokens, char *grp, FILE *f)
{
printf("/* found supertemplate %s */", id);
- dump_tokens(tokens);
+
+ /* discard equals sign */
+ int c = fgetc(f);
+ assert(c == '=');
+
+ grp = collect_until(grp, f, '{');
+ assert(grp);
+ char *inst = strdup(grp);
+ tokens_append(tokens, inst);
+
+ grp = collect_curly_block(grp, f);
+ char *body = strdup(grp);
+ tokens_append(tokens, body);
+
+ char *space = NULL;
+ if ((space = optional_space(f)))
+ tokens_append(tokens, space);
+
+ struct def *exists = defs_find(&templates, id);
+ if (exists) {
+ fprintf(stderr, "template %s redefined\n", id);
+ drop_tokens(tokens);
+ return grp;
+ }
+
+ struct def def = {
+ .id = strdup(id),
+ .types = strdup(types),
+ .args = strdup(args),
+ .body = strdup(body),
+ .inst = strdup(inst)
+ };
+
+ defs_insert(&templates, def.id, def);
+ drop_tokens(tokens);
return grp;
}
@@ -347,7 +442,8 @@ static char *maybe_process_template(char *id, struct tokens *tokens, char *grp,
.id = strdup(id),
.types = strdup(types),
.args = strdup(args),
- .body = strdup(body)
+ .body = strdup(body),
+ .inst = NULL
};
defs_insert(&templates, def.id, def);
@@ -355,94 +451,111 @@ static char *maybe_process_template(char *id, struct tokens *tokens, char *grp,
return grp;
}
-static bool word(char *hay, char *needle, size_t len)
+static char *replace_id(char *body, char *replace, char *id)
{
+ 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) {
- if (hay[i] != needle[i])
- return false;
+ assert(isalnum(replace[i]) || replace[i] == '_');
+ }
+
+ char *new = malloc(1 * sizeof(char));
+ new[0] = '\0';
+
+ size_t idx = 0;
+ while (body[idx]) {
+ if (!isalnum(body[idx]) && body[idx] != '_') {
+ new = append(new, body[idx++]);
+ continue;
+ }
+
+ size_t start = idx;
+ while (body[idx] && (isalnum(body[idx]) || body[idx] == '_'))
+ idx++;
+
+ size_t diff = idx - start;
+ if (strncmp(&body[start], replace, diff) == 0) {
+ for (size_t i = 0; i < idlen; ++i)
+ new = append(new, id[i]);
+
+ continue;
+ }
+
+ for (size_t i = 0; i < diff; ++i)
+ new = append(new, body[start + i]);
}
- /* word ends in something other than alphanumeric */
- return !isalnum(hay[len]);
+ free(body);
+ return new;
}
-static char *replace(char *body, char *replace, char *id, bool wordboundary)
+static char *replace(char *body, char *replace, char *id)
{
assert(body);
assert(id);
- char *orig = body;
char *new = malloc(1 * sizeof(char));
new[0] = '\0';
- size_t len = strlen(replace);
+ size_t len = strlen(replace);
+ size_t idlen = strlen(id);
- while (body[0]) {
- /* lol terrible */
- bool found = wordboundary ? word(body, replace, len)
- : strncmp(body, replace, len) == 0;
+ size_t idx = 0;
+ while (body[idx]) {
+ if (body[idx] != replace[0]) {
+ new = append(new, body[idx++]);
+ continue;
+ }
- if (found) {
- char *copy = id;
- while (*copy) {
- new = append(new, *copy);
- copy++;
- }
+ if (strncmp(&body[idx], replace, len) == 0) {
+ for (size_t i = 0; i < idlen; ++i)
+ new = append(new, id[i]);
- body += len;
+ idx += len;
continue;
}
-
- new = append(new, body[0]);
- body += 1;
}
- free(orig);
+ free(body);
return new;
}
-static char *process_instance(char *id, struct tokens *tokens, char *grp, FILE *f)
+static void expand_instance(char *id, char *instance)
{
- printf("/* found instance %s */", id);
- /* discard equals sign */
- int c = fgetc(f);
- assert(c == '=');
-
- char *space = optional_space(f);
- if (space)
- tokens_append(tokens, space);
-
- /* template */
- grp = next_grp(grp, f);
- char *template = strdup(grp);
- assert(is_identifier(template));
- tokens_append(tokens, template);
+ char *grp = NULL;
- /* types */
- space = optional_space(f);
- if (space)
- tokens_append(tokens, space);
+ size_t instance_idx = 0;
+ optional_str_space(instance, &instance_idx);
+ grp = next_str_grp(grp, instance, &instance_idx);
+ assert(is_identifier(grp));
+ char *name = strdup(grp);
- grp = collect_square_block(grp, f);
+ optional_str_space(instance, &instance_idx);
+ grp = collect_str_square_block(grp, instance, &instance_idx);
char *types = strdup(grp);
- tokens_append(tokens, types);
-
- /* args */
- space = optional_space(f);
- if (space)
- tokens_append(tokens, space);
- grp = collect_paren_block(grp, f);
+ optional_str_space(instance, &instance_idx);
+ grp = collect_str_paren_block(grp, instance, &instance_idx);
char *args = strdup(grp);
- tokens_append(tokens, args);
- struct def *def = defs_find(&templates, template);
+ optional_str_space(instance, &instance_idx);
+ struct def *def = defs_find(&templates, name);
if (!def) {
/** @todo location info and so on */
- fprintf(stderr, "no such template: %s\n", template);
- return grp;
+ fprintf(stderr, "no such template: %s\n", name);
+ free(name);
+ free(args);
+ free(types);
+ return;
}
+ free(name);
+
+
/** @todo check traits */
/* +1 to skip leading '{' */
@@ -450,8 +563,6 @@ static char *process_instance(char *id, struct tokens *tokens, char *grp, FILE *
/* overwrite trailing '}' */
body[strlen(body) - 1] = '\0';
- body = replace(body, "<>", id, false);
-
/* handle type args */
char *params = def->types;
assert(params[0] == '[');
@@ -462,16 +573,21 @@ static char *process_instance(char *id, struct tokens *tokens, char *grp, FILE *
/* skip '(' in args */
size_t types_idx = 1;
+ 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);
- char *trait = next_str_grp(params, &params_idx);
- assert(is_identifier(trait));
+ grp = next_str_grp(grp, params, &params_idx);
+ assert(is_identifier(grp));
+ char *trait = strdup(grp);
optional_str_space(params, &params_idx);
- char *name = next_str_grp(params, &params_idx);
- assert(is_identifier(name));
+ grp = next_str_grp(grp, params, &params_idx);
+ assert(is_identifier(grp));
+ char *name = strdup(grp);
optional_str_space(params, &params_idx);
char delim = params[params_idx++];
@@ -479,16 +595,16 @@ static char *process_instance(char *id, struct tokens *tokens, char *grp, FILE *
/* get arg type */
optional_str_space(types, &types_idx);
- char *type = next_str_until(types, &types_idx, ",]");
+ grp = next_str_until(grp, types, &types_idx, ",]");
+ char *type = strdup(grp);
+
char last = types[types_idx++];
assert(last == ',' || last == ']');
- /** @todo assert that we're dealing with a type? */
- body = replace(body, name, type, true);
+ tokens_append(&type_params, name);
+ tokens_append(&type_args, type);
free(trait);
- free(name);
- free(type);
if (delim == ']' && last == ']')
break;
@@ -496,23 +612,72 @@ static char *process_instance(char *id, struct tokens *tokens, char *grp, FILE *
if (delim == ']') {
fprintf(stderr, "more type args than params\n");
free(body);
- drop_tokens(tokens);
- return grp;
+ drop_tokens(&type_params);
+ drop_tokens(&type_args);
+ free(args);
+ free(types);
+ free(grp);
+ return;
}
if (last == ']') {
fprintf(stderr, "more type params than args\n");
free(body);
- drop_tokens(tokens);
- return grp;
+ drop_tokens(&type_params);
+ drop_tokens(&type_args);
+ free(args);
+ free(types);
+ free(grp);
+ return;
}
}
+ 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);
+
+ body = replace_id(body, name, type);
+
+ if (super)
+ super = replace_id(super, name, type);
+ }
+
+ 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);
+
printf(body);
free(body);
+ free(super);
+
+ free(types);
+ free(args);
+ free(grp);
+}
+
+static char *process_instance(char *id, struct tokens *tokens, char *grp, FILE *f)
+{
+ printf("/* found instance %s */", id);
+ /* discard equals sign */
+ int c = fgetc(f);
+ assert(c == '=');
+
+ grp = collect_until(grp, f, ';');
+ char *instance = strdup(grp);
+ tokens_append(tokens, instance);
+
+ expand_instance(id, instance);
/* ; can probably be ignored...?*/
drop_tokens(tokens);
@@ -581,6 +746,7 @@ static void free_defs(struct defs *defs)
free(d.types);
free(d.args);
free(d.body);
+ free(d.inst);
}
defs_destroy(defs);