summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2019-11-11 16:18:26 -0500
committerLeo Tenenbaum <pommicket@gmail.com>2019-11-11 16:18:26 -0500
commit98fcdba9bf63ad79f40b832f3bff42f54aca6aab (patch)
tree1bf446829bcd78a8dfada37e104d062d0be32823
parente800a25fd2c4945b465b4cd90b4d212272d1641c (diff)
declarations for functions with constant parameters
-rw-r--r--allocator.c2
-rw-r--r--arr.c2
-rw-r--r--cgen.c38
-rw-r--r--decls_cgen.c55
-rw-r--r--eval.c9
-rw-r--r--hash_tables.c7
-rw-r--r--main.c24
-rw-r--r--parse.c14
-rw-r--r--test.toc9
-rw-r--r--tokenizer.c19
-rw-r--r--types.c16
-rw-r--r--types.h9
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))
diff --git a/arr.c b/arr.c
index 8f63a44..ab92319 100644
--- a/arr.c
+++ b/arr.c
@@ -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))
diff --git a/cgen.c b/cgen.c
index a388b9b..3830359 100644
--- a/cgen.c
+++ b/cgen.c
@@ -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);
diff --git a/eval.c b/eval.c
index b367ac1..b09e41d 100644
--- a/eval.c
+++ b/eval.c
@@ -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) {
diff --git a/main.c b/main.c
index b02b030..8e8878e 100644
--- a/main.c
+++ b/main.c
@@ -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);
}
+
diff --git a/parse.c b/parse.c
index 83ef2fe..4fe1f26 100644
--- a/parse.c
+++ b/parse.c
@@ -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 */
diff --git a/test.toc b/test.toc
index 02811e2..2316a89 100644
--- a/test.toc
+++ b/test.toc
@@ -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);
}
diff --git a/types.c b/types.c
index 9b8629f..bafc786 100644
--- a/types.c
+++ b/types.c
@@ -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);
-}
diff --git a/types.h b/types.h
index 9ba5bc0..da06d30 100644
--- a/types.h
+++ b/types.h
@@ -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? */