harec

[hare] Hare compiler, written in C11 for POSIX OSs
Log | Files | Refs | README | LICENSE

commit 1f8d030130795ba8458c8f5234cbc153463d3b13
parent 262374062088bd4c4ca9d17019b0b4ad966e7589
Author: Joe Finney <me@spxtr.net>
Date:   Mon, 31 Oct 2022 10:07:09 -0700

Allow abort/assert to accept non-constant strings.

This is useful for tests, allowing for statements like:
    assert(a == b, fmt::asprintf("expected {}, got {}, a, b));

The message for the above assertion (if a = 4, b = 5) will be:
    Abort: /path/to/file.ha:42:1: expected 4, got 5

This patch reorders the output for assert(false), without the
message string, to be consistent with assert(false, "foo").
Previously it was "Abort: Assertion failed: location", but now it
is "Abort: location: Assertion failed" to match "Abort: location:
foo".

This patch also changes the signature for rt::_abort, adding a
location parameter (matching abort_fixed).

Related to ~sircmpwn/hare#109.

Signed-off-by: Joe Finney <me@spxtr.net>

Diffstat:
Mdocs/runtime.txt | 4++--
Minclude/expr.h | 2+-
Mrt/abort.ha | 14+++++---------
Msrc/check.c | 26++------------------------
Msrc/gen.c | 18+++++++++++++++++-
Msrc/parse.c | 4++--
6 files changed, 29 insertions(+), 39 deletions(-)

diff --git a/docs/runtime.txt b/docs/runtime.txt @@ -1,9 +1,9 @@ harec expects the runtime to provide some features under the "rt" namespace. -@noreturn @symbol("rt.abort") fn _abort(msg: str) void; +@noreturn @symbol("rt.abort") fn _abort(loc: str, msg: str) void; Print a diagnostic message and terminate the program. -@noreturn fn abort_fixed(reason: int) void; +@noreturn fn abort_fixed(loc: str, reason: int) void; Print a diagnostic message from a list of pre-determined abort reasons, and terminate the program. The list of reasons are: diff --git a/include/expr.h b/include/expr.h @@ -347,7 +347,7 @@ struct expression { const struct type *result; enum expr_type type; bool terminates; - struct location loc; // For fixed aborts + struct location loc; // For aborts union { struct expression_access access; struct expression_alloc alloc; diff --git a/rt/abort.ha b/rt/abort.ha @@ -1,6 +1,9 @@ -export @noreturn @symbol("rt.abort") fn _abort(msg: str) void = { +export @noreturn @symbol("rt.abort") fn _abort(loc: str, msg: str) void = { const prefix = "Abort: "; + const sep = ": "; write(2, constchar(prefix), len(prefix)); + write(2, constchar(loc), len(loc)); + write(2, constchar(sep), len(sep)); write(2, constchar(msg), len(msg)); write(2, constchar("\n"), 1); kill(getpid(), SIGABRT); @@ -16,12 +19,5 @@ const reasons: [_]str = [ ]; export @noreturn fn abort_fixed(loc: str, i: int) void = { - const prefix = "Abort: "; - const sep = ": "; - write(2, constchar(prefix), len(prefix)); - write(2, constchar(loc), len(loc)); - write(2, constchar(sep), len(sep)); - write(2, constchar(reasons[i]), len(reasons[i])); - write(2, constchar("\n"), 1); - kill(getpid(), SIGABRT); + _abort(loc, reasons[i]); }; diff --git a/src/check.c b/src/check.c @@ -601,33 +601,11 @@ check_expr_assert(struct context *ctx, "Assertion message must be string"); return; } - - assert(expr->assert.message->type == EXPR_CONSTANT); - size_t n = snprintf(NULL, 0, "%s:%d:%d: ", - sources[aexpr->loc.file], - aexpr->loc.lineno, aexpr->loc.colno); - size_t s_len = expr->assert.message->constant.string.len; - char *s = xcalloc(1, n + s_len + 1); - snprintf(s, n + 1, "%s:%d:%d: ", sources[aexpr->loc.file], - aexpr->loc.lineno, aexpr->loc.colno); - memcpy(s+n, expr->assert.message->constant.string.value, s_len); - s[n + s_len] = '\0'; - - expr->assert.message->constant.string.value = s; - expr->assert.message->constant.string.len = n + s_len; } else { - int n = snprintf(NULL, 0, "Assertion failed: %s:%d:%d", - sources[aexpr->loc.file], - aexpr->loc.lineno, aexpr->loc.colno); - char *s = xcalloc(1, n + 1); - snprintf(s, n, "Assertion failed: %s:%d:%d", - sources[aexpr->loc.file], - aexpr->loc.lineno, aexpr->loc.colno); - expr->assert.message->type = EXPR_CONSTANT; expr->assert.message->result = &builtin_type_const_str; - expr->assert.message->constant.string.value = s; - expr->assert.message->constant.string.len = n - 1; + expr->assert.message->constant.string.value = "Assertion failed"; + expr->assert.message->constant.string.len = 16; } if (expr->assert.is_static) { diff --git a/src/gen.c b/src/gen.c @@ -808,7 +808,23 @@ gen_expr_assert(struct gen_context *ctx, const struct expression *expr) } struct qbe_value qmsg = mkqval(ctx, &msg); - pushi(ctx->current, NULL, Q_CALL, &rtfunc, &qmsg, NULL); + + int n = snprintf(NULL, 0, "%s:%d:%d", + sources[expr->loc.file], expr->loc.lineno, + expr->loc.colno); + char *s = xcalloc(1, n + 1); + snprintf(s, n, "%s:%d:%d", + sources[expr->loc.file], expr->loc.lineno, + expr->loc.colno); + struct expression eloc = {0}; + eloc.type = EXPR_CONSTANT; + eloc.result = &builtin_type_const_str; + eloc.constant.string.value = s; + eloc.constant.string.len = n - 1; + struct gen_value loc_msg = gen_expr(ctx, &eloc); + struct qbe_value loc_qmsg = mkqval(ctx, &loc_msg); + + pushi(ctx->current, NULL, Q_CALL, &rtfunc, &loc_qmsg, &qmsg, NULL); if (expr->assert.cond) { push(&ctx->current->body, &passedl); diff --git a/src/parse.c b/src/parse.c @@ -1112,7 +1112,7 @@ parse_assertion_expression(struct lexer *lexer, bool is_static) want(lexer, T_LPAREN, &tok); exp->assert.cond = parse_expression(lexer); if (lex(lexer, &tok) == T_COMMA) { - exp->assert.message = parse_constant(lexer); + exp->assert.message = parse_expression(lexer); } else { unlex(lexer, &tok); } @@ -1122,7 +1122,7 @@ parse_assertion_expression(struct lexer *lexer, bool is_static) want(lexer, T_LPAREN, &tok); if (lex(lexer, &tok) != T_RPAREN) { unlex(lexer, &tok); - exp->assert.message = parse_constant(lexer); + exp->assert.message = parse_expression(lexer); want(lexer, T_RPAREN, &tok); } break;