Add switch case statement

This commit is contained in:
Krzosa Karol
2022-06-19 09:31:16 +02:00
parent fc0d4345ee
commit 94b820a071
7 changed files with 114 additions and 2 deletions

26
ast.cpp
View File

@@ -26,6 +26,8 @@ enum Ast_Kind: U32{
AST_LENGTH_OF,
AST_ALIGN_OF,
AST_SWITCH,
AST_SWITCH_CASE,
AST_VAR_UNPACK,
AST_BREAK,
AST_COMPOUND,
@@ -174,6 +176,18 @@ struct Ast_Array: Ast_Expr{
Ast_Expr *expr;
};
struct Ast_Switch_Case: Ast{
Array<Ast_Expr *> labels;
Ast_Scope *scope;
B32 fallthrough;
};
struct Ast_Switch: Ast{
Ast_Expr *value;
Array<Ast_Switch_Case *> cases;
Ast_Scope *default_scope;
};
/*
How does current declaration order resolver works:
* First we put all the global declarations into the global scope (when parsing) all unresolved
@@ -251,6 +265,18 @@ struct Ast_Decl: Ast{
result->pos = ipos; \
result->di = ++pctx->unique_ids
#define MAKE_AST(T,kind,pos,flags) (T *)ast_new(sizeof(T), kind, pos, flags)
function Ast *
ast_new(SizeU size, Ast_Kind kind, Token *pos, Ast_Flag flags = 0){
Ast *result = (Ast *)exp_alloc(pctx->perm, size, AF_ZeroMemory);
result->flags = flags;
result->kind = kind;
result->parent_scope = pctx->currently_parsed_scope;
result->pos = pos;
result->di = ++pctx->unique_ids;
return result;
}
function Ast_Atom *
ast_str(Token *pos, Intern_String string){
AST_NEW(Atom, VALUE, pos, AST_EXPR | AST_ATOM);

View File

@@ -192,7 +192,7 @@ gen_value(Value a){
}
function void
gen_stmt_scope(Ast_Scope *scope){
gen_stmt_scope(Ast_Scope *scope, B32 switch_case_gen_break = 0){
gen("{");
global_indent++;
For(scope->stmts) {
@@ -200,6 +200,7 @@ gen_stmt_scope(Ast_Scope *scope){
genln("");
gen_ast(it);
}
if(switch_case_gen_break == 1) genln("break;");
global_indent--;
genln("}");
}
@@ -570,6 +571,33 @@ gen_ast(Ast *ast){
BREAK();
}
CASE(SWITCH, Switch){
gen("switch(");
gen_expr(node->value);
gen("){");
global_indent++;
For(node->cases){
For_Named(it->labels, label){
genln("case ");
gen_expr(label);
gen(":");
}
gen_stmt_scope(it->scope, it->fallthrough ? false : true);
}
if(node->default_scope){
genln("default: ");
gen_stmt_scope(node->default_scope);
}
global_indent--;
genln("}");
BREAK();
}
CASE(VAR_UNPACK, Var_Unpack){
For(node->vars)
gen_ast(it);
@@ -771,6 +799,7 @@ typedef S64 SizeS;
typedef float F32;
typedef double F64;
typedef S32 Bool;
typedef S64 Type;
#define true 1
#define false 0

View File

@@ -163,6 +163,8 @@ Intern_String keyword_true;
Intern_String keyword_false;
Intern_String keyword_for;
Intern_String keyword_pass;
Intern_String keyword_default;
Intern_String keyword_switch;
Intern_String keyword_break;
Intern_String keyword_elif;
Intern_String keyword_assert;
@@ -219,9 +221,11 @@ lex_init(Allocator *token_string_arena, Allocator *map_allocator, Lexer *l){
keyword_lengthof = l->intern("length_of"_s);
keyword_alignof = l->intern("align_of"_s);
keyword_true = l->intern("true"_s);
keyword_default = l->intern("default"_s);
keyword_break = l->intern("break"_s);
keyword_false = l->intern("false"_s);
keyword_return = l->intern("return"_s);
keyword_switch = l->intern("switch"_s);
keyword_assert = l->intern("assert"_s);
keyword_if = l->intern("if"_s);
keyword_elif = l->intern("elif"_s);

View File

@@ -234,6 +234,37 @@ parse_stmt_scope(Ast_Scope *scope_defined_outside = 0){
scope->stmts.add(ast_pass(token));
}
else if(token_match_keyword(keyword_switch)){
Ast_Switch *result = MAKE_AST(Ast_Switch, AST_SWITCH, token, AST_STMT);
result->value = parse_expr();
result->cases = {scratch};
token_expect(OPEN_SCOPE);
do{
if(token_match_keyword(keyword_default)){
result->default_scope = parse_stmt_scope();
continue;
}
Ast_Switch_Case *switch_case = MAKE_AST(Ast_Switch_Case, AST_SWITCH_CASE, token_get(), AST_STMT);
if(token_match_pound(pctx->intern("fallthrough"_s)))
switch_case->fallthrough = true;
switch_case->labels = {scratch};
do{
switch_case->labels.add(parse_expr());
}while(token_match(TK_Comma));
switch_case->labels = switch_case->labels.tight_copy(pctx->perm);
switch_case->scope = parse_stmt_scope();
result->cases.add(switch_case);
}while(token_match(SAME_SCOPE));
token_expect(CLOSE_SCOPE);
result->cases = result->cases.tight_copy(pctx->perm);
scope->stmts.add(result);
}
else if(token_match_keyword(keyword_assert)){
token_expect(TK_OpenParen);
Ast_Expr *expr = parse_expr();

View File

@@ -41,6 +41,13 @@ create_bitmap :: (size: Vec2I, bottom_up: Bool = true): Windows_Bitmap
result.hdc = CreateCompatibleDC(hdc)
return result
print :: (type: Type)
switch type
int, S64, S32, S16, S8
OutputDebugStringA("int")
default
OutputDebugStringA("unknown_type")
app_is_running := true
window_procedure :: (hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM): LRESULT
if msg == WM_DESTROY

View File

@@ -580,6 +580,21 @@ resolve_stmt(Ast *ast, Ast_Type *ret){
BREAK();
}
CASE(SWITCH, Switch){
// @todo better typechecking
resolve_expr(node->value, AST_CANT_BE_NULL);
For(node->cases){
For_Named(it->labels, label){
Operand op = resolve_expr(label, AST_CANT_BE_NULL);
if(!op.is_const) compiler_error(label->pos, "Switch label required to be constant");
}
For_Named(it->scope->stmts, stmt) resolve_stmt(stmt, ret);
}
For_Named(node->default_scope->stmts, stmt) resolve_stmt(stmt, ret);
BREAK();
}
CASE(VAR_UNPACK, Var_Unpack){
Operand expr_op = resolve_expr(node->expr, AST_CANT_BE_NULL);
if(!is_tuple(expr_op.type))

View File

@@ -124,7 +124,7 @@ name(Ast_Type *type){
case TYPE_U64: return "U64";
case TYPE_ANY: return "Any";
case TYPE_TUPLE: return "Tuple";
case TYPE_TYPE: return "S64";
case TYPE_TYPE: return "Type";
invalid_default_case;
}
return "<unknown_type>";