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_ITEM,
AST_CALL, AST_CALL,
AST_CONSTANT_ASSERT,
AST_RUNTIME_ASSERT,
AST_SIZE_OF, AST_SIZE_OF,
AST_LENGTH_OF, AST_LENGTH_OF,
AST_ALIGN_OF, AST_ALIGN_OF,
@@ -119,7 +121,8 @@ struct Ast_Binary: Ast_Expr{
struct Ast_Builtin: Ast_Expr{ struct Ast_Builtin: Ast_Expr{
Ast_Expr *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 // 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; Ast_Module *module;
}; };
struct Ast_Module: Ast_Scope{ struct Ast_Module: Ast_Scope{
Array<Ast_File *> all_loaded_files; Array<Ast_File *> all_loaded_files;
}; };
@@ -507,6 +509,22 @@ ast_module(Intern_String filename){
return result; 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 * function Ast_Builtin *
ast_sizeof(Token *pos, Ast_Expr *expr){ ast_sizeof(Token *pos, Ast_Expr *expr){
AST_NEW(Builtin, SIZE_OF, pos, AST_EXPR); AST_NEW(Builtin, SIZE_OF, pos, AST_EXPR);

View File

@@ -365,6 +365,18 @@ function void
gen_ast(Ast *ast){ gen_ast(Ast *ast){
switch(ast->kind){ 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){ CASE(RETURN, Return){
gen("return"); gen("return");
if(node->expr){ if(node->expr){
@@ -504,6 +516,7 @@ gen_ast(Ast *ast){
BREAK(); BREAK();
} }
case AST_CONSTANT_ASSERT:
case AST_MODULE_NAMESPACE: case AST_MODULE_NAMESPACE:
CASE(FILE_NAMESPACE, File_Namespace){unused(node); BREAK();} 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_for;
Intern_String keyword_pass; Intern_String keyword_pass;
Intern_String keyword_elif; Intern_String keyword_elif;
Intern_String keyword_assert;
Intern_String keyword_sizeof; Intern_String keyword_sizeof;
Intern_String keyword_alignof; Intern_String keyword_alignof;
Intern_String keyword_lengthof; 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_true = l->intern("true"_s);
keyword_false = l->intern("false"_s); keyword_false = l->intern("false"_s);
keyword_return = l->intern("return"_s); keyword_return = l->intern("return"_s);
keyword_assert = l->intern("assert"_s);
keyword_if = l->intern("if"_s); keyword_if = l->intern("if"_s);
keyword_elif = l->intern("elif"_s); keyword_elif = l->intern("elif"_s);
keyword_pass = l->intern("pass"_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)); 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)){ else if(token_match_keyword(keyword_for)){
Ast_Scope *for_scope = begin_stmt_scope(scratch, token_get()); Ast_Scope *for_scope = begin_stmt_scope(scratch, token_get());
Ast_Expr *init = 0; Ast_Expr *init = 0;

View File

@@ -13,8 +13,6 @@ UTF16_Result :: struct
len : S32 len : S32
error : S32 error : S32
BINARY :: 0b1001
utf8_to_utf32 :: (c: *U8, max_advance: S64): UTF32_Result utf8_to_utf32 :: (c: *U8, max_advance: S64): UTF32_Result
result: UTF32_Result result: UTF32_Result
if (c[0] & 0b10000000) == 0 if (c[0] & 0b10000000) == 0
@@ -91,18 +89,14 @@ utf32_to_utf16 :: (codepoint: U32): UTF16_Result
// return result; // return result;
// } // }
Vec2I :: struct;; x: S32; y: S32
Vec2 :: struct;; x: F32; y: F32
Windows_Bitmap :: struct Windows_Bitmap :: struct
size: Vec2I size: Vec2I
data: *U32 data: *U32
hdc: HDC hdc: HDC
dib: HBITMAP dib: HBITMAP
Vec2I :: struct;; x: S32; y: S32
Vec2 :: struct;; x: F32; y: F32
create_bitmap :: (size: Vec2I, bottom_up: Bool = true): Windows_Bitmap create_bitmap :: (size: Vec2I, bottom_up: Bool = true): Windows_Bitmap
result: Windows_Bitmap = {size = size} result: Windows_Bitmap = {size = size}
if bottom_up == false 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 main :: (argc: int, argv: **char): int
bitmap := create_bitmap({1280, 720}) bitmap := create_bitmap({1280, 720})
result := utf8_to_utf32(&"A"[0], 1) 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)
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(); 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){ CASE(FOR, For){
if(node->init && node->cond == 0 && node->iter == 0){ if(node->init && node->cond == 0 && node->iter == 0){
if(!is_flag_set(node->init->flags, AST_STMT)){ if(!is_flag_set(node->init->flags, AST_STMT)){