diff options
-rw-r--r-- | allocator.c | 6 | ||||
-rw-r--r-- | arr.c | 2 | ||||
-rwxr-xr-x | build.sh | 2 | ||||
-rw-r--r-- | cgen.c | 148 | ||||
-rw-r--r-- | decls_cgen.c | 35 | ||||
-rw-r--r-- | eval.c | 4 | ||||
-rw-r--r-- | identifiers.c | 21 | ||||
-rw-r--r-- | main.c | 8 | ||||
-rw-r--r-- | parse.c | 18 | ||||
-rw-r--r-- | test.toc | 57 | ||||
-rw-r--r-- | typedefs_cgen.c | 15 | ||||
-rw-r--r-- | types.c | 58 | ||||
-rw-r--r-- | types.h | 29 |
13 files changed, 190 insertions, 213 deletions
diff --git a/allocator.c b/allocator.c index 1995733..f47cc97 100644 --- a/allocator.c +++ b/allocator.c @@ -1,7 +1,7 @@ -#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 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)) +#define PAGE_MAX_ALIGNS (PAGE_BYTES / sizeof(MaxAlign)) static void allocr_create(Allocator *a) { a->first = a->last = NULL; @@ -17,7 +17,7 @@ static void *allocr_malloc(Allocator *a, size_t bytes) { size_t pos = PAGE_MAX_ALIGNS; if (a->last) pos = a->last->used; - size_t max_aligns = (bytes + sizeof(max_align_t) - 1) / sizeof(max_align_t); + size_t max_aligns = (bytes + sizeof(MaxAlign) - 1) / sizeof(MaxAlign); if (pos + max_aligns > PAGE_MAX_ALIGNS) { /* make a new page for this data */ @@ -2,7 +2,7 @@ typedef struct { size_t len; size_t cap; - max_align_t data[]; + MaxAlign data[]; } ArrHeader; static inline ArrHeader *arr_hdr(void *arr) { @@ -14,7 +14,7 @@ fi # - must be set if the zero value of a pointer (as might be set by calloc/memset) # is not the NULL pointer. -ADDITIONAL_FLAGS='-Wno-unused-function' +# ADDITIONAL_FLAGS='-Wno-unused-function' if [ "$CC" = "clang" ]; then WARNINGS='-Wall -Wextra -Wpedantic -Wshadow -Wconversion -Wimplicit-fallthrough -Wno-unused-parameter' @@ -226,7 +226,7 @@ static void cgen_ident(CGenerator *g, Identifier i) { cgen_write(g, "main__"); } else { cgen_indent(g); - fprint_ident(cgen_writing_to(g), i); + fprint_ident_reduced_charset(cgen_writing_to(g), i); } } @@ -449,7 +449,7 @@ static bool cgen_fn_header(CGenerator *g, FnExpr *f, Location where, I64 instanc } } } - if (out_param) { + if (out_param) { if (f->ret_type.kind == TYPE_TUPLE) { /* multiple return variables */ for (size_t i = 0; i < arr_len(f->ret_type.tuple); i++) { @@ -480,7 +480,7 @@ static bool cgen_fn_header(CGenerator *g, FnExpr *f, Location where, I64 instanc /* Either set_expr or set_str should be NULL and either to_expr or to_str should be NULL Also, set_str and/or to_str should be NULL - this will call cgen_expr_pre for set_expr and to_expr + this DOES NOT call cgen_expr_pre for set_expr or to_expr */ static bool cgen_set(CGenerator *g, Expression *set_expr, const char *set_str, Expression *to_expr, const char *to_str) { @@ -489,12 +489,10 @@ static bool cgen_set(CGenerator *g, Expression *set_expr, const char *set_str, E if (set_expr) { type = &set_expr->type; where = set_expr->where; - if (!cgen_expr_pre(g, set_expr)) return false; } else { assert(to_expr); type = &to_expr->type; where = to_expr->where; - if (!cgen_expr_pre(g, to_expr)) return false; } type = type_inner(type); switch (type->kind) { @@ -562,7 +560,7 @@ static bool cgen_set(CGenerator *g, Expression *set_expr, const char *set_str, E return true; } -/* one of exprs, idents, and prefix should be NULL. */ +/* one of exprs, idents, and prefix should be NULL. does NOT call cgen_expr_pre for to/exprs */ static bool cgen_set_tuple(CGenerator *g, Expression *exprs, Identifier *idents, const char *prefix, Expression *to) { IdentID prefix_id; /* ID of prefix for block */ switch (to->kind) { @@ -614,7 +612,7 @@ static bool cgen_set_tuple(CGenerator *g, Expression *exprs, Identifier *idents, cgen_write(g, "&(%s%lu_)", prefix, i); } } - cgen_writeln(g, ");"); + cgen_writeln(g, "); "); } break; case EXPR_IF: prefix_id = to->if_.c.id; @@ -667,57 +665,6 @@ static bool cgen_set_tuple(CGenerator *g, Expression *exprs, Identifier *idents, return true; } -/* generates the C code for new'ing a slice of array type t (e.g. [5]int) and putting it in the given ident id. */ -static bool cgen_new_slice(CGenerator *g, Type *t, IdentID id, Location where) { - Expression *n_expr = t->arr.n_expr; - assert(!(t->flags & TYPE_IS_RESOLVED)); /* we don't want this to be resolved, because the size might only be known at runtime. */ - if (!cgen_expr_pre(g, n_expr)) return false; - cgen_write(g, "size_t s"); - cgen_ident_id(g, id); - cgen_write(g, " = "); - if (!cgen_expr(g, n_expr)) return false; - cgen_write(g, "; slice_ "); - cgen_ident_id(g, id); - cgen_write(g, ";"); - cgen_ident_id(g, id); - cgen_write(g, ".data = e__calloc(s"); - cgen_ident_id(g, id); - cgen_write(g, ", sizeof("); - if (t->arr.of->kind == TYPE_ARR) { - cgen_write(g, "slice_"); - } else { - if (!cgen_type_pre(g, t->arr.of, where)) - return false; - if (!cgen_type_post(g, t->arr.of, where)) - return false; - } - cgen_write(g, ")); "); - cgen_ident_id(g, id); - cgen_write(g, ".n = s"); - cgen_ident_id(g, id); - cgen_write(g, ";"); - if (t->arr.of->kind == TYPE_ARR) { - /* slice of slices. initialize the inner slices. */ - IdentID child_id = g->ident_counter++; - cgen_write(g, "for (i64 i_ = 0; i_ < s"); - cgen_ident_id(g, id); - cgen_write(g, "; i_++) {"); - cgen_nl(g); - g->indent_lvl++; - if (!cgen_new_slice(g, t->arr.of, child_id, where)) - return false; - cgen_write(g, " ((slice_*)"); - cgen_ident_id(g, id); - cgen_write(g, ".data)[i_] = "); - cgen_ident_id(g, child_id); - cgen_write(g, ";"); - cgen_nl(g); - g->indent_lvl--; - cgen_write(g, "}"); - } - return true; -} - static bool cgen_expr_pre(CGenerator *g, Expression *e) { IdentID id = 0; char ret_name[64]; @@ -990,7 +937,8 @@ static bool cgen_expr_pre(CGenerator *g, Expression *e) { } i++; } - if (cgen_uses_ptr(&e->type)) { + if (cgen_uses_ptr(&e->type) + && e->type.kind != TYPE_TUPLE) { e->call.c.id = g->ident_counter++; if (!cgen_type_pre(g, &e->type, e->where)) return false; cgen_write(g, " "); @@ -1441,6 +1389,8 @@ static bool cgen_block(CGenerator *g, Block *b, const char *ret_name, U16 flags) if (!cgen_stmt(g, s)) return false; if (b->ret_expr && ret_name) { + if (!cgen_expr_pre(g, b->ret_expr)) + return false; if (b->ret_expr->type.kind == TYPE_TUPLE) { if (!cgen_set_tuple(g, NULL, NULL, ret_name, b->ret_expr)) return false; @@ -1529,12 +1479,34 @@ static bool cgen_fn(CGenerator *g, FnExpr *f, Location where, I64 instance, Valu if (!cgen_block(g, &f->body, NULL, CGEN_BLOCK_NOENTER | CGEN_BLOCK_NOBRACES)) return false; if (f->ret_decls) { - if (cgen_uses_ptr(&f->ret_type)) { + /* OPTIM */ + + /* long-winded code to generate a return expression using the ret_decls. */ + Expression ret_expr; + ret_expr.flags = EXPR_FOUND_TYPE; + ret_expr.type = f->ret_type; + if (arr_len(f->ret_decls) == 1 + && arr_len(f->ret_decls[0].idents) == 1) { + ret_expr.kind = EXPR_IDENT; + ret_expr.ident = f->ret_decls[0].idents[0]; } else { - cgen_write(g, "return "); - cgen_ident(g, f->ret_decls[0].idents[0]); - cgen_writeln(g, ";"); + ret_expr.kind = EXPR_TUPLE; + ret_expr.tuple = NULL; + size_t i = 0; + arr_foreach(f->ret_decls, Declaration, d) { + arr_foreach(d->idents, Identifier, ident) { + Expression *element = arr_add(&ret_expr.tuple); + element->flags = EXPR_FOUND_TYPE; + element->kind = EXPR_IDENT; + element->type = f->ret_type.tuple[i]; + element->ident = *ident; + i++; + } + } } + + if (!cgen_ret(g, &ret_expr)) + return false; } else if (f->body.ret_expr) { if (!cgen_ret(g, f->body.ret_expr)) return false; } @@ -1668,28 +1640,12 @@ static bool cgen_decl(CGenerator *g, Declaration *d) { Type *type = is_tuple ? &d->type.tuple[idx] : &d->type; Value *val = is_tuple ? &d->val.tuple[idx] : &d->val; if (type->kind == TYPE_TYPE) { - /* mostly handled in typedefs_cgen, except for struct declarations */ - if (val->type->kind == TYPE_STRUCT) { - cgen_write(g, "struct "); - if (g->block == NULL) - cgen_ident(g, i); - else - cgen_ident_id(g, d->c.ids[idx]); - cgen_write(g, "{"); - cgen_nl(g); - g->indent_lvl++; - arr_foreach(val->type->struc.fields, Field, f) { - if (!cgen_type_pre(g, f->type, d->where)) return false; - cgen_write(g, " "); - cgen_ident(g, f->name); - if (!cgen_type_post(g, f->type, d->where)) return false; - cgen_write(g, ";"); - cgen_nl(g); - } - g->indent_lvl--; - cgen_write(g, "};"); - cgen_nl(g); - } + /* + confusingly, + struct declarations are handled by typedefs_cgen, + and struct definitions are handled by decls_cgen. + we don't need to do anything here. + */ continue; } else if (type->kind == TYPE_FN && (d->flags & DECL_IS_CONST)) { /* don't generate function pointer declaration for constant fns */ @@ -1731,11 +1687,11 @@ static bool cgen_decl(CGenerator *g, Declaration *d) { cgen_write(g, "; "); } if (has_expr) { + if (!cgen_expr_pre(g, &d->expr)) return false; if (d->expr.type.kind == TYPE_TUPLE) { if (!cgen_set_tuple(g, NULL, d->idents, NULL, &d->expr)) return false; } else { cgen_write(g, "{"); - cgen_nl(g); if (!cgen_type_pre(g, &d->type, d->expr.where)) return false; cgen_write(g, " expr__"); @@ -1760,6 +1716,7 @@ 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) { @@ -1771,9 +1728,8 @@ static bool cgen_ret(CGenerator *g, Expression *ret) { } else { if (!cgen_set(g, NULL, "*ret_", ret, NULL)) return false; } - cgen_write(g, "return"); + cgen_write(g, " return"); } else { - if (!cgen_expr_pre(g, ret)) return false; cgen_write(g, "return "); if (!cgen_expr(g, ret)) return false; @@ -1787,10 +1743,9 @@ static bool cgen_ret(CGenerator *g, Expression *ret) { static bool cgen_stmt(CGenerator *g, Statement *s) { /* TODO(eventually): optionally this: + cgen_write(g, "/\* %s:%d *\/", s->where.ctx->filename, s->where.line); + (or even #line directives!) */ - // cgen_write(g, "/* %s:%d */", s->where.ctx->filename, s->where.line); - /* (or even #line directives!) */ - switch (s->kind) { case STMT_DECL: if (!cgen_decl(g, &s->decl)) return false; @@ -1801,10 +1756,15 @@ static bool cgen_stmt(CGenerator *g, Statement *s) { cgen_write(g, ";"); cgen_nl(g); break; - case STMT_RET: - if (!cgen_ret(g, s->ret.flags & RET_HAS_EXPR ? &s->ret.expr : NULL)) + 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; + } break; } return true; } diff --git a/decls_cgen.c b/decls_cgen.c index 1a23a90..0e9fff3 100644 --- a/decls_cgen.c +++ b/decls_cgen.c @@ -4,7 +4,7 @@ static bool cgen_decls_block(CGenerator *g, Block *b); static bool cgen_decls_expr(CGenerator *g, Expression *e) { cgen_recurse_subexprs(g, e, cgen_decls_expr, cgen_decls_block); switch (e->kind) { - case EXPR_CALL: + case EXPR_CALL: { e->call.c.instance = 0; assert(e->call.fn->type.kind == TYPE_FN); FnType *fn_type = &e->call.fn->type.fn; @@ -53,7 +53,7 @@ static bool cgen_decls_expr(CGenerator *g, Expression *e) { e->call.c.instance = (U32)instance_number; } } - break; + } break; case EXPR_FN: e->fn.c.name = NULL; if (!e->fn.c.id) @@ -98,6 +98,37 @@ static bool cgen_decls_decl(CGenerator *g, Declaration *d) { return false; fn_exit(&d->expr.fn); } else if (d->flags & DECL_HAS_EXPR) { + if (d->flags & DECL_IS_CONST) { + for (size_t idx = 0; idx < arr_len(d->idents); idx++) { + Identifier i = d->idents[idx]; + Type *type = d->type.kind == TYPE_TUPLE ? &d->type.tuple[idx] : &d->type; + if (type->kind == TYPE_TYPE) { + Value *val = d->type.kind == TYPE_TUPLE ? &d->val.tuple[idx] : &d->val; + if (val->type->kind == TYPE_STRUCT) { + /* generate struct definition */ + cgen_write(g, "struct "); + if (g->block == NULL) + cgen_ident(g, i); + else + cgen_ident_id(g, d->c.ids[idx]); + cgen_write(g, "{"); + cgen_nl(g); + g->indent_lvl++; + arr_foreach(val->type->struc.fields, Field, f) { + if (!cgen_type_pre(g, f->type, d->where)) return false; + cgen_write(g, " "); + cgen_ident(g, f->name); + if (!cgen_type_post(g, f->type, d->where)) return false; + cgen_write(g, ";"); + cgen_nl(g); + } + g->indent_lvl--; + cgen_write(g, "};"); + cgen_nl(g); + } + } + } + } if (!(d->flags & DECL_IS_CONST) || (d->expr.kind == EXPR_FN)) { if (!cgen_decls_expr(g, &d->expr)) return false; @@ -1526,8 +1526,8 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) { } static bool eval_decl(Evaluator *ev, Declaration *d) { - int has_expr = d->flags & DECL_HAS_EXPR; - int is_const = d->flags & DECL_IS_CONST; + unsigned has_expr = d->flags & DECL_HAS_EXPR; + unsigned is_const = d->flags & DECL_IS_CONST; Value val = {0}; if (has_expr) { diff --git a/identifiers.c b/identifiers.c index cc9315f..b7f5e06 100644 --- a/identifiers.c +++ b/identifiers.c @@ -188,27 +188,6 @@ static int ident_index_in_decl(Identifier i, Declaration *d) { return -1; } -static Type *ident_typeval(Identifier i) { - Value *val; - IdentDecl *idecl = ident_decl(i); - if (!idecl) return NULL; - Declaration *d = idecl->decl; - if (!(d->flags & DECL_IS_CONST)) - return NULL; - assert(d->flags & DECL_FOUND_TYPE); - if (d->type.kind == TYPE_TUPLE) { - size_t idx; - for (idx = 0; idx < arr_len(d->idents); idx++) { - if (d->idents[idx] == i) - break; - } - assert(idx < arr_len(d->idents)); - val = &d->val.tuple[idx]; - } else val = &d->val; - - return val->type; -} - static bool ident_eq_str(Identifier i, const char *s) { const char *t = s + (strlen(s) - 1); while (1) { @@ -1,7 +1,7 @@ /* TODO: -evaluate default arguments -make sure they're only evaluated once +memory leaks! +deal with unused functions compile time arguments + out parameters (in C) double check that val_get_ptr is being used everywhere it should be compile-time arguments for out parameter functions @@ -12,7 +12,6 @@ struct parameters don't allow while {3; 5} (once break is added) any odd number of "s for a string modifiable string literals -unicode variable names (cgen support) make sure futurely/currently-declared types are only used by pointer/slice allow omission of trailing ; in foo @= fn() {}? */ @@ -127,7 +126,8 @@ int main(int argc, char **argv) { free(contents); allocr_free_all(&main_allocr); - + evalr_free(&ev); + fclose(out); /* fclose(h_out); */ idents_free(&file_idents); @@ -622,7 +622,7 @@ static bool parser_is_definitely_type(Parser *p, Token **end) { } else break; } } break; - case KW_FN: + case KW_FN: { ret = false; t->token++; if (!token_is_kw(t->token, KW_LPAREN)) { @@ -643,14 +643,16 @@ static bool parser_is_definitely_type(Parser *p, Token **end) { if (is_decl(t)) /* has return declaration */ goto end; Type return_type; - bool prev = t->token->where.ctx->enabled; - t->token->where.ctx->enabled = false; + bool *enabled = &t->token->where.ctx->enabled; + bool prev_enabled = *enabled; + *enabled = false; if (!parse_type(p, &return_type)) { /* couldn't parse a return type. void fn type */ + *enabled = prev_enabled; ret = true; goto end; } - t->token->where.ctx->enabled = prev; + *enabled = prev_enabled; if (token_is_kw(t->token, KW_LBRACE)) { /* non-void fn expr */ goto end; @@ -664,7 +666,7 @@ static bool parser_is_definitely_type(Parser *p, Token **end) { } t->token++; } - break; + } break; case KW_AMPERSAND: t->token++; /* continue; see if next thing is definitely a type */ goto continu; @@ -804,6 +806,12 @@ static bool parse_fn_expr(Parser *p, FnExpr *f) { f->ret_decls = NULL; if (!parse_decl_list(p, &f->ret_decls, DECL_END_LBRACE_COMMA)) return false; + arr_foreach(f->ret_decls, Declaration, d) { + if (d->flags & DECL_IS_CONST) { + err_print(d->where, "Named return values cannot be constant."); + return false; + } + } t->token--; /* move back to { */ if (arr_len(f->ret_decls) > 1 || arr_len(f->ret_decls[0].idents) > 1) { f->ret_type.kind = TYPE_TUPLE; @@ -1,51 +1,28 @@ - puti @= fn(x: int) { #C("printf(\"%ld\\n\", (long)x); "); }; -// putf @= fn(x: float) { -// #C("printf(\"%f\\n\", (double)x); -// "); -// }; - - -// Foo @= struct { -// x, y: int; -// z: float; -// }; - - -// bar @= fn() (f: Foo) { -// f.x = 3; -// f.y = 123; -// f.z += 43.2; -// }; - -f @= fn(x @ int = 3+5) i: int { - i = x; +☃ @= struct { + x, y: int; + z: float; }; -g @= fn(x, y : (int, int) = (3+5, 4+9)) i: int { - i = x + y; +something @= fn() int { + 5 }; +bar @= fn(a := something()) f: ☃, g: int { + f.x = a; + f.y = 123; + f.z += 43.2; + g = 17; +}; main @= fn() { - puti(f(313)); - puti(f(128)); - puti(f(231)); - puti(f(100+213)); - puti(f()); - puti(g()); - +f,g := bar(); +puti(g); +puti(f.x); +puti(f.y); +h,i := bar(); +puti(h.x); }; -// b := bar(); - -// f @= fn(x: int, y @ int) int { x + y }; -// puti(f(3,5)); - -// puti(f(4, 5)); -// puti(f(3, 6)); -// puti((fn(x: int, y @ int) int { x + y })(1,2)); -// }; - diff --git a/typedefs_cgen.c b/typedefs_cgen.c index 08b582d..879eb2f 100644 --- a/typedefs_cgen.c +++ b/typedefs_cgen.c @@ -35,7 +35,20 @@ static bool typedefs_decl(CGenerator *g, Declaration *d) { /* generate typedef */ IdentID id = 0; if (g->block != NULL) id = d->c.ids[idx] = g->ident_counter++; - if (val->type->kind == TYPE_STRUCT) continue; /* we don't need to typedef this; we can just use its tag */ + if (val->type->kind == TYPE_STRUCT) { + /* we'll actually define the struct later; here we can just declare it */ + cgen_write(g, "struct "); + if (g->block == NULL) { + /* we can refer to this by its name */ + cgen_ident(g, i); + } else { + /* we need to use an ID ): */ + cgen_ident_id(g, id); + } + cgen_write(g, ";"); + cgen_nl(g); + continue; + } cgen_write(g, "typedef "); if (!cgen_type_pre(g, val->type, d->where)) return false; cgen_write(g, " "); @@ -62,7 +62,7 @@ static bool type_eq(Type *a, Type *b) { } return true; } - case TYPE_TUPLE: + case TYPE_TUPLE: { if (arr_len(a->tuple) != arr_len(b->tuple)) return false; Type *a_types = a->tuple, *b_types = b->tuple; for (size_t i = 0; i < arr_len(a->tuple); i++) { @@ -70,6 +70,7 @@ static bool type_eq(Type *a, Type *b) { return false; } return true; + } case TYPE_ARR: if (a->arr.n != b->arr.n) return false; return type_eq(a->arr.of, b->arr.of); @@ -255,13 +256,15 @@ static bool type_of_fn(Typer *tr, Expression *e, Type *t) { } } if (decl->flags & DECL_HAS_EXPR) { - Value val; - if (!eval_expr(tr->evalr, &decl->expr, &val)) { - info_print(decl->where, "Was trying to evaluate default arguments (which must be constants!)"); - return false; + if (decl->expr.kind != EXPR_VAL) { + Value val; + if (!eval_expr(tr->evalr, &decl->expr, &val)) { + info_print(decl->where, "Was trying to evaluate default arguments (which must be constants!)"); + return false; + } + decl->expr.kind = EXPR_VAL; + decl->expr.val = val; } - decl->expr.kind = EXPR_VAL; - decl->expr.val = val; } for (size_t i = 0; i < arr_len(decl->idents); i++) { Type *param_type = typer_arr_add(tr, &t->fn.types); @@ -614,22 +617,13 @@ static bool types_expr(Typer *tr, Expression *e) { 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 *prev_fn = tr->fn; FnExpr *f = &e->fn; if (!type_of_fn(tr, e, t)) { success = false; goto fn_ret; } - bool has_named_ret_vals = f->ret_decls != NULL; - if (has_named_ret_vals) { - /* set return type to void to not allow return values */ - tr->ret_type.kind = TYPE_VOID; - tr->ret_type.flags = 0; - } else { - tr->ret_type = t->fn.types[0]; - } - tr->can_ret = true; + tr->fn = f; if (!fn_enter(f, SCOPE_CHECK_REDECL)) return false; bool block_success = true; @@ -642,6 +636,7 @@ static bool types_expr(Typer *tr, Expression *e) { Expression *ret_expr = f->body.ret_expr; assert(t->kind == TYPE_FN); Type *ret_type = t->fn.types; + bool has_named_ret_vals = f->ret_decls != NULL; if (ret_expr) { if (!types_expr(tr, ret_expr)) { success = false; @@ -663,7 +658,8 @@ static bool types_expr(Typer *tr, Expression *e) { if (last_stmt->kind == STMT_RET) { /* last statement is a return, so it doesn't matter that the function has no return value - ideally this would handle if foo { return 5; } else { return 6; } */ + ideally this would handle if foo { return 5; } else { return 6; } + */ success = true; goto fn_ret; } @@ -677,8 +673,7 @@ static bool types_expr(Typer *tr, Expression *e) { goto fn_ret; } fn_ret: - tr->ret_type = prev_ret_type; - tr->can_ret = prev_can_ret; + tr->fn = prev_fn; if (!success) return false; } break; case EXPR_LITERAL_INT: @@ -1567,7 +1562,7 @@ static bool types_decl(Typer *tr, Declaration *d) { d->type = d->expr.type; d->type.flags &= (uint16_t)~(uint16_t)TYPE_IS_FLEXIBLE; /* x := 5; => x is not flexible */ } - if ((d->flags & DECL_IS_CONST) || tr->block == NULL) { + if ((d->flags & DECL_IS_CONST) || (tr->block == NULL && tr->fn == NULL)) { if (!(d->flags & DECL_FOUND_VAL)) { if (!eval_expr(tr->evalr, &d->expr, &d->val)) { success = false; @@ -1633,25 +1628,30 @@ static bool types_stmt(Typer *tr, Statement *s) { return false; break; case STMT_RET: - if (!tr->can_ret) { + if (!tr->fn) { err_print(s->where, "return outside of a function."); return false; } if (s->ret.flags & RET_HAS_EXPR) { - if (tr->ret_type.kind == TYPE_VOID) { - err_print(s->where, "Return value in function which should not return a value."); + if (tr->fn->ret_type.kind == TYPE_VOID) { + err_print(s->where, "Return value in a void function."); + return false; + } + if (tr->fn->ret_decls) { + err_print(s->where, "Return expression in a function with named return values."); return false; } if (!types_expr(tr, &s->ret.expr)) return false; - if (!type_eq(&tr->ret_type, &s->ret.expr.type)) { + if (!type_eq(&tr->fn->ret_type, &s->ret.expr.type)) { char *got = type_to_str(&s->ret.expr.type); - char *expected = type_to_str(&tr->ret_type); + char *expected = type_to_str(&tr->fn->ret_type); err_print(s->where, "Returning type %s in function which returns %s.", got, expected); return false; } } else { - if (tr->ret_type.kind != TYPE_VOID) { + if (tr->fn->ret_type.kind != TYPE_VOID + && !tr->fn->ret_decls) { err_print(s->where, "No return value in non-void function."); return false; } @@ -1663,7 +1663,7 @@ static bool types_stmt(Typer *tr, Statement *s) { static void typer_create(Typer *tr, Evaluator *ev, Allocator *allocr) { tr->block = NULL; - tr->can_ret = false; + tr->fn = NULL; tr->evalr = ev; tr->in_decls = NULL; tr->in_expr_decls = NULL; @@ -3,8 +3,18 @@ typedef uint64_t UInteger; typedef long double Floating; /* OPTIM: Switch to double, but make sure floating-point literals are right */ #if __STDC_VERSION__ < 201112 -/* assume long double has the strictest alignment */ -typedef long double max_align_t; +/* try to find the type with the strictest alignment */ +typedef union { + long double floating; + void *ptr; + #if __STDC_VERSION__ >= 199901 + long + #endif + long integer; + void (*fn_ptr)(void); +} MaxAlign; +#else +typedef max_align_t MaxAlign; #endif #define INTEGER_MAX INT64_MAX @@ -50,8 +60,8 @@ typedef struct { typedef struct Page { struct Page *next; - size_t used; /* number of max_align_t's used, not bytes */ - max_align_t data[]; + size_t used; /* number MaxAligns used, not bytes */ + MaxAlign data[]; } Page; typedef struct { @@ -376,10 +386,10 @@ typedef enum { EXPR_DALIGNOF, EXPR_SLICE, EXPR_TYPE, - /* a value (it's useful to have this). - USE WITH CAUTION - expression values are never to be cgenerated! if cgen encounters one, - it will assert(0)! + /* + a value (it's useful to have this). + right now they don't work with cgen_set_tuple + (as of yet, that is unneeded) */ EXPR_VAL } ExprKind; @@ -654,8 +664,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; - bool can_ret; - Type ret_type; /* the return type of the function we're currently parsing. */ + FnExpr *fn; /* the function we're currently parsing. */ } Typer; typedef struct { |