From 54da571f3d6600033e9f7bac3be4aeebdf20d374 Mon Sep 17 00:00:00 2001 From: Leo Tenenbaum Date: Thu, 17 Oct 2019 20:19:22 -0400 Subject: basic cgen block return values --- cgen.c | 141 +++++++++++++++++++++++++++++++++++++++++++++++++++++---------- main.c | 3 +- out.c | 19 +++++++-- runv | 7 +++- test.toc | 8 ++-- types.c | 4 ++ 6 files changed, 152 insertions(+), 30 deletions(-) diff --git a/cgen.c b/cgen.c index 82fac70..23bef3e 100644 --- a/cgen.c +++ b/cgen.c @@ -1,5 +1,6 @@ static bool cgen_stmt(CGenerator *g, Statement *s); -static bool cgen_block(CGenerator *g, Block *b); +static bool cgen_block(CGenerator *g, Block *b, const char *ret_name); +static bool cgen_expr_pre(CGenerator *g, Expression *e); static bool cgen_expr(CGenerator *g, Expression *e); static bool cgen_set_tuple(CGenerator *g, Expression *exprs, Identifier *idents, Expression *to); static bool cgen_type_pre(CGenerator *g, Type *t, Location where); @@ -116,6 +117,11 @@ static void cgen_ident_id(CGenerator *g, IdentID id) { cgen_write(g, "a%lu_", (unsigned long)id); } +/* buffer should be at least 32 bytes */ +static inline void cgen_ident_id_to_str(char *buffer, IdentID id) { + snprintf(buffer, 32, "a%lu_", (unsigned long)id); +} + static bool cgen_type_post(CGenerator *g, Type *t, Location where); static bool cgen_type_pre(CGenerator *g, Type *t, Location where) { switch (t->kind) { @@ -279,6 +285,7 @@ static bool cgen_fn_header(CGenerator *g, FnExpr *f, Location where) { /* 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 */ static bool cgen_set(CGenerator *g, Expression *set_expr, const char *set_str, Expression *to_expr, const char *to_str) { @@ -287,10 +294,12 @@ 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; } switch (type->kind) { case TYPE_BUILTIN: @@ -411,6 +420,74 @@ static bool cgen_set_tuple(CGenerator *g, Expression *exprs, Identifier *idents, return true; } +static bool cgen_expr_pre(CGenerator *g, Expression *e) { + switch (e->kind) { + case EXPR_IF: { + char ret_name[32]; + IfExpr *curr = &e->if_; + curr->c.id = g->ident_counter++; + cgen_ident_id_to_str(ret_name, curr->c.id); + if (e->type.kind != TYPE_VOID) { + cgen_type_pre(g, &e->type, e->where); + cgen_write(g, " %s", ret_name); + cgen_type_post(g, &e->type, e->where); + cgen_write(g, ";"); + cgen_nl(g); + } + + while (1) { + if (curr->cond) { + cgen_write(g, "if ("); + if (!cgen_expr(g, curr->cond)) + return false; + cgen_write(g, ") "); + } + if (!cgen_block(g, &curr->body, ret_name)) + return false; + if (curr->next_elif) { + cgen_write(g, " else "); + curr = &curr->next_elif->if_; + } else break; + } + } break; + case EXPR_WHILE: + break; + case EXPR_BLOCK: + break; + case EXPR_CALL: + if (!cgen_expr_pre(g, e->call.fn)) return false; + arr_foreach(e->call.arg_exprs, Expression, arg) + if (!cgen_expr_pre(g, arg)) return false; + break; + case EXPR_UNARY_OP: + if (!cgen_expr_pre(g, e->unary.of)) return false; + break; + case EXPR_BINARY_OP: + if (!cgen_expr_pre(g, e->binary.lhs)) return false; + if (!cgen_expr_pre(g, e->binary.rhs)) return false; + break; + case EXPR_CAST: + if (!cgen_expr_pre(g, e->cast.expr)) return false; + break; + case EXPR_NEW: + /* TODO */ + break; + case EXPR_LITERAL_INT: + case EXPR_LITERAL_FLOAT: + case EXPR_LITERAL_BOOL: + case EXPR_LITERAL_CHAR: + case EXPR_LITERAL_STR: + case EXPR_IDENT: + case EXPR_FN: + case EXPR_DIRECT: + break; + case EXPR_TUPLE: + assert(0); + return false; + } + return true; +} + static bool cgen_expr(CGenerator *g, Expression *e) { switch (e->kind) { case EXPR_LITERAL_FLOAT: @@ -512,23 +589,9 @@ static bool cgen_expr(CGenerator *g, Expression *e) { return false; cgen_write(g, ")))"); break; - case EXPR_IF: { - IfExpr *curr = &e->if_; - while (1) { - if (curr->cond) { - cgen_write(g, "if ("); - if (!cgen_expr(g, curr->cond)) - return false; - cgen_write(g, ") "); - } - if (!cgen_block(g, &curr->body)) - return false; - if (curr->next_elif) { - cgen_write(g, " else "); - curr = &curr->next_elif->if_; - } else break; - } - } break; + case EXPR_IF: + cgen_ident_id(g, e->if_.c.id); + break; case EXPR_CALL: cgen_write(g, "("); if (!cgen_expr(g, e->call.fn)) @@ -554,6 +617,21 @@ static bool cgen_expr(CGenerator *g, Expression *e) { case DIRECT_COUNT: assert(0); break; } break; + case EXPR_CAST: + cgen_write(g, "(("); + cgen_type_pre(g, &e->cast.type, e->where); + cgen_type_post(g, &e->cast.type, e->where); + cgen_write(g, ")("); + if (!cgen_expr(g, e->cast.expr)) + return false; + cgen_write(g, "))"); + break; + case EXPR_TUPLE: + /* the only time this should happen is if you're stating + a tuple, e.g. 3, 5;, but we've errored about that before + (the comma operator does not exist in toc!) */ + assert(0); + break; case EXPR_FN: { if (g->block != NULL) { Expression **eptr = arr_add(&g->anon_fns); @@ -565,7 +643,12 @@ static bool cgen_expr(CGenerator *g, Expression *e) { return true; } -static bool cgen_block(CGenerator *g, Block *b) { +/* + ret_name = variable to store block return value in; NULL for none. NOTE: + functions always call with NULL as ret_name, even if they use out params, for now + at least. +*/ +static bool cgen_block(CGenerator *g, Block *b, const char *ret_name) { Block *prev = g->block; cgen_block_enter(g, b); cgen_write(g, "{"); @@ -573,7 +656,12 @@ static bool cgen_block(CGenerator *g, Block *b) { arr_foreach(b->stmts, Statement, s) if (!cgen_stmt(g, s)) return false; - + + if (b->ret_expr && ret_name) { + if (!cgen_set(g, NULL, ret_name, b->ret_expr, NULL)) + return false; + cgen_nl(g); + } cgen_block_exit(g, prev); cgen_write(g, "}"); return true; @@ -612,7 +700,7 @@ static bool cgen_fn(CGenerator *g, FnExpr *f, Location where) { arr_foreach(f->ret_decls, Declaration, d) { cgen_decl(g, d); } - if (!cgen_block(g, &f->body)) + if (!cgen_block(g, &f->body, NULL)) return false; if (f->ret_decls) { if (cgen_uses_ptr(&f->ret_type)) { @@ -639,6 +727,12 @@ static bool cgen_decl(CGenerator *g, Declaration *d) { } else if (d->flags & DECL_FLAG_CONST) { /* TODO? */ } else { + /* TODO: Globals just cgen val */ + if (g->block != NULL && (d->flags & DECL_FLAG_HAS_EXPR)) { + if (!cgen_expr_pre(g, &d->expr)) + return false; + } + for (size_t idx = 0; idx < arr_len(d->idents); idx++) { Identifier *i = &d->idents[idx]; Type *t = d->type.kind == TYPE_TUPLE ? &d->type.tuple[idx] : &d->type; @@ -713,11 +807,16 @@ 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.filename, s->where.line); + */ switch (s->kind) { case STMT_DECL: if (!cgen_decl(g, &s->decl)) return false; break; case STMT_EXPR: + if (!cgen_expr_pre(g, &s->expr)) return false; if (!cgen_expr(g, &s->expr)) return false; cgen_write(g, ";"); cgen_nl(g); diff --git a/main.c b/main.c index d6e40d9..2b0227d 100644 --- a/main.c +++ b/main.c @@ -1,6 +1,7 @@ /* TODO: -cgen tuples +blocks which return tuples +new run-time type resolution unicode variable names re-do cgen make sure initializers for global variables are compile-time constants diff --git a/out.c b/out.c index 4b7dfc7..1c3ff2c 100644 --- a/out.c +++ b/out.c @@ -28,7 +28,7 @@ int main() { void puti(i64 x) { { - printf("%lu\n", x); + printf("%ld\n", (long)x); }} @@ -40,7 +40,7 @@ void mktup(i64 a, i64 b, i64(*ret0_), i64(*ret1_)) { i64 asdf(void) { { -}return 7; +}return 32187318; } @@ -48,9 +48,22 @@ void main__(void) { { i64 a; i64 b; mktup(10, 20, &a, &b); - (puti((asdf()))); + (puti(((i64)(((u8)((asdf()))))))); (puti(a)); (puti(b)); + i64 a0_; + if (5) { + a0_ = 6; + } else { + a0_ = 7; + }i64 x; { + i64 expr__; i64 a1_; + if (5) { + a1_ = 6; + } else { + a1_ = 7; + }expr__ = (5+(-a1_));x = expr__;} + (puti(x)); }} diff --git a/runv b/runv index bf00c4f..698e83d 100755 --- a/runv +++ b/runv @@ -1,2 +1,5 @@ -#!/bin/bash -valgrind -q --track-origins=yes ./toc test.toc +#!/bin/sh +valgrind -q --track-origins=yes ./toc test.toc || exit 1 +if [ "$1" = "c" ]; then + gcc out.c && ./a.out +fi diff --git a/test.toc b/test.toc index 0b402b4..cda73e2 100644 --- a/test.toc +++ b/test.toc @@ -1,5 +1,5 @@ puti @= fn(x: int) { - #C("printf(\"%lu\\n\", x)"); + #C("printf(\"%ld\\n\", (long)x)"); }; mktup @= fn(a: int, b: int) (int, int) { @@ -7,12 +7,14 @@ mktup @= fn(a: int, b: int) (int, int) { }; asdf @= fn() int { - 7 + 32187318 }; main @= fn() { a, b := mktup(10, 20); // x := mktup; - puti(asdf()); + puti(asdf() as u8 as i64); puti(a); puti(b); + x := 5+-if 5 { 6 } else { 7 }; + puti(x); }; \ No newline at end of file diff --git a/types.c b/types.c index 39de36a..6ae52a9 100644 --- a/types.c +++ b/types.c @@ -1102,6 +1102,10 @@ static bool types_stmt(Typer *tr, Statement *s) { if (!types_expr(tr, &s->expr)) { return false; } + if (s->expr.type.kind == TYPE_TUPLE) { + err_print(s->where, "Statement of a tuple is not allowed. The comma operator does not exist in toc; use a semicolon instead."); + return false; + } break; case STMT_DECL: if (!types_decl(tr, &s->decl)) -- cgit v1.2.3