summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2020-04-24 17:43:21 -0400
committerLeo Tenenbaum <pommicket@gmail.com>2020-04-24 17:43:21 -0400
commitecf8b49cf99ccf0bf941a2ed9707ee5d43ebf0ad (patch)
tree43638dcef61e96f1ad25c7d3815ebcbca50bb7d2
parent2de90e47312b8a7de69712015590fc7fbd3d9b0a (diff)
improve cgen for loops and allow returning something of unknown type
-rw-r--r--cgen.c136
-rw-r--r--main.c7
-rw-r--r--misc.c10
-rw-r--r--test.toc22
-rw-r--r--types.c20
5 files changed, 89 insertions, 106 deletions
diff --git a/cgen.c b/cgen.c
index 9fde5a6..5e5054e 100644
--- a/cgen.c
+++ b/cgen.c
@@ -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);
diff --git a/main.c b/main.c
index debaaae..0c71a21 100644
--- a/main.c
+++ b/main.c
@@ -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;
diff --git a/misc.c b/misc.c
index 9b21209..4e82ff8 100644
--- a/misc.c
+++ b/misc.c
@@ -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);
-
diff --git a/test.toc b/test.toc
index ed66392..011b5a3 100644
--- a/test.toc
+++ b/test.toc
@@ -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);
+ }
}
diff --git a/types.c b/types.c
index 2eb64f0..1567c59 100644
--- a/types.c
+++ b/types.c
@@ -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;
}