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:
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;