diff options
-rw-r--r-- | allocator.c | 2 | ||||
-rw-r--r-- | cgen.c | 88 | ||||
-rw-r--r-- | decls_cgen.c | 69 | ||||
-rw-r--r-- | instance_table.c (renamed from hash_tables.c) | 82 | ||||
-rw-r--r-- | main.c | 3 | ||||
-rw-r--r-- | parse.c | 5 | ||||
-rwxr-xr-x | runv | 2 | ||||
-rw-r--r-- | test.toc | 25 | ||||
-rw-r--r-- | tests.c | 1 | ||||
-rw-r--r-- | toc.c | 2 | ||||
-rw-r--r-- | tokenizer.c | 2 | ||||
-rw-r--r-- | typedefs_cgen.c | 3 | ||||
-rw-r--r-- | types.c | 58 | ||||
-rw-r--r-- | types.h | 22 |
14 files changed, 176 insertions, 188 deletions
diff --git a/allocator.c b/allocator.c index f47cc97..e49ea3e 100644 --- a/allocator.c +++ b/allocator.c @@ -1,4 +1,4 @@ -/* #define NO_ALLOCATOR 0 /\* useful for debugging; valgrind checks writing past the end of a malloc, but that won't work with an allocator *\/ */ +#define NO_ALLOCATOR 1 /* useful for debugging; valgrind (maybe) 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(MaxAlign)) @@ -1,4 +1,3 @@ - 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 */ @@ -25,9 +24,10 @@ static bool cgen_val(CGenerator *g, Value v, Type *t, Location where); static bool cgen_val_pre(CGenerator *g, Value v, Type *t, Location where); static bool cgen_val_ptr(CGenerator *g, void *v, Type *t, Location where); static bool cgen_defs_block(CGenerator *g, Block *b); +static bool cgen_defs_decl(CGenerator *g, Declaration *d); -/* calls f on every sub-expression of e, and block_f on every sub-block. */ -#define cgen_recurse_subexprs(g, e, f, block_f) \ +/* calls f on every sub-expression of e, block_f on every sub-block, and decl_f on every sub-declaration. */ +#define cgen_recurse_subexprs(g, e, f, block_f, decl_f) \ switch (e->kind) { \ case EXPR_TYPE: \ case EXPR_VAL: \ @@ -112,6 +112,12 @@ static bool cgen_defs_block(CGenerator *g, Block *b); break; \ case EXPR_FN: \ if (!fn_enter(&e->fn, 0)) return false; \ + arr_foreach(e->fn.params, Declaration, param) \ + if (!decl_f(g, param)) \ + return false; \ + arr_foreach(e->fn.ret_decls, Declaration, r) \ + if (!decl_f(g, r)) \ + return false; \ if (!block_f(g, &e->fn.body)) \ return false; \ fn_exit(&e->fn); \ @@ -413,7 +419,7 @@ static inline void cgen_fn_name(CGenerator *g, FnExpr *f) { } /* unless f has const/semi-const args, instance and which_are_const can be set to 0 */ -static bool cgen_fn_header(CGenerator *g, FnExpr *f, Location where, I64 instance, U64 which_are_const) { +static bool cgen_fn_header(CGenerator *g, FnExpr *f, Location where, U64 instance, U64 which_are_const) { bool out_param = cgen_uses_ptr(&f->ret_type); bool any_params = false; if (!f->c.name) /* anonymous fn */ @@ -426,20 +432,22 @@ static bool cgen_fn_header(CGenerator *g, FnExpr *f, Location where, I64 instanc } cgen_fn_name(g, f); if (instance) { - cgen_write(g, "%"PRId64, instance); + cgen_write(g, "%"PRIu64, instance); } if (!out_param) { if (!cgen_type_post(g, &f->ret_type, where)) return false; } cgen_write(g, "("); int semi_const_idx = 0; + bool any_args = false; arr_foreach(f->params, Declaration, d) { if (!(d->flags & DECL_IS_CONST) && !((d->flags & DECL_SEMI_CONST) && (which_are_const & (((U64)1) << semi_const_idx++)))) { long idx = 0; arr_foreach(d->idents, Identifier, i) { - if (d != f->params || i != d->idents) + if (any_args) cgen_write(g, ", "); + any_args = true; Type *type = d->type.kind == TYPE_TUPLE ? &d->type.tuple[idx++] : &d->type; any_params = true; if (!cgen_type_pre(g, type, where)) @@ -451,7 +459,8 @@ static bool cgen_fn_header(CGenerator *g, FnExpr *f, Location where, I64 instanc } } } - if (out_param) { + if (out_param) { + any_args = true; if (f->ret_type.kind == TYPE_TUPLE) { /* multiple return variables */ for (size_t i = 0; i < arr_len(f->ret_type.tuple); i++) { @@ -472,7 +481,7 @@ static bool cgen_fn_header(CGenerator *g, FnExpr *f, Location where, I64 instanc return false; } } - if (!out_param && arr_len(f->params) == 0) + if (!any_args) cgen_write(g, "void"); cgen_write(g, ")"); return true; @@ -589,8 +598,8 @@ static bool cgen_set_tuple(CGenerator *g, Expression *exprs, Identifier *idents, case EXPR_CALL: { /* e.g. a, b = fn_which_returns_tuple(); */ if (!cgen_expr(g, to->call.fn)) return false; - if (to->call.c.instance) - cgen_write(g, "%"PRId64, to->call.c.instance); + if (to->call.instance) + cgen_write(g, "%"PRIu64, to->call.instance->c.id); cgen_write(g, "("); bool any_args = false; Constness *constness = to->call.fn->type.fn.constness; @@ -956,8 +965,8 @@ static bool cgen_expr_pre(CGenerator *g, Expression *e) { if (!cgen_type_post(g, &e->type, e->where)) return false; cgen_write(g, ";"); cgen_nl(g); if (!cgen_expr(g, e->call.fn)) return false; - if (e->call.c.instance) { - cgen_write(g, "%"PRId64, e->call.c.instance); + if (e->call.instance) { + cgen_write(g, "%"PRIu64, e->call.instance->c.id); } cgen_write(g, "("); bool any_args = false; @@ -1315,8 +1324,8 @@ static bool cgen_expr(CGenerator *g, Expression *e) { cgen_write(g, "("); if (!cgen_expr(g, e->call.fn)) return false; - if (e->call.c.instance) { - cgen_write(g, "%"PRId64, e->call.c.instance); + if (e->call.instance) { + cgen_write(g, "%"PRIu64, e->call.instance->c.id); } cgen_write(g, "("); bool first_arg = true; @@ -1455,7 +1464,7 @@ static void cgen_zero_value(CGenerator *g, Type *t) { } /* pass 0 for instance and NULL for compile_time_args if there are no compile time arguments. */ -static bool cgen_fn(CGenerator *g, FnExpr *f, Location where, I64 instance, Value *compile_time_args) { +static bool cgen_fn(CGenerator *g, FnExpr *f, Location where, U64 instance, Value *compile_time_args) { /* see also cgen_defs_expr */ FnExpr *prev_fn = g->fn; Block *prev_block = g->block; @@ -1482,15 +1491,26 @@ static bool cgen_fn(CGenerator *g, FnExpr *f, Location where, I64 instance, Valu arr_foreach(param->idents, Identifier, ident) { Type *type = param->type.kind == TYPE_TUPLE ? ¶m->type.tuple[i] : ¶m->type; - if (!cgen_val_pre(g, compile_time_args[carg_idx], type, where)) - return false; - if (!cgen_type_pre(g, type, where)) return false; - cgen_write(g, " const "); - cgen_ident(g, *ident); - if (!cgen_type_post(g, type, where)) return false; - cgen_write(g, " = "); - if (!cgen_val(g, compile_time_args[carg_idx], type, where)) - return false; + Value arg = compile_time_args[carg_idx]; + if (type->kind == TYPE_TYPE) { + cgen_write(g, "typedef "); + if (!cgen_type_pre(g, arg.type, where)) + return false; + cgen_write(g, " "); + cgen_ident(g, *ident); + if (!cgen_type_post(g, arg.type, where)) + return false; + } else { + if (!cgen_val_pre(g, arg, type, where)) + return false; + if (!cgen_type_pre(g, type, where)) return false; + cgen_write(g, " const "); + cgen_ident(g, *ident); + if (!cgen_type_post(g, type, where)) return false; + cgen_write(g, " = "); + if (!cgen_val(g, arg, type, where)) + return false; + } cgen_write(g, ";"); cgen_nl(g); carg_idx++; @@ -1812,16 +1832,14 @@ static bool cgen_defs_expr(CGenerator *g, Expression *e) { } } if (fn_type->constness) { - HashTable *instances = f->c.instances; - if (instances) { - /* generate each instance */ - ValNumPair *pairs = instances->data; - for (U64 i = 0; i < instances->cap; i++) { - if (instances->occupied[i]) { - /* generate this instance */ - if (!cgen_fn(g, f, e->where, pairs[i].num, pairs[i].val.tuple)) - return false; - } + HashTable *instances = &f->instances; + /* generate each instance */ + Instance **is = instances->data; + for (U64 i = 0; i < instances->cap; i++) { + if (instances->occupied[i]) { + /* generate this instance */ + if (!cgen_fn(g, f, e->where, is[i]->c.id, is[i]->val.tuple)) + return false; } } } @@ -1831,7 +1849,7 @@ static bool cgen_defs_expr(CGenerator *g, Expression *e) { } } - cgen_recurse_subexprs(g, e, cgen_defs_expr, cgen_defs_block); + cgen_recurse_subexprs(g, e, cgen_defs_expr, cgen_defs_block, cgen_defs_decl); return true; } diff --git a/decls_cgen.c b/decls_cgen.c index 6b52291..1df359d 100644 --- a/decls_cgen.c +++ b/decls_cgen.c @@ -1,75 +1,10 @@ static bool cgen_decls_stmt(CGenerator *g, Statement *s); static bool cgen_decls_block(CGenerator *g, Block *b); +static bool cgen_decls_decl(CGenerator *g, Declaration *d); static bool cgen_decls_expr(CGenerator *g, Expression *e) { - cgen_recurse_subexprs(g, e, cgen_decls_expr, cgen_decls_block); + cgen_recurse_subexprs(g, e, cgen_decls_expr, cgen_decls_block, cgen_decls_decl); switch (e->kind) { - case EXPR_CALL: { - e->call.c.instance = 0; - assert(e->call.fn->type.kind == TYPE_FN); - FnType *fn_type = &e->call.fn->type.fn; - if (fn_type->constness) { - Value fval; - /* e->call.fn had better be a compile-time constant if it has compile-time arguments */ - if (!eval_expr(g->evalr, e->call.fn, &fval)) - return false; - FnExpr *f = fval.fn; - /* directly calling a function; might need to generate a copy of this function */ - - /* OPTIM should we really be constructing a tuple & type every time? */ - Value *compile_time_args = NULL; - Type *tuple_types = NULL; - size_t nparams = arr_len(fn_type->types)-1; - Value *which_are_const_val = arr_add(&compile_time_args); - U64 *which_are_const = &which_are_const_val->u64; - Type *u64t = arr_add(&tuple_types); - u64t->kind = TYPE_BUILTIN; - u64t->flags = TYPE_IS_RESOLVED; - u64t->builtin = BUILTIN_U64; - *which_are_const = 0; - int semi_const_arg_index = 0; - for (size_t i = 0; i < nparams; i++) { - Expression *arg = &e->call.arg_exprs[i]; - if (arg_is_const(arg, fn_type->constness[i])) { - if (fn_type->constness[i] == CONSTNESS_SEMI) { - if (semi_const_arg_index >= 64) { - err_print(e->where, "You can't have more than 64 semi-constant parameters in a function at the moment."); - return false; - } - *which_are_const |= ((U64)1) << semi_const_arg_index; - semi_const_arg_index++; - } - 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++; - } - } - 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, *which_are_const)) - return false; - cgen_write(g, ";"); - cgen_nl(g); - } - arr_clear(&tuple_types); - e->call.c.instance = (U32)instance_number; - } - } - } break; case EXPR_FN: e->fn.c.name = NULL; if (!e->fn.c.id) diff --git a/hash_tables.c b/instance_table.c index 58ccbfd..5da4a77 100644 --- a/hash_tables.c +++ b/instance_table.c @@ -217,24 +217,24 @@ static bool val_eq(Value u, Value v, Type *t) { } /* - for a value hash table, you must either ALWAYS or NEVER use an allocator - all values in the hash table must have the same type. - returns true iff the value was already present, and sets associated_number accordingly. - otherwise, associates the value with associated_number, and returns false. + if already_exists is not NULL, this will create the instance if it does not exist, + and set already_exists accordingly */ -static bool val_hash_table_adda(Allocator *a, HashTable *h, Value v, Type *t, I64 *associated_number) { +/* OPTIM: store instances in a block array (remember that the pointers need to stay valid!) */ +static Instance *instance_table_adda(Allocator *a, HashTable *h, Value v, Type *t, + bool *already_exists) { if (h->n * 2 >= h->cap) { - U64 new_cap = h->cap * 2 + 2; - ValNumPair *new_data = a ? allocr_malloc(a, (size_t)new_cap * sizeof *new_data) + U64 new_cap = h->cap * 2 + 3; + Instance **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; + Instance **old_data = h->data; bool *old_occupied = h->occupied; for (U64 i = 0; i < h->cap; i++) { /* re-hash */ if (old_occupied[i]) { - U64 index = val_hash(old_data[i].val, t) % new_cap; + U64 index = val_hash(old_data[i]->val, t) % new_cap; while (new_occupied[index]) { index++; if (index >= new_cap) @@ -255,67 +255,37 @@ static bool val_hash_table_adda(Allocator *a, HashTable *h, Value v, Type *t, I6 } h->cap = new_cap; } - ValNumPair *data = h->data; + Instance **data = h->data; U64 index = val_hash(v, t) % h->cap; while (1) { if (h->occupied[index]) { - if (val_eq(v, data[index].val, t)) { - *associated_number = data[index].num; - return true; + if (val_eq(v, data[index]->val, t)) { + *already_exists = true; + return data[index]; } } else break; index++; if (index >= h->cap) index -= h->cap; } - data[index].val = v; - data[index].num = *associated_number; - h->occupied[index] = true; - h->n++; - return false; + if (already_exists) { + /* create, because it doesn't exist */ + *already_exists = false; + data[index] = a ? allocr_malloc(a, sizeof *data[index]) + : malloc(sizeof *data[index]); + data[index]->val = v; + h->occupied[index] = true; + h->n++; + return data[index]; + } + return NULL; } -/* see above */ -static bool val_hash_table_add(HashTable *h, Value v, Type *t, I64 *associated_number) { - return val_hash_table_adda(NULL, h, v, t, associated_number); -} +#if 0 /* 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) { - HashTable h = {0}; - Type type; - type.kind = TYPE_BUILTIN; - type.builtin = BUILTIN_I64; - type.flags = TYPE_IS_RESOLVED; - for (I64 n = 0; n < 100; n++) { - Value v = {.i64 = n * n}; - if (val_hash_table_add(&h, v, &type, &n)) { - assert(!*"n*n already exists."); - } - } - for (I64 n = 0; n < 100; n++) { - Value v = {.i64 = n * n}; - I64 m = 0; - if (!val_hash_table_add(&h, v, &type, &m)) { - assert(!*"n*n does not exist."); - } - if (m != n) { - assert(!*"n*n exists, but has wrong associated value."); - } - } - I64 x = 100; - Value v = {.i64 = 8}; - if (val_hash_table_add(&h, v, &type, &x)) { - assert(!*"8 exists"); - } - hash_table_free(&h); -} - -static void hash_table_test(void) { - val_hash_table_test(); -} +#endif @@ -1,6 +1,7 @@ /* TODO: -type parameters (e.g. fn(foo @ type) {x: foo;}) +declarations of things with constant params +deal with typing functions with type parameters (we need to type every single instance) struct parameters don't allow while {3; 5} (once break is added) @@ -389,6 +389,11 @@ static bool parse_type(Parser *p, Type *type) { } } /* Not a builtin */ + if (t->token->kw == KW_TYPE) { + type->kind = TYPE_TYPE; + t->token++; + break; + } switch (t->token->kw) { case KW_FN: { /* function type */ @@ -1,5 +1,5 @@ #!/bin/sh -valgrind -q --track-origins=yes --error-exitcode=1 ./toc test.toc || exit 1 +valgrind -q --track-origins=yes --error-exitcode=1 --malloc-fill=0xcd ./toc test.toc || exit 1 if [ "$1" = "c" ]; then gcc out.c && ./a.out elif [ "$1" = "pc" ]; then @@ -6,13 +6,24 @@ puti @= fn(x: int) { // #C("printf(\"%f\\n\", (double)x); // "); // }; -// f@= fn(x: int, y :@ int) int { -// x+y -// }; - -asdf @= fn(x :@= 18) int { x }; +f@= fn(x : int, y :@ int) int { + x+y +}; main @= fn() { - something := asdf; - puti(something(100)); + something := f(10, 20); + puti(something); + something2 @= f(10, 20); + puti(something2); + something3 := f(10, 10+10); + puti(something3); + something4 := f(10, 23); + puti(something4); + r := 20; + something5 := f(10, r); + puti(something5); +g := f; +something6 := g(10, r); +puti(something6); + }; @@ -27,5 +27,4 @@ static void test_all(void) { arr_test(); block_arr_test(); idents_test(); - hash_table_test(); } @@ -35,7 +35,7 @@ static Type *type_inner(Type *t) { #include "arr.c" #include "blockarr.c" #include "str.c" -#include "hash_tables.c" +#include "instance_table.c" #include "identifiers.c" #include "tokenizer.c" diff --git a/tokenizer.c b/tokenizer.c index 06ffdcc..342bbd7 100644 --- a/tokenizer.c +++ b/tokenizer.c @@ -7,7 +7,7 @@ static const char *keywords[KW_COUNT] = "if", "elif", "else", "while", "each", "return", "fn", "as", "new", "del", "struct", "int", "i8", "i16", "i32", "i64", - "u8", "u16", "u32", "u64", "float", "f32", "f64", + "u8", "u16", "u32", "u64", "float", "f32", "f64", "Type", "char", "bool", "true", "false"}; static inline const char *kw_to_str(Keyword k) { return keywords[k]; } diff --git a/typedefs_cgen.c b/typedefs_cgen.c index 77ea7f5..be2785d 100644 --- a/typedefs_cgen.c +++ b/typedefs_cgen.c @@ -1,4 +1,5 @@ static bool typedefs_stmt(CGenerator *g, Statement *s); +static bool typedefs_decl(CGenerator *g, Declaration *d); static bool typedefs_block(CGenerator *g, Block *b) { Block *prev = g->block; @@ -12,7 +13,7 @@ static bool typedefs_block(CGenerator *g, Block *b) { } static bool typedefs_expr(CGenerator *g, Expression *e) { - cgen_recurse_subexprs(g, e, typedefs_expr, typedefs_block); + cgen_recurse_subexprs(g, e, typedefs_expr, typedefs_block, typedefs_decl); if (e->kind == EXPR_FN) { /* needs to go before decls_cgen.c... */ e->fn.c.id = g->ident_counter++; @@ -447,7 +447,7 @@ static bool type_resolve(Typer *tr, Type *t, Location where) { err_print(where, "Use of non-type identifier %s as type.", s); info_print(decl->where, "%s is declared here.", s); free(s); - return s; + return false; } /* resolve inner type */ Value *val = decl_val_at_index(decl, index); @@ -600,7 +600,10 @@ 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 */ + { + HashTable z = {0}; + e->fn.instances = z; + } FnExpr *prev_fn = tr->fn; FnExpr *f = &e->fn; if (!type_of_fn(tr, e, t)) { @@ -933,6 +936,7 @@ static bool types_expr(Typer *tr, Expression *e) { } break; case EXPR_CALL: { CallExpr *c = &e->call; + c->instance = NULL; Expression *f = c->fn; if (f->kind == EXPR_IDENT) { /* allow calling a function before declaring it */ @@ -1062,13 +1066,28 @@ static bool types_expr(Typer *tr, Expression *e) { } } if (fn_type->constness) { - /* evaluate compile-time arguments */ + /* evaluate compile-time arguments + add an instance */ + Type table_index_type; + table_index_type.flags = TYPE_IS_RESOLVED; + table_index_type.kind = TYPE_TUPLE; + table_index_type.tuple = NULL; + Type *u64t = arr_add(&table_index_type.tuple); + u64t->flags = TYPE_IS_RESOLVED; + u64t->kind = TYPE_BUILTIN; + u64t->builtin = BUILTIN_U64; + Value table_index; + table_index.tuple = NULL; + /* we need to keep table_index's memory around because instance_table_add makes a copy of it to compare against. */ + Value *which_are_const_val = typer_arr_add(tr, &table_index.tuple); + U64 *which_are_const = &which_are_const_val->u64; + *which_are_const = 0; + int semi_const_index = 0; for (size_t i = 0; i < arr_len(fn_type->types)-1; i++) { bool should_be_evald = arg_is_const(&new_args[i], fn_type->constness[i]); if (should_be_evald) { - Value arg_val; - if (!eval_expr(tr->evalr, &new_args[i], &arg_val)) { + Value *arg_val = typer_arr_add(tr, &table_index.tuple); + if (!eval_expr(tr->evalr, &new_args[i], arg_val)) { if (tr->evalr->enabled) { info_print(new_args[i].where, "(error occured while trying to evaluate compile-time argument, argument #%lu)", (unsigned long)i); } @@ -1076,10 +1095,35 @@ static bool types_expr(Typer *tr, Expression *e) { } new_args[i].kind = EXPR_VAL; new_args[i].flags = 0; - new_args[i].val = arg_val; - i++; + new_args[i].val = *arg_val; + + Type *type = arr_add(&table_index_type.tuple); + *type = fn_type->types[i+1]; + + if (fn_type->constness[i] == CONSTNESS_SEMI) { + if (semi_const_index >= 64) { + err_print(new_args[i].where, "You can't have more than 64 semi-constant arguments to a function at the moment (sorry)."); + return false; + } + *which_are_const |= ((U64)1) << semi_const_index; + } + } + if (fn_type->constness[i] == CONSTNESS_SEMI) { + semi_const_index++; } } + + /* the function had better be a compile time constant if it has constant params */ + Value fn_val = {0}; + if (!eval_expr(tr->evalr, f, &fn_val)) + return false; + + FnExpr *fn = fn_val.fn; + + bool instance_already_exists; + c->instance = instance_table_adda(tr->allocr, &fn->instances, table_index, &table_index_type, &instance_already_exists); + c->instance->c.id = fn->instances.n; /* let's help cgen out and assign an ID to this */ + arr_clear(&table_index_type.tuple); } *t = *ret_type; c->arg_exprs = new_args; @@ -222,6 +222,7 @@ typedef enum { KW_FLOAT, KW_F32, KW_F64, + KW_TYPE, KW_CHAR, KW_BOOL, KW_TRUE, @@ -430,14 +431,21 @@ typedef enum { } BinaryOp; typedef struct { + Value val; + struct { + U64 id; + } c; +} Instance; + +typedef struct { struct Expression *fn; union { struct Argument *args; struct Expression *arg_exprs; }; + Instance *instance; /* NULL = ordinary function, no compile time args */ struct { IdentID id; - U32 instance; /* 0 = ordinary function, no compile time args */ } c; } CallExpr; @@ -491,23 +499,19 @@ typedef struct { U64 cap; } HashTable; -/* these are found in value hash tables */ -typedef struct { - Value val; - I64 num; -} ValNumPair; - typedef struct FnExpr { struct Declaration *params; /* declarations of the parameters to this function */ struct Declaration *ret_decls; /* array of decls, if this has named return values. otherwise, NULL */ Type ret_type; Block body; + HashTable instances; /* for fns with constant parameters. the key is a tuple where + the first element is a u64 value whose ith bit (1<<i) is 1 + if the ith semi-constant parameter is constant. + */ struct { /* if name = NULL, this is an anonymous function, and id will be the ID of the fn. */ Identifier name; IdentID id; - HashTable *instances; /* for fns with constant parameters. the key is a tuple of the - constant parameters (note that this can be a 1-tuple) */ } c; } FnExpr; /* an expression such as fn(x: int) int { 2 * x } */ |