diff options
author | Leo Tenenbaum <pommicket@gmail.com> | 2020-01-03 23:57:33 -0500 |
---|---|---|
committer | Leo Tenenbaum <pommicket@gmail.com> | 2020-01-03 23:57:33 -0500 |
commit | 50c892e0a68c7e6d17ce49edf0c13ada7e1cdbfc (patch) | |
tree | 024761d74f69ebd869ece7475c935b0157b42ff3 | |
parent | 5665bde91427725cf0231cab7e54a6b37b6fba7f (diff) |
fixed a bug with returning
-rw-r--r-- | arr.c | 2 | ||||
-rw-r--r-- | binfile.c | 1 | ||||
-rw-r--r-- | cgen.c | 12 | ||||
-rw-r--r-- | err.c | 6 | ||||
-rw-r--r-- | location.c | 6 | ||||
-rw-r--r-- | main.c | 16 | ||||
-rw-r--r-- | package.c | 139 | ||||
-rw-r--r-- | parse.c | 2 | ||||
-rw-r--r-- | test.toc | 6 | ||||
-rw-r--r-- | toc.c | 7 | ||||
-rw-r--r-- | types.h | 20 |
11 files changed, 195 insertions, 22 deletions
@@ -186,7 +186,7 @@ You shouldn't rely on this, though, e.g. by doing #define arr_last(arr) arr_last_((void *)(arr), sizeof *(arr)) /* one past last, or NULL if empty */ #define arr_end(arr) arr_end_((void *)(arr), sizeof *(arr)) -#define arr_foreach(arr, type, var) for (type *var = arr, *join(var,_foreach_end) = arr_end(arr); var < join(var,_foreach_end); ++var) /* NOTE: < is useful here because currently it's possible for var_foreach_end to be NULL but var could start out not null */ +#define arr_foreach(arr, type, var) for (type *var = arr, *JOIN(var,_foreach_end) = arr_end(arr); var < JOIN(var,_foreach_end); ++var) /* NOTE: < is useful here because currently it's possible for var_foreach_end to be NULL but var could start out not null */ #define arr_remove_last(arr) arr_remove_last_((void **)(arr)), (void)sizeof **(arr) #define arr_remove_lasta(arr, a) arr_remove_lasta_((void **)(arr), sizeof **(arr), (a)) #define arr_copya(out, in, a) do { assert(sizeof *(in) == sizeof **(out)); arr_copya_((void **)(out), (in), sizeof **(out), (a)); } while(0) @@ -15,6 +15,7 @@ static inline void write_u8(FILE *fp, U8 u8) { col = 0; printf("\n"); } + fflush(stdout); #endif } @@ -1819,10 +1819,13 @@ static bool cgen_decl(CGenerator *g, Declaration *d) { return true; } -/* does NOT call cgen_expr_pre for ret. */ static bool cgen_ret(CGenerator *g, Expression *ret) { assert((g->fn->ret_type.kind == TYPE_VOID) == (ret == NULL)); - if (ret) assert(type_eq(&g->fn->ret_type, &ret->type)); + if (ret) { + assert(type_eq(&g->fn->ret_type, &ret->type)); + if (!cgen_expr_pre(g, ret)) + return false; + } if (!ret) { cgen_write(g, "return"); } else if (cgen_uses_ptr(&g->fn->ret_type)) { @@ -1835,7 +1838,6 @@ static bool cgen_ret(CGenerator *g, Expression *ret) { cgen_write(g, " return"); } else { cgen_write(g, "return "); - if (!cgen_expr(g, ret)) return false; } cgen_write(g, ";"); @@ -1862,10 +1864,6 @@ static bool cgen_stmt(CGenerator *g, Statement *s) { break; case STMT_RET: { unsigned has_expr = s->ret.flags & RET_HAS_EXPR; - if (has_expr) { - if (!cgen_expr_pre(g, &s->ret.expr)) - return false; - } if (!cgen_ret(g, has_expr ? &s->ret.expr : NULL)) return false; } break; @@ -55,6 +55,8 @@ static void err_vfprint(const char *fmt, va_list args) { } static void err_print_header_(Location where) { + if (!where.ctx) + err_fprint("Error (no location available):\n"); #if ERR_EMACS err_fprint("%s:%lu: " TEXT_ERROR("error") ":\n", where.ctx->filename, (unsigned long)where.line); #else @@ -63,6 +65,8 @@ static void err_print_header_(Location where) { } static void info_print_header_(Location where) { + if (!where.ctx) + err_fprint("Info (no location available):\n"); #if ERR_EMACS err_fprint("%s:%lu: " TEXT_INFO("info") ":\n", where.ctx->filename, (unsigned long)where.line); #else @@ -71,6 +75,8 @@ static void info_print_header_(Location where) { } static void warn_print_header_(Location where) { + if (!where.ctx) + err_fprint("Warning (no location available):\n"); #if ERR_EMACS err_fprint("%s:%lu: " TEXT_WARN("warning") ":\n", where.ctx->filename, (unsigned long)where.line); #else @@ -8,8 +8,14 @@ static bool location_after(Location a, Location b) { /* a is after b? */ return a.pos > b.pos; } +static Location const LOCATION_NONE = {0}; + /* for debugging */ static void fprint_location(FILE *out, Location location) { + if (!location.ctx) { + fprintf(out, "No location available."); + return; + } char *str = location.ctx->str + location.pos; char *newline = strchr(str, '\n'); if (newline) *newline = 0; @@ -122,10 +122,12 @@ int main(int argc, char **argv) { evalr_create(&ev, &tr, &main_allocr); typer_create(&tr, &ev, &main_allocr); tr.exptr = &exptr; - + #ifdef TOC_DEBUG FILE *out_pkg = fopen("out.top", "wb"); exptr_create(&exptr, out_pkg); + exptr.export_locations = false; + #endif if (!block_enter(NULL, f.stmts, SCOPE_CHECK_REDECL)) /* enter global scope */ return false; @@ -136,6 +138,15 @@ int main(int argc, char **argv) { return EXIT_FAILURE; } #ifdef TOC_DEBUG + if (!exptr_finish(&exptr)) { + fclose(out_pkg); + err_fprint(TEXT_IMPORTANT("Errors occured while exporting things.\n")); + return EXIT_FAILURE; + } + fclose(out_pkg); +#endif +#ifdef TOC_DEBUG + printf("\n\n"); fprint_parsed_file(stdout, &f); #endif FILE *out = fopen(out_filename, "w"); @@ -158,9 +169,6 @@ int main(int argc, char **argv) { evalr_free(&ev); fclose(out); -#ifdef TOC_DEBUG - fclose(out_pkg); -#endif idents_free(&file_idents); return 0; } @@ -3,11 +3,17 @@ This file is part of toc. toc is distributed under version 3 of the GNU General Public License, without any warranty whatsoever. You should have received a copy of the GNU General Public License along with toc. If not, see <https://www.gnu.org/licenses/>. */ +static bool export_decl(Exporter *ex, Declaration *d); +static bool export_block(Exporter *ex, Block *b); + + static void exptr_create(Exporter *exptr, FILE *out) { exptr->out = out; exptr->export_locations = true; + exptr->exported_fns = NULL; } + static void export_u8(Exporter *ex, U8 u8) { write_u8(ex->out, u8); } @@ -63,16 +69,33 @@ static void export_ident(Exporter *ex, Identifier i) { } } +static bool export_len8(Exporter *ex, size_t len, const char *for_, Location where) { + if (len > U8_MAX) { + err_print(where, "Too many %s (the maximum is " STRINGIFY(U8_MAX) ").", for_); + return false; + } + export_u8(ex, (U8)len); + return true; +} static bool export_len16(Exporter *ex, size_t len, const char *for_, Location where) { - if (len > 65535) { - err_print(where, "Too many %s (the maximum is 65535).", for_); + if (len > U16_MAX) { + err_print(where, "Too many %s (the maximum is " STRINGIFY(U16_MAX) ").", for_); return false; } export_u16(ex, (U16)len); return true; } +static bool export_len32(Exporter *ex, size_t len, const char *for_, Location where) { + if (len > U32_MAX) { + err_print(where, "Too many %s (the maximum is " STRINGIFY(U32_MAX) ").", for_); + return false; + } + export_u32(ex, (U32)len); + return true; +} + static bool export_type(Exporter *ex, Type *type, Location where) { assert(type->flags & TYPE_IS_RESOLVED); export_u8(ex, (U8)type->kind); @@ -98,6 +121,18 @@ static bool export_type(Exporter *ex, Type *type, Location where) { if (!export_type(ex, type->arr.of, where)) return false; break; + case TYPE_FN: + if (!export_len16(ex, arr_len(type->fn.types), "types in a function type", where)) + return false; + arr_foreach(type->fn.types, Type, sub) + if (!export_type(ex, sub, where)) + return false; + export_u8(ex, type->fn.constness != NULL); + /* [implied] if (type->fn.constness) */ + assert(sizeof(Constness) == 1); /* future-proofing */ + arr_foreach(type->fn.constness, Constness, c) + export_u8(ex, *c); + break; case TYPE_EXPR: assert(0); return false; @@ -105,6 +140,20 @@ static bool export_type(Exporter *ex, Type *type, Location where) { return true; } +static bool export_fn_ptr(Exporter *ex, FnExpr *f, Location where) { + if (f->export.id == 0) { + FnWithLocation *floc = arr_add(&ex->exported_fns); + floc->fn = f; + floc->where = where; + if (arr_len(ex->exported_fns) > U32_MAX) { + err_print(where, "Too many exported functions (the maximum is " STRINGIFY(U32_MAX) ")."); + } + f->export.id = (U32)arr_len(ex->exported_fns); + } + export_u32(ex, f->export.id); + return true; +} + static bool export_val(Exporter *ex, Value val, Type *type, Location where); static bool export_val_ptr(Exporter *ex, void *val, Type *type, Location where) { switch (type->kind) { @@ -168,6 +217,10 @@ static bool export_val_ptr(Exporter *ex, void *val, Type *type, Location where) ptr += item_size; } } break; + case TYPE_FN: + if (!export_fn_ptr(ex, *(FnExpr **)val, where)) + return false; + break; case TYPE_UNKNOWN: case TYPE_EXPR: assert(0); @@ -237,6 +290,22 @@ static bool export_expr(Exporter *ex, Expression *e) { if (!export_type(ex, &e->typeval, e->where)) return false; break; + case EXPR_FN: + if (!export_fn_ptr(ex, e->fn, e->where)) + return false; + break; + case EXPR_BLOCK: + if (!export_block(ex, &e->block)) + return false; + break; + case EXPR_NEW: + if (!export_type(ex, &e->new.type, e->where)) + return false; + export_u8(ex, e->new.n != NULL); + if (e->new.n) + if (!export_expr(ex, e->new.n)) + return false; + break; case EXPR_DSIZEOF: case EXPR_DALIGNOF: assert(0); @@ -287,3 +356,69 @@ static bool export_decl(Exporter *ex, Declaration *d) { } return true; } + +static bool export_stmt(Exporter *ex, Statement *s) { + export_u8(ex, (U8)s->kind); + switch (s->kind) { + case STMT_EXPR: + if (!export_expr(ex, &s->expr)) + return false; + break; + case STMT_DECL: + if (!export_decl(ex, &s->decl)) + return false; + break; + case STMT_RET: + assert(sizeof s->ret.flags == 1); + export_u8(ex, (U8)s->ret.flags); + if (s->ret.flags & RET_HAS_EXPR) + if (!export_expr(ex, &s->ret.expr)) + return false; + break; + } + return true; +} + +static bool export_block(Exporter *ex, Block *b) { + export_location(ex, b->start); + export_location(ex, b->end); + if (!export_len32(ex, arr_len(b->stmts), "statements in a block", b->start)) + return false; + arr_foreach(b->stmts, Statement, s) { + if (!export_stmt(ex, s)) + return false; + } + export_u8(ex, b->ret_expr != NULL); + if (b->ret_expr) + if (!export_expr(ex, b->ret_expr)) + return false; + return true; +} + +static bool export_fn(Exporter *ex, FnExpr *f, Location where) { + if (!export_len16(ex, arr_len(f->params), "parameters in a function", where)) + return false; + arr_foreach(f->params, Declaration, param) + if (!export_decl(ex, param)) + return false; + if (!export_len8(ex, arr_len(f->ret_decls), "return declarations", where)) + return false; + arr_foreach(f->ret_decls, Declaration, ret_decl) + if (!export_decl(ex, ret_decl)) + return false; + /* no need to export the return type */ + if (!export_block(ex, &f->body)) + return false; + return true; +} + +/* does NOT close the file */ +static bool exptr_finish(Exporter *ex) { + if (!export_len32(ex, arr_len(ex->exported_fns), "exported functions", LOCATION_NONE)) + return false; + arr_foreach(ex->exported_fns, FnWithLocation, f) { + if (!export_fn(ex, f->fn, f->where)) + return false; + } + return true; +} @@ -1021,7 +1021,7 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) { e->kind = EXPR_FN; if (!parse_fn_expr(p, e->fn = parser_malloc(p, sizeof *e->fn))) return false; - + e->fn->export.id = 0; if (t->token != end) { if (token_is_kw(t->token, KW_LPAREN)) tokr_err(t, "Direct function calling in an expression is not supported.\nYou can wrap the function in parentheses."); @@ -1,2 +1,4 @@ -#export asdf ::= int; -#export ghjk := #sizeof(asdf);
\ No newline at end of file +#export main ::= fn() int { + {3} +}; +// #export ghjk := #sizeof(asdf);
\ No newline at end of file @@ -31,6 +31,12 @@ /* forward declarations for debugging */ static void print_val(Value v, Type *t); + +/* misc */ +#define JOIN(a,b) a##b +#define STRINGIFY2(x) #x +#define STRINGIFY(x) STRINGIFY2(x) + static void fprint_char_literal(FILE *f, char c) { if (isprint(c)) fprintf(f, "'%c'", c); @@ -39,6 +45,7 @@ static void fprint_char_literal(FILE *f, char c) { } + /* utilities */ #include "allocator.c" #include "arr.c" @@ -69,13 +69,11 @@ typedef double F64; typedef U32 IdentID; /* identifier ID for cgen (anonymous variables). not to be confused with IdentTree.id */ -#define join(a,b) a##b - /* for keeping track of whence something came */ #ifdef TOC_DEBUG #define SOURCE_LOCATION char *src_file; int src_line; #define SOURCE_LOCATION_PARAMS char *src_file, int src_line, -#define DEBUG_UNDERSCORE(x) join(x,_) +#define DEBUG_UNDERSCORE(x) JOIN(x,_) #else #define SOURCE_LOCATION #define SOURCE_LOCATION_PARAMS @@ -547,6 +545,7 @@ typedef struct EachExpr { }; } EachExpr; + 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 */ @@ -557,6 +556,11 @@ typedef struct FnExpr { if the ith semi-constant parameter is constant. */ struct { + U32 id; /* (index of function in ex->exported_fns) + 1, + or 0 if this function has not been + added to the exporting array yet */ + } export; + struct { /* if name = NULL, this is an anonymous function, and id will be the ID of the fn. */ Identifier name; IdentID id; @@ -669,7 +673,7 @@ enum { DECL_EXPORT = 0x0200 }; -typedef U32 DeclFlags; +typedef U16 DeclFlags; /* OPTIM: Instead of using dynamic arrays, do two passes. */ typedef struct Declaration { @@ -691,7 +695,7 @@ enum { RET_HAS_EXPR = 0x01, }; typedef struct Return { - U16 flags; + U8 flags; /* if this changes, go to package.c */ Expression expr; } Return; @@ -745,9 +749,15 @@ typedef struct Typer { FnExpr *fn; /* the function we're currently parsing. */ } Typer; +typedef struct { + FnExpr *fn; + Location where; +} FnWithLocation; + typedef struct Exporter { FILE *out; /* .top (toc package) to output to */ bool export_locations; + FnWithLocation *exported_fns; } Exporter; typedef struct CGenerator { |