Add switch case statement
This commit is contained in:
26
ast.cpp
26
ast.cpp
@@ -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);
|
||||
|
||||
31
ccodegen.cpp
31
ccodegen.cpp
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
31
parsing.cpp
31
parsing.cpp
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
Reference in New Issue
Block a user