diff options
-rw-r--r-- | cgen.c | 34 | ||||
-rw-r--r-- | copy.c | 14 | ||||
-rw-r--r-- | decls_cgen.c | 34 | ||||
-rw-r--r-- | eval.c | 31 | ||||
-rw-r--r-- | main.c | 4 | ||||
-rw-r--r-- | parse.c | 15 | ||||
-rwxr-xr-x | test-build.sh | 2 | ||||
-rw-r--r-- | test.toc | 3 | ||||
-rw-r--r-- | types.c | 124 | ||||
-rw-r--r-- | types.h | 13 |
10 files changed, 147 insertions, 127 deletions
@@ -2135,16 +2135,6 @@ static void cgen_stmt(CGenerator *g, Statement *s) { unsigned has_expr = r->flags & RET_HAS_EXPR; cgen_ret(g, r->referring_to, has_expr ? &r->expr : NULL); } break; - case STMT_INCLUDE: { - Include *i = s->inc; - if (i->inc_file && (i->inc_file->flags & INC_FILE_CGEND)){ - /* already generated */ - } else { - if (i->inc_file) i->inc_file->flags |= INC_FILE_CGEND; - arr_foreach(i->stmts, Statement, sub) - cgen_stmt(g, sub); - } - } break; case STMT_BREAK: { Block *b = s->referring_to; cgen_deferred_up_to(g, b); @@ -2165,6 +2155,13 @@ static void cgen_stmt(CGenerator *g, Statement *s) { case STMT_USE: case STMT_MESSAGE: break; + case STMT_INLINE_BLOCK: + arr_foreach(s->inline_block, Statement, sub) + cgen_stmt(g, sub); + break; + case STMT_INCLUDE: + assert(0); + break; } } @@ -2210,16 +2207,6 @@ static void cgen_defs_stmt(CGenerator *g, Statement *s) { if (s->ret->flags & RET_HAS_EXPR) cgen_defs_expr(g, &s->ret->expr); break; - case STMT_INCLUDE: { - Include *i = s->inc; - if (i->inc_file && (i->inc_file->flags & INC_FILE_CGEND_DEFS)) { - /* already generated */ - } else { - if (i->inc_file) i->inc_file->flags |= INC_FILE_CGEND_DEFS; - arr_foreach(i->stmts, Statement, sub) - cgen_defs_stmt(g, sub); - } - } break; case STMT_BREAK: case STMT_CONT: case STMT_MESSAGE: @@ -2230,6 +2217,13 @@ static void cgen_defs_stmt(CGenerator *g, Statement *s) { case STMT_USE: cgen_defs_expr(g, &s->use->expr); break; + case STMT_INLINE_BLOCK: + arr_foreach(s->inline_block, Statement, sub) + cgen_defs_stmt(g, sub); + break; + case STMT_INCLUDE: + assert(0); + break; } } @@ -378,6 +378,7 @@ static void copy_decl(Copier *c, Declaration *out, Declaration *in) { static void copy_stmt(Copier *c, Statement *out, Statement *in) { *out = *in; + assert(!(in->flags & STMT_TYPED)); switch (in->kind) { case STMT_RET: out->ret = copier_malloc(c, sizeof *out->ret); @@ -388,15 +389,7 @@ static void copy_stmt(Copier *c, Statement *out, Statement *in) { case STMT_INCLUDE: out->inc = copier_malloc(c, sizeof *out->inc); *out->inc = *in->inc; - if (in->flags & STMT_TYPED) { - size_t nstmts = arr_len(in->inc->stmts); - arr_set_lena(out->inc->stmts, nstmts, c->allocr); - for (size_t i = 0; i < nstmts; ++i) { - copy_stmt(c, &out->inc->stmts[i], &in->inc->stmts[i]); - } - } else { - copy_expr(c, &out->inc->filename, &in->inc->filename); - } + copy_expr(c, &out->inc->filename, &in->inc->filename); break; case STMT_EXPR: out->expr = copy_expr_(c, in->expr); @@ -420,6 +413,9 @@ static void copy_stmt(Copier *c, Statement *out, Statement *in) { *out->use = *in->use; copy_expr(c, &out->use->expr, &in->use->expr); break; + case STMT_INLINE_BLOCK: + assert(0); /* only exists after typing */ + break; } } diff --git a/decls_cgen.c b/decls_cgen.c index 80b6a38..5b2603b 100644 --- a/decls_cgen.c +++ b/decls_cgen.c @@ -138,16 +138,6 @@ static void cgen_sdecls_stmt(CGenerator *g, Statement *s) { if (r->flags & RET_HAS_EXPR) cgen_sdecls_expr(g, &r->expr); } break; - case STMT_INCLUDE: { - Include *i = s->inc; - if (i->inc_file && (i->inc_file->flags & INC_FILE_CGEND_SDECLS)) { - /* already generated */ - } else { - if (i->inc_file) i->inc_file->flags |= INC_FILE_CGEND_SDECLS; - arr_foreach(i->stmts, Statement, sub) - cgen_sdecls_stmt(g, sub); - } - } break; case STMT_BREAK: if (!s->referring_to->c.break_lbl) { s->referring_to->c.break_lbl = ++g->lbl_counter; @@ -166,6 +156,13 @@ static void cgen_sdecls_stmt(CGenerator *g, Statement *s) { case STMT_USE: cgen_sdecls_expr(g, &s->use->expr); break; + case STMT_INLINE_BLOCK: + arr_foreach(s->inline_block, Statement, sub) + cgen_sdecls_stmt(g, sub); + break; + case STMT_INCLUDE: + assert(0); + break; } } @@ -386,16 +383,6 @@ static void cgen_decls_stmt(CGenerator *g, Statement *s) { if (r->flags & RET_HAS_EXPR) cgen_decls_expr(g, &r->expr); } break; - case STMT_INCLUDE: { - Include *i = s->inc; - if (i->inc_file && (i->inc_file->flags & INC_FILE_CGEND_DECLS)) { - /* already generated */ - } else { - if (i->inc_file) i->inc_file->flags |= INC_FILE_CGEND_DECLS; - arr_foreach(i->stmts, Statement, sub) - cgen_decls_stmt(g, sub); - } - } break; case STMT_BREAK: case STMT_CONT: case STMT_MESSAGE: @@ -406,6 +393,13 @@ static void cgen_decls_stmt(CGenerator *g, Statement *s) { case STMT_USE: cgen_sdecls_expr(g, &s->use->expr); break; + case STMT_INLINE_BLOCK: + arr_foreach(s->inline_block, Statement, sub) + cgen_decls_stmt(g, sub); + break; + case STMT_INCLUDE: + assert(0); + break; } } @@ -1641,7 +1641,7 @@ static void eval_exit_stmts(Statement *stmts, Statement *last_reached) { Declaration *d = s->decl; decl_remove_val(d); } - /* STMT_INCLUDEs are handled by eval_stmt; don't worry */ + /* inline blocks are handled by eval_stmt; don't worry */ } } } @@ -1675,19 +1675,6 @@ static Status eval_stmt(Evaluator *ev, Statement *stmt) { ev->returning = stmt->referring_to; ev->is_break = false; break; - case STMT_INCLUDE: { - Include *i = stmt->inc; - Statement *last_reached = arr_last_ptr(i->stmts); - arr_foreach(i->stmts, Statement, sub) { - if (!eval_stmt(ev, sub)) - return false; - if (ev->returning) { - last_reached = sub; - break; - } - } - eval_exit_stmts(i->stmts, last_reached); - } break; case STMT_MESSAGE: break; case STMT_DEFER: @@ -1695,6 +1682,22 @@ static Status eval_stmt(Evaluator *ev, Statement *stmt) { break; case STMT_USE: break; + case STMT_INLINE_BLOCK: { + Statement *stmts = stmt->inline_block; + Statement *last_reached = arr_last_ptr(stmts); + arr_foreach(stmts, Statement, s) { + if (!eval_stmt(ev, s)) + return false; + if (ev->returning) { + last_reached = s; + break; + } + } + eval_exit_stmts(stmts, last_reached); + } break; + case STMT_INCLUDE: + assert(0); + break; } return true; } @@ -8,10 +8,10 @@ /* @TODO: -#if should not create a block &void null fix including something twice - just use the non-namespacey version if it exists or pick one namespace to use everywhere otherwise + - maybe store info about namespaces which are secretly the same as inline blocks/other namespaces in the Typer &&, || start making a standard library... (printf; stringbuilder would be nice to have) improve type_to_str: @@ -214,7 +214,7 @@ int main(int argc, char **argv) { Typer tr; Evaluator ev; evalr_create(&ev, &tr, &main_allocr); - typer_create(&tr, &ev, &file, &err_ctx, &main_allocr, &globals); + typer_create(&tr, &ev, &err_ctx, &main_allocr, &globals); if (!types_file(&tr, &f)) { err_text_important(&err_ctx, "Errors occured while determining types.\n"); @@ -2869,14 +2869,9 @@ static void fprint_stmt(FILE *out, Statement *s) { } break; case STMT_INCLUDE: { Include *i = s->inc; - if (s->flags & STMT_TYPED) { - arr_foreach(i->stmts, Statement, sub) - fprint_stmt(out, sub); - } else { - fprintf(out, "#include "); - fprint_expr(out, &i->filename); - fprintf(out, ";\n"); - } + fprintf(out, "#include "); + fprint_expr(out, &i->filename); + fprintf(out, ";\n"); } break; case STMT_MESSAGE: { Message *m = s->message; @@ -2909,6 +2904,10 @@ static void fprint_stmt(FILE *out, Statement *s) { fprint_expr(out, &s->use->expr); fprintf(out, ";\n"); break; + case STMT_INLINE_BLOCK: + arr_foreach(s->inline_block, Statement, sub) + fprint_stmt(out, sub); + break; } } diff --git a/test-build.sh b/test-build.sh index ec63972..45a44f7 100755 --- a/test-build.sh +++ b/test-build.sh @@ -1,5 +1,5 @@ #!/bin/sh -echo "tcc -w main.c -o toc" && tcc -w main.c -o toc || exit 1 +echo "tcc -Wall main.c -o toc" && tcc -Wall main.c -o toc || exit 1 # test without any compiler flags for CC in tcc gcc clang g++ ; do CC="$CC" CFLAGS='-Werror' ./build.sh || exit 1 CC="$CC" CFLAGS='-Werror' ./build.sh release || exit 1 @@ -4,7 +4,8 @@ main ::= fn() { #if "hello" { x := 5; } else { - x := 6; + x : FOOTYPE = 6.3 + "foo"; + _+3=bar; } puti(x); } @@ -2162,39 +2162,9 @@ static Status types_expr(Typer *tr, Expression *e) { IfExpr *i = e->if_; IfExpr *curr = i; if (curr->flags & IF_STATIC) { - while (1) { - Expression *cond = curr->cond; - Expression *next = curr->next_elif; - Value v; - if (cond) { - if (!types_expr(tr, cond)) - return false; - if (!eval_expr(tr->evalr, cond, &v)) - return false; - } - if (!cond || val_truthiness(v, &cond->type)) { - Block *true_block = &curr->body; - Statement *last = arr_last_ptr(true_block->stmts); - if (last && last->kind == STMT_EXPR && (last->flags & STMT_EXPR_NO_SEMICOLON)) { - err_print(last->where, "#ifs can't return values."); - return false; - } - e->kind = EXPR_BLOCK; - e->block = true_block; - break; - } - if (!next) break; - curr = next->if_; - } - if (e->kind == EXPR_IF) { - /* all conds were false */ - e->kind = EXPR_BLOCK; - e->block = typer_calloc(tr, 1, sizeof *e->block); - e->block->where = e->where; - e->block->parent = tr->block; - idents_create(&e->block->idents, tr->allocr, e->block); - } - goto expr_block; + /* handled in types_stmt unless there's a problem */ + err_print(e->where, "You can't use #if in this way. It has to be a statement on its own, and can't return a value."); + return false; } Type *curr_type = t; bool has_else = false; @@ -2852,7 +2822,6 @@ static Status types_expr(Typer *tr, Expression *e) { free(order); *t = *ret_type; } break; - expr_block: case EXPR_BLOCK: { Block *b = e->block; if (!types_block(tr, b)) @@ -3623,11 +3592,77 @@ static Status types_decl(Typer *tr, Declaration *d) { return success; } +static Status fix_ident_decls_inline_block(Typer *tr, Statement *stmts) { + Identifiers *idents = typer_get_idents(tr); + arr_foreach(stmts, Statement, s) { + if (s->kind == STMT_DECL) { + Declaration *d = s->decl; + arr_foreach(d->idents, Identifier, ident) { + Identifier i = *ident = ident_translate_forced(*ident, idents); + if (i->decl) { + char *istr = ident_to_str(i); + err_print(d->where, "Redeclaration of identifier %s.", istr); + info_print(i->decl->where, "%s was also declared here.", istr); + free(istr); + return false; + } + i->decl = d; + } + } + } + return true; +} + static Status types_stmt(Typer *tr, Statement *s) { if (s->flags & STMT_TYPED) return true; switch (s->kind) { case STMT_EXPR: { Expression *e = s->expr; + if (e->kind == EXPR_IF && (e->if_->flags & IF_STATIC)) { + /* handle #if */ + IfExpr *curr = e->if_; + while (1) { + Expression *cond = curr->cond; + Expression *next = curr->next_elif; + Value v; + if (cond) { + if (!types_expr(tr, cond)) + return false; + if (!eval_expr(tr->evalr, cond, &v)) + return false; + } + if (!cond || val_truthiness(v, &cond->type)) { + Block *true_block = &curr->body; + Statement *last = arr_last_ptr(true_block->stmts); + if (last && last->kind == STMT_EXPR && (last->flags & STMT_EXPR_NO_SEMICOLON)) { + err_print(last->where, "#ifs can't return values."); + return false; + } + s->kind = STMT_INLINE_BLOCK; + s->inline_block = true_block->stmts; + if (!fix_ident_decls_inline_block(tr, s->inline_block)) + return false; + bool success = true; + arr_foreach(s->inline_block, Statement, sub) { + if (!types_stmt(tr, sub)) { + success = false; + } + } + if (!success) return false; + goto success; + } + if (!next) break; + curr = next->if_; + } + if (e->kind == EXPR_IF) { + /* all conds were false */ + /* empty inline block */ + s->kind = STMT_INLINE_BLOCK; + s->inline_block = NULL; + } + break; + } + if (!types_expr(tr, e)) { return false; } @@ -3696,6 +3731,9 @@ static Status types_stmt(Typer *tr, Statement *s) { return false; size_t filename_len = strlen(filename); IncludedFile *inc_f = NULL; + + s->kind = STMT_INLINE_BLOCK; + if (s->flags & STMT_INC_TO_NMS) { if (!(inc->flags & INC_FORCED)) { inc_f = str_hash_table_get(&tr->included_files, filename, filename_len); @@ -3703,12 +3741,11 @@ static Status types_stmt(Typer *tr, Statement *s) { tr->nms->body.idents = inc_f->main_nms->body.idents; tr->nms->body.idents.scope = &tr->nms->body; tr->nms->points_to = inc_f->main_nms; - inc->inc_file = inc_f; - inc->stmts = inc_f->stmts; + s->inline_block = inc_f->stmts; break; } } - inc->inc_file = inc_f = str_hash_table_insert(&tr->included_files, filename, filename_len); + inc_f = str_hash_table_insert(&tr->included_files, filename, filename_len); inc_f->main_nms = tr->nms; } char *contents = read_file_contents(tr->allocr, filename, s->where); @@ -3737,16 +3774,12 @@ static Status types_stmt(Typer *tr, Statement *s) { if (inc_f) { inc_f->stmts = stmts_inc; } - inc->stmts = stmts_inc; - File *prev = tr->file; - tr->file = file; + s->inline_block = stmts_inc; arr_foreach(stmts_inc, Statement, s_incd) { if (!types_stmt(tr, s_incd)) { - tr->file = prev; return false; } } - tr->file = prev; } break; case STMT_MESSAGE: { Message *m = s->message; @@ -3805,18 +3838,21 @@ static Status types_stmt(Typer *tr, Statement *s) { else typer_arr_add(tr, tr->uses, u); } break; + case STMT_INLINE_BLOCK: + assert(0); /* only exists after typing */ + break; } +success: s->flags |= STMT_TYPED; return true; } -static void typer_create(Typer *tr, Evaluator *ev, File *file, ErrCtx *err_ctx, Allocator *allocr, Identifiers *idents) { +static void typer_create(Typer *tr, Evaluator *ev, ErrCtx *err_ctx, Allocator *allocr, Identifiers *idents) { tr->block = NULL; tr->blocks = NULL; tr->fn = NULL; tr->nms = NULL; tr->evalr = ev; - tr->file = file; tr->err_ctx = err_ctx; tr->in_decls = NULL; tr->had_include_err = false; @@ -915,10 +915,11 @@ typedef enum { STMT_RET, STMT_BREAK, STMT_CONT, - STMT_INCLUDE, + STMT_INCLUDE, /* turns into STMT_INLINE_BLOCK after typing */ STMT_MESSAGE, STMT_DEFER, - STMT_USE + STMT_USE, + STMT_INLINE_BLOCK /* a group of statements acting as one statement */ } StatementKind; enum { @@ -949,11 +950,7 @@ enum { typedef union { U8 flags; - union { - Expression filename; /* before typing */ - struct Statement *stmts; /* after typing */ - }; - IncludedFile *inc_file; + Expression filename; } Include; typedef enum { @@ -989,6 +986,7 @@ typedef struct Statement { Message *message; /* #error, #warn, #info */ Block *referring_to; /* for break/continue; set during typing */ struct Statement *defer; + struct Statement *inline_block; /* statements in an inline block (dynamic array) */ Use *use; }; } Statement; @@ -1044,7 +1042,6 @@ typedef struct Typer { ParsedFile *parsed_file; Namespace *nms; StrHashTable included_files; /* maps to IncludedFile */ - File *file; /* have we had an error because we couldn't find a file that was #include'd (so that we can stop compiling immediately) |