Add static and runtime assert

This commit is contained in:
Krzosa Karol
2022-06-15 10:30:33 +02:00
parent e984049429
commit aab89ffada
6 changed files with 76 additions and 10 deletions

22
ast.cpp
View File

@@ -20,6 +20,8 @@ enum Ast_Kind: U32{
AST_CALL_ITEM,
AST_CALL,
AST_CONSTANT_ASSERT,
AST_RUNTIME_ASSERT,
AST_SIZE_OF,
AST_LENGTH_OF,
AST_ALIGN_OF,
@@ -119,7 +121,8 @@ struct Ast_Binary: Ast_Expr{
struct Ast_Builtin: Ast_Expr{
Ast_Expr *expr;
U64 padding[3]; // For folding constants into atoms
Intern_String assert_message;
U64 padding[1]; // For folding constants into atoms
};
// Problem: We are parsing out of order, in the middle of parsing a function
@@ -197,7 +200,6 @@ struct Ast_Scope: Ast{
Ast_Module *module;
};
struct Ast_Module: Ast_Scope{
Array<Ast_File *> all_loaded_files;
};
@@ -507,6 +509,22 @@ ast_module(Intern_String filename){
return result;
}
function Ast_Builtin *
ast_runtime_assert(Token *pos, Ast_Expr *expr, Intern_String message){
AST_NEW(Builtin, RUNTIME_ASSERT, pos, AST_EXPR);
result->expr = expr;
result->assert_message = message;
return result;
}
function Ast_Builtin *
ast_constant_assert(Token *pos, Ast_Expr *expr, Intern_String message){
AST_NEW(Builtin, CONSTANT_ASSERT, pos, AST_EXPR);
result->expr = expr;
result->assert_message = message;
return result;
}
function Ast_Builtin *
ast_sizeof(Token *pos, Ast_Expr *expr){
AST_NEW(Builtin, SIZE_OF, pos, AST_EXPR);

View File

@@ -365,6 +365,18 @@ function void
gen_ast(Ast *ast){
switch(ast->kind){
CASE(RUNTIME_ASSERT, Builtin){
if(node->assert_message.len == 0) gen("assert");
else gen("assert_msg");
gen("(");
gen_expr(node->expr);
if(node->assert_message.len){
gen(", \"%s\"", node->assert_message.str);
}
gen(");");
BREAK();
}
CASE(RETURN, Return){
gen("return");
if(node->expr){
@@ -504,6 +516,7 @@ gen_ast(Ast *ast){
BREAK();
}
case AST_CONSTANT_ASSERT:
case AST_MODULE_NAMESPACE:
CASE(FILE_NAMESPACE, File_Namespace){unused(node); BREAK();}

View File

@@ -164,6 +164,7 @@ Intern_String keyword_false;
Intern_String keyword_for;
Intern_String keyword_pass;
Intern_String keyword_elif;
Intern_String keyword_assert;
Intern_String keyword_sizeof;
Intern_String keyword_alignof;
Intern_String keyword_lengthof;
@@ -211,6 +212,7 @@ lex_init(Allocator *token_string_arena, Allocator *map_allocator, Lexer *l){
keyword_true = l->intern("true"_s);
keyword_false = l->intern("false"_s);
keyword_return = l->intern("return"_s);
keyword_assert = l->intern("assert"_s);
keyword_if = l->intern("if"_s);
keyword_elif = l->intern("elif"_s);
keyword_pass = l->intern("pass"_s);

View File

@@ -224,6 +224,30 @@ parse_stmt_scope(Ast_Scope *scope_defined_outside = 0){
scope->stmts.add(ast_pass(token));
}
else if(token_match_keyword(keyword_assert)){
token_expect(TK_OpenParen);
Ast_Expr *expr = parse_expr();
Intern_String message = {};
if(token_match(TK_Comma)){
Token *t = token_expect(TK_StringLit);
message = t->intern_val;
}
token_expect(TK_CloseParen);
scope->stmts.add(ast_runtime_assert(token, expr, message));
}
else if(token_match_pound(keyword_assert)){
token_expect(TK_OpenParen);
Ast_Expr *expr = parse_expr();
Intern_String message = {};
if(token_match(TK_Comma)){
Token *t = token_expect(TK_StringLit);
message = t->intern_val;
}
token_expect(TK_CloseParen);
scope->stmts.add(ast_constant_assert(token, expr, message));
}
else if(token_match_keyword(keyword_for)){
Ast_Scope *for_scope = begin_stmt_scope(scratch, token_get());
Ast_Expr *init = 0;

View File

@@ -13,8 +13,6 @@ UTF16_Result :: struct
len : S32
error : S32
BINARY :: 0b1001
utf8_to_utf32 :: (c: *U8, max_advance: S64): UTF32_Result
result: UTF32_Result
if (c[0] & 0b10000000) == 0
@@ -91,18 +89,14 @@ utf32_to_utf16 :: (codepoint: U32): UTF16_Result
// return result;
// }
Vec2I :: struct;; x: S32; y: S32
Vec2 :: struct;; x: F32; y: F32
Windows_Bitmap :: struct
size: Vec2I
data: *U32
hdc: HDC
dib: HBITMAP
Vec2I :: struct;; x: S32; y: S32
Vec2 :: struct;; x: F32; y: F32
create_bitmap :: (size: Vec2I, bottom_up: Bool = true): Windows_Bitmap
result: Windows_Bitmap = {size = size}
if bottom_up == false
@@ -136,6 +130,7 @@ window_procedure :: (hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM): LRE
main :: (argc: int, argv: **char): int
bitmap := create_bitmap({1280, 720})
result := utf8_to_utf32(&"A"[0], 1)
assert(result.out_str == 'A, "Invalid decode")
result = utf8_to_utf32(&"ć"[0], 2)
result = utf8_to_utf32(&"ó"[0], 2)

View File

@@ -443,6 +443,20 @@ resolve_stmt(Ast *ast, Ast_Type *ret){
BREAK();
}
CASE(RUNTIME_ASSERT, Builtin){
resolve_and_require_bool("Assert condition is not boolean", node->expr, AST_CAN_BE_NULL);
BREAK();
}
CASE(CONSTANT_ASSERT, Builtin){
Operand op = resolve_and_require_bool("Assert condition is not boolean", node->expr, AST_CAN_BE_NULL);
if(!op.is_const) compiler_error(node->pos, "#assert expression required to be constant");
if(op.bool_val == false){
compiler_error(node->pos, "#assert condition not met :: %.*s", (int)node->assert_message.len, node->assert_message.str);
}
BREAK();
}
CASE(FOR, For){
if(node->init && node->cond == 0 && node->iter == 0){
if(!is_flag_set(node->init->flags, AST_STMT)){