diff options
author | Leo Tenenbaum <pommicket@gmail.com> | 2020-04-24 17:43:21 -0400 |
---|---|---|
committer | Leo Tenenbaum <pommicket@gmail.com> | 2020-04-24 17:43:21 -0400 |
commit | ecf8b49cf99ccf0bf941a2ed9707ee5d43ebf0ad (patch) | |
tree | 43638dcef61e96f1ad25c7d3815ebcbca50bb7d2 | |
parent | 2de90e47312b8a7de69712015590fc7fbd3d9b0a (diff) |
improve cgen for loops and allow returning something of unknown type
-rw-r--r-- | cgen.c | 136 | ||||
-rw-r--r-- | main.c | 7 | ||||
-rw-r--r-- | misc.c | 10 | ||||
-rw-r--r-- | test.toc | 22 | ||||
-rw-r--r-- | types.c | 20 |
5 files changed, 89 insertions, 106 deletions
@@ -1448,6 +1448,9 @@ static void cgen_expr(CGenerator *g, Expression *e) { bool has_val = !ident_eq_str(val_ident, "_"); bool has_index = !ident_eq_str(index_ident, "_"); + Type *of_type = NULL; + bool uses_ptr = false; + if (is_range) { cgen_expr_pre(g, fo->range.from); if (fo->range.to) @@ -1488,31 +1491,73 @@ static void cgen_expr(CGenerator *g, Expression *e) { cgen_set(g, NULL, "val_", fo->range.from, NULL); } } else { - /* pre-generate of */ - cgen_type_pre(g, &fo->of->type); - cgen_write(g, " of_"); - cgen_type_post(g, &fo->of->type); - cgen_write(g, "; "); + of_type = &fo->of->type; + if (of_type->kind == TYPE_PTR) { + uses_ptr = true; + of_type = of_type->ptr; + } - cgen_set(g, NULL, "of_", fo->of, NULL); + /* pre-generate of */ + switch (of_type->kind) { + case TYPE_SLICE: + cgen_type_pre(g, of_type); + cgen_write(g, " of_"); + cgen_type_post(g, of_type); + cgen_write(g, " = "); + if (uses_ptr) cgen_write(g, "*"); + cgen_expr(g, fo->of); + cgen_write(g, "; "); + break; + case TYPE_ARR: + cgen_type_pre(g, of_type->arr.of); + cgen_write(g, " (* of_)"); + cgen_type_post(g, of_type->arr.of); + cgen_write(g, " = "); + if (uses_ptr) cgen_write(g, "*"); + cgen_expr(g, fo->of); + cgen_write(g, "; "); + break; + default: assert(0); break; + } } - cgen_write(g, "for ("); - - bool generate_index = has_index || !is_range; - if (generate_index) { + if (has_index) { cgen_type_pre(g, index_type); cgen_write(g, " "); - if (has_index) - cgen_ident(g, index_ident); - else - cgen_write(g, "i_"); + cgen_ident(g, index_ident); cgen_type_post(g, index_type); /* not needed yet, but keeping it here to prevent potential future problems */ - cgen_write(g, " = 0"); + cgen_write(g, " = 0; "); + } + + cgen_write(g, "for ("); + + if (!is_range) { + cgen_type_pre(g, val_type); + cgen_write(g, "(%sp_)", uses_ptr ? "" : "*"); + cgen_type_post(g, val_type); + cgen_write(g, " = "); + switch (of_type->kind) { + case TYPE_ARR: + cgen_write(g, "of_"); + break; + case TYPE_SLICE: + cgen_write(g, "of_.data"); + break; + default: assert(0); break; + } + cgen_write(g, ", (*end_) = p_ + "); + switch (of_type->kind) { + case TYPE_ARR: + cgen_write(g, U64_FMT, (U64)of_type->arr.n); + break; + case TYPE_SLICE: + cgen_write(g, "of_.n"); + break; + default: assert(0); break; + } } + cgen_write(g, "; "); - bool uses_ptr = false; - Type *of_type = NULL; if (!(is_range && !fo->range.to)) { /* if it's finite */ if (is_range) { if (has_val) @@ -1523,25 +1568,7 @@ static void cgen_expr(CGenerator *g, Expression *e) { = fo->range.stepval == NULL || val_is_nonnegative(*fo->range.stepval, val_type); cgen_write(g, " %c= to_", positive_step ? '<' : '>'); } else { - if (has_index) - cgen_ident(g, index_ident); - else - cgen_write(g, "i_"); - cgen_write(g, " < "); - of_type = &fo->of->type; - uses_ptr = of_type->kind == TYPE_PTR; - if (uses_ptr) { - of_type = of_type->ptr; - } - switch (of_type->kind) { - case TYPE_ARR: - cgen_write(g, "%lu", (unsigned long)of_type->arr.n); - break; - case TYPE_SLICE: - cgen_write(g, "of_%sn", uses_ptr ? "->" : "."); - break; - default: assert(0); break; - } + cgen_write(g, "p_ != end_"); } } cgen_write(g, "; "); @@ -1560,45 +1587,18 @@ static void cgen_expr(CGenerator *g, Expression *e) { cgen_write(g, "1"); } if (has_index) cgen_write(g, ", "); + } else { + cgen_write(g, "++p_"); + if (has_index) cgen_write(g, ", "); } - if (generate_index) { - if (has_index) - cgen_ident(g, index_ident); - else - cgen_write(g, "i_"); + if (has_index) { cgen_write(g, "++"); + cgen_ident(g, index_ident); } cgen_write(g, ") {"); cgen_nl(g); if (has_val) { if (!is_range) { - /* necessary for iterating over, e.g., an array of arrays */ - cgen_type_pre(g, val_type); - if (uses_ptr) - cgen_write(g, " p_"); - else - cgen_write(g, "(*p_)"); - cgen_type_post(g, val_type); - cgen_write(g, " = "); - if (of_type->kind == TYPE_SLICE) { - cgen_write(g, "(("); - cgen_type_pre(g, val_type); - if (!uses_ptr) cgen_write(g, "(*)"); - cgen_type_post(g, val_type); - cgen_write(g, ")of_%sdata) + ", uses_ptr ? "->" : "."); - if (has_index) - cgen_ident(g, index_ident); - else - cgen_write(g, "i_"); - } else { - cgen_write(g, "&%sof_%s[", uses_ptr ? "(*" : "", uses_ptr ? ")" : ""); - if (has_index) - cgen_ident(g, index_ident); - else - cgen_write(g, "i_"); - cgen_write(g, "]"); - } - cgen_write(g, "; "); cgen_type_pre(g, val_type); cgen_write(g, " "); cgen_ident(g, val_ident); @@ -8,10 +8,6 @@ /* @TODO: -always use pointers in cgen'd non-range for loops (sometimes also indices) -is there a problem where we can get TYPE_UNKNOWN in cgen, triggering an assert(0)? - -simple example, but maybe try other stuff: x := #C("5"); - -also make sure you can't do x:#C("5"); local structs should not be named in C make sure global slices work allow `use ???;` if an error has already occurred @@ -20,6 +16,7 @@ make sure you can do a[i] where a is &[5]int or &[]char or something do we consistently handle x := &some_array_or_slice; x.len use - use with struct members (e.g. SuperPoint ::= struct { use p: Point; }) +compile to a temp file, then move it if compilation succeeds &void simplify eval macros with val_to_u/i64 #if should not create a block @@ -29,9 +26,9 @@ switch - #fallthrough enums unions -compile to a temp file, then move it if compilation succeeds --- switch to / add as an alternative: libffi +don't bother generating ret_ if nothing's deferred X ::= newtype(int); or something any odd number of "s for a string use point #except x; @@ -77,13 +77,3 @@ static char const *indefinite_article(char const *s) { return "a"; } -#ifdef __GNUC__ -#define if_likely(x) if (__builtin_expect(x, 1)) -#define if_unlikely(x) if (__builtin_expect(x, 0)) -#else -#define if_likely if -#define if_unlikely if -#endif - -#define check(x) do { if_unlikely (!x) return false; } while (0); - @@ -1,18 +1,14 @@ #include "std/io.toc"; - -foo ::= fn() int { - puts("Hello"); - 3 -} - -bar ::= fn() (int, int) { - foo(), foo() +c_add ::= fn(x:int, y:int) int { + #C("x+y") } main ::= fn() { - _ := 5; - _ := 6+_; - _ := foo(); - _,_ := bar(); - _,_ := bar(); + xs : [5]int; + for x, i := &xs { + *x = c_add(i*i, i*i*i); + } + for x := xs { + puti(x); + } } @@ -1105,7 +1105,14 @@ static Status types_fn(Typer *tr, FnExpr *f, Type *t, Instance *instance) { ret_type = t->fn.types; has_named_ret_vals = f->ret_decls != NULL; if (ret_expr) { - if (!type_eq_implicit(&ret_expr->type, ret_type)) { + if (ret_expr->type.kind == TYPE_UNKNOWN) { + if (ret_type->kind == TYPE_UNKNOWN) { + err_print(ret_expr->where, "Can't determine type of return value. Try assigning it to a variable before returning it."); + return false; + } + if (!tr->err_ctx->have_errored) /* if we've had an error, this could be a placeholder because something failed earlier */ + ret_expr->type = *ret_type; + } else if (!type_eq_implicit(&ret_expr->type, ret_type)) { char *got = type_to_str(&ret_expr->type); char *expected = type_to_str(ret_type); err_print(ret_expr->where, "Returning type %s, but function returns type %s.", got, expected); @@ -1117,14 +1124,6 @@ static Status types_fn(Typer *tr, FnExpr *f, Type *t, Instance *instance) { success = false; goto ret; } - if (ret_expr->type.kind == TYPE_UNKNOWN) { - /* maybe it's just unknown because something messed up (like typing another function), - and ??? is a placeholder */ - if (!tr->err_ctx->have_errored) { - err_print(ret_expr->where, "Can't determine type of return value. Try assigning it to a variable before returning it."); - return false; - } - } } else if (ret_type->kind != TYPE_VOID && !has_named_ret_vals) { Statement *stmts = f->body.stmts; if (arr_len(stmts)) { @@ -1252,6 +1251,7 @@ static Status call_arg_param_order(FnExpr *fn, Type *fn_type, Argument *args, Lo if (order[param_idx] != -1) { err_print(arg->where, "Parameter #%d set twice.", param_idx+1); info_print(args[order[param_idx]].where, "Parameter was previously set here."); + return false; } order[param_idx] = arg_idx; } @@ -1946,7 +1946,7 @@ static Status types_expr(Typer *tr, Expression *e) { String i = e->ident_str; char *i_str = i.str; size_t i_len = i.len; - if_unlikely (str_eq_cstr(i, "_")) { + if (str_eq_cstr(i, "_")) { err_print(e->where, "You cannot use _ as a variable. It is used for ignoring results of function calls, e.g. _, y := function_which_returns_two_things();"); return false; } |