summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cgen.c104
-rw-r--r--eval.c3
-rw-r--r--main.c11
-rw-r--r--parse.c4
-rw-r--r--test.toc28
-rw-r--r--types.h3
6 files changed, 109 insertions, 44 deletions
diff --git a/cgen.c b/cgen.c
index 3595ed4..5641d6f 100644
--- a/cgen.c
+++ b/cgen.c
@@ -28,7 +28,7 @@ static void cgen_set_tuple(CGenerator *g, Expression *exprs, Identifier *idents,
static void cgen_type_pre(CGenerator *g, Type *t);
static void cgen_type_post(CGenerator *g, Type *t);
static void cgen_decl(CGenerator *g, Declaration *d);
-static void cgen_ret(CGenerator *g, Expression *ret);
+static void cgen_ret(CGenerator *g, Block *returning_from, Expression *ret_expr);
/* yes, these do need to take pointers, and furthermore they must be the same pointer (because of slices) */
static void cgen_val(CGenerator *g, Value *v, Type *t);
static void cgen_val_pre(CGenerator *g, Value *v, Type *t);
@@ -322,7 +322,10 @@ static void cgen_type_pre(CGenerator *g, Type *t) {
assert(0); break;
} break;
case TYPE_PTR:
- cgen_type_pre(g, t->ptr);
+ if (t->ptr->kind == TYPE_UNKNOWN)
+ cgen_write(g, "void"); /* #C &"foo", for example */
+ else
+ cgen_type_pre(g, t->ptr);
cgen_write(g, "(*");
break;
case TYPE_ARR:
@@ -669,6 +672,18 @@ static void cgen_fn_header(CGenerator *g, FnExpr *f, U64 which_are_const) {
}
}
+static inline void cgen_deferred_stmts_from_block(CGenerator *g, Block *from) {
+ arr_foreach(from->deferred, StatementPtr, s) {
+ cgen_stmt(g, *s);
+ }
+}
+
+/* generates deferred statements in g->block, g->block->parent, ..., to) */
+static void cgen_deferred_stmts_up_to(CGenerator *g, Block *to) {
+ for (Block *b = g->block; b; b = b == to ? NULL : b->parent) {
+ cgen_deferred_stmts_from_block(g, b);
+ }
+}
/*
Either set_expr or set_str should be NULL and either to_expr or to_str should be NULL
@@ -1676,6 +1691,7 @@ static void cgen_expr(CGenerator *g, Expression *e) {
static void cgen_block(CGenerator *g, Block *b, const char *ret_name, U16 flags) {
Block *prev_block = g->block;
g->block = b;
+ b->deferred = NULL;
++g->indent_lvl;
if (!(flags & CGEN_BLOCK_NOBRACES)) {
@@ -1698,6 +1714,8 @@ static void cgen_block(CGenerator *g, Block *b, const char *ret_name, U16 flags)
}
--g->indent_lvl;
if (!(flags & CGEN_BLOCK_NOBRACES)) {
+ cgen_deferred_stmts_from_block(g, b);
+ arr_clear(&b->deferred);
cgen_write(g, "}");
if (b->c.break_lbl) {
cgen_lbl(g, b->c.break_lbl);
@@ -1803,12 +1821,7 @@ static void cgen_fn(CGenerator *g, FnExpr *f, Value *compile_time_args) {
}
cgen_block(g, &f->body, NULL, CGEN_BLOCK_NOBRACES);
- if (f->ret_decls) {
- cgen_ret(g, NULL);
- } else if (f->body.ret_expr) {
- cgen_ret(g, f->body.ret_expr);
- }
-
+ cgen_ret(g, &f->body, f->body.ret_expr);
cgen_writeln(g, "}");
g->fn = prev_fn;
@@ -1906,21 +1919,31 @@ static void cgen_decl(CGenerator *g, Declaration *d) {
}
}
-static void cgen_ret(CGenerator *g, Expression *ret) {
+static void cgen_ret(CGenerator *g, Block *returning_from, Expression *ret_expr) {
FnExpr *f = g->fn;
+ if (ret_expr) {
+ cgen_expr_pre(g, ret_expr);
+ /* set ret_ to ret_expr */
+ cgen_type_pre(g, &ret_expr->type);
+ cgen_write(g, " ret_");
+ cgen_type_post(g, &ret_expr->type);
+ cgen_write(g, "; ");
+ cgen_set(g, NULL, "ret_", ret_expr, NULL);
+ cgen_nl(g);
+ }
+ cgen_deferred_stmts_up_to(g, returning_from);
if (f->ret_decls) {
- assert(!ret);
if (f->ret_type.kind == TYPE_TUPLE) {
- Expression ret_expr = {0};
- ret_expr.flags = EXPR_FOUND_TYPE;
- ret_expr.type = f->ret_type;
- ret_expr.kind = EXPR_TUPLE;
- ret_expr.tuple = NULL;
- arr_set_len(&ret_expr.tuple, arr_len(f->ret_type.tuple));
+ Expression tuple_expr = {0};
+ tuple_expr.flags = EXPR_FOUND_TYPE;
+ tuple_expr.type = f->ret_type;
+ tuple_expr.kind = EXPR_TUPLE;
+ tuple_expr.tuple = NULL;
+ arr_set_len(&tuple_expr.tuple, arr_len(f->ret_type.tuple));
int idx = 0;
arr_foreach(f->ret_decls, Declaration, d) {
arr_foreach(d->idents, Identifier, ident) {
- Expression *e = &ret_expr.tuple[idx];
+ Expression *e = &tuple_expr.tuple[idx];
e->flags = EXPR_FOUND_TYPE;
e->type = f->ret_type.tuple[idx];
e->kind = EXPR_IDENT;
@@ -1928,15 +1951,15 @@ static void cgen_ret(CGenerator *g, Expression *ret) {
++idx;
}
}
- cgen_set_tuple(g, NULL, NULL, "*ret__", &ret_expr);
- arr_clear(&ret_expr.tuple);
+ cgen_set_tuple(g, NULL, NULL, "*ret__", &tuple_expr);
+ arr_clear(&tuple_expr.tuple);
} else if (cgen_uses_ptr(&f->ret_type)) {
- Expression ret_expr = {0};
- ret_expr.flags = EXPR_FOUND_TYPE;
- ret_expr.type = f->ret_type;
- ret_expr.kind = EXPR_IDENT;
- ret_expr.ident = f->ret_decls[0].idents[0];
- cgen_set(g, NULL, "*ret__", &ret_expr, NULL);
+ Expression expr = {0};
+ expr.flags = EXPR_FOUND_TYPE;
+ expr.type = f->ret_type;
+ expr.kind = EXPR_IDENT;
+ expr.ident = f->ret_decls[0].idents[0];
+ cgen_set(g, NULL, "*ret__", &expr, NULL);
cgen_writeln(g, ";");
cgen_writeln(g, "return;");
} else {
@@ -1946,24 +1969,21 @@ static void cgen_ret(CGenerator *g, Expression *ret) {
}
return;
}
- if (ret) {
- assert(type_eq(&f->ret_type, &ret->type));
- cgen_expr_pre(g, ret);
- }
- if (!ret) {
- cgen_write(g, "return");
- } else if (cgen_uses_ptr(&f->ret_type)) {
+ if (cgen_uses_ptr(&f->ret_type)) {
+ Expression ret = {0};
+ ret.kind = EXPR_IDENT;
+ ret.ident = ident_get(g->globals, "ret_");
+ ret.flags = EXPR_FOUND_TYPE;
+ ret.type = f->ret_type;
if (f->ret_type.kind == TYPE_TUPLE) {
- cgen_set_tuple(g, NULL, NULL, "*ret__", ret);
+ cgen_set_tuple(g, NULL, NULL, "*ret__", &ret);
} else {
- cgen_set(g, NULL, "*ret__", ret, NULL);
+ cgen_set(g, NULL, "*ret__", &ret, NULL);
}
- cgen_write(g, " return");
- } else {
- cgen_write(g, "return ");
- cgen_expr(g, ret);
+ cgen_write(g, " return;");
+ } else if (f->ret_type.kind != TYPE_VOID) {
+ cgen_writeln(g, "return ret_;");
}
- cgen_writeln(g, ";");
}
static void cgen_stmt(CGenerator *g, Statement *s) {
@@ -1986,7 +2006,7 @@ static void cgen_stmt(CGenerator *g, Statement *s) {
break;
case STMT_RET: {
unsigned has_expr = s->ret.flags & RET_HAS_EXPR;
- cgen_ret(g, has_expr ? &s->ret.expr : NULL);
+ cgen_ret(g, s->ret.referring_to, has_expr ? &s->ret.expr : NULL);
} break;
case STMT_INCLUDE:
if (s->inc.inc_file && (s->inc.inc_file->flags & INC_FILE_CGEND)){
@@ -2009,6 +2029,9 @@ static void cgen_stmt(CGenerator *g, Statement *s) {
break;
case STMT_MESSAGE:
break;
+ case STMT_DEFER:
+ *(Statement **)arr_add(&g->block->deferred) = s->defer;
+ break;
}
}
@@ -2080,6 +2103,7 @@ static void cgen_defs_block(CGenerator *g, Block *b) {
*/
Block *prev_block = g->block;
g->block = b;
+ b->deferred = NULL;
arr_foreach(b->stmts, Statement, s) {
cgen_defs_stmt(g, s);
}
diff --git a/eval.c b/eval.c
index d916ef4..c694c41 100644
--- a/eval.c
+++ b/eval.c
@@ -1712,6 +1712,9 @@ static Status eval_stmt(Evaluator *ev, Statement *stmt) {
} break;
case STMT_MESSAGE:
break;
+ case STMT_DEFER:
+ /* TODO */
+ break;
}
return true;
}
diff --git a/main.c b/main.c
index 1c7c9e9..f50b9ac 100644
--- a/main.c
+++ b/main.c
@@ -9,6 +9,8 @@
/*
TODO:
defer
+make sure defer works with for
+make sure you can't return a #C() (because of the current defer system)
use
&&, ||
start making a standard library... (printf; stringbuilder would be nice to have)
@@ -37,6 +39,9 @@ macros
#include <signal.h>
#include <execinfo.h>
#include <unistd.h>
+
+static char *program_name;
+
static void signal_handler(int num) {
switch (num) {
case SIGABRT:
@@ -55,7 +60,10 @@ static void signal_handler(int num) {
int naddrs = (int)(sizeof addrs / sizeof *addrs);
naddrs = backtrace(addrs, naddrs);
/* char **syms = backtrace_symbols(addrs, naddrs); */
- char command[2048] = "addr2line -p -f -a -e toc ";
+ char command[2048] = "addr2line -p -f -a -e ";
+ strcat(command, program_name);
+ strcat(command, " ");
+
for (int i = 4; i < naddrs; ++i) {
snprintf(command + strlen(command), sizeof command - strlen(command), "%p ", addrs[i]);
}
@@ -67,6 +75,7 @@ static void signal_handler(int num) {
int main(int argc, char **argv) {
#ifdef BACKTRACE
+ program_name = argv[0];
signal(SIGABRT, signal_handler);
signal(SIGSEGV, signal_handler);
#endif
diff --git a/parse.c b/parse.c
index 7c6fe7d..37bf68e 100644
--- a/parse.c
+++ b/parse.c
@@ -2449,6 +2449,10 @@ static Status parse_stmt(Parser *p, Statement *s, bool *was_a_statement) {
}
goto success;
case KW_DEFER:
+ if (p->block == NULL) {
+ tokr_err(t, "You can't defer something at global scope.");
+ return false;
+ }
s->kind = STMT_DEFER;
++t->token;
s->defer = parser_malloc(p, sizeof *s->defer);
diff --git a/test.toc b/test.toc
index 66dfe61..790a115 100644
--- a/test.toc
+++ b/test.toc
@@ -1,5 +1,27 @@
-#include "std/io.toc";
+#include "std/mem.toc", mem;
+#include "std/io.toc", io;
+
+calculation ::= fn() int {
+ total := 0;
+ i := mem.new(int);
+ *i = 3;
+ ns := mem.news(int, 10);
+ for n, i := &ns {
+ if i % 2 == 0 {
+ *n = i;
+ }
+ }
+ for n := ns {
+ total += n;
+ }
+ total += *i;
+ mem.del(i);
+ mem.dels(ns);
+ total
+}
+
main ::= fn() {
- defer puts("bye");
- puts("hello");
+ io.puti(calculation());
+ x ::= calculation();
+ io.puti(x);
}
diff --git a/types.h b/types.h
index b2efa50..3549ad6 100644
--- a/types.h
+++ b/types.h
@@ -509,6 +509,7 @@ typedef struct Block {
struct Statement *stmts;
struct Expression *ret_expr; /* the return expression of this block, e.g. {foo(); 3} => 3 NULL for no expression. */
struct Block *parent;
+ struct Statement **deferred; /* deferred stuff from this block; used by both eval and cgen */
} Block;
enum {
@@ -984,6 +985,8 @@ typedef struct Statement {
};
} Statement;
+typedef Statement *StatementPtr;
+
typedef struct ParsedFile {
Statement *stmts;
} ParsedFile;