diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/main.c | 334 |
1 files changed, 250 insertions, 84 deletions
@@ -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, ¶ms_idx); - char *trait = next_str_grp(params, ¶ms_idx); - assert(is_identifier(trait)); + grp = next_str_grp(grp, params, ¶ms_idx); + assert(is_identifier(grp)); + char *trait = strdup(grp); optional_str_space(params, ¶ms_idx); - char *name = next_str_grp(params, ¶ms_idx); - assert(is_identifier(name)); + grp = next_str_grp(grp, params, ¶ms_idx); + assert(is_identifier(grp)); + char *name = strdup(grp); optional_str_space(params, ¶ms_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); |