From cfabc0e61f2c3dc00fd367e3f9bf1a89461971ef Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 28 Nov 2017 22:12:33 +0000 Subject: Remove `using` in arrays; Remove `_` non-exported struct fields Start determining slow parts of the compiler --- src/check_stmt.cpp | 400 +++++++++++++++++++++++++++-------------------------- 1 file changed, 202 insertions(+), 198 deletions(-) (limited to 'src/check_stmt.cpp') diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index bbc1aaab3..24c82545e 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -41,7 +41,6 @@ void check_stmt_list(Checker *c, Array stmts, u32 flags) { check_stmt(c, n, new_flags); } - } bool check_is_terminating_list(Array stmts) { @@ -576,6 +575,207 @@ bool check_using_stmt_entity(Checker *c, AstNodeUsingStmt *us, AstNode *expr, bo return true; } +void check_switch_stmt(Checker *c, AstNode *node, u32 mod_flags) { + ast_node(ss, SwitchStmt, node); + + Operand x = {}; + + mod_flags |= Stmt_BreakAllowed | Stmt_FallthroughAllowed; + check_open_scope(c, node); + defer (check_close_scope(c)); + + check_label(c, ss->label); // TODO(bill): What should the label's "scope" be? + + if (ss->init != nullptr) { + check_stmt(c, ss->init, 0); + } + if (ss->tag != nullptr) { + check_expr(c, &x, ss->tag); + check_assignment(c, &x, nullptr, str_lit("switch expression")); + } else { + x.mode = Addressing_Constant; + x.type = t_bool; + x.value = exact_value_bool(true); + + Token token = {}; + token.pos = ast_node_token(ss->body).pos; + token.string = str_lit("true"); + x.expr = ast_ident(c->curr_ast_file, token); + } + if (is_type_vector(x.type)) { + gbString str = type_to_string(x.type); + error(x.expr, "Invalid switch expression type: %s", str); + gb_string_free(str); + return; + } + + + // NOTE(bill): Check for multiple defaults + AstNode *first_default = nullptr; + ast_node(bs, BlockStmt, ss->body); + for_array(i, bs->stmts) { + AstNode *stmt = bs->stmts[i]; + AstNode *default_stmt = nullptr; + if (stmt->kind == AstNode_CaseClause) { + ast_node(cc, CaseClause, stmt); + if (cc->list.count == 0) { + default_stmt = stmt; + } + } else { + error(stmt, "Invalid AST - expected case clause"); + } + + if (default_stmt != nullptr) { + if (first_default != nullptr) { + TokenPos pos = ast_node_token(first_default).pos; + error(stmt, + "multiple default clauses\n" + "\tfirst at %.*s(%td:%td)", + LIT(pos.file), pos.line, pos.column); + } else { + first_default = default_stmt; + } + } + } + + Map seen = {}; // NOTE(bill): Multimap + map_init(&seen, heap_allocator()); + defer (map_destroy(&seen)); + + for_array(stmt_index, bs->stmts) { + AstNode *stmt = bs->stmts[stmt_index]; + if (stmt->kind != AstNode_CaseClause) { + // NOTE(bill): error handled by above multiple default checker + continue; + } + ast_node(cc, CaseClause, stmt); + + for_array(j, cc->list) { + AstNode *expr = unparen_expr(cc->list[j]); + + if (is_ast_node_a_range(expr)) { + ast_node(ie, BinaryExpr, expr); + Operand lhs = {}; + Operand rhs = {}; + check_expr(c, &lhs, ie->left); + if (x.mode == Addressing_Invalid) { + continue; + } + if (lhs.mode == Addressing_Invalid) { + continue; + } + check_expr(c, &rhs, ie->right); + if (rhs.mode == Addressing_Invalid) { + continue; + } + + if (!is_type_ordered(x.type)) { + gbString str = type_to_string(x.type); + error(expr, "Unordered type '%s', is invalid for an interval expression", str); + gb_string_free(str); + continue; + } + + + TokenKind op = Token_Invalid; + + Operand a = lhs; + Operand b = rhs; + check_comparison(c, &a, &x, Token_LtEq); + if (a.mode == Addressing_Invalid) { + continue; + } + switch (ie->op.kind) { + case Token_Ellipsis: op = Token_GtEq; break; + case Token_HalfClosed: op = Token_Gt; break; + default: error(ie->op, "Invalid interval operator"); continue; + } + + check_comparison(c, &b, &x, op); + if (b.mode == Addressing_Invalid) { + continue; + } + + switch (ie->op.kind) { + case Token_Ellipsis: op = Token_LtEq; break; + case Token_HalfClosed: op = Token_Lt; break; + default: error(ie->op, "Invalid interval operator"); continue; + } + + Operand a1 = lhs; + Operand b1 = rhs; + check_comparison(c, &a1, &b1, op); + } else { + Operand y = {}; + check_expr(c, &y, expr); + + if (x.mode == Addressing_Invalid || + y.mode == Addressing_Invalid) { + continue; + } + + convert_to_typed(c, &y, x.type); + if (y.mode == Addressing_Invalid) { + continue; + } + + // NOTE(bill): the ordering here matters + Operand z = y; + check_comparison(c, &z, &x, Token_CmpEq); + if (z.mode == Addressing_Invalid) { + continue; + } + if (y.mode != Addressing_Constant) { + continue; + } + + + if (y.value.kind != ExactValue_Invalid) { + HashKey key = hash_exact_value(y.value); + TypeAndToken *found = map_get(&seen, key); + if (found != nullptr) { + gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); + defer (gb_temp_arena_memory_end(tmp)); + + isize count = multi_map_count(&seen, key); + TypeAndToken *taps = gb_alloc_array(c->tmp_allocator, TypeAndToken, count); + + multi_map_get_all(&seen, key, taps); + bool continue_outer = false; + + for (isize i = 0; i < count; i++) { + TypeAndToken tap = taps[i]; + if (are_types_identical(y.type, tap.type)) { + TokenPos pos = tap.token.pos; + gbString expr_str = expr_to_string(y.expr); + error(y.expr, + "Duplicate case '%s'\n" + "\tprevious case at %.*s(%td:%td)", + expr_str, + LIT(pos.file), pos.line, pos.column); + gb_string_free(expr_str); + continue_outer = true; + break; + } + } + + + if (continue_outer) { + continue; + } + } + TypeAndToken tap = {y.type, ast_node_token(y.expr)}; + multi_map_insert(&seen, key, tap); + } + } + } + + check_open_scope(c, stmt); + check_stmt_list(c, cc->stmts, mod_flags); + check_close_scope(c); + } +} + void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { u32 mod_flags = flags & (~Stmt_FallthroughAllowed); switch (node->kind) { @@ -940,7 +1140,6 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { check_assignment(c, &operands[i], e->type, str_lit("return statement")); } } - case_end; case_ast_node(fs, ForStmt, node); @@ -1193,202 +1392,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { case_end; case_ast_node(ss, SwitchStmt, node); - Operand x = {}; - - mod_flags |= Stmt_BreakAllowed | Stmt_FallthroughAllowed; - check_open_scope(c, node); - defer (check_close_scope(c)); - - check_label(c, ss->label); // TODO(bill): What should the label's "scope" be? - - if (ss->init != nullptr) { - check_stmt(c, ss->init, 0); - } - if (ss->tag != nullptr) { - check_expr(c, &x, ss->tag); - check_assignment(c, &x, nullptr, str_lit("switch expression")); - } else { - x.mode = Addressing_Constant; - x.type = t_bool; - x.value = exact_value_bool(true); - - Token token = {}; - token.pos = ast_node_token(ss->body).pos; - token.string = str_lit("true"); - x.expr = ast_ident(c->curr_ast_file, token); - } - if (is_type_vector(x.type)) { - gbString str = type_to_string(x.type); - error(x.expr, "Invalid switch expression type: %s", str); - gb_string_free(str); - break; - } - - - // NOTE(bill): Check for multiple defaults - AstNode *first_default = nullptr; - ast_node(bs, BlockStmt, ss->body); - for_array(i, bs->stmts) { - AstNode *stmt = bs->stmts[i]; - AstNode *default_stmt = nullptr; - if (stmt->kind == AstNode_CaseClause) { - ast_node(cc, CaseClause, stmt); - if (cc->list.count == 0) { - default_stmt = stmt; - } - } else { - error(stmt, "Invalid AST - expected case clause"); - } - - if (default_stmt != nullptr) { - if (first_default != nullptr) { - TokenPos pos = ast_node_token(first_default).pos; - error(stmt, - "multiple default clauses\n" - "\tfirst at %.*s(%td:%td)", - LIT(pos.file), pos.line, pos.column); - } else { - first_default = default_stmt; - } - } - } - - Map seen = {}; // NOTE(bill): Multimap - map_init(&seen, heap_allocator()); - defer (map_destroy(&seen)); - - for_array(stmt_index, bs->stmts) { - AstNode *stmt = bs->stmts[stmt_index]; - if (stmt->kind != AstNode_CaseClause) { - // NOTE(bill): error handled by above multiple default checker - continue; - } - ast_node(cc, CaseClause, stmt); - - for_array(j, cc->list) { - AstNode *expr = unparen_expr(cc->list[j]); - - if (is_ast_node_a_range(expr)) { - ast_node(ie, BinaryExpr, expr); - Operand lhs = {}; - Operand rhs = {}; - check_expr(c, &lhs, ie->left); - if (x.mode == Addressing_Invalid) { - continue; - } - if (lhs.mode == Addressing_Invalid) { - continue; - } - check_expr(c, &rhs, ie->right); - if (rhs.mode == Addressing_Invalid) { - continue; - } - - if (!is_type_ordered(x.type)) { - gbString str = type_to_string(x.type); - error(expr, "Unordered type '%s', is invalid for an interval expression", str); - gb_string_free(str); - continue; - } - - - TokenKind op = Token_Invalid; - - Operand a = lhs; - Operand b = rhs; - check_comparison(c, &a, &x, Token_LtEq); - if (a.mode == Addressing_Invalid) { - continue; - } - switch (ie->op.kind) { - case Token_Ellipsis: op = Token_GtEq; break; - case Token_HalfClosed: op = Token_Gt; break; - default: error(ie->op, "Invalid interval operator"); continue; - } - - check_comparison(c, &b, &x, op); - if (b.mode == Addressing_Invalid) { - continue; - } - - switch (ie->op.kind) { - case Token_Ellipsis: op = Token_LtEq; break; - case Token_HalfClosed: op = Token_Lt; break; - default: error(ie->op, "Invalid interval operator"); continue; - } - - Operand a1 = lhs; - Operand b1 = rhs; - check_comparison(c, &a1, &b1, op); - } else { - Operand y = {}; - check_expr(c, &y, expr); - - if (x.mode == Addressing_Invalid || - y.mode == Addressing_Invalid) { - continue; - } - - convert_to_typed(c, &y, x.type); - if (y.mode == Addressing_Invalid) { - continue; - } - - // NOTE(bill): the ordering here matters - Operand z = y; - check_comparison(c, &z, &x, Token_CmpEq); - if (z.mode == Addressing_Invalid) { - continue; - } - if (y.mode != Addressing_Constant) { - continue; - } - - - if (y.value.kind != ExactValue_Invalid) { - HashKey key = hash_exact_value(y.value); - TypeAndToken *found = map_get(&seen, key); - if (found != nullptr) { - gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); - defer (gb_temp_arena_memory_end(tmp)); - - isize count = multi_map_count(&seen, key); - TypeAndToken *taps = gb_alloc_array(c->tmp_allocator, TypeAndToken, count); - - multi_map_get_all(&seen, key, taps); - bool continue_outer = false; - - for (isize i = 0; i < count; i++) { - TypeAndToken tap = taps[i]; - if (are_types_identical(y.type, tap.type)) { - TokenPos pos = tap.token.pos; - gbString expr_str = expr_to_string(y.expr); - error(y.expr, - "Duplicate case '%s'\n" - "\tprevious case at %.*s(%td:%td)", - expr_str, - LIT(pos.file), pos.line, pos.column); - gb_string_free(expr_str); - continue_outer = true; - break; - } - } - - - if (continue_outer) { - continue; - } - } - TypeAndToken tap = {y.type, ast_node_token(y.expr)}; - multi_map_insert(&seen, key, tap); - } - } - } - - check_open_scope(c, stmt); - check_stmt_list(c, cc->stmts, mod_flags); - check_close_scope(c); - } + check_switch_stmt(c, node, mod_flags); case_end; case_ast_node(ss, TypeSwitchStmt, node); -- cgit v1.2.3