Name change, some updates using "from end" indexing.

This commit is contained in:
Christoffer Lerno
2023-06-24 18:21:16 +02:00
parent fedffc2f35
commit be04473af4
8 changed files with 97 additions and 12 deletions

View File

@@ -85,6 +85,7 @@
- Allow enums to use a distinct type as the backing type.
- Update addition and subtraction on enums.
- `@ensure` checks only non-optional results.
- `assert` may now take varargs for formatting.
### Stdlib changes
- Updated posix/win32 stdlib namespacing

View File

@@ -1374,6 +1374,7 @@ typedef struct
bool is_ensure;
ExprId message;
ExprId expr;
Expr **args;
} AstAssertStmt;

View File

@@ -586,6 +586,7 @@ RETRY:
case AST_CT_ASSERT:
MACRO_COPY_EXPRID(ast->assert_stmt.expr);
MACRO_COPY_EXPRID(ast->assert_stmt.message);
MACRO_COPY_EXPR_LIST(ast->assert_stmt.args);
break;
case AST_BREAK_STMT:
case AST_CONTINUE_STMT:

View File

@@ -1001,16 +1001,28 @@ static inline void llvm_emit_assert_stmt(GenContext *c, Ast *ast)
llvm_emit_cond_br(c, &value, on_ok, on_fail);
llvm_emit_block(c, on_fail);
SourceSpan loc = assert_expr->span;
const char *error;
if (ast->assert_stmt.message)
const char *error = NULL;
Expr *message_expr = exprptrzero(ast->assert_stmt.message);
BEValue *values = NULL;
if (message_expr)
{
error = exprptr(ast->assert_stmt.message)->const_expr.string.chars;
Expr **args = ast->assert_stmt.args;
if (vec_size(args))
{
FOREACH_BEGIN(Expr *arg, args)
BEValue var;
llvm_emit_expr(c, &var, arg);
llvm_emit_any_from_value(c, &var, arg->type);
vec_add(values, var);
FOREACH_END();
}
}
else
{
error = "Assert violation";
}
llvm_emit_panic(c, error, loc, NULL, NULL);
llvm_emit_panic(c, values ? NULL : error, loc, values ? error : NULL, values);
llvm_emit_br(c, on_ok);
llvm_emit_block(c, on_ok);
}

View File

@@ -1080,7 +1080,14 @@ static inline Ast *parse_assert_stmt(ParseContext *c)
if (try_consume(c, TOKEN_COMMA))
{
ASSIGN_EXPRID_OR_RET(ast->assert_stmt.message, parse_expr(c), poisoned_ast);
Expr **args = NULL;
ASSIGN_EXPRID_OR_RET(ast->assert_stmt.message, parse_constant_expr(c), poisoned_ast);
while (try_consume(c, TOKEN_COMMA))
{
ASSIGN_EXPR_OR_RET(Expr *expr, parse_expr(c), poisoned_ast);
vec_add(args, expr);
}
ast->assert_stmt.args = args;
}
TRY_CONSUME_OR_RET(TOKEN_RPAREN, "The ending ')' was expected here.", poisoned_ast);
return consume_eos(c, ast);

View File

@@ -82,14 +82,12 @@ static inline bool sema_analyse_assert_stmt(SemaContext *context, Ast *statement
if (message_expr)
{
if (!sema_analyse_expr(context, message_expr)) return false;
if (!expr_is_const_string(message_expr))
{
SEMA_ERROR(message_expr, "Expected a string as the error message.");
return false;
}
if (!expr_is_const_string(message_expr)) RETURN_SEMA_ERROR(message_expr, "Expected a string as the error message.");
FOREACH_BEGIN(Expr *e, statement->assert_stmt.args)
if (!sema_analyse_expr(context, e)) return false;
FOREACH_END();
}
// Handle force unwrapping using assert, e.g. assert(try x)
if (expr->expr_kind == EXPR_TRY_UNWRAP_CHAIN)
{
@@ -111,7 +109,7 @@ static inline bool sema_analyse_assert_stmt(SemaContext *context, Ast *statement
// If it's ensure (and an error) we print an error.
if (statement->assert_stmt.is_ensure)
{
if (message_expr)
if (message_expr && expr_is_const(message_expr) && vec_size(statement->assert_stmt.args))
{
SEMA_ERROR(expr, "%.*s", EXPAND_EXPR_STRING(message_expr));
}

View File

@@ -1 +1 @@
#define COMPILER_VERSION "0.4.538"
#define COMPILER_VERSION "0.4.539"

View File

@@ -0,0 +1,65 @@
// #target: macos-x64
// #safe: yes
module main;
fn void! main()
{
for (usz i = 0; i < 100000000; i++)
{
assert(i != 2, "Test %s %s", i, i * 2);
}
}
/* #expect: main.ll
define i64 @main.main() #0 {
entry:
%i = alloca i64, align 8
%taddr = alloca i64, align 8
%varargslots = alloca [2 x %any], align 16
%indirectarg = alloca %"any[]", align 8
%reterr = alloca i64, align 8
store i64 0, ptr %i, align 8
br label %loop.cond
loop.cond: ; preds = %assert_ok, %entry
%0 = load i64, ptr %i, align 8
%gt = icmp ugt i64 100000000, %0
br i1 %gt, label %loop.body, label %loop.exit
loop.body: ; preds = %loop.cond
%1 = load i64, ptr %i, align 8
%neq = icmp ne i64 2, %1
br i1 %neq, label %assert_ok, label %assert_fail
assert_fail: ; preds = %loop.body
%2 = insertvalue %any undef, ptr %i, 0
%3 = insertvalue %any %2, i64 ptrtoint (ptr @"$ct.ulong" to i64), 1
%4 = load i64, ptr %i, align 8
%mul = mul i64 %4, 2
store i64 %mul, ptr %taddr, align 8
%5 = insertvalue %any undef, ptr %taddr, 0
%6 = insertvalue %any %5, i64 ptrtoint (ptr @"$ct.long" to i64), 1
%7 = getelementptr inbounds [2 x %any], ptr %varargslots, i64 0, i64 0
store %any %3, ptr %7, align 16
%8 = getelementptr inbounds [2 x %any], ptr %varargslots, i64 0, i64 1
store %any %6, ptr %8, align 16
%9 = insertvalue %"any[]" undef, ptr %varargslots, 0
%10 = insertvalue %"any[]" %9, i64 2, 1
store %"any[]" %10, ptr %indirectarg, align 8
call void @std.core.builtin.panicf(ptr @.panic_msg, i64 10, ptr @.file, i64 10, ptr @.func, i64 4, i32 7, ptr byval(%"any[]") align 8 %indirectarg)
br label %assert_ok
assert_ok: ; preds = %assert_fail, %loop.body
%11 = load i64, ptr %i, align 8
%neq1 = icmp ne i64 2, %11
call void @llvm.assume(i1 %neq1)
%12 = load i64, ptr %i, align 8
%add = add i64 %12, 1
store i64 %add, ptr %i, align 8
br label %loop.cond
loop.exit: ; preds = %loop.cond
ret i64 0
}