diff options
author | Leo Tenenbaum <pommicket@gmail.com> | 2019-11-11 16:18:26 -0500 |
---|---|---|
committer | Leo Tenenbaum <pommicket@gmail.com> | 2019-11-11 16:18:26 -0500 |
commit | 98fcdba9bf63ad79f40b832f3bff42f54aca6aab (patch) | |
tree | 1bf446829bcd78a8dfada37e104d062d0be32823 | |
parent | e800a25fd2c4945b465b4cd90b4d212272d1641c (diff) |
declarations for functions with constant parameters
-rw-r--r-- | allocator.c | 2 | ||||
-rw-r--r-- | arr.c | 2 | ||||
-rw-r--r-- | cgen.c | 38 | ||||
-rw-r--r-- | decls_cgen.c | 55 | ||||
-rw-r--r-- | eval.c | 9 | ||||
-rw-r--r-- | hash_tables.c | 7 | ||||
-rw-r--r-- | main.c | 24 | ||||
-rw-r--r-- | parse.c | 14 | ||||
-rw-r--r-- | test.toc | 9 | ||||
-rw-r--r-- | tokenizer.c | 19 | ||||
-rw-r--r-- | types.c | 16 | ||||
-rw-r--r-- | types.h | 9 |
12 files changed, 128 insertions, 76 deletions
diff --git a/allocator.c b/allocator.c index ce880a8..1995733 100644 --- a/allocator.c +++ b/allocator.c @@ -1,4 +1,4 @@ -#define NO_ALLOCATOR 1 /* useful for debugging; valgrind checks writing past the end of a malloc, but that won't work with an allocator */ +#define NO_ALLOCATOR 0 /* useful for debugging; valgrind checks writing past the end of a malloc, but that won't work with an allocator */ /* number of bytes a page hold, not including the header */ #define PAGE_BYTES (16384 - sizeof(Page)) #define PAGE_MAX_ALIGNS (PAGE_BYTES / sizeof(max_align_t)) @@ -135,7 +135,7 @@ You shouldn't rely on this, though, e.g. by doing #define arr_resva(arr, n, allocr) arr_resva_((void **)(arr), n, sizeof **(arr), allocr) #define arr_set_len(arr, n) arr_set_len_((void **)(arr), n, sizeof **(arr)) #define arr_set_lena(arr, n, a) arr_set_lena_((void **)(arr), n, sizeof **(arr), a) -#define arr_clear(arr) arr_clear_((void **)(arr)) +#define arr_clear(arr) arr_clear_((void **)(arr)), (void)sizeof **arr /* second part makes sure most of the time that you don't accidentally call it without taking the address */ #define arr_last(arr) arr_last_((void *)(arr), sizeof *(arr)) #define arr_foreach(arr, type, var) for (type *var = arr_len(arr) ? arr : NULL, *var##_foreach_end = arr_last(arr); var; var == var##_foreach_end ? var = NULL : var++) #define arr_remove_last(arr) arr_remove_last_((void **)(arr), sizeof **(arr)) @@ -1,5 +1,5 @@ -static void cgen_create(CGenerator *g, FILE *out, Identifiers *ids, Evaluator *ev) { +static void cgen_create(CGenerator *g, FILE *out, Identifiers *ids, Evaluator *ev, Allocator *allocr) { g->outc = out; g->ident_counter = 1; /* some places use 0 to mean no id */ g->main_ident = ident_get(ids, "main"); @@ -8,6 +8,7 @@ static void cgen_create(CGenerator *g, FILE *out, Identifiers *ids, Evaluator *e g->indent_lvl = 0; g->anon_fns = NULL; g->idents = ids; + g->allocr = allocr; } static bool cgen_stmt(CGenerator *g, Statement *s); @@ -411,7 +412,8 @@ static inline void cgen_fn_name(CGenerator *g, FnExpr *f) { } } -static bool cgen_fn_header(CGenerator *g, FnExpr *f, Location where) { +/* unless f needs multiple instances, instance can be set to 0 */ +static bool cgen_fn_header(CGenerator *g, FnExpr *f, Location where, I64 instance) { bool out_param = cgen_uses_ptr(&f->ret_type); bool any_params = false; if (!f->c.name) /* anonymous fn */ @@ -423,23 +425,28 @@ static bool cgen_fn_header(CGenerator *g, FnExpr *f, Location where) { cgen_write(g, " "); } cgen_fn_name(g, f); + if (instance) { + cgen_write(g, "%"PRId64, instance); + } if (!out_param) { if (!cgen_type_post(g, &f->ret_type, where)) return false; } cgen_write(g, "("); arr_foreach(f->params, Declaration, d) { - long idx = 0; - arr_foreach(d->idents, Identifier, i) { - if (d != f->params || i != d->idents) - cgen_write(g, ", "); - Type *type = d->type.kind == TYPE_TUPLE ? &d->type.tuple[idx++] : &d->type; - any_params = true; - if (!cgen_type_pre(g, type, where)) - return false; - cgen_write(g, " "); - cgen_ident(g, *i); - if (!cgen_type_post(g, type, where)) - return false; + if (!(d->flags & DECL_IS_CONST)) { + long idx = 0; + arr_foreach(d->idents, Identifier, i) { + if (d != f->params || i != d->idents) + cgen_write(g, ", "); + Type *type = d->type.kind == TYPE_TUPLE ? &d->type.tuple[idx++] : &d->type; + any_params = true; + if (!cgen_type_pre(g, type, where)) + return false; + cgen_write(g, " "); + cgen_ident(g, *i); + if (!cgen_type_post(g, type, where)) + return false; + } } } if (out_param) { @@ -1439,7 +1446,7 @@ static bool cgen_fn(CGenerator *g, FnExpr *f, Location where) { FnExpr *prev_fn = g->fn; Block *prev_block = g->block; fn_enter(f, 0); - if (!cgen_fn_header(g, f, where)) + if (!cgen_fn_header(g, f, where, 0)) return false; cgen_write(g, " "); g->fn = f; @@ -1810,6 +1817,7 @@ static bool cgen_file(CGenerator *g, ParsedFile *f) { "#define true ((bool)1)\n" "static inline slice_ mkslice_(void *data, i64 n) { slice_ ret; ret.data = data; ret.n = n; return ret; }\n" "static void *e__calloc(size_t n, size_t sz) { void *ret = calloc(n, sz); if (!ret) { fprintf(stderr, \"Out of memory.\\n\"); abort(); } return ret; }\n\n\n"); + if (!typedefs_file(g, f)) return false; if (!cgen_decls_file(g, f)) diff --git a/decls_cgen.c b/decls_cgen.c index 190c004..92b0f3c 100644 --- a/decls_cgen.c +++ b/decls_cgen.c @@ -6,18 +6,63 @@ static bool cgen_decls_expr(CGenerator *g, Expression *e) { case EXPR_CALL: if (e->call.fn->kind == EXPR_IDENT) { IdentDecl *idecl = ident_decl(e->call.fn->ident); + Block *prev = g->block; + /* temporarily set g->block so that cgen_fn_is_direct works */ + g->block = idecl->scope; if (idecl->kind == IDECL_DECL && - idecl->decl->expr.kind == EXPR_FN) { + cgen_fn_is_direct(g, idecl->decl)) { + g->block = prev; + FnExpr *f = &idecl->decl->expr.fn; + f->c.name = idecl->decl->idents[0]; /* directly calling a function; might need to generate a copy of this function */ - /* TODO ASDF */ + + /* OPTIM should we really be constructing a tuple & type every time? */ + Value *compile_time_args = NULL; + Type *tuple_types = NULL; + size_t i = 0; + arr_foreach(f->params, Declaration, param) { + if (param->flags & DECL_IS_CONST) { + arr_foreach(param->idents, Identifier, ident) { + Expression *arg = &e->call.arg_exprs[i]; + assert(arg->kind == EXPR_VAL); /* should have been evaluated by types.c */ + *(Value *)arr_adda(&compile_time_args, g->allocr) = arg->val; + *(Type *)arr_add(&tuple_types) = arg->type; + i++; + } + } else { + i += arr_len(param->idents); + } + } + if (compile_time_args) { + Value tuple; + Type tuple_type; + tuple.tuple = compile_time_args; + tuple_type.kind = TYPE_TUPLE; + tuple_type.flags = TYPE_IS_RESOLVED; + tuple_type.tuple = tuple_types; + if (!f->c.instances) { + f->c.instances = allocr_calloc(g->allocr, 1, sizeof *f->c.instances); + } + /* lookup compile time arguments */ + I64 instance_number = (I64)f->c.instances->n + 1; + bool already_generated_decl = val_hash_table_adda(g->allocr, f->c.instances, tuple, &tuple_type, &instance_number); + if (!already_generated_decl) { + /* generate a copy of this function */ + if (!cgen_fn_header(g, f, e->where, instance_number)) + return false; + cgen_write(g, ";"); + cgen_nl(g); + } + arr_clear(&tuple_types); + } /* else, there are no compile time arguments; we don't need to generate a separate declaration for this call */ } } break; case EXPR_FN: e->fn.c.name = NULL; - e->fn.c.id = g->ident_counter++; + e->fn.c.id = g->ident_counter++; fn_enter(&e->fn, 0); - if (!cgen_fn_header(g, &e->fn, e->where)) + if (!cgen_fn_header(g, &e->fn, e->where, 0)) return false; cgen_write(g, ";"); cgen_nl(g); @@ -46,7 +91,7 @@ static bool cgen_decls_decl(CGenerator *g, Declaration *d) { if (!fn_has_any_const_params(&d->expr.fn)) { d->expr.fn.c.name = d->idents[0]; fn_enter(&d->expr.fn, 0); - if (!cgen_fn_header(g, &d->expr.fn, d->where)) + if (!cgen_fn_header(g, &d->expr.fn, d->where, 0)) return false; cgen_write(g, ";"); cgen_nl(g); @@ -7,16 +7,15 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v); static bool block_enter(Block *b, Statement *stmts, U32 flags); static void block_exit(Block *b, Statement *stmts); -static void evalr_create(Evaluator *ev, Typer *tr) { - allocr_create(&ev->allocr); +static void evalr_create(Evaluator *ev, Typer *tr, Allocator *allocr) { ev->returning = NULL; ev->to_free = NULL; ev->typer = tr; ev->enabled = true; + ev->allocr = allocr; } static void evalr_free(Evaluator *ev) { - allocr_free_all(&ev->allocr); typedef void *VoidPtr; arr_foreach(ev->to_free, VoidPtr, f) free(*f); @@ -24,10 +23,10 @@ static void evalr_free(Evaluator *ev) { } static inline void *evalr_malloc(Evaluator *ev, size_t bytes) { - return allocr_malloc(&ev->allocr, bytes); + return allocr_malloc(ev->allocr, bytes); } static inline void *evalr_calloc(Evaluator *ev, size_t n, size_t bytes) { - return allocr_calloc(&ev->allocr, n, bytes); + return allocr_calloc(ev->allocr, n, bytes); } static size_t compiler_sizeof_builtin(BuiltinType b) { diff --git a/hash_tables.c b/hash_tables.c index a8a5c82..e5f1652 100644 --- a/hash_tables.c +++ b/hash_tables.c @@ -60,6 +60,8 @@ static U64 f64_hash(F64 f) { return hash; } +static void fprint_val(FILE *f, Value v, Type *t); /* DELME */ +static void fprint_type(FILE *out, Type *t); /* !! */ /* Note that for these value hashing functions, values of different types may collide */ static U64 val_ptr_hash(void *v, Type *t) { switch (t->kind) { @@ -223,8 +225,8 @@ static bool val_eq(Value u, Value v, Type *t) { static bool val_hash_table_adda(Allocator *a, HashTable *h, Value v, Type *t, I64 *associated_number) { if (h->n * 2 >= h->cap) { U64 new_cap = h->cap * 2 + 2; - ValNumPair *new_data = a ? allocr_malloc(a, new_cap * (U64)sizeof *new_data) - : malloc(new_cap * sizeof *new_data); + ValNumPair *new_data = a ? allocr_malloc(a, (size_t)new_cap * sizeof *new_data) + : malloc((size_t)new_cap * sizeof *new_data); bool *new_occupied = a ? allocr_calloc(a, (size_t)new_cap, sizeof *new_occupied) : calloc((size_t)new_cap, sizeof *new_occupied); ValNumPair *old_data = h->data; @@ -281,6 +283,7 @@ static bool val_hash_table_add(HashTable *h, Value v, Type *t, I64 *associated_n /* only call if you're not using an allocator */ static void hash_table_free(HashTable *h) { free(h->data); + free(h->occupied); } static void val_hash_table_test(void) { @@ -14,6 +14,7 @@ unicode variable names (cgen support) make sure futurely/currently-declared types are only used by pointer/slice allow omission of trailing ; in foo @= fn() {}? */ + #include "toc.c" int main(int argc, char **argv) { @@ -59,10 +60,12 @@ int main(int argc, char **argv) { Identifiers file_idents; idents_create(&file_idents); Tokenizer t; + Allocator main_allocr; + allocr_create(&main_allocr); ErrCtx err_ctx; err_ctx.filename = in_filename; err_ctx.enabled = true; - tokr_create(&t, &file_idents, &err_ctx); + tokr_create(&t, &file_idents, &err_ctx, &main_allocr); if (!tokenize_string(&t, contents)) { err_fprint(TEXT_IMPORTANT("Errors occured while preprocessing.\n")); @@ -76,22 +79,24 @@ int main(int argc, char **argv) { /* } */ /* printf("\n"); */ Parser p; - parser_from_tokenizer(&p, &t); + parser_create(&p, &t, &main_allocr); ParsedFile f; if (!parse_file(&p, &f)) { err_fprint(TEXT_IMPORTANT("Errors occured while parsing.\n")); return EXIT_FAILURE; } - tokr_free_tokens(&t); /* fprint_parsed_file(stdout, &f); */ /* printf("\n\n-----\n\n"); */ + tokr_free(&t); + Typer tr; Evaluator ev; - evalr_create(&ev, &tr); - typer_create(&tr, &ev); + evalr_create(&ev, &tr, &main_allocr); + typer_create(&tr, &ev, &main_allocr); + if (!block_enter(NULL, f.stmts, SCOPE_CHECK_REDECL)) /* enter global scope */ return false; @@ -109,7 +114,7 @@ int main(int argc, char **argv) { return EXIT_FAILURE; } CGenerator g; - cgen_create(&g, out, &file_idents, &ev); + cgen_create(&g, out, &file_idents, &ev, &main_allocr); if (!cgen_file(&g, &f)) { fclose(out); err_fprint(TEXT_IMPORTANT("Errors occured while generating C code.\n")); @@ -118,14 +123,11 @@ int main(int argc, char **argv) { block_exit(NULL, f.stmts); /* exit global scope */ - tokr_free(&t); - free(contents); + allocr_free_all(&main_allocr); - parser_free(&p); - typer_free(&tr); - evalr_free(&ev); fclose(out); /* fclose(h_out); */ idents_free(&file_idents); } + @@ -191,7 +191,7 @@ static size_t type_to_str_(Type *t, char *buffer, size_t bufsize) { case TYPE_ARR: { size_t written = str_copy(buffer, bufsize, "["); if (t->flags & TYPE_IS_RESOLVED) { - snprintf(buffer + written, bufsize - written, PRIu64, t->arr.n); + snprintf(buffer + written, bufsize - written, "%"PRIu64, t->arr.n); written += strlen(buffer + written); } else { written += str_copy(buffer + written, bufsize - written, "N"); @@ -245,13 +245,13 @@ static char *type_to_str(Type *t) { } static inline void *parser_arr_add_(Parser *p, void **a, size_t sz) { - return arr_adda_(a, sz, &p->allocr); + return arr_adda_(a, sz, p->allocr); } #define parser_arr_add(p, a) parser_arr_add_(p, (void **)(a), sizeof **(a)) static inline void *parser_malloc(Parser *p, size_t bytes) { - return allocr_malloc(&p->allocr, bytes); + return allocr_malloc(p->allocr, bytes); } /* @@ -1864,10 +1864,10 @@ static bool parse_stmt(Parser *p, Statement *s) { } } -static void parser_from_tokenizer(Parser *p, Tokenizer *t) { +static void parser_create(Parser *p, Tokenizer *t, Allocator *allocr) { p->tokr = t; p->block = NULL; - allocr_create(&p->allocr); + p->allocr = allocr; } static bool parse_file(Parser *p, ParsedFile *f) { @@ -1886,10 +1886,6 @@ static bool parse_file(Parser *p, ParsedFile *f) { return ret; } -static void parser_free(Parser *p) { - allocr_free_all(&p->allocr); -} - #define PARSE_PRINT_LOCATION(l) //fprintf(out, "[l%lu]", (unsigned long)(l).line); /* in theory, this shouldn't be global, but these functions are mostly for debugging anyways */ @@ -4,16 +4,17 @@ puti @= fn(x: int) { "); }; -// putf @= fn(x: float) { -// #C("printf(\"%f\\n\", (double)x); -// "); -// }; +putf @= fn(x: float) { + #C("printf(\"%f\\n\", (double)x); +"); +}; add @= fn(x: int, y @int) int { x + y }; main @= fn() { +add(3,10); puti(add(3, 10)); x @= add(3, 7); puti(add(4, x)); diff --git a/tokenizer.c b/tokenizer.c index adbb7b1..539f2cd 100644 --- a/tokenizer.c +++ b/tokenizer.c @@ -174,16 +174,20 @@ static void tokr_get_location(Tokenizer *tokr, Token *t) { tokr->s = t->where.code; } -static void tokr_create(Tokenizer *t, Identifiers *idents, ErrCtx *err_ctx) { +/* +the allocator you pass it will be used for string literals, so it shouldn't be freed +until everything is done +*/ +static void tokr_create(Tokenizer *t, Identifiers *idents, ErrCtx *err_ctx, Allocator *allocr) { t->tokens = NULL; arr_resv(&t->tokens, 256); - allocr_create(&t->allocr); + t->allocr = allocr; t->idents = idents; t->err_ctx = err_ctx; } static inline void *tokr_malloc(Tokenizer *t, size_t bytes) { - return allocr_malloc(&t->allocr, bytes); + return allocr_malloc(t->allocr, bytes); } static Token *tokr_add(Tokenizer *t) { @@ -517,12 +521,7 @@ static void tokr_skip_semicolon(Tokenizer *t) { } } -/* ONLY frees tokens, not string literals. You can call this followed by tokr_free. */ -static void tokr_free_tokens(Tokenizer *t) { - arr_clear(&t->tokens); -} - +/* only frees tokens, not string literals (because those are on the allocator). */ static void tokr_free(Tokenizer *t) { - tokr_free_tokens(t); - allocr_free_all(&t->allocr); + arr_clear(&t->tokens); } @@ -5,15 +5,15 @@ static bool types_block(Typer *tr, Block *b); static bool type_resolve(Typer *tr, Type *t, Location where); static inline void *typer_malloc(Typer *tr, size_t bytes) { - return allocr_malloc(&tr->allocr, bytes); + return allocr_malloc(tr->allocr, bytes); } static inline void *typer_calloc(Typer *tr, size_t n, size_t sz) { - return allocr_calloc(&tr->allocr, n, sz); + return allocr_calloc(tr->allocr, n, sz); } static inline void *typer_arr_add_(Typer *tr, void **arr, size_t sz) { - return arr_adda_(arr, sz, &tr->allocr); + return arr_adda_(arr, sz, tr->allocr); } static inline bool type_is_builtin(Type *t, BuiltinType b) { @@ -586,6 +586,7 @@ static bool types_expr(Typer *tr, Expression *e) { bool success = true; switch (e->kind) { case EXPR_FN: { + e->fn.c.instances = NULL; /* maybe this should be handled by cgen... oh well */ Type prev_ret_type = tr->ret_type; bool prev_can_ret = tr->can_ret; FnExpr *f = &e->fn; @@ -954,7 +955,7 @@ static bool types_expr(Typer *tr, Expression *e) { bool ret = true; FnExpr *fn_decl = NULL; Expression *new_args = NULL; - arr_set_lena(&new_args, nparams, &tr->allocr); + arr_set_lena(&new_args, nparams, tr->allocr); bool *params_set = nparams ? typer_calloc(tr, nparams, sizeof *params_set) : NULL; if (f->kind == EXPR_IDENT) { IdentDecl *decl = ident_decl(f->ident); @@ -1625,13 +1626,13 @@ static bool types_stmt(Typer *tr, Statement *s) { return true; } -static void typer_create(Typer *tr, Evaluator *ev) { +static void typer_create(Typer *tr, Evaluator *ev, Allocator *allocr) { tr->block = NULL; tr->can_ret = false; tr->evalr = ev; tr->in_decls = NULL; tr->in_expr_decls = NULL; - allocr_create(&tr->allocr); + tr->allocr = allocr; } static bool types_file(Typer *tr, ParsedFile *f) { @@ -1644,6 +1645,3 @@ static bool types_file(Typer *tr, ParsedFile *f) { return ret; } -static void typer_free(Typer *tr) { - allocr_free_all(&tr->allocr); -} @@ -253,7 +253,7 @@ typedef struct { } Token; typedef struct { - Allocator allocr; + Allocator *allocr; Token *tokens; char *s; /* string being parsed */ ErrCtx *err_ctx; @@ -620,7 +620,7 @@ typedef struct { typedef struct { Tokenizer *tokr; - Allocator allocr; + Allocator *allocr; Block *block; /* which block are we in? NULL = file scope */ } Parser; @@ -631,7 +631,7 @@ typedef enum { } DeclEndKind; typedef struct { - Allocator allocr; + Allocator *allocr; struct Typer *typer; bool returning; Value ret_val; @@ -640,7 +640,7 @@ typedef struct { } Evaluator; typedef struct Typer { - Allocator allocr; + Allocator *allocr; Evaluator *evalr; Expression **in_expr_decls; /* an array of expressions whose declarations (e.g. each **x := foo**) we are currently inside */ Declaration **in_decls; /* array of declarations we are currently inside */ @@ -650,6 +650,7 @@ typedef struct Typer { } Typer; typedef struct { + Allocator *allocr; FILE *outc; IdentID ident_counter; int indent_lvl; /* how many levels of indentation? */ |