diff options
| author | Kimplul <kimi.h.kuparinen@gmail.com> | 2026-05-01 20:35:00 +0300 |
|---|---|---|
| committer | Kimplul <kimi.h.kuparinen@gmail.com> | 2026-05-01 22:16:26 +0300 |
| commit | 8946c27306abed7065afad3f015df5ee81e72ad2 (patch) | |
| tree | c53c9a2c0437109e9c1e3f873bf8a54220ee5ded /src | |
| parent | 7790e27b3423901e2080bfd3c600a65a48d42886 (diff) | |
| download | fwd-8946c27306abed7065afad3f015df5ee81e72ad2.tar.gz fwd-8946c27306abed7065afad3f015df5ee81e72ad2.zip | |
add support for coverage
Diffstat (limited to 'src')
| -rw-r--r-- | src/analyze.c | 43 | ||||
| -rw-r--r-- | src/ast.c | 124 | ||||
| -rw-r--r-- | src/compiler.c | 57 | ||||
| -rw-r--r-- | src/debug.c | 14 | ||||
| -rw-r--r-- | src/lexer.l | 17 | ||||
| -rw-r--r-- | src/main.c | 5 | ||||
| -rw-r--r-- | src/parser.y | 174 | ||||
| -rw-r--r-- | src/path.c | 32 | ||||
| -rw-r--r-- | src/rewrite.c | 14 | ||||
| -rw-r--r-- | src/scope.c | 8 | ||||
| -rw-r--r-- | src/tracker.c | 22 |
11 files changed, 335 insertions, 175 deletions
diff --git a/src/analyze.c b/src/analyze.c index fd1aabb..df00b2f 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -2,6 +2,7 @@ /* Copyright 2024 Kim Kuparinen < kimi.h.kuparinen@gmail.com > */ #include <fwd/compiler.h> +#include <fwd/tracker.h> #include <fwd/analyze.h> #include <fwd/rewrite.h> #include <fwd/mod.h> @@ -65,9 +66,12 @@ static int analyze_proc(struct state *state, struct scope *scope, group++; /* start of new group */ /* otherwise same or ending group, don't increment */ + struct type *ct = clone_type(param->t); + if (!ct) + return -1; param->t->group = group; - type_append(&proc_type->t0, clone_type(param->t)); + type_append(&proc_type->t0, ct); } node->t = proc_type; @@ -432,7 +436,11 @@ static int analyze_closure(struct state *state, struct scope *scope, } foreach_node(binding, closure_bindings(node)) { - type_append(&callable->t0, clone_type(binding->t)); + struct type *ct = clone_type(binding->t); + if (!ct) + return -1; + + type_append(&callable->t0, ct); } node->t = callable; @@ -608,7 +616,8 @@ static int analyze_construct(struct state *state, struct scope *scope, * a memory allocation? */ } - node->t = tgen_id(strdup(construct_id(node)), node->loc); + + node->t = tgen_id(construct_id(node), node->loc); return 0; } @@ -797,7 +806,11 @@ static int analyze_nil_check(struct state *state, struct scope *scope, struct ast *var = nil_check_ref(node); struct type *base = tptr_base(expr->t); - struct type *ref = tgen_ref(clone_type(base), node->loc); + struct type *ct = clone_type(base); + if (!ct) + return -1; + + struct type *ref = tgen_ref(ct, node->loc); if (!var_type(var)) var_type(var) = ref; @@ -1190,8 +1203,13 @@ int fwd_register(struct fwd_state *state, const char *name, fwd_extern_t func, /* eight bytes is likely more than enough, since first three are * var, then we have four bytes for indexes and one trailing * NULL */ - char *name = calloc(8, sizeof(char)); - assert(name); + char *name = callocc(8, sizeof(char)); + if (!name) { + internal_error("failed allocating ext var name"); + return -1; + } + + track_ptr(name); sprintf(name, "%s%zu", "var", idx); struct ast *new = gen_var(name, fwd_type_kind(type), @@ -1208,8 +1226,7 @@ int fwd_register(struct fwd_state *state, const char *name, fwd_extern_t func, /* append 'return' as a continuation */ if (rtype != FWD_VOID) { - char *name = strdup("ret"); - struct ast *new = gen_var(name, + struct ast *new = gen_var("ret", tgen_closure( fwd_type_kind(rtype), NULL_LOC() @@ -1224,7 +1241,15 @@ int fwd_register(struct fwd_state *state, const char *name, fwd_extern_t func, vars = reverse_ast_list(vars); - struct ast *def = gen_proc(strdup(name), vars, + char *cname = strdupc(name); + if (!cname) { + internal_error("failed allocating ext name copy"); + return -1; + } + + track_ptr(cname); + + struct ast *def = gen_proc(cname, vars, fwd_type_kind(rtype), NULL, NULL_LOC() ); @@ -16,6 +16,7 @@ #include <fwd/ast.h> #include <fwd/scope.h> +#include <fwd/tracker.h> #define VEC_NAME ast_vec #define VEC_TYPE struct ast * @@ -25,77 +26,29 @@ #define VEC_TYPE struct type * #include <conts/vec.h> -static struct ast_vec nodes; -static struct type_vec types; - -static void destroy_ast_node(struct ast *n) -{ - if (!n) - return; - - if (n->s) - free(n->s); - - free(n); -} - -static void destroy_type(struct type *n) -{ - if (!n) - return; - - if (n->id) - free(n->id); - - free(n); -} - -static void destroy_ast_nodes() -{ - foreach(ast_vec, n, &nodes) { - destroy_ast_node(*n); - } - - ast_vec_destroy(&nodes); -} - -static void destroy_types() -{ - foreach(type_vec, t, &types) { - destroy_type(*t); - } - - type_vec_destroy(&types); -} - -void destroy_allocs() -{ - destroy_ast_nodes(); - destroy_types(); -} - static struct ast *create_empty_ast() { - if (ast_vec_uninit(&nodes)) - nodes = ast_vec_create(1); - - struct ast *n = calloc(1, sizeof(struct ast)); - if (!n) + struct ast *n = callocc(1, sizeof(struct ast)); + if (!n) { + internal_error("failed allocating empty ast node"); return NULL; + } /* just to be safe */ n->k = AST_EMPTY; - ast_vec_append(&nodes, n); + track_ptr(n); return n; } static struct type *create_empty_type() { - if (type_vec_uninit(&types)) - types = type_vec_create(1); + struct type *n = callocc(1, sizeof(struct type)); + if (!n) { + internal_error("failed allocating empty type node"); + return NULL; + } - struct type *n = calloc(1, sizeof(struct type)); - type_vec_append(&types, n); + track_ptr(n); return n; } @@ -326,23 +279,34 @@ struct ast *clone_ast(struct ast *n) new->v = n->v; new->d = n->d; - if (n->s) - new->s = strdup(n->s); + /* names are handled by pointer tracker, so we can just copy a reference + * to the string directly */ + new->s = n->s; - if (n->a0) - new->a0 = clone_ast_list(n->a0); + if (n->a0 && !(new->a0 = clone_ast_listc(n->a0))) { + internal_error("failed cloning ast a0"); + return NULL; + } - if (n->a1) - new->a1 = clone_ast_list(n->a1); + if (n->a1 && !(new->a1 = clone_ast_listc(n->a1))) { + internal_error("failed cloning ast a1"); + return NULL; + } - if (n->a2) - new->a2 = clone_ast_list(n->a2); + if (n->a2 && !(new->a2 = clone_ast_listc(n->a2))) { + internal_error("failed cloning ast a2"); + return NULL; + } - if (n->a3) - new->a3 = clone_ast_list(n->a3); + if (n->a3 && !(new->a3 = clone_ast_listc(n->a3))) { + internal_error("failed cloning ast a3"); + return NULL; + } - if (n->t2) - new->t2 = clone_type_list(n->t2); + if (n->t2 && !(new->t2 = clone_type_listc(n->t2))) { + internal_error("failed cloning ast t2"); + return NULL; + } /** @todo rebuild opt group? */ @@ -353,7 +317,9 @@ struct ast *clone_ast_list(struct ast *root) { struct ast *n = root, *new_root = NULL, *prev = NULL; while (n) { - struct ast *new = clone_ast(n); + struct ast *new = clone_astc(n); + if (!new) + return NULL; if (prev) prev->n = new; else new_root = new; @@ -375,11 +341,13 @@ struct type *clone_type(struct type *type) return NULL; new->k = type->k; - if (type->id) - new->id = strdup(type->id); + /* names are tracked by the tracker, so no need to duplicate */ + new->id = type->id; - if (type->t0) - new->t0 = clone_type_list(type->t0); + if (type->t0 && !(new->t0 = clone_type_listc(type->t0))) { + internal_error("failed cloning type t0"); + return NULL; + } new->or = type->or; new->group = type->group; @@ -391,7 +359,9 @@ struct type *clone_type_list(struct type *root) { struct type *n = root, *new_root = NULL, *prev = NULL; while (n) { - struct type *new = clone_type(n); + struct type *new = clone_typec(n); + if (!new) + return NULL; if (prev) prev->n = new; else new_root = new; diff --git a/src/compiler.c b/src/compiler.c index f367f9a..f72ab1c 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -16,7 +16,9 @@ #include <errno.h> #include <fwd/compiler.h> +#include <fwd/coverage.h> #include <fwd/analyze.h> +#include <fwd/tracker.h> #include <fwd/parser.h> #include <fwd/debug.h> #include <fwd/lower.h> @@ -46,13 +48,16 @@ static char *read_file(const char *file, FILE *f) fseek(f, 0, SEEK_SET); - char *buf = malloc((size_t)(s + 1)); - if (!buf) + char *buf = mallocc((size_t)(s + 1)); + if (!buf) { + internal_error("failed allocating fread buffer"); return NULL; + } fread(buf, (size_t)(s + 1), 1, f); /* remember terminating null */ buf[s] = 0; + track_ptr(buf); return buf; } @@ -81,10 +86,8 @@ static int process(struct scope *scope, const char *file) return -1; struct parser *p = create_parser(); - if (!p) { - free((void *)buf); + if (!p) return -1; - } parse(p, file, buf); @@ -92,15 +95,21 @@ static int process(struct scope *scope, const char *file) bool failed = p->failed; destroy_parser(p); - if (failed) { - free((void *)buf); + if (failed) return -1; - } ast_dump_list(0, tree); + char *fname = strdupc(file); + if (!fname) { + internal_error("failed allocating fname"); + return -1; + } + + track_ptr(fname); + scope->fctx.fbuf = buf; - scope->fctx.fname = strdup(file); + scope->fctx.fname = fname; if (analyze_root(scope, tree)) return -1; @@ -124,7 +133,6 @@ static void destroy_scopes() { foreach(scopes, n, &scopes) { destroy_scope(n->data); - free((void *)n->key); } scopes_destroy(&scopes); @@ -136,57 +144,56 @@ struct scope *compile_file(const char *file) const char *base = NULL, *dir = NULL, *cwd = NULL, *real = NULL; if (!(base = fwd_basename(file))) { error("couldn't get basename of %s", file); - goto out; + return NULL; } if (!(dir = fwd_dirname(file))) { error("couldn't get dirname of %s", file); - goto out; + return NULL; } if (!(cwd = fwd_cwdname())) { error("couldn't get current working dir"); - goto out; + return NULL; } if (*dir != 0 && chdir(dir)) { error("couldn't change to directory %s: %s", dir, strerror(errno) ); - goto out; + return NULL; } if (!(real = realpath(base, NULL))) { error("no such file: %s", file); - goto out; + return NULL; } + /* const cast, ech */ + track_ptr((void *)real); + struct scope **exists = scopes_find(&scopes, real); if (exists) { scope = *exists; - goto out; + return NULL; } scope = create_scope(); - scopes_insert(&scopes, strdup(real), scope); + scopes_insert(&scopes, real, scope); if (process(scope, base)) { scope = NULL; - goto out; + return NULL; } if (chdir(cwd)) { error("couldn't change back to directory %s: %s", cwd, strerror(errno) ); - goto out; + + return NULL; } -out: - free((void *)base); - free((void *)dir); - free((void *)cwd); - free((void *)real); return scope; } @@ -207,6 +214,6 @@ int compile(const char *input) { out: destroy_scopes(); - destroy_allocs(); + free_tracked_ptrs(); return ret; } diff --git a/src/debug.c b/src/debug.c index 2426277..d229ae6 100644 --- a/src/debug.c +++ b/src/debug.c @@ -14,6 +14,7 @@ #include <string.h> #include <stdarg.h> +#include <fwd/tracker.h> #include <fwd/debug.h> #include <fwd/scope.h> @@ -272,8 +273,15 @@ static void _type_str(FILE *f, struct type *type) char *type_str(struct type *t) { - if (!t) - return strdup("NULL"); + if (!t) { + char *s = strdupc("NULL"); + if (!s) { + internal_error("failed allocating null string"); + return NULL; + } + + return s; + } char *buf = NULL; size_t size = 0; FILE *memstream = open_memstream(&buf, &size); @@ -283,6 +291,8 @@ char *type_str(struct type *t) _type_str(memstream, t); fclose(memstream); + + track_ptr(buf); return buf; } diff --git a/src/lexer.l b/src/lexer.l index 4f6598a..1f4c520 100644 --- a/src/lexer.l +++ b/src/lexer.l @@ -4,6 +4,7 @@ %option reentrant noyywrap nounput noinput nodefault %{ #define FROM_LEXER +#include <fwd/tracker.h> #include <fwd/parser.h> #include <fwd/debug.h> @@ -140,7 +141,13 @@ STRING \"(\\.|[^"\\])*\" "sizeof" {return SIZEOF;} {STRING} { - yylval->str = strdup(yytext); + yylval->str = strdupc(yytext); + if (!yylval->str) { + internal_error("failed allocating lexed string"); + return ERROR; + } + + track_ptr(yylval->str); return STRING; } @@ -150,7 +157,13 @@ STRING \"(\\.|[^"\\])*\" } {ID} { - yylval->str = strdup(yytext); + yylval->str = strdupc(yytext); + if (!yylval->str) { + internal_error("failed allocating lexed ID"); + return ERROR; + } + + track_ptr(yylval->str); return ID; } @@ -45,6 +45,11 @@ static void usage() */ int main(int argc, char *argv[]) { +#ifdef COVERAGE + assert(!covsrv_init()); + atexit(covsrv_destroy); +#endif + int opt; while ((opt = getopt(argc, argv, "hI:")) != -1) { switch (opt) { diff --git a/src/parser.y b/src/parser.y index 776e1c9..bd5b033 100644 --- a/src/parser.y +++ b/src/parser.y @@ -191,12 +191,17 @@ static char match_escape(char c); */ static char *strip(const char *s); +#define Q(x) if (!(x)) { YYABORT; } + %} %start input; %% param - : type ID { $$ = gen_var($2, $1, src_loc(@$)); } + : type ID { + $$ = gen_var($2, $1, src_loc(@$)); + Q($$); + } rev_params : rev_params "," param { $$ = $3; $$->n = $1; } @@ -214,7 +219,10 @@ opt_params var : param - | ID { $$ = gen_var($1, NULL, src_loc(@$)); } + | ID { + $$ = gen_var($1, NULL, src_loc(@$)); + Q($$); + } rev_vars : rev_vars "," var { $$ = $3; $$->n = $1; } @@ -231,52 +239,60 @@ opt_vars proc : ID "(" opt_params ")" body { $$ = gen_proc($[ID], $[opt_params], NULL, $[body], src_loc(@$)); + Q($$); } proc_decl : ID "(" opt_params ")" ";" { $$ = gen_proc($[ID], $[opt_params], NULL, NULL, src_loc(@$)); + Q($$); } binop - : expr "+" expr { $$ = gen_binop(AST_ADD, $1, $3, src_loc(@$)); } - | expr "-" expr { $$ = gen_binop(AST_SUB, $1, $3, src_loc(@$)); } - | expr "*" expr { $$ = gen_binop(AST_MUL, $1, $3, src_loc(@$)); } - | expr "/" expr { $$ = gen_binop(AST_DIV, $1, $3, src_loc(@$)); } - | expr "%" expr { $$ = gen_binop(AST_REM, $1, $3, src_loc(@$)); } - | expr "<" expr { $$ = gen_comparison(AST_LT, $1, $3, src_loc(@$)); } - | expr ">" expr { $$ = gen_comparison(AST_GT, $1, $3, src_loc(@$)); } - | expr "<<" expr { $$ = gen_binop(AST_LSHIFT, $1, $3, src_loc(@$)); } - | expr ">>" expr { $$ = gen_binop(AST_RSHIFT, $1, $3, src_loc(@$)); } - | expr "<=" expr { $$ = gen_comparison(AST_LE, $1, $3, src_loc(@$)); } - | expr ">=" expr { $$ = gen_comparison(AST_GE, $1, $3, src_loc(@$)); } - | expr "!=" expr { $$ = gen_comparison(AST_NE, $1, $3, src_loc(@$)); } - | expr "==" expr { $$ = gen_comparison(AST_EQ, $1, $3, src_loc(@$)); } - | id "~" id { $$ = gen_paste($1, $3, src_loc(@$)); } + : expr "+" expr { $$ = gen_binop(AST_ADD, $1, $3, src_loc(@$)); Q($$); } + | expr "-" expr { $$ = gen_binop(AST_SUB, $1, $3, src_loc(@$)); Q($$); } + | expr "*" expr { $$ = gen_binop(AST_MUL, $1, $3, src_loc(@$)); Q($$); } + | expr "/" expr { $$ = gen_binop(AST_DIV, $1, $3, src_loc(@$)); Q($$); } + | expr "%" expr { $$ = gen_binop(AST_REM, $1, $3, src_loc(@$)); Q($$); } + | expr "<" expr { $$ = gen_comparison(AST_LT, $1, $3, src_loc(@$)); Q($$); } + | expr ">" expr { $$ = gen_comparison(AST_GT, $1, $3, src_loc(@$)); Q($$); } + | expr "<<" expr { $$ = gen_binop(AST_LSHIFT, $1, $3, src_loc(@$)); Q($$); } + | expr ">>" expr { $$ = gen_binop(AST_RSHIFT, $1, $3, src_loc(@$)); Q($$); } + | expr "<=" expr { $$ = gen_comparison(AST_LE, $1, $3, src_loc(@$)); Q($$); } + | expr ">=" expr { $$ = gen_comparison(AST_GE, $1, $3, src_loc(@$)); Q($$); } + | expr "!=" expr { $$ = gen_comparison(AST_NE, $1, $3, src_loc(@$)); Q($$); } + | expr "==" expr { $$ = gen_comparison(AST_EQ, $1, $3, src_loc(@$)); Q($$); } + | id "~" id { $$ = gen_paste($1, $3, src_loc(@$)); Q($$); } unop - : "-" expr { $$ = gen_unop(AST_NEG, $2, src_loc(@$)); } - | "!" expr { $$ = gen_unop(AST_LNOT, $2, src_loc(@$)); } - | "~" expr { $$ = gen_unop(AST_BNEG, $2, src_loc(@$)); } + : "-" expr { $$ = gen_unop(AST_NEG, $2, src_loc(@$)); Q($$); } + | "!" expr { $$ = gen_unop(AST_LNOT, $2, src_loc(@$)); Q($$); } + | "~" expr { $$ = gen_unop(AST_BNEG, $2, src_loc(@$)); Q($$); } type - : ID { $$ = tgen_id($1, src_loc(@$)); } - | "(" opt_types ")" { $$ = tgen_closure($2, src_loc(@$)); } + : ID { + $$ = tgen_id($1, src_loc(@$)); + Q($$); + } + | "(" opt_types ")" { $$ = tgen_closure($2, src_loc(@$)); Q($$); } | "&&" type { if ($2->k == TYPE_CLOSURE) { $$ = $2; $$->k = TYPE_PURE_CLOSURE; } else { $$ = tgen_ref($2, src_loc(@$)); + Q($$); } /* heh */ $$ = tgen_ref($$, src_loc(@$)); + Q($$); } | "&" type { if ($2->k == TYPE_CLOSURE) { $$ = $2; $$->k = TYPE_PURE_CLOSURE; } else { $$ = tgen_ref($2, src_loc(@$)); + Q($$); } } | "*" type { @@ -284,6 +300,7 @@ type $$ = $2; $$->k = TYPE_FUNC_PTR; } else { $$ = tgen_ptr($2, src_loc(@$)); + Q($$); } } @@ -302,6 +319,7 @@ opt_types construction : expr "=>" ID { $$ = gen_construction($3, $1, src_loc(@$)); + Q($$); } constructions @@ -315,6 +333,7 @@ opt_constructions deconstruction : ID "=>" var { $$ = gen_deconstruction($1, $3, src_loc(@$)); + Q($$); } deconstructions @@ -328,23 +347,33 @@ opt_deconstructions construct : "[" opt_constructions "]" ID { $$ = gen_construct($4, $2, src_loc(@$)); + Q($$); } id - : ID { $$ = gen_id($1, src_loc(@$)); } + : ID { + $$ = gen_id($1, src_loc(@$)); + Q($$); + } expr - : "sizeof" "(" type ")" { $$ = gen_sizeof($3, src_loc(@$)); } - | STRING { $$ = gen_const_str(strip($1), src_loc(@$)); } - | FLOAT { $$ = gen_const_float($1, src_loc(@$)); } - | BOOL { $$ = gen_const_bool($1, src_loc(@$)); } - | CHAR { $$ = gen_const_char($1, src_loc(@$)); } - | INT { $$ = gen_const_int($1, src_loc(@$)); } - | "*" { $$ = gen_nil(src_loc(@$)); } + : "sizeof" "(" type ")" { $$ = gen_sizeof($3, src_loc(@$)); Q($$); } + | STRING { + char *s = strip($1); + Q(s); + + $$ = gen_const_str(s, src_loc(@$)); + Q($$); + } + | FLOAT { $$ = gen_const_float($1, src_loc(@$)); Q($$); } + | BOOL { $$ = gen_const_bool($1, src_loc(@$)); Q($$); } + | CHAR { $$ = gen_const_char($1, src_loc(@$)); Q($$); } + | INT { $$ = gen_const_int($1, src_loc(@$)); Q($$); } + | "*" { $$ = gen_nil(src_loc(@$)); Q($$); } | "(" expr ")" { $$ = $2; } - | expr "&" { $$ = gen_ref($1, src_loc(@$)); } - | expr "*" { $$ = gen_deref($1, src_loc(@$)); } - | expr "as" type { $$ = gen_as($1, $3, src_loc(@$)); } + | expr "&" { $$ = gen_ref($1, src_loc(@$)); Q($$); } + | expr "*" { $$ = gen_deref($1, src_loc(@$)); Q($$); } + | expr "as" type { $$ = gen_as($1, $3, src_loc(@$)); Q($$); } | construct | id | binop @@ -364,9 +393,11 @@ opt_exprs closure : "=>" opt_vars body { $$ = gen_closure($[opt_vars], $[body], src_loc(@$)); + Q($$); } | "&" "=>" opt_vars body { $$ = gen_closure($[opt_vars], $[body], src_loc(@$)); + Q($$); ast_set_flags($$, AST_FLAG_NOMOVES); } @@ -375,9 +406,13 @@ rev_closures | closure trailing_closure - : "=>" opt_vars ";" { $$ = gen_closure($[opt_vars], NULL, src_loc(@$));} + : "=>" opt_vars ";" { + $$ = gen_closure($[opt_vars], NULL, src_loc(@$)); + Q($$); + } | "&" "=>" opt_vars ";" { $$ = gen_closure($[opt_vars], NULL, src_loc(@$)); + Q($$); ast_set_flags($$, AST_FLAG_NOMOVES); } @@ -398,46 +433,66 @@ closures call : expr "(" opt_exprs ")" { $$ = gen_call($1, $[opt_exprs], src_loc(@$)); + Q($$); } | expr "(" opt_exprs ")" "=>" opt_vars ";" { /* the rest of the function body is our closure, gets fixed up * later */ struct ast *closure = gen_closure($[opt_vars], NULL, src_loc(@$)); + Q(closure); + ast_append(&$[opt_exprs], closure); $$ = gen_call($[expr], $[opt_exprs], src_loc(@$)); + Q($$); } | expr "(" opt_exprs ")" closures { ast_append(&$[opt_exprs], $[closures]); $$ = gen_call($[expr], $[opt_exprs], src_loc(@$)); + Q($$); } put - : put "*" { $$ = gen_put($1, src_loc(@$)); } - | id "*" { $$ = gen_put($1, src_loc(@$)); } + : put "*" { $$ = gen_put($1, src_loc(@$)); Q($$); } + | id "*" { $$ = gen_put($1, src_loc(@$)); Q($$); } let - : expr "=>" var ";" { $$ = gen_let($3, $1, src_loc(@$)); } - | expr "=>" put ";" { $$ = gen_write($3, $1, src_loc(@$)); } + : expr "=>" var ";" { + $$ = gen_let($3, $1, src_loc(@$)); + Q($$); + } + | expr "=>" put ";" { + $$ = gen_write($3, $1, src_loc(@$)); + Q($$); + } explode : expr "=>" "[" opt_deconstructions "]" { $$ = gen_explode($4, $1, src_loc(@$)); + Q($$); } if - : "if" expr body "else" body { $$ = gen_if($2, $3, $5, src_loc(@$)); } - | "if" expr body "else" if { $$ = gen_if($2, $3, $5, src_loc(@$)); } + : "if" expr body "else" body { + $$ = gen_if($2, $3, $5, src_loc(@$)); + Q($$); + } + | "if" expr body "else" if { + $$ = gen_if($2, $3, $5, src_loc(@$)); + Q($$); + } nil : "nil" expr body "=>" var ";" { /** @todo should nil check define new scope for created * variable? */ $$ = gen_nil_check($2, $3, $5, src_loc(@$)); + Q($$); } forget : "nil" ID ";" { $$ = gen_forget($2, src_loc(@$)); + Q($$); } statement @@ -448,7 +503,7 @@ statement | let | nil | if - | ";" { $$ = gen_empty(src_loc(@$)); } + | ";" { $$ = gen_empty(src_loc(@$)); Q($$); } rev_statements : rev_statements statement { $$ = $2; $2->n = $1; } @@ -467,6 +522,7 @@ opt_statements body : "{" opt_statements "}" { $$ = gen_block($2, src_loc(@$)); + Q($$); } behaviour @@ -483,7 +539,10 @@ opt_behaviours | { $$ = NULL; } impl - : ID "!" { $$ = gen_implements($1, src_loc(@$)); } + : ID "!" { + $$ = gen_implements($1, src_loc(@$)); + Q($$); + } member : param @@ -499,7 +558,10 @@ opt_members type_param : ID ID { struct type *t = tgen_id($1, src_loc(@1)); + Q(t); + $$ = gen_var($2, t, src_loc(@$)); + Q($$); } type_params @@ -532,38 +594,50 @@ opt_elements template : ID "[" opt_type_params "]" "(" opt_vars ")" "{" opt_elements "}" { $$ = gen_template($1, $3, $6, $9, src_loc(@$)); + Q($$); } supertemplate : ID "[" opt_type_params "]" "(" opt_vars ")" "=" id "[" opt_types "]" "(" opt_exprs ")" "{" opt_elements "}" { struct ast *pseudoinst = gen_instance(NULL, $9, $11, $14, src_loc(@$)); + Q(pseudoinst); + $$ = gen_supertemplate($1, $3, $6, pseudoinst, $17, src_loc(@$)); + Q($$); } struct : ID "{" opt_members "}" { $$ = gen_struct($1, $3, src_loc(@$)); + Q($$); } struct_cont : "continue" ID "{" opt_behaviours "}" { $$ = gen_instance_cont($2, $4, src_loc(@$)); + Q($$); } trait : ID "=" "{" opt_behaviours "}" { $$ = gen_trait($1, $4, src_loc(@$)); + Q($$); } instance : ID "=" id "[" opt_types "]" "(" opt_exprs ")" { $$ = gen_instance($1, $3, $5, $8, src_loc(@$)); + Q($$); } import : "import" STRING { - $$ = gen_import(strip($2), src_loc(@$)); + char *s = strip($2); + Q(s); + + $$ = gen_import(s, src_loc(@$)); + Q($$); } top @@ -585,6 +659,8 @@ top | "pub" supertemplate { $$ = $2; ast_set_flags($$, AST_FLAG_PUBLIC); } | error { $$ = gen_empty(src_loc(@$)); + Q($$); + parser->failed = true; /* ignore any content inside a top level thing and just move onto * the next one */ @@ -679,11 +755,11 @@ static char match_escape(char c) static char *strip(const char *str) { const size_t len = strlen(str) + 1; - char *buf = malloc(len); + char *buf = mallocc(len); if (!buf) { /* should probably try to handle the error in some way... */ internal_error("failed allocating buffer for string clone"); - free((void *)str); + /* str should be in tracker already, so no need to free it */ return NULL; } @@ -693,14 +769,20 @@ static char *strip(const char *str) buf[j++] = str[i]; buf[j] = 0; - free((void *)str); + track_ptr(buf); return buf; } struct parser *create_parser() { - return calloc(1, sizeof(struct parser)); + struct parser *p = callocc(1, sizeof(struct parser)); + if (!p) { + internal_error("failed allocating parser"); + return NULL; + } + + return p; } void destroy_parser(struct parser *p) @@ -15,6 +15,8 @@ #include <fwd/path.h> #include <fwd/debug.h> +#include <fwd/tracker.h> +#include <fwd/coverage.h> char *fwd_basename(const char *file) { @@ -25,10 +27,19 @@ char *fwd_basename(const char *file) break; } + char *s = NULL; if (n == 0) - return strdup(file); + s = strdupc(file); + else + s = strndupc(file + n + 1, l - n); + + if (!s) { + internal_error("failed allocating basename"); + return NULL; + } - return strndup(file + n + 1, l - n); + track_ptr(s); + return s; } char *fwd_dirname(const char *file) @@ -40,7 +51,14 @@ char *fwd_dirname(const char *file) break; } - return strndup(file, n); + char *s = strndupc(file, n); + if (!s) { + internal_error("failed allocating dirname"); + return NULL; + } + + track_ptr(s); + return s; } char *fwd_cwdname() @@ -52,13 +70,15 @@ char *fwd_cwdname() else size = (size_t)path_max; - char *buf = malloc(size); - if (!buf) + char *buf = mallocc(size); + if (!buf) { + internal_error("failed allocating cwd buf"); return NULL; + } + track_ptr(buf); if (!getcwd(buf, size)) { error("%s\n", strerror(errno)); - free(buf); return NULL; } diff --git a/src/rewrite.c b/src/rewrite.c index c5a497a..6409686 100644 --- a/src/rewrite.c +++ b/src/rewrite.c @@ -1,4 +1,5 @@ #include <fwd/rewrite.h> +#include <fwd/debug.h> #include <stddef.h> #include <stdlib.h> @@ -11,7 +12,12 @@ struct type_helper { static int rewrite_type_ids(struct type *type, char *orig, char *new) { if (type->k == TYPE_ID && strcmp(type->id, orig) == 0) { - char *r = strdup(new); + char *r = strdupc(new); + if (!r) { + internal_error("failed allocating hole"); + return -1; + } + free(type->id); type->id = r; } @@ -49,7 +55,11 @@ static char *rewrite_hole(char *old, char *new) size_t nn = strlen(new); /* +1 for null terminator */ - char *r = malloc(on + nn + 1); + char *r = mallocc(on + nn + 1); + if (!r) { + internal_error("failed allocating hole rewrite buf"); + return NULL; + } memcpy(r, new, nn); diff --git a/src/scope.c b/src/scope.c index 251edef..f350090 100644 --- a/src/scope.c +++ b/src/scope.c @@ -14,6 +14,7 @@ #include <stdio.h> #include <dlfcn.h> +#include <fwd/coverage.h> #include <fwd/debug.h> #include <fwd/scope.h> @@ -22,7 +23,7 @@ struct scope *create_scope() /* if I ever try making the parser multithreaded, this should be atomic. */ static size_t counter = 0; - struct scope *scope = calloc(1, sizeof(struct scope)); + struct scope *scope = callocc(1, sizeof(struct scope)); if (!scope) { internal_error("ran out of memory allocating scope"); return NULL; @@ -42,11 +43,6 @@ void destroy_scope(struct scope *scope) if (!scope) return; - if (!scope->parent) { - free((void *)scope->fctx.fbuf); - free((void *)scope->fctx.fname); - } - foreach(mod_vec, m, &scope->mods) { dlclose(*m); } diff --git a/src/tracker.c b/src/tracker.c new file mode 100644 index 0000000..2bf56d4 --- /dev/null +++ b/src/tracker.c @@ -0,0 +1,22 @@ +#include <fwd/tracker.h> + +#define VEC_NAME ptr_tracker +#define VEC_TYPE void * +#include <conts/vec.h> + +static struct ptr_tracker ptrs; + +void *track_ptr(void *p) +{ + ptr_tracker_append(&ptrs, p); + return p; +} + +void free_tracked_ptrs() +{ + foreach(ptr_tracker, ptr, &ptrs) { + free(*ptr); + } + + ptr_tracker_destroy(&ptrs); +} |
