| author | |
| committer | |
| log | 5ceaae288c4f80fe5ce1449cd9d2efe0e541d629 |
| tree | 7cf0b1b188c9f9ca8df0d4f379b47a6348adf6fd |
| parent | ffc593b8082eb0fa83b1a3d1b63c840379911cd5 |
7 files changed, 55 insertions(+), 2 deletions(-)
doc/langref.md+3-1| ... | ... | @@ -146,7 +146,7 @@ ArrayAccessExpression : token(LBracket) Expression token(RBracket) |
| 146 | 146 | |
| 147 | 147 | PrefixOp : token(Not) | token(Dash) | token(Tilde) | (token(Ampersand) option(token(Const))) |
| 148 | 148 | |
| 149 | PrimaryExpression : token(Number) | token(String) | KeywordLiteral | GroupedExpression | Goto | BlockExpression | token(Symbol) | StructValueExpression | |
| 149 | PrimaryExpression : token(Number) | token(String) | KeywordLiteral | GroupedExpression | Goto | Break | BlockExpression | token(Symbol) | StructValueExpression | |
| 150 | 150 | |
| 151 | 151 | StructValueExpression : token(Type) token(LBrace) list(StructValueExpressionField, token(Comma)) token(RBrace) |
| 152 | 152 | |
| ... | ... | @@ -154,6 +154,8 @@ StructValueExpressionField : token(Dot) token(Symbol) token(Eq) Expression |
| 154 | 154 | |
| 155 | 155 | Goto: token(Goto) token(Symbol) |
| 156 | 156 | |
| 157 | Break: token(Break) | |
| 158 | ||
| 157 | 159 | GroupedExpression : token(LParen) Expression token(RParen) |
| 158 | 160 | |
| 159 | 161 | KeywordLiteral : token(Unreachable) | token(Void) | token(True) | token(False) |
src/analyze.cpp+13| ... | ... | @@ -48,6 +48,7 @@ static AstNode *first_executing_node(AstNode *node) { |
| 48 | 48 | case NodeTypeIfExpr: |
| 49 | 49 | case NodeTypeLabel: |
| 50 | 50 | case NodeTypeGoto: |
| 51 | case NodeTypeBreak: | |
| 51 | 52 | case NodeTypeAsmExpr: |
| 52 | 53 | case NodeTypeFieldAccessExpr: |
| 53 | 54 | case NodeTypeStructDecl: |
| ... | ... | @@ -530,6 +531,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, |
| 530 | 531 | case NodeTypeWhileExpr: |
| 531 | 532 | case NodeTypeLabel: |
| 532 | 533 | case NodeTypeGoto: |
| 534 | case NodeTypeBreak: | |
| 533 | 535 | case NodeTypeAsmExpr: |
| 534 | 536 | case NodeTypeFieldAccessExpr: |
| 535 | 537 | case NodeTypeStructField: |
| ... | ... | @@ -598,6 +600,7 @@ static void preview_types(CodeGen *g, ImportTableEntry *import, AstNode *node) { |
| 598 | 600 | case NodeTypeWhileExpr: |
| 599 | 601 | case NodeTypeLabel: |
| 600 | 602 | case NodeTypeGoto: |
| 603 | case NodeTypeBreak: | |
| 601 | 604 | case NodeTypeAsmExpr: |
| 602 | 605 | case NodeTypeFieldAccessExpr: |
| 603 | 606 | case NodeTypeStructField: |
| ... | ... | @@ -1360,6 +1363,12 @@ static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import, |
| 1360 | 1363 | return g->builtin_types.entry_void; |
| 1361 | 1364 | } |
| 1362 | 1365 | |
| 1366 | static TypeTableEntry *analyze_break_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | |
| 1367 | TypeTableEntry *expected_type, AstNode *node) | |
| 1368 | { | |
| 1369 | return g->builtin_types.entry_unreachable; | |
| 1370 | } | |
| 1371 | ||
| 1363 | 1372 | static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 1364 | 1373 | TypeTableEntry *expected_type, AstNode *node) |
| 1365 | 1374 | { |
| ... | ... | @@ -1439,6 +1448,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 1439 | 1448 | return_type = g->builtin_types.entry_unreachable; |
| 1440 | 1449 | break; |
| 1441 | 1450 | } |
| 1451 | case NodeTypeBreak: | |
| 1452 | return_type = analyze_break_expr(g, import, context, expected_type, node); | |
| 1453 | break; | |
| 1442 | 1454 | case NodeTypeAsmExpr: |
| 1443 | 1455 | { |
| 1444 | 1456 | node->data.asm_expr.return_count = 0; |
| ... | ... | @@ -1792,6 +1804,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, |
| 1792 | 1804 | case NodeTypeWhileExpr: |
| 1793 | 1805 | case NodeTypeLabel: |
| 1794 | 1806 | case NodeTypeGoto: |
| 1807 | case NodeTypeBreak: | |
| 1795 | 1808 | case NodeTypeAsmExpr: |
| 1796 | 1809 | case NodeTypeFieldAccessExpr: |
| 1797 | 1810 | case NodeTypeStructField: |
src/analyze.hpp+1| ... | ... | @@ -196,6 +196,7 @@ struct CodeGen { |
| 196 | 196 | FnTableEntry *cur_fn; |
| 197 | 197 | LLVMBasicBlockRef cur_basic_block; |
| 198 | 198 | BlockContext *cur_block_context; |
| 199 | LLVMBasicBlockRef cur_break_block; | |
| 199 | 200 | bool c_stdint_used; |
| 200 | 201 | AstNode *root_export_decl; |
| 201 | 202 | int version_major; |
src/codegen.cpp+12| ... | ... | @@ -1024,13 +1024,23 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) { |
| 1024 | 1024 | LLVMBuildCondBr(g->builder, cond_val, body_block, end_block); |
| 1025 | 1025 | |
| 1026 | 1026 | LLVMPositionBuilderAtEnd(g->builder, body_block); |
| 1027 | g->cur_break_block = end_block; | |
| 1027 | 1028 | gen_expr(g, node->data.while_expr.body); |
| 1029 | g->cur_break_block = nullptr; | |
| 1028 | 1030 | LLVMBuildBr(g->builder, cond_block); |
| 1029 | 1031 | |
| 1030 | 1032 | LLVMPositionBuilderAtEnd(g->builder, end_block); |
| 1031 | 1033 | return nullptr; |
| 1032 | 1034 | } |
| 1033 | 1035 | |
| 1036 | static LLVMValueRef gen_break(CodeGen *g, AstNode *node) { | |
| 1037 | assert(node->type == NodeTypeBreak); | |
| 1038 | assert(g->cur_break_block); | |
| 1039 | ||
| 1040 | add_debug_source_node(g, node); | |
| 1041 | return LLVMBuildBr(g->builder, g->cur_break_block); | |
| 1042 | } | |
| 1043 | ||
| 1034 | 1044 | static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) { |
| 1035 | 1045 | switch (node->type) { |
| 1036 | 1046 | case NodeTypeBinOpExpr: |
| ... | ... | @@ -1160,6 +1170,8 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) { |
| 1160 | 1170 | case NodeTypeGoto: |
| 1161 | 1171 | add_debug_source_node(g, node); |
| 1162 | 1172 | return LLVMBuildBr(g->builder, node->codegen_node->data.label_entry->basic_block); |
| 1173 | case NodeTypeBreak: | |
| 1174 | return gen_break(g, node); | |
| 1163 | 1175 | case NodeTypeLabel: |
| 1164 | 1176 | { |
| 1165 | 1177 | LabelTableEntry *label_entry = node->codegen_node->data.label_entry; |
src/parser.cpp+10-1| ... | ... | @@ -122,6 +122,8 @@ const char *node_type_str(NodeType node_type) { |
| 122 | 122 | return "Label"; |
| 123 | 123 | case NodeTypeGoto: |
| 124 | 124 | return "Goto"; |
| 125 | case NodeTypeBreak: | |
| 126 | return "Break"; | |
| 125 | 127 | case NodeTypeAsmExpr: |
| 126 | 128 | return "AsmExpr"; |
| 127 | 129 | case NodeTypeFieldAccessExpr: |
| ... | ... | @@ -336,6 +338,9 @@ void ast_print(AstNode *node, int indent) { |
| 336 | 338 | case NodeTypeGoto: |
| 337 | 339 | fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.go_to.name)); |
| 338 | 340 | break; |
| 341 | case NodeTypeBreak: | |
| 342 | fprintf(stderr, "%s\n", node_type_str(node->type)); | |
| 343 | break; | |
| 339 | 344 | case NodeTypeAsmExpr: |
| 340 | 345 | fprintf(stderr, "%s\n", node_type_str(node->type)); |
| 341 | 346 | break; |
| ... | ... | @@ -1102,7 +1107,7 @@ static AstNode *ast_parse_struct_val_expr(ParseContext *pc, int *token_index) { |
| 1102 | 1107 | } |
| 1103 | 1108 | |
| 1104 | 1109 | /* |
| 1105 | PrimaryExpression : token(Number) | token(String) | KeywordLiteral | GroupedExpression | Goto | BlockExpression | token(Symbol) | StructValueExpression | |
| 1110 | PrimaryExpression : token(Number) | token(String) | KeywordLiteral | GroupedExpression | Goto | Break | BlockExpression | token(Symbol) | StructValueExpression | |
| 1106 | 1111 | */ |
| 1107 | 1112 | static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool mandatory) { |
| 1108 | 1113 | Token *token = &pc->tokens->at(*token_index); |
| ... | ... | @@ -1156,6 +1161,10 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool |
| 1156 | 1161 | |
| 1157 | 1162 | ast_buf_from_token(pc, dest_symbol, &node->data.go_to.name); |
| 1158 | 1163 | return node; |
| 1164 | } else if (token->id == TokenIdKeywordBreak) { | |
| 1165 | AstNode *node = ast_create_node(pc, NodeTypeBreak, token); | |
| 1166 | *token_index += 1; | |
| 1167 | return node; | |
| 1159 | 1168 | } |
| 1160 | 1169 | |
| 1161 | 1170 | AstNode *grouped_expr_node = ast_parse_grouped_expr(pc, token_index, false); |
src/parser.hpp+1| ... | ... | @@ -48,6 +48,7 @@ enum NodeType { |
| 48 | 48 | NodeTypeWhileExpr, |
| 49 | 49 | NodeTypeLabel, |
| 50 | 50 | NodeTypeGoto, |
| 51 | NodeTypeBreak, | |
| 51 | 52 | NodeTypeAsmExpr, |
| 52 | 53 | NodeTypeStructDecl, |
| 53 | 54 | NodeTypeStructField, |
test/run_tests.cpp+15| ... | ... | @@ -656,6 +656,21 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { |
| 656 | 656 | i += 1; |
| 657 | 657 | } |
| 658 | 658 | return 0; |
| 659 | } | |
| 660 | )SOURCE", "loop\nloop\nloop\nloop\n"); | |
| 661 | ||
| 662 | add_simple_case("break out of while loop", R"SOURCE( | |
| 663 | use "std.zig"; | |
| 664 | export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { | |
| 665 | var i : i32 = 0; | |
| 666 | while true { | |
| 667 | if i >= 4 { | |
| 668 | break; | |
| 669 | } | |
| 670 | print_str("loop\n"); | |
| 671 | i += 1; | |
| 672 | } | |
| 673 | return 0; | |
| 659 | 674 | } |
| 660 | 675 | )SOURCE", "loop\nloop\nloop\nloop\n"); |
| 661 | 676 | } |