harec

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit 26f865e29ba17223d71143db62395cceaf3a9aa9
parent faa2bb7d3f1ae5ca68b43eddbf92d595bd4cd518
Author: Drew DeVault <sir@cmpwn.com>
Date:   Wed, 30 Dec 2020 14:19:25 -0500

gen: implement assertion expressions

Note that, without a runtime, these don't do very much yet.

Diffstat:
Mrt/Makefile | 2+-
Art/abort.ha | 7+++++++
Drt/assert.ha | 12------------
Msrc/check.c | 8++++++--
Msrc/gen.c | 50+++++++++++++++++++++++++++++++++++++++++++++++++-
5 files changed, 63 insertions(+), 16 deletions(-)

diff --git a/rt/Makefile b/rt/Makefile @@ -1,5 +1,5 @@ libhart_srcs=\ - rt/assert.ha \ + rt/abort.ha \ rt/malloc.ha \ rt/memcmp.ha \ rt/memcpy.ha \ diff --git a/rt/abort.ha b/rt/abort.ha @@ -0,0 +1,7 @@ +export @noreturn @symbol("rt.abort") fn _abort(msg: str) void = { + const prefix = "Abort: "; + write(2, prefix: *char, len(prefix)); + write(2, msg: *char, len(msg)); + write(2, "\n": *char, 1); + kill(getpid(), SIGABRT); +}; diff --git a/rt/assert.ha b/rt/assert.ha @@ -1,12 +0,0 @@ -export @noreturn fn abort() void = kill(getpid(), SIGABRT); - -export @symbol("sys.assert") fn assert_(cond: bool, msg: str) void = { - if (!cond) { - const prefix = "Assertion failed: "; - write(2, prefix: *char, len(prefix)); - write(2, msg: *char, len(msg)); - write(2, "\n": *char, 1); - abort(); - }; -}; - diff --git a/src/check.c b/src/check.c @@ -685,7 +685,6 @@ check_function(struct context *ctx, const struct ast_function_decl *afndecl = &adecl->function; trenter(TR_CHECK, "function"); - assert(!afndecl->symbol); // TODO const struct ast_type fn_atype = { .storage = TYPE_STORAGE_FUNCTION, @@ -701,7 +700,12 @@ check_function(struct context *ctx, decl->type = DECL_FUNC; decl->func.type = fntype; decl->func.flags = afndecl->flags; - mkident(ctx, &decl->ident, &afndecl->ident); + + if (afndecl->symbol) { + decl->ident.name = strdup(afndecl->symbol); + } else { + mkident(ctx, &decl->ident, &afndecl->ident); + } decl->func.scope = scope_push(&ctx->scope, TR_CHECK); struct ast_function_parameters *params = afndecl->prototype.params; diff --git a/src/gen.c b/src/gen.c @@ -333,6 +333,53 @@ gen_expr_access(struct gen_context *ctx, } static void +gen_expr_assert(struct gen_context *ctx, + const struct expression *expr, + const struct qbe_value *out) +{ + assert(!out); // Invariant + assert(expr->assert.message); // Invariant + + struct qbe_statement failedl = {0}, passedl = {0}; + struct qbe_value bfailed = {0}, bpassed = {0}; + + struct qbe_value msg = {0}; + + struct qbe_value rtfunc = {0}; + rtfunc.kind = QV_GLOBAL; + rtfunc.name = strdup("rt.abort"); + rtfunc.type = &qbe_long; + + if (expr->assert.cond) { + bfailed.kind = QV_LABEL; + bfailed.name = strdup(genl(&failedl, &ctx->id, "failed.%d")); + bpassed.kind = QV_LABEL; + bpassed.name = strdup(genl(&passedl, &ctx->id, "passed.%d")); + + struct qbe_value cond = {0}; + gen_temp(ctx, &cond, &qbe_word, "assert.%d"); + gen_expression(ctx, expr->assert.cond, &cond); + + alloc_temp(ctx, &msg, &builtin_type_const_str, "msg.%d"); + qval_deref(&msg); + gen_expression(ctx, expr->assert.message, &msg); + + pushi(ctx->current, NULL, Q_JNZ, &cond, &bpassed, &bfailed, NULL); + push(&ctx->current->body, &failedl); + } else { + alloc_temp(ctx, &msg, &builtin_type_const_str, "msg.%d"); + qval_deref(&msg); + gen_expression(ctx, expr->assert.message, &msg); + } + + pushi(ctx->current, NULL, Q_CALL, &rtfunc, &msg, NULL); + + if (expr->assert.cond) { + push(&ctx->current->body, &passedl); + } +} + +static void gen_expr_assign_ptr(struct gen_context *ctx, const struct expression *expr, const struct qbe_value *out) @@ -795,7 +842,8 @@ gen_expression(struct gen_context *ctx, gen_expr_access(ctx, expr, out); break; case EXPR_ASSERT: - assert(0); // TODO + gen_expr_assert(ctx, expr, out); + break; case EXPR_ASSIGN: gen_expr_assign(ctx, expr, out); break;