diff options
| author | Ginger Bill <bill@gingerbill.org> | 2016-12-30 22:52:43 +0000 |
|---|---|---|
| committer | Ginger Bill <bill@gingerbill.org> | 2016-12-30 22:52:43 +0000 |
| commit | 0c6775ca14ced37ac58a03ccad4028e225bda7d6 (patch) | |
| tree | 1d53d0bc67fb5287d609bba3c2e0933c70a9f0d6 /src | |
| parent | 6748f305db791e0b3db3fe567ea44ba96935c7d9 (diff) | |
Fix give expressions
Diffstat (limited to 'src')
| -rw-r--r-- | src/checker/expr.c | 229 | ||||
| -rw-r--r-- | src/checker/stmt.c | 19 | ||||
| -rw-r--r-- | src/checker/types.c | 3 | ||||
| -rw-r--r-- | src/parser.c | 54 | ||||
| -rw-r--r-- | src/ssa.c | 2 | ||||
| -rw-r--r-- | src/tokenizer.c | 4 |
6 files changed, 183 insertions, 128 deletions
diff --git a/src/checker/expr.c b/src/checker/expr.c index 3033a3ab8..77e9bd58e 100644 --- a/src/checker/expr.c +++ b/src/checker/expr.c @@ -3657,34 +3657,32 @@ bool check_set_index_data(Operand *o, Type *t, i64 *max_count) { } -bool check_is_giving(AstNode *node, AstNode **give_expr); - -bool check_giving_list(AstNodeArray stmts, AstNode **give_expr) { - // Iterate backwards - for (isize n = stmts.count-1; n >= 0; n--) { - AstNode *stmt = stmts.e[n]; - if (stmt->kind != AstNode_EmptyStmt) { - return check_is_giving(stmt, give_expr); - } - } - - if (give_expr) *give_expr = NULL; - return false; -} - bool check_is_giving(AstNode *node, AstNode **give_expr) { switch (node->kind) { case_ast_node(es, ExprStmt, node); - return check_is_giving(es->expr, give_expr); + if (es->expr->kind == AstNode_GiveExpr) { + if (give_expr) *give_expr = es->expr; + return true; + } case_end; - case_ast_node(ye, GiveExpr, node); + case_ast_node(ge, GiveExpr, node); if (give_expr) *give_expr = node; return true; case_end; case_ast_node(be, BlockExpr, node); - return check_giving_list(be->stmts, give_expr); + // Iterate backwards + for (isize n = be->stmts.count-1; n >= 0; n--) { + AstNode *stmt = be->stmts.e[n]; + if (stmt->kind == AstNode_EmptyStmt) { + continue; + } + if (stmt->kind == AstNode_ExprStmt && stmt->ExprStmt.expr->kind == AstNode_GiveExpr) { + if (give_expr) *give_expr = stmt->ExprStmt.expr; + return true; + } + } case_end; } @@ -3742,6 +3740,79 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint o->type = proc_type; case_end; + case_ast_node(ge, GiveExpr, node); + if (c->proc_stack.count == 0) { + error_node(node, "A give expression is only allowed within a procedure"); + goto error; + } + + if (ge->results.count == 0) { + error_node(node, "`give` has no results"); + goto error; + } + + gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); + + Array(Operand) operands; + array_init_reserve(&operands, c->tmp_allocator, 2*ge->results.count); + + for_array(i, ge->results) { + AstNode *rhs = ge->results.e[i]; + Operand o = {0}; + check_multi_expr(c, &o, rhs); + if (!is_operand_value(o)) { + error_node(rhs, "Expected a value for a `give`"); + continue; + } + if (o.type->kind != Type_Tuple) { + array_add(&operands, o); + } else { + TypeTuple *tuple = &o.type->Tuple; + for (isize j = 0; j < tuple->variable_count; j++) { + o.type = tuple->variables[j]->type; + array_add(&operands, o); + } + } + } + + if (operands.count == 0) { + error_node(node, "`give` has no value"); + gb_temp_arena_memory_end(tmp); + goto error; + } else if (operands.count == 1) { + Operand operand = operands.e[0]; + if (type_hint != NULL) { + convert_to_typed(c, &operand, type_hint, 0); + } + o->type = default_type(operand.type); + o->mode = Addressing_Value; + } else { + Type *tuple = make_type_tuple(c->allocator); + + Entity **variables = gb_alloc_array(c->allocator, Entity *, operands.count); + isize variable_index = 0; + for_array(i, operands) { + Operand operand = operands.e[i]; + // Type *type = default_type(operand.type); + Type *type = operand.type; + switch (operand.mode) { + case Addressing_Constant: + variables[variable_index++] = make_entity_constant(c->allocator, NULL, empty_token, type, operand.value); + break; + default: + variables[variable_index++] = make_entity_param(c->allocator, NULL, empty_token, type, false); + break; + } + } + tuple->Tuple.variables = variables; + tuple->Tuple.variable_count = operands.count; + + o->type = tuple; + o->mode = Addressing_Value; + } + gb_temp_arena_memory_end(tmp); + case_end; + case_ast_node(be, BlockExpr, node); if (c->proc_stack.count == 0) { error_node(node, "A block expression is only allowed within a procedure"); @@ -3755,26 +3826,34 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint be->stmts.count--; } - check_open_scope(c, node); - check_stmt_list(c, be->stmts, Stmt_GiveAllowed); - check_close_scope(c); - - if (be->stmts.count == 0) { error_node(node, "Empty block expression"); goto error; } + + check_open_scope(c, node); + check_stmt_list(c, be->stmts, Stmt_GiveAllowed); + check_close_scope(c); + AstNode *give_node = NULL; if (!check_is_giving(node, &give_node) || give_node == NULL) { - error_node(node, "Missing give statement at"); + error_node(node, "Missing give statement at end of block expression"); goto error; } GB_ASSERT(give_node != NULL && give_node->kind == AstNode_GiveExpr); be->give_node = give_node; - o->type = type_of_expr(&c->info, give_node); - o->mode = Addressing_Value; + Type *type = type_of_expr(&c->info, give_node); + if (type == NULL) { + goto error; + } else if (type == t_invalid) { + o->type = t_invalid; + o->mode = Addressing_Invalid; + } else { + o->type = type; + o->mode = Addressing_Value; + } case_end; case_ast_node(ie, IfExpr, node); @@ -3795,17 +3874,20 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint error_node(ie->cond, "Non-boolean condition in if expression"); } + + Operand x = {Addressing_Invalid}; + Operand y = {Addressing_Invalid}; Type *if_type = NULL; Type *else_type = NULL; - check_expr(c, &operand, ie->body); - if_type = operand.type; + check_expr(c, &x, ie->body); + if_type = x.type; if (ie->else_expr != NULL) { switch (ie->else_expr->kind) { case AstNode_IfExpr: case AstNode_BlockExpr: - check_expr(c, &operand, ie->else_expr); - else_type = operand.type; + check_expr(c, &y, ie->else_expr); + else_type = y.type; break; default: error_node(ie->else_expr, "Invalid else expression in if expression"); @@ -3819,84 +3901,32 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint check_close_scope(c); - GB_ASSERT(if_type != NULL && - else_type != NULL); - - if (!are_types_identical(if_type, else_type)) { - gbString its = type_to_string(if_type); - gbString ets = type_to_string(else_type); - error_node(node, "if expression type and else expression type do not match, %s != %s", its, ets); - gb_string_free(ets); - gb_string_free(its); + if (if_type == NULL || if_type == t_invalid || + else_type == NULL || else_type == t_invalid) { goto error; } - - o->type = if_type; - o->mode = Addressing_Value; - case_end; - - case_ast_node(ye, GiveExpr, node); - if (c->proc_stack.count == 0) { - error_node(node, "A give expression is only allowed within a procedure"); + convert_to_typed(c, &x, y.type, 0); + if (x.mode == Addressing_Invalid) { goto error; } - - if (ye->results.count == 0) { - error_node(node, "No give values"); + convert_to_typed(c, &y, x.type, 0); + if (y.mode == Addressing_Invalid) { + x.mode = Addressing_Invalid; goto error; } - gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); - - Array(Operand) operands; - array_init_reserve(&operands, c->tmp_allocator, 2*ye->results.count); - - for_array(i, ye->results) { - AstNode *rhs = ye->results.e[i]; - Operand o = {0}; - check_multi_expr(c, &o, rhs); - if (!is_operand_value(o)) { - error_node(rhs, "Expected a value for a `give`"); - continue; - } - if (o.type->kind != Type_Tuple) { - array_add(&operands, o); - } else { - TypeTuple *tuple = &o.type->Tuple; - for (isize j = 0; j < tuple->variable_count; j++) { - o.type = tuple->variables[j]->type; - array_add(&operands, o); - } - } - } - - Type *give_type = NULL; - if (operands.count == 0) { - error_node(node, "`give` has no type"); - gb_temp_arena_memory_end(tmp); + if (!are_types_identical(if_type, else_type)) { + gbString its = type_to_string(if_type); + gbString ets = type_to_string(else_type); + error_node(node, "Mismatched types in if expression, %s vs %s", its, ets); + gb_string_free(ets); + gb_string_free(its); goto error; - } else if (operands.count == 1) { - give_type = default_type(operands.e[0].type); - } else { - Type *tuple = make_type_tuple(c->allocator); - - Entity **variables = gb_alloc_array(c->allocator, Entity *, operands.count); - isize variable_index = 0; - for_array(i, operands) { - Type *type = default_type(operands.e[i].type); - variables[variable_index++] = make_entity_param(c->allocator, NULL, empty_token, type, false); - } - tuple->Tuple.variables = variables; - tuple->Tuple.variable_count = operands.count; - - give_type = tuple; } - gb_temp_arena_memory_end(tmp); - - o->type = give_type; + o->type = if_type; o->mode = Addressing_Value; case_end; @@ -4491,6 +4521,13 @@ gbString write_expr_to_string(gbString str, AstNode *node) { str = gb_string_appendc(str, "}"); case_end; + case_ast_node(be, BlockExpr, node); + str = gb_string_appendc(str, "block expression"); + case_end; + case_ast_node(ie, IfExpr, node); + str = gb_string_appendc(str, "if expression"); + case_end; + case_ast_node(te, TagExpr, node); str = gb_string_appendc(str, "#"); str = string_append_token(str, te->name); diff --git a/src/checker/stmt.c b/src/checker/stmt.c index 83ccf69e8..45906b94e 100644 --- a/src/checker/stmt.c +++ b/src/checker/stmt.c @@ -6,7 +6,7 @@ void check_stmt_list(Checker *c, AstNodeArray stmts, u32 flags) { check_scope_decls(c, stmts, 1.2*stmts.count, NULL); bool ft_ok = (flags & Stmt_FallthroughAllowed) != 0; - u32 f = flags & (~Stmt_FallthroughAllowed); + flags &= ~Stmt_FallthroughAllowed; isize max = stmts.count; for (isize i = stmts.count-1; i >= 0; i--) { @@ -20,16 +20,21 @@ void check_stmt_list(Checker *c, AstNodeArray stmts, u32 flags) { if (n->kind == AstNode_EmptyStmt) { continue; } - u32 new_flags = f; + u32 new_flags = flags; if (ft_ok && i+1 == max) { new_flags |= Stmt_FallthroughAllowed; } - if (n->kind == AstNode_ReturnStmt && i+1 < max) { - error_node(n, "Statements after this `return` are never executed"); - } else if (n->kind == AstNode_ExprStmt && i+1 < max) { - if (n->ExprStmt.expr->kind == AstNode_GiveExpr) { - error_node(n, "A `give` must be the last statement in a block"); + if (i+1 < max) { + switch (n->kind) { + case AstNode_ReturnStmt: + error_node(n, "Statements after this `return` are never executed"); + break; + case AstNode_ExprStmt: + if (n->ExprStmt.expr->kind == AstNode_GiveExpr) { + error_node(n, "A `give` must be the last statement in a block"); + } + break; } } diff --git a/src/checker/types.c b/src/checker/types.c index e58876025..4e81c5a38 100644 --- a/src/checker/types.c +++ b/src/checker/types.c @@ -763,6 +763,9 @@ bool are_types_identical(Type *x, Type *y) { Type *default_type(Type *type) { + if (type == NULL) { + return t_invalid; + } if (type->kind == Type_Basic) { switch (type->Basic.kind) { case Basic_UntypedBool: return t_bool; diff --git a/src/parser.c b/src/parser.c index 75e2c7d90..bfed77b0b 100644 --- a/src/parser.c +++ b/src/parser.c @@ -1275,27 +1275,36 @@ void expect_semicolon(AstFile *f, AstNode *s) { return; } - if (s != NULL && prev_token.pos.line != f->curr_token.pos.line) { - switch (s->kind) { - case AstNode_ProcDecl: - return; - case AstNode_GenericDecl: - if (s->GenericDecl.close.kind == Token_CloseBrace) { + if (s != NULL) { + if (prev_token.pos.line != f->curr_token.pos.line) { + switch (s->kind) { + case AstNode_ProcDecl: return; - } else if (s->GenericDecl.token.kind == Token_type) { + case AstNode_GenericDecl: + if (s->GenericDecl.close.kind == Token_CloseBrace) { + return; + } else if (s->GenericDecl.token.kind == Token_type) { + if (f->prev_token.kind == Token_CloseBrace) { + return; + } + } + break; + + case AstNode_TypeSpec: if (f->prev_token.kind == Token_CloseBrace) { return; } + break; } - break; - - case AstNode_TypeSpec: - if (f->prev_token.kind == Token_CloseBrace) { - return; + } else { + switch (s->kind) { + case AstNode_GiveExpr: + if (f->curr_token.kind == Token_CloseBrace) { + return; + } + break; } - break; } - syntax_error(prev_token, "Expected `;` after %.*s, got %.*s", LIT(ast_node_strings[s->kind]), LIT(token_strings[prev_token.kind])); } else { @@ -2752,10 +2761,11 @@ AstNode *parse_return_stmt(AstFile *f) { } Token token = expect_token(f, Token_return); - AstNodeArray results = make_ast_node_array(f); - + AstNodeArray results; if (f->curr_token.kind != Token_Semicolon && f->curr_token.kind != Token_CloseBrace) { results = parse_rhs_expr_list(f); + } else { + results = make_ast_node_array(f); } expect_semicolon(f, results.e[0]); @@ -2774,9 +2784,15 @@ AstNode *parse_give_stmt(AstFile *f) { } Token token = expect_token(f, Token_give); - AstNodeArray results = parse_rhs_expr_list(f); - expect_semicolon(f, results.e[0]); - return make_expr_stmt(f, make_give_expr(f, token, results)); + AstNodeArray results; + if (f->curr_token.kind != Token_Semicolon && f->curr_token.kind != Token_CloseBrace) { + results = parse_rhs_expr_list(f); + } else { + results = make_ast_node_array(f); + } + AstNode *ge = make_give_expr(f, token, results); + expect_semicolon(f, ge); + return make_expr_stmt(f, ge); } AstNode *parse_for_stmt(AstFile *f) { @@ -2665,7 +2665,6 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue ssaValue *cond = ssa_build_cond(proc, ie->cond, then, else_); proc->curr_block = then; - ssa_open_scope(proc); array_add(&edges, ssa_build_expr(proc, ie->body)); ssa_close_scope(proc, ssaDeferExit_Default, NULL); @@ -2721,7 +2720,6 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue ssaValue *field = ssa_emit_struct_ep(proc, v, i); ssa_emit_store(proc, field, res); } - v = ssa_emit_load(proc, v); gb_temp_arena_memory_end(tmp); diff --git a/src/tokenizer.c b/src/tokenizer.c index 51510af3d..2c42df1c5 100644 --- a/src/tokenizer.c +++ b/src/tokenizer.c @@ -180,10 +180,8 @@ void init_global_error_collector(void) { gb_mutex_init(&global_error_collector.mutex); } - void warning_va(Token token, char *fmt, va_list va) { gb_mutex_lock(&global_error_collector.mutex); - global_error_collector.warning_count++; // NOTE(bill): Duplicate error, skip it if (!token_pos_eq(global_error_collector.prev, token.pos)) { @@ -198,7 +196,6 @@ void warning_va(Token token, char *fmt, va_list va) { void error_va(Token token, char *fmt, va_list va) { gb_mutex_lock(&global_error_collector.mutex); - global_error_collector.count++; // NOTE(bill): Duplicate error, skip it if (!token_pos_eq(global_error_collector.prev, token.pos)) { @@ -213,7 +210,6 @@ void error_va(Token token, char *fmt, va_list va) { void syntax_error_va(Token token, char *fmt, va_list va) { gb_mutex_lock(&global_error_collector.mutex); - global_error_collector.count++; // NOTE(bill): Duplicate error, skip it if (!token_pos_eq(global_error_collector.prev, token.pos)) { |