From 9793ad8e938e90fd92ce3666d0e988525ea5c2eb Mon Sep 17 00:00:00 2001 From: rexim Date: Fri, 25 Jun 2021 23:45:13 +0700 Subject: [PATCH 1/5] Implement variable initialization on definition --- bang/src/bang_compiler.c | 66 ++++++++++++++++++---------------------- bang/src/bang_compiler.h | 3 +- bang/src/bang_parser.c | 16 ++++++++-- bang/src/bang_parser.h | 5 ++- 4 files changed, 47 insertions(+), 43 deletions(-) diff --git a/bang/src/bang_compiler.c b/bang/src/bang_compiler.c index bc70ae2..0058e3d 100644 --- a/bang/src/bang_compiler.c +++ b/bang/src/bang_compiler.c @@ -541,7 +541,7 @@ void compile_stmt_into_basm(Bang *bang, Basm *basm, Bang_Stmt stmt) break; case BANG_STMT_KIND_VAR_DEF: - compile_stack_var_def_into_basm(bang, stmt.as.var_def); + compile_var_def_into_basm(bang, basm, stmt.as.var_def, BANG_VAR_STACK_STORAGE); break; case COUNT_BANG_STMT_KINDS: @@ -625,7 +625,7 @@ void compile_bang_module_into_basm(Bang *bang, Basm *basm, Bang_Module module) } break; case BANG_TOP_KIND_VAR: { - compile_static_var_def_into_basm(bang, basm, top->as.var); + compile_var_def_into_basm(bang, basm, top->as.var, BANG_VAR_STATIC_STORAGE); } break; case COUNT_BANG_TOP_KINDS: @@ -684,7 +684,7 @@ void bang_prepare_var_stack(Bang *bang, Basm *basm, size_t stack_size) basm, (uint8_t*) &stack_start_addr, sizeof(stack_start_addr)).as_u64; } -void compile_static_var_def_into_basm(Bang *bang, Basm *basm, Bang_Var_Def var_def) +void compile_var_def_into_basm(Bang *bang, Basm *basm, Bang_Var_Def var_def, Bang_Var_Storage storage) { Bang_Type type = 0; if (!bang_type_by_name(var_def.type_name, &type)) { @@ -713,51 +713,43 @@ void compile_static_var_def_into_basm(Bang *bang, Basm *basm, Bang_Var_Def var_d Compiled_Var new_var = {0}; new_var.def = var_def; - new_var.storage = BANG_VAR_STATIC_STORAGE; - new_var.addr = basm_push_byte_array_to_memory(basm, bang_type_def(type).size, 0).as_u64; new_var.type = type; + new_var.storage = storage; - bang_scope_push_var(bang->scope, new_var); -} + Bang_Type_Def type_def = bang_type_def(type); -void compile_stack_var_def_into_basm(Bang *bang, Bang_Var_Def var_def) -{ - Bang_Type type = 0; - if (!bang_type_by_name(var_def.type_name, &type)) { - fprintf(stderr, Bang_Loc_Fmt": ERROR: type `"SV_Fmt"` does not exist\n", - Bang_Loc_Arg(var_def.loc), - SV_Arg(var_def.type_name)); - exit(1); + switch (storage) { + case BANG_VAR_STATIC_STORAGE: { + new_var.addr = basm_push_byte_array_to_memory(basm, type_def.size, 0).as_u64; } + break; - if (type == BANG_TYPE_VOID) { - fprintf(stderr, Bang_Loc_Fmt": ERROR: defining variables with type %s is not allowed\n", - Bang_Loc_Arg(var_def.loc), - bang_type_def(type).name); - exit(1); + case BANG_VAR_STACK_STORAGE: { + assert(type_def.size > 0); + bang->frame_size += type_def.size; + new_var.addr = bang->frame_size; } + break; - // TODO(#457): bang compile does not warn about shadowing of the variable - - Compiled_Var *existing_var = bang_scope_get_compiled_var_by_name(bang->scope, var_def.name); - if (existing_var) { - fprintf(stderr, Bang_Loc_Fmt": ERROR: variable `"SV_Fmt"` is already defined\n", - Bang_Loc_Arg(var_def.loc), - SV_Arg(var_def.name)); - fprintf(stderr, Bang_Loc_Fmt": NOTE: the first definition is located here\n", - Bang_Loc_Arg(existing_var->def.loc)); + default: + assert(false && "unreachable"); exit(1); } - Bang_Type_Def type_def = bang_type_def(type); + if (var_def.has_init) { + compile_get_var_addr(bang, basm, &new_var); - Compiled_Var new_var = {0}; - new_var.def = var_def; - new_var.type = type; - new_var.storage = BANG_VAR_STACK_STORAGE; - assert(type_def.size > 0); - bang->frame_size += type_def.size; - new_var.addr = bang->frame_size; + Compiled_Expr expr = compile_bang_expr_into_basm(bang, basm, var_def.init); + if (expr.type != new_var.type) { + fprintf(stderr, Bang_Loc_Fmt": ERROR: cannot assign expression of type `%s` to a variable of type `%s`\n", + Bang_Loc_Arg(var_def.loc), + bang_type_def(expr.type).name, + bang_type_def(new_var.type).name); + exit(1); + } + + compile_typed_write(basm, expr.type); + } bang_scope_push_var(bang->scope, new_var); } diff --git a/bang/src/bang_compiler.h b/bang/src/bang_compiler.h index 2038af4..3f37d47 100644 --- a/bang/src/bang_compiler.h +++ b/bang/src/bang_compiler.h @@ -101,8 +101,7 @@ void compile_bang_if_into_basm(Bang *bang, Basm *basm, Bang_If eef); void compile_bang_while_into_basm(Bang *bang, Basm *basm, Bang_While hwile); void compile_bang_var_assign_into_basm(Bang *bang, Basm *basm, Bang_Var_Assign var_assign); void compile_bang_module_into_basm(Bang *bang, Basm *basm, Bang_Module module); -void compile_static_var_def_into_basm(Bang *bang, Basm *basm, Bang_Var_Def var_def); -void compile_stack_var_def_into_basm(Bang *bang, Bang_Var_Def var_def); +void compile_var_def_into_basm(Bang *bang, Basm *basm, Bang_Var_Def var_def, Bang_Var_Storage storage); Bang_Type compile_var_read_into_basm(Bang *bang, Basm *basm, Bang_Var_Read var_read); Bang_Type compile_binary_op_into_basm(Bang *bang, Basm *basm, Bang_Binary_Op binary_op); void compile_get_var_addr(Bang *bang, Basm *basm, Compiled_Var *var); diff --git a/bang/src/bang_parser.c b/bang/src/bang_parser.c index cf3020c..67e09d6 100644 --- a/bang/src/bang_parser.c +++ b/bang/src/bang_parser.c @@ -437,7 +437,7 @@ Bang_Stmt parse_bang_stmt(Arena *arena, Bang_Lexer *lexer) } else if (sv_eq(token.text, SV("var"))) { Bang_Stmt stmt = {0}; stmt.kind = BANG_STMT_KIND_VAR_DEF; - stmt.as.var_def = parse_bang_var_def(lexer); + stmt.as.var_def = parse_bang_var_def(arena, lexer); return stmt; } else { Bang_Token next_token = {0}; @@ -531,7 +531,7 @@ Bang_Proc_Def parse_bang_proc_def(Arena *arena, Bang_Lexer *lexer) return result; } -Bang_Var_Def parse_bang_var_def(Bang_Lexer *lexer) +Bang_Var_Def parse_bang_var_def(Arena *arena, Bang_Lexer *lexer) { Bang_Var_Def var_def = {0}; @@ -539,6 +539,16 @@ Bang_Var_Def parse_bang_var_def(Bang_Lexer *lexer) var_def.name = bang_lexer_expect_token(lexer, BANG_TOKEN_KIND_NAME).text; bang_lexer_expect_token(lexer, BANG_TOKEN_KIND_COLON); var_def.type_name = bang_lexer_expect_token(lexer, BANG_TOKEN_KIND_NAME).text; + + { + Bang_Token token = {0}; + if (bang_lexer_peek(lexer, &token, 0) && token.kind == BANG_TOKEN_KIND_EQ) { + bang_lexer_next(lexer, &token); + var_def.has_init = true; + var_def.init = parse_bang_expr(arena, lexer); + } + } + bang_lexer_expect_token(lexer, BANG_TOKEN_KIND_SEMICOLON); return var_def; @@ -565,7 +575,7 @@ Bang_Module parse_bang_module(Arena *arena, Bang_Lexer *lexer) top->as.proc = parse_bang_proc_def(arena, lexer); } else if (sv_eq(token.text, SV("var"))) { top->kind = BANG_TOP_KIND_VAR; - top->as.var = parse_bang_var_def(lexer); + top->as.var = parse_bang_var_def(arena, lexer); } else { static_assert(COUNT_BANG_TOP_KINDS == 2, "The error message below assumes that there is only two top level definition kinds"); (void) BANG_TOP_KIND_PROC; // The error message below assumes there is a proc top level definition. Please update the message if needed. diff --git a/bang/src/bang_parser.h b/bang/src/bang_parser.h index cd1df74..f9b155e 100644 --- a/bang/src/bang_parser.h +++ b/bang/src/bang_parser.h @@ -138,6 +138,9 @@ struct Bang_Var_Def { Bang_Loc loc; String_View name; String_View type_name; + + Bang_Expr init; + bool has_init; }; union Bang_Stmt_As { @@ -203,7 +206,7 @@ Bang_If parse_bang_if(Arena *arena, Bang_Lexer *lexer); Bang_Stmt parse_bang_stmt(Arena *arena, Bang_Lexer *lexer); Bang_Proc_Def parse_bang_proc_def(Arena *arena, Bang_Lexer *lexer); Bang_Top parse_bang_top(Arena *arena, Bang_Lexer *lexer); -Bang_Var_Def parse_bang_var_def(Bang_Lexer *lexer); +Bang_Var_Def parse_bang_var_def(Arena *arena, Bang_Lexer *lexer); Bang_Module parse_bang_module(Arena *arena, Bang_Lexer *lexer); Bang_Var_Assign parse_bang_var_assign(Arena *arena, Bang_Lexer *lexer); Bang_While parse_bang_while(Arena *arena, Bang_Lexer *lexer); From 77d38e2e4397990b3804a475fc9a761e91b6ebbe Mon Sep 17 00:00:00 2001 From: rexim Date: Sat, 26 Jun 2021 00:06:13 +0700 Subject: [PATCH 2/5] Disable global var initialization for now --- bang/src/bang_compiler.c | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/bang/src/bang_compiler.c b/bang/src/bang_compiler.c index 0058e3d..dfe144c 100644 --- a/bang/src/bang_compiler.c +++ b/bang/src/bang_compiler.c @@ -721,6 +721,13 @@ void compile_var_def_into_basm(Bang *bang, Basm *basm, Bang_Var_Def var_def, Ban switch (storage) { case BANG_VAR_STATIC_STORAGE: { new_var.addr = basm_push_byte_array_to_memory(basm, type_def.size, 0).as_u64; + + // TODO: global variables cannot be initialized at the moment + if (var_def.has_init) { + fprintf(stderr, Bang_Loc_Fmt": ERROR: global variables cannot be initialized at the moment.\n", + Bang_Loc_Arg(var_def.loc)); + exit(1); + } } break; @@ -728,6 +735,21 @@ void compile_var_def_into_basm(Bang *bang, Basm *basm, Bang_Var_Def var_def, Ban assert(type_def.size > 0); bang->frame_size += type_def.size; new_var.addr = bang->frame_size; + + if (var_def.has_init) { + compile_get_var_addr(bang, basm, &new_var); + + Compiled_Expr expr = compile_bang_expr_into_basm(bang, basm, var_def.init); + if (expr.type != new_var.type) { + fprintf(stderr, Bang_Loc_Fmt": ERROR: cannot assign expression of type `%s` to a variable of type `%s`\n", + Bang_Loc_Arg(var_def.loc), + bang_type_def(expr.type).name, + bang_type_def(new_var.type).name); + exit(1); + } + + compile_typed_write(basm, expr.type); + } } break; @@ -736,21 +758,6 @@ void compile_var_def_into_basm(Bang *bang, Basm *basm, Bang_Var_Def var_def, Ban exit(1); } - if (var_def.has_init) { - compile_get_var_addr(bang, basm, &new_var); - - Compiled_Expr expr = compile_bang_expr_into_basm(bang, basm, var_def.init); - if (expr.type != new_var.type) { - fprintf(stderr, Bang_Loc_Fmt": ERROR: cannot assign expression of type `%s` to a variable of type `%s`\n", - Bang_Loc_Arg(var_def.loc), - bang_type_def(expr.type).name, - bang_type_def(new_var.type).name); - exit(1); - } - - compile_typed_write(basm, expr.type); - } - bang_scope_push_var(bang->scope, new_var); } From 86e93bd00a603f5379c23ee5b8832e770e601247 Mon Sep 17 00:00:00 2001 From: rexim Date: Sat, 26 Jun 2021 00:17:27 +0700 Subject: [PATCH 3/5] Refactor rule 110 to use variable initialization --- bang/examples/rule110.bang | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/bang/examples/rule110.bang b/bang/examples/rule110.bang index 777a331..82a7366 100644 --- a/bang/examples/rule110.bang +++ b/bang/examples/rule110.bang @@ -38,8 +38,7 @@ proc print_state_current() { var cell_ptr: ptr; var cell: u8; - var i: i64; - i = 0; + var i: i64 = 0; while i < state_size { cell_ptr = states_base + cast(ptr, state_current * state_size + i); cell = load_ptr(u8, cell_ptr); @@ -65,8 +64,7 @@ proc next_state() { state_next = 1 - state_current; - var i: i64; - i = 1; + var i: i64 = 1; while i < state_size - 1 { table_index = cast(u8, 0); @@ -95,8 +93,7 @@ proc next_state() { proc main() { init(); - var i: i64; - i = 0; + var i: i64 = 0; while i < state_size - 2 { print_state_current(); next_state(); From 8814adeffd388bf3f1d1bc76c8502c32a1ae50d6 Mon Sep 17 00:00:00 2001 From: rexim Date: Sat, 26 Jun 2021 00:20:41 +0700 Subject: [PATCH 4/5] Refactor gol to use var init --- bang/examples/gol.bang | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/bang/examples/gol.bang b/bang/examples/gol.bang index 36b56c7..7d41451 100644 --- a/bang/examples/gol.bang +++ b/bang/examples/gol.bang @@ -26,14 +26,12 @@ proc init() { } proc print_board_current() { - var row: i64; - row = 0; + var row: i64 = 0; while row < board_rows { var cell_ptr: ptr; var cell: u8; - var col: i64; - col = 0; + var col: i64 = 0; while col < board_cols { cell_ptr = boards_base + cast(ptr, board_size * board_current + row * board_cols + col); cell = load_ptr(u8, cell_ptr); @@ -59,24 +57,19 @@ proc print_board_current() { proc next_board() { board_next = 1 - board_current; - var row: i64; - row = 0; + var row: i64 = 0; while row < board_rows { var cell_ptr: ptr; var cell: u8; - var col: i64; - col = 0; + var col: i64 = 0; while col < board_cols { # Nbors begin - var nbors: i64; - nbors = 0; + var nbors: i64 = 0; - var drow: i64; - drow = row - 1; + var drow: i64 = row - 1; while drow < row + 2 { - var dcol: i64; - dcol = col - 1; + var dcol: i64 = col - 1; while dcol < col + 2 { if drow >= 0 && drow < board_rows { if dcol >= 0 && dcol < board_cols { @@ -124,8 +117,7 @@ proc next_board() { proc main() { init(); - var i: i64; - i = 0; + var i: i64 = 0; while i < 10 { print_board_current(); next_board(); From f413dfa4b26db4f8d409d38a4be21df7674db4f4 Mon Sep 17 00:00:00 2001 From: rexim Date: Sat, 26 Jun 2021 00:22:31 +0700 Subject: [PATCH 5/5] Add TODO(#476) --- bang/src/bang_compiler.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bang/src/bang_compiler.c b/bang/src/bang_compiler.c index dfe144c..5b9fc1b 100644 --- a/bang/src/bang_compiler.c +++ b/bang/src/bang_compiler.c @@ -722,7 +722,7 @@ void compile_var_def_into_basm(Bang *bang, Basm *basm, Bang_Var_Def var_def, Ban case BANG_VAR_STATIC_STORAGE: { new_var.addr = basm_push_byte_array_to_memory(basm, type_def.size, 0).as_u64; - // TODO: global variables cannot be initialized at the moment + // TODO(#476): global variables cannot be initialized at the moment if (var_def.has_init) { fprintf(stderr, Bang_Loc_Fmt": ERROR: global variables cannot be initialized at the moment.\n", Bang_Loc_Arg(var_def.loc));