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_LENGTH_OF,
|
||||||
AST_ALIGN_OF,
|
AST_ALIGN_OF,
|
||||||
|
|
||||||
|
AST_SWITCH,
|
||||||
|
AST_SWITCH_CASE,
|
||||||
AST_VAR_UNPACK,
|
AST_VAR_UNPACK,
|
||||||
AST_BREAK,
|
AST_BREAK,
|
||||||
AST_COMPOUND,
|
AST_COMPOUND,
|
||||||
@@ -174,6 +176,18 @@ struct Ast_Array: Ast_Expr{
|
|||||||
Ast_Expr *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:
|
How does current declaration order resolver works:
|
||||||
* First we put all the global declarations into the global scope (when parsing) all unresolved
|
* 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->pos = ipos; \
|
||||||
result->di = ++pctx->unique_ids
|
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 *
|
function Ast_Atom *
|
||||||
ast_str(Token *pos, Intern_String string){
|
ast_str(Token *pos, Intern_String string){
|
||||||
AST_NEW(Atom, VALUE, pos, AST_EXPR | AST_ATOM);
|
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
|
function void
|
||||||
gen_stmt_scope(Ast_Scope *scope){
|
gen_stmt_scope(Ast_Scope *scope, B32 switch_case_gen_break = 0){
|
||||||
gen("{");
|
gen("{");
|
||||||
global_indent++;
|
global_indent++;
|
||||||
For(scope->stmts) {
|
For(scope->stmts) {
|
||||||
@@ -200,6 +200,7 @@ gen_stmt_scope(Ast_Scope *scope){
|
|||||||
genln("");
|
genln("");
|
||||||
gen_ast(it);
|
gen_ast(it);
|
||||||
}
|
}
|
||||||
|
if(switch_case_gen_break == 1) genln("break;");
|
||||||
global_indent--;
|
global_indent--;
|
||||||
genln("}");
|
genln("}");
|
||||||
}
|
}
|
||||||
@@ -570,6 +571,33 @@ gen_ast(Ast *ast){
|
|||||||
BREAK();
|
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){
|
CASE(VAR_UNPACK, Var_Unpack){
|
||||||
For(node->vars)
|
For(node->vars)
|
||||||
gen_ast(it);
|
gen_ast(it);
|
||||||
@@ -771,6 +799,7 @@ typedef S64 SizeS;
|
|||||||
typedef float F32;
|
typedef float F32;
|
||||||
typedef double F64;
|
typedef double F64;
|
||||||
typedef S32 Bool;
|
typedef S32 Bool;
|
||||||
|
typedef S64 Type;
|
||||||
#define true 1
|
#define true 1
|
||||||
#define false 0
|
#define false 0
|
||||||
|
|
||||||
|
|||||||
@@ -163,6 +163,8 @@ Intern_String keyword_true;
|
|||||||
Intern_String keyword_false;
|
Intern_String keyword_false;
|
||||||
Intern_String keyword_for;
|
Intern_String keyword_for;
|
||||||
Intern_String keyword_pass;
|
Intern_String keyword_pass;
|
||||||
|
Intern_String keyword_default;
|
||||||
|
Intern_String keyword_switch;
|
||||||
Intern_String keyword_break;
|
Intern_String keyword_break;
|
||||||
Intern_String keyword_elif;
|
Intern_String keyword_elif;
|
||||||
Intern_String keyword_assert;
|
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_lengthof = l->intern("length_of"_s);
|
||||||
keyword_alignof = l->intern("align_of"_s);
|
keyword_alignof = l->intern("align_of"_s);
|
||||||
keyword_true = l->intern("true"_s);
|
keyword_true = l->intern("true"_s);
|
||||||
|
keyword_default = l->intern("default"_s);
|
||||||
keyword_break = l->intern("break"_s);
|
keyword_break = l->intern("break"_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_switch = l->intern("switch"_s);
|
||||||
keyword_assert = l->intern("assert"_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);
|
||||||
|
|||||||
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));
|
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)){
|
else if(token_match_keyword(keyword_assert)){
|
||||||
token_expect(TK_OpenParen);
|
token_expect(TK_OpenParen);
|
||||||
Ast_Expr *expr = parse_expr();
|
Ast_Expr *expr = parse_expr();
|
||||||
|
|||||||
@@ -41,6 +41,13 @@ create_bitmap :: (size: Vec2I, bottom_up: Bool = true): Windows_Bitmap
|
|||||||
result.hdc = CreateCompatibleDC(hdc)
|
result.hdc = CreateCompatibleDC(hdc)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
print :: (type: Type)
|
||||||
|
switch type
|
||||||
|
int, S64, S32, S16, S8
|
||||||
|
OutputDebugStringA("int")
|
||||||
|
default
|
||||||
|
OutputDebugStringA("unknown_type")
|
||||||
|
|
||||||
app_is_running := true
|
app_is_running := true
|
||||||
window_procedure :: (hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM): LRESULT
|
window_procedure :: (hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM): LRESULT
|
||||||
if msg == WM_DESTROY
|
if msg == WM_DESTROY
|
||||||
|
|||||||
@@ -580,6 +580,21 @@ resolve_stmt(Ast *ast, Ast_Type *ret){
|
|||||||
BREAK();
|
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){
|
CASE(VAR_UNPACK, Var_Unpack){
|
||||||
Operand expr_op = resolve_expr(node->expr, AST_CANT_BE_NULL);
|
Operand expr_op = resolve_expr(node->expr, AST_CANT_BE_NULL);
|
||||||
if(!is_tuple(expr_op.type))
|
if(!is_tuple(expr_op.type))
|
||||||
|
|||||||
2
types.h
2
types.h
@@ -124,7 +124,7 @@ name(Ast_Type *type){
|
|||||||
case TYPE_U64: return "U64";
|
case TYPE_U64: return "U64";
|
||||||
case TYPE_ANY: return "Any";
|
case TYPE_ANY: return "Any";
|
||||||
case TYPE_TUPLE: return "Tuple";
|
case TYPE_TUPLE: return "Tuple";
|
||||||
case TYPE_TYPE: return "S64";
|
case TYPE_TYPE: return "Type";
|
||||||
invalid_default_case;
|
invalid_default_case;
|
||||||
}
|
}
|
||||||
return "<unknown_type>";
|
return "<unknown_type>";
|
||||||
|
|||||||
Reference in New Issue
Block a user