diff options
-rw-r--r-- | copy.c | 7 | ||||
-rw-r--r-- | eval.c | 15 | ||||
-rw-r--r-- | identifiers.c | 3 | ||||
-rw-r--r-- | main.c | 7 | ||||
-rw-r--r-- | parse.c | 1 | ||||
-rwxr-xr-x | runv | 2 | ||||
-rw-r--r-- | test.toc | 86 | ||||
-rw-r--r-- | types.c | 111 | ||||
-rw-r--r-- | types.h | 7 |
9 files changed, 133 insertions, 106 deletions
@@ -182,7 +182,8 @@ static void copy_expr(Copier *c, Expression *out, Expression *in) { case EXPR_EACH: { EachExpr *ein = &in->each; EachExpr *eout = &out->each; - copy_type(c, &eout->type, &ein->type); + if (ein->flags & EACH_ANNOTATED_TYPE) + copy_type(c, &eout->type, &ein->type); if (ein->flags & EACH_IS_RANGE) { copy_expr(c, eout->range.from = allocr_malloc(a, sizeof *eout->range.from), ein->range.from); if (ein->range.to) @@ -294,7 +295,7 @@ static void copy_block(Copier *c, Block *out, Block *in) { *out = *in; size_t nstmts = arr_len(in->stmts); out->stmts = NULL; - out->parent = c->block; + Block *prev = c->block; c->block = out; if (in->ret_expr) copy_expr(c, out->ret_expr = allocr_malloc(c->allocr, sizeof *out->ret_expr), in->ret_expr); @@ -303,5 +304,5 @@ static void copy_block(Copier *c, Block *out, Block *in) { for (size_t i = 0; i < nstmts; i++) { copy_stmt(c, &out->stmts[i], &in->stmts[i]); } - c->block = out->parent; + c->block = prev; } @@ -1,5 +1,5 @@ static bool types_block(Typer *tr, Block *b); -static bool types_decl(Typer *tr, Declaration *d); +static bool types_decl(Typer *tr, Declaration *d, TypesDeclFlags flags); static bool type_resolve(Typer *tr, Type *t, Location where); static size_t compiler_sizeof(Type *t); static bool eval_block(Evaluator *ev, Block *b, Type *t, Value *v); @@ -332,9 +332,10 @@ static void fprint_val_ptr(FILE *f, void *p, Type *t) { } fprintf(f, "]"); break; - case TYPE_EXPR: break; + case TYPE_EXPR: + assert(0); + break; } - assert(0); } static void fprint_val(FILE *f, Value v, Type *t) { @@ -1317,18 +1318,14 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) { Declaration *d = NULL; if (is_decl) { d = idecl->decl; - if (!types_decl(ev->typer, d)) return false; + if (!types_decl(ev->typer, d, 0)) return false; assert(d->type.flags & TYPE_IS_RESOLVED); } if (idecl->flags & IDECL_HAS_VAL) { *v = idecl->val; } else if (is_decl && (d->flags & DECL_IS_CONST)) { if (!(d->flags & DECL_FOUND_VAL)) { - if (!(d->flags & DECL_HAS_EXPR)){ - print_location(d->where); - abort(); - assert(d->flags & DECL_HAS_EXPR); /* KEEP */ - } + assert(d->flags & DECL_HAS_EXPR); /* KEEP */ if (!eval_expr(ev, &d->expr, &d->val)) return false; d->flags |= DECL_FOUND_VAL; } diff --git a/identifiers.c b/identifiers.c index b7f5e06..7aa6ee8 100644 --- a/identifiers.c +++ b/identifiers.c @@ -144,12 +144,13 @@ static char *ident_to_str(Identifier i) { return str; } -static void ident_add_decl(Identifier i, struct Declaration *d, struct Block *b) { +static IdentDecl *ident_add_decl(Identifier i, struct Declaration *d, struct Block *b) { IdentDecl *id_decl = arr_add(&i->decls); id_decl->decl = d; id_decl->scope = b; id_decl->flags = 0; id_decl->kind = IDECL_DECL; + return id_decl; } static IdentDecl *ident_decl(Identifier i) { @@ -1,9 +1,13 @@ /* TODO: test ArrInt @= Arr(int); -new version of copy_val for copying types +make sure fn(t @ Type, x : t) t works +check fn(x @ int, y := x) +new version of copy_val for copying types?? there are probably places where we enter a function and never exit (in typing?) if there's an error +switch struct."field" to struct["field"] + packages X @= newtype(int); or something don't allow while {3; 5} (once break is added) @@ -19,6 +23,7 @@ allow omission of trailing ; in foo @= fn() {}? #include "toc.c" + int main(int argc, char **argv) { #ifdef TOC_DEBUG test_all(); @@ -770,7 +770,6 @@ static bool parse_block(Parser *p, Block *b) { b->flags = 0; Tokenizer *t = p->tokr; Block *prev_block = p->block; - b->parent = prev_block; p->block = b; if (!token_is_kw(t->token, KW_LBRACE)) { tokr_err(t, "Expected '{' to open block."); @@ -12,7 +12,7 @@ fi valgrind $FLAGS --track-origins=yes --error-exitcode=1 --malloc-fill=0xcd --free-fill=0xef --num-callers=100 ./toc $tocf || exit 1 if [ "$1" = "c" ]; then - gcc out.c && ./a.out + gcc out.c -g && ./a.out elif [ "$1" = "pc" ]; then cat out.c fi @@ -1,51 +1,53 @@ -// // puti @= fn(x: int) { -// // #C("printf(\"%ld\\n\", (long)x); -// // "); -// // }; -// // putf @= fn(x: float) { -// // #C("printf(\"%f\\n\", (double)x); -// // "); -// // }; - -// Arr @= fn (t @ Type) Type { -// struct { -// data : t; -// // len, cap : u64; -// } +puti @= fn(x: int) { + #C("printf(\"%ld\\n\", (long)x); +"); +}; +// putf @= fn(x: float) { +// #C("printf(\"%f\\n\", (double)x); +// "); // }; -// // todo: test that t @ type doesn't cause problems -// arr_add @= fn(t @ Type, a : &Arr(t)) { -// // if a.len >= a.cap { -// // a.cap = a.cap * 2 + 2; -// // new_data := new(t, a.cap); -// // each i := 0..a.len { -// // new_data[i] = a.data[i]; -// // } -// // a.data = new_data; -// // } -// // a.data[a.len] = x; -// // a.len += 1; -// }; +Arr @= fn (t @ Type) Type { + struct { + data : []t; + len, cap : int; + } +}; +// todo: test that t @ type doesn't cause problems +arr_add @= fn(t @ Type, a : &Arr(t), x : t) { + if a.len >= a.cap { + a.cap = a.cap * 2 + 2; + new_data := new(t, a.cap); + each i := 0..a.len-1 { + new_data[i] = a.data[i]; + } + a.data = new_data; + } + a.data[a.len] = x; + a.len += 1; +}; -// main @= fn() { -// // arr : Arr(int); -// // // arr_add(int, &arr, 5); -// // // arr_add(int, &arr, 10); -// // // arr_add(int, &arr, 20); -// // // each i := 0..arr.len - 1 { -// // // puti(arr.data[i]); -// // // } -// }; -// // t @= fn(x @ Type) Type { struct { t: x; } }; -// // // pass the wrong thing to t, and the error is in the wrong place +main @= fn() { + arr : Arr(int); + arr_add(int, &arr, 5); + arr_add(int, &arr, 10); + arr_add(int, &arr, 20); + each i := 0..arr.len - 1 { + puti(arr.data[i]); + } +}; -// // f @= fn(x: t(int)) {}; +// t @= fn(x @ Type) Type { struct { t: x; } }; +// // pass the wrong thing to t, and the error is in the wrong place -f @= fn(t @ Type, x : t) { -}; +// f @= fn(x: t(int)) {}; -main @= fn() { f(int, 3); };
\ No newline at end of file +// f @= fn(t @ Type, x : t) { +// }; + +// main @= fn() { +// f(int,3); +// };
\ No newline at end of file @@ -1,5 +1,4 @@ static bool types_stmt(Typer *tr, Statement *s); -static bool types_decl(Typer *tr, Declaration *d); static bool types_expr(Typer *tr, Expression *e); static bool types_block(Typer *tr, Block *b); static bool type_resolve(Typer *tr, Type *t, Location where); @@ -184,7 +183,8 @@ static bool expr_must_lval(Expression *e) { } enum { - TYPE_OF_FN_NO_COPY_EVEN_IF_CONST = 0x01, + /* is f an instance? (changes behaviour a bit) */ + TYPE_OF_FN_IS_INSTANCE = 0x01 }; static bool type_of_fn(Typer *tr, FnExpr *f, Location where, Type *t, U16 flags) { @@ -198,7 +198,7 @@ static bool type_of_fn(Typer *tr, FnExpr *f, Location where, Type *t, U16 flags) FnExpr fn_copy; - if (!(flags & TYPE_OF_FN_NO_COPY_EVEN_IF_CONST) && fn_has_any_const_params(f)) { + if (!(flags & TYPE_OF_FN_IS_INSTANCE) && fn_has_any_const_params(f)) { Copier cop = copier_create(tr->allocr, tr->block); copy_fn_expr(&cop, &fn_copy, f, false); f = &fn_copy; @@ -214,8 +214,11 @@ static bool type_of_fn(Typer *tr, FnExpr *f, Location where, Type *t, U16 flags) entered_fn = true; for (param_idx = 0; param_idx < nparams; param_idx++) { Declaration *param = &f->params[param_idx]; - print_location(param->where); - if (!types_decl(tr, param)) { + U16 types_decl_flags = 0; + if (!(flags & TYPE_OF_FN_IS_INSTANCE) && fn_has_any_const_params(f)) { + types_decl_flags |= TYPES_DECL_DONT_RESOLVE; + } + if (!types_decl(tr, param, types_decl_flags)) { success = false; goto ret; } @@ -225,10 +228,6 @@ static bool type_of_fn(Typer *tr, FnExpr *f, Location where, Type *t, U16 flags) goto ret; } - if (!type_resolve(tr, ¶m->type, where)) { - success = false; - goto ret; - } U32 is_at_all_const = param->flags & (DECL_IS_CONST | DECL_SEMI_CONST); if (is_at_all_const) { if (!t->fn.constness) { @@ -278,7 +277,7 @@ static bool type_of_fn(Typer *tr, FnExpr *f, Location where, Type *t, U16 flags) if (f->ret_decls && f->ret_type.kind == TYPE_VOID /* haven't found return type yet */) { /* find return type */ arr_foreach(f->ret_decls, Declaration, d) { - if (!types_decl(tr, d)) { + if (!types_decl(tr, d, 0)) { success = false; goto ret; } @@ -305,7 +304,7 @@ static bool type_of_fn(Typer *tr, FnExpr *f, Location where, Type *t, U16 flags) arr_foreach(f->ret_decls, Declaration, decl) { - if (!types_decl(tr, decl)) { + if (!types_decl(tr, decl, 0)) { success = false; goto ret; } @@ -341,13 +340,15 @@ static bool type_of_ident(Typer *tr, Location where, Identifier i, Type *t) { case IDECL_DECL: { Declaration *d = decl->decl; bool captured = false; - if (decl->scope != NULL) - for (Block *block = tr->block; block && block != decl->scope; block = block->parent) { - if (block->flags & BLOCK_IS_FN) { + if (decl->scope != NULL) { + /* go back through scopes */ + for (Block **block = arr_last(tr->blocks); *block && *block != decl->scope; block--) { + if ((*block)->flags & BLOCK_IS_FN) { captured = true; break; } } + } if (captured && !(d->flags & DECL_IS_CONST)) { err_print(where, "Variables cannot be captured into inner functions (but constants can)."); return false; @@ -387,7 +388,7 @@ static bool type_of_ident(Typer *tr, Location where, Identifier i, Type *t) { free(s); } else { /* let's type the declaration, and redo this (for evaling future functions) */ - if (!types_decl(tr, d)) return false; + if (!types_decl(tr, d, 0)) return false; return type_of_ident(tr, where, i, t); } return false; @@ -511,6 +512,8 @@ static bool type_resolve(Typer *tr, Type *t, Location where) { return true; } + + static bool type_can_be_truthy(Type *t) { assert(t->flags & TYPE_IS_RESOLVED); switch (t->kind) { @@ -1171,34 +1174,22 @@ static bool types_expr(Typer *tr, Expression *e) { U64 *which_are_const = &which_are_const_val->u64; *which_are_const = 0; int semi_const_index = 0; - /* keep track of the declaration so we can add values */ + /* keep track of the declaration */ Declaration *param_decl = fn->params; size_t ident_idx = 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 = typer_arr_add(tr, &table_index.tuple); - printf("Evaluating expression: "); - print_location(new_args[i].where); - - if (!eval_expr(tr->evalr, &new_args[i], arg_val)) { + 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)", 1+(unsigned long)i); } return false; } - - Type *type = arr_add(&table_index_type.tuple); - *type = fn_type->types[i+1]; - /* we need to check the type here so copy_val doesn't mess up */ - Type *expected = type; - Type *got = &new_args[i].type; - if (!type_eq(type, &new_args[i].type)) { - char *estr = type_to_str(expected); - char *gstr = type_to_str(got); - err_print(new_args[i].where, "Expected type %s as %lu%s argument to function, but got %s.", estr, 1+(unsigned long)i, ordinals(1+i), gstr); - return false; - } + + Type *type = &new_args[i].type; + *(Type *)arr_add(&table_index_type.tuple) = *type; new_args[i].kind = EXPR_VAL; new_args[i].flags = EXPR_FOUND_TYPE; @@ -1231,17 +1222,21 @@ static bool types_expr(Typer *tr, Expression *e) { if (!instance_already_exists) { c->instance->fn = fn_copy; /* type param declarations, etc */ - if (!type_of_fn(tr, &c->instance->fn, e->where, &f->type, TYPE_OF_FN_NO_COPY_EVEN_IF_CONST)) + if (!type_of_fn(tr, &c->instance->fn, e->where, &f->type, TYPE_OF_FN_IS_INSTANCE)) return false; /* fix parameter and return types (they were kind of problematic before, because we didn't know about the instance) */ - ret_type = f->type.fn.types; - param_types = ret_type + 1; c->instance->c.id = original_fn->instances.n; /* let's help cgen out and assign an ID to this */ /* type this instance */ - if (!types_fn(tr, fn, &f->type, e->where, c->instance)) + if (!types_fn(tr, fn = &c->instance->fn, &f->type, e->where, c->instance)) return false; + c->instance->fn_type = &f->type; arr_clear(&table_index_type.tuple); + } else { + fn = &c->instance->fn; + f->type = *c->instance->fn_type; } + ret_type = f->type.fn.types; + param_types = ret_type + 1; } /* check types of arguments */ @@ -1668,18 +1663,31 @@ static bool types_expr(Typer *tr, Expression *e) { return true; } +static bool typer_block_enter(Typer *tr, Block *b) { + tr->block = b; + *(Block **)arr_adda(&tr->blocks, tr->allocr) = b; + if (!block_enter(b, b->stmts, SCOPE_CHECK_REDECL)) return false; + return true; +} + +static void typer_block_exit(Typer *tr) { + Block *b = tr->block; + block_exit(b, b->stmts); + arr_remove_last(&tr->blocks); + tr->block = *(Block **)arr_last(tr->blocks); +} + static bool types_block(Typer *tr, Block *b) { if (b->flags & BLOCK_FOUND_TYPES) return true; bool success = true; - Block *prev_block = tr->block; - tr->block = b; - if (!block_enter(b, b->stmts, SCOPE_CHECK_REDECL)) return false; + if (!typer_block_enter(tr, b)) + return false; b->ret_expr = NULL; arr_foreach(b->stmts, Statement, s) { if (!types_stmt(tr, s)) success = false; - if (s->kind == STMT_EXPR && (s->flags & STMT_EXPR_NO_SEMICOLON)) { + else if (s->kind == STMT_EXPR && (s->flags & STMT_EXPR_NO_SEMICOLON)) { /* not voided */ Expression *e = &s->expr; if (e->type.kind == TYPE_VOID) { @@ -1688,24 +1696,27 @@ static bool types_block(Typer *tr, Block *b) { || e->kind == EXPR_WHILE || e->kind == EXPR_EACH)) { err_print(e->where, "void expression must be followed by ;"); + success = false; + goto ret; } } else { if (s != (Statement *)arr_last(b->stmts)) { err_print(e->where, "Return value must be the last statement in a block."); - return false; + success = false; + goto ret; } b->ret_expr = e; arr_remove_last(&b->stmts); } } } - block_exit(b, b->stmts); - tr->block = prev_block; + ret: + typer_block_exit(tr); b->flags |= BLOCK_FOUND_TYPES; return success; } -static bool types_decl(Typer *tr, Declaration *d) { +static bool types_decl(Typer *tr, Declaration *d, TypesDeclFlags flags) { bool success = true; if (d->flags & DECL_FOUND_TYPE) return true; Declaration **dptr = typer_arr_add(tr, &tr->in_decls); @@ -1713,7 +1724,12 @@ static bool types_decl(Typer *tr, Declaration *d) { if (d->flags & DECL_ANNOTATES_TYPE) { /* type supplied */ assert(d->type.kind != TYPE_VOID); /* there's no way to annotate void */ - if (!type_resolve(tr, &d->type, d->where)) { + /* + if it's a parameter, only partially resolve the type, so that, + for example, fn (x @ Type, y : x) works + */ + if (!(flags & TYPES_DECL_DONT_RESOLVE) + && !type_resolve(tr, &d->type, d->where)) { success = false; goto ret; } @@ -1816,7 +1832,7 @@ static bool types_stmt(Typer *tr, Statement *s) { } break; case STMT_DECL: - if (!types_decl(tr, &s->decl)) + if (!types_decl(tr, &s->decl, 0)) return false; break; case STMT_RET: @@ -1855,12 +1871,13 @@ static bool types_stmt(Typer *tr, Statement *s) { static void typer_create(Typer *tr, Evaluator *ev, Allocator *allocr) { tr->block = NULL; + tr->blocks = NULL; tr->fn = NULL; tr->evalr = ev; tr->in_decls = NULL; tr->in_expr_decls = NULL; tr->allocr = allocr; - + *(Block **)arr_adda(&tr->blocks, allocr) = NULL; } static bool types_file(Typer *tr, ParsedFile *f) { @@ -388,7 +388,6 @@ typedef struct Block { Location start; Location end; struct Statement *stmts; - struct Block *parent; struct Expression *ret_expr; /* the return expression of this block, e.g. {foo(); 3} => 3 NULL for no expression. */ } Block; @@ -529,6 +528,7 @@ typedef struct FnExpr { typedef struct Instance { Value val; /* key into hash table */ FnExpr fn; /* the typed function */ + Type *fn_type; /* type of fn */ struct { U64 id; } c; @@ -701,6 +701,7 @@ typedef struct Typer { 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 */ Block *block; + Block **blocks; /* dyn array of all the block's we're in ([0] = NULL for global scope) */ FnExpr *fn; /* the function we're currently parsing. */ } Typer; @@ -717,3 +718,7 @@ typedef struct CGenerator { Identifier main_ident; Identifiers *idents; } CGenerator; + +typedef enum { + TYPES_DECL_DONT_RESOLVE = 0x01 /* don't resolve the annotated type (used for parameters). */ +} TypesDeclFlags; |