authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-24 15:36:49-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-24 15:36:49-07:00
log5943f995106f9fc2c7c5b416c8d4a2ebba2b8315
treee7c67f1b85260de9b54e22a85de8eb3212788d86
parent44ca5e19dc174383b1b0490e636398092711306d

implement continue expression

closes #6

7 files changed, 55 insertions(+), 11 deletions(-)

doc/langref.md+1-3
...@@ -146,7 +146,7 @@ ArrayAccessExpression : token(LBracket) Expression token(RBracket)...@@ -146,7 +146,7 @@ ArrayAccessExpression : token(LBracket) Expression token(RBracket)
146146
147PrefixOp : token(Not) | token(Dash) | token(Tilde) | (token(Ampersand) option(token(Const)))147PrefixOp : token(Not) | token(Dash) | token(Tilde) | (token(Ampersand) option(token(Const)))
148148
149PrimaryExpression : token(Number) | token(String) | KeywordLiteral | GroupedExpression | Goto | Break | BlockExpression | token(Symbol) | StructValueExpression149PrimaryExpression : token(Number) | token(String) | KeywordLiteral | GroupedExpression | Goto | token(Break) | token(Continue) | BlockExpression | token(Symbol) | StructValueExpression
150150
151StructValueExpression : token(Type) token(LBrace) list(StructValueExpressionField, token(Comma)) token(RBrace)151StructValueExpression : token(Type) token(LBrace) list(StructValueExpressionField, token(Comma)) token(RBrace)
152152
...@@ -154,8 +154,6 @@ StructValueExpressionField : token(Dot) token(Symbol) token(Eq) Expression...@@ -154,8 +154,6 @@ StructValueExpressionField : token(Dot) token(Symbol) token(Eq) Expression
154154
155Goto: token(Goto) token(Symbol)155Goto: token(Goto) token(Symbol)
156156
157Break: token(Break)
158
159GroupedExpression : token(LParen) Expression token(RParen)157GroupedExpression : token(LParen) Expression token(RParen)
160158
161KeywordLiteral : token(Unreachable) | token(Void) | token(True) | token(False)159KeywordLiteral : token(Unreachable) | token(Void) | token(True) | token(False)
src/analyze.cpp+17
...@@ -49,6 +49,7 @@ static AstNode *first_executing_node(AstNode *node) {...@@ -49,6 +49,7 @@ static AstNode *first_executing_node(AstNode *node) {
49 case NodeTypeLabel:49 case NodeTypeLabel:
50 case NodeTypeGoto:50 case NodeTypeGoto:
51 case NodeTypeBreak:51 case NodeTypeBreak:
52 case NodeTypeContinue:
52 case NodeTypeAsmExpr:53 case NodeTypeAsmExpr:
53 case NodeTypeFieldAccessExpr:54 case NodeTypeFieldAccessExpr:
54 case NodeTypeStructDecl:55 case NodeTypeStructDecl:
...@@ -532,6 +533,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,...@@ -532,6 +533,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
532 case NodeTypeLabel:533 case NodeTypeLabel:
533 case NodeTypeGoto:534 case NodeTypeGoto:
534 case NodeTypeBreak:535 case NodeTypeBreak:
536 case NodeTypeContinue:
535 case NodeTypeAsmExpr:537 case NodeTypeAsmExpr:
536 case NodeTypeFieldAccessExpr:538 case NodeTypeFieldAccessExpr:
537 case NodeTypeStructField:539 case NodeTypeStructField:
...@@ -601,6 +603,7 @@ static void preview_types(CodeGen *g, ImportTableEntry *import, AstNode *node) {...@@ -601,6 +603,7 @@ static void preview_types(CodeGen *g, ImportTableEntry *import, AstNode *node) {
601 case NodeTypeLabel:603 case NodeTypeLabel:
602 case NodeTypeGoto:604 case NodeTypeGoto:
603 case NodeTypeBreak:605 case NodeTypeBreak:
606 case NodeTypeContinue:
604 case NodeTypeAsmExpr:607 case NodeTypeAsmExpr:
605 case NodeTypeFieldAccessExpr:608 case NodeTypeFieldAccessExpr:
606 case NodeTypeStructField:609 case NodeTypeStructField:
...@@ -1381,6 +1384,16 @@ static TypeTableEntry *analyze_break_expr(CodeGen *g, ImportTableEntry *import,...@@ -1381,6 +1384,16 @@ static TypeTableEntry *analyze_break_expr(CodeGen *g, ImportTableEntry *import,
1381 return g->builtin_types.entry_unreachable;1384 return g->builtin_types.entry_unreachable;
1382}1385}
13831386
1387static TypeTableEntry *analyze_continue_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
1388 TypeTableEntry *expected_type, AstNode *node)
1389{
1390 if (!context->break_allowed) {
1391 add_node_error(g, node,
1392 buf_sprintf("'continue' expression not in loop"));
1393 }
1394 return g->builtin_types.entry_unreachable;
1395}
1396
1384static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,1397static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
1385 TypeTableEntry *expected_type, AstNode *node)1398 TypeTableEntry *expected_type, AstNode *node)
1386{1399{
...@@ -1463,6 +1476,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -1463,6 +1476,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
1463 case NodeTypeBreak:1476 case NodeTypeBreak:
1464 return_type = analyze_break_expr(g, import, context, expected_type, node);1477 return_type = analyze_break_expr(g, import, context, expected_type, node);
1465 break;1478 break;
1479 case NodeTypeContinue:
1480 return_type = analyze_continue_expr(g, import, context, expected_type, node);
1481 break;
1466 case NodeTypeAsmExpr:1482 case NodeTypeAsmExpr:
1467 {1483 {
1468 node->data.asm_expr.return_count = 0;1484 node->data.asm_expr.return_count = 0;
...@@ -1817,6 +1833,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,...@@ -1817,6 +1833,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,
1817 case NodeTypeLabel:1833 case NodeTypeLabel:
1818 case NodeTypeGoto:1834 case NodeTypeGoto:
1819 case NodeTypeBreak:1835 case NodeTypeBreak:
1836 case NodeTypeContinue:
1820 case NodeTypeAsmExpr:1837 case NodeTypeAsmExpr:
1821 case NodeTypeFieldAccessExpr:1838 case NodeTypeFieldAccessExpr:
1822 case NodeTypeStructField:1839 case NodeTypeStructField:
src/analyze.hpp+1
...@@ -197,6 +197,7 @@ struct CodeGen {...@@ -197,6 +197,7 @@ struct CodeGen {
197 LLVMBasicBlockRef cur_basic_block;197 LLVMBasicBlockRef cur_basic_block;
198 BlockContext *cur_block_context;198 BlockContext *cur_block_context;
199 ZigList<LLVMBasicBlockRef> break_block_stack;199 ZigList<LLVMBasicBlockRef> break_block_stack;
200 ZigList<LLVMBasicBlockRef> continue_block_stack;
200 bool c_stdint_used;201 bool c_stdint_used;
201 AstNode *root_export_decl;202 AstNode *root_export_decl;
202 int version_major;203 int version_major;
src/codegen.cpp+12
...@@ -1025,8 +1025,10 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {...@@ -1025,8 +1025,10 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {
10251025
1026 LLVMPositionBuilderAtEnd(g->builder, body_block);1026 LLVMPositionBuilderAtEnd(g->builder, body_block);
1027 g->break_block_stack.append(end_block);1027 g->break_block_stack.append(end_block);
1028 g->continue_block_stack.append(cond_block);
1028 gen_expr(g, node->data.while_expr.body);1029 gen_expr(g, node->data.while_expr.body);
1029 g->break_block_stack.pop();1030 g->break_block_stack.pop();
1031 g->continue_block_stack.pop();
1030 if (get_expr_type(node->data.while_expr.body)->id != TypeTableEntryIdUnreachable) {1032 if (get_expr_type(node->data.while_expr.body)->id != TypeTableEntryIdUnreachable) {
1031 LLVMBuildBr(g->builder, cond_block);1033 LLVMBuildBr(g->builder, cond_block);
1032 }1034 }
...@@ -1043,6 +1045,14 @@ static LLVMValueRef gen_break(CodeGen *g, AstNode *node) {...@@ -1043,6 +1045,14 @@ static LLVMValueRef gen_break(CodeGen *g, AstNode *node) {
1043 return LLVMBuildBr(g->builder, dest_block);1045 return LLVMBuildBr(g->builder, dest_block);
1044}1046}
10451047
1048static LLVMValueRef gen_continue(CodeGen *g, AstNode *node) {
1049 assert(node->type == NodeTypeContinue);
1050 LLVMBasicBlockRef dest_block = g->continue_block_stack.last();
1051
1052 add_debug_source_node(g, node);
1053 return LLVMBuildBr(g->builder, dest_block);
1054}
1055
1046static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {1056static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
1047 switch (node->type) {1057 switch (node->type) {
1048 case NodeTypeBinOpExpr:1058 case NodeTypeBinOpExpr:
...@@ -1174,6 +1184,8 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {...@@ -1174,6 +1184,8 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
1174 return LLVMBuildBr(g->builder, node->codegen_node->data.label_entry->basic_block);1184 return LLVMBuildBr(g->builder, node->codegen_node->data.label_entry->basic_block);
1175 case NodeTypeBreak:1185 case NodeTypeBreak:
1176 return gen_break(g, node);1186 return gen_break(g, node);
1187 case NodeTypeContinue:
1188 return gen_continue(g, node);
1177 case NodeTypeLabel:1189 case NodeTypeLabel:
1178 {1190 {
1179 LabelTableEntry *label_entry = node->codegen_node->data.label_entry;1191 LabelTableEntry *label_entry = node->codegen_node->data.label_entry;
src/parser.cpp+10-1
...@@ -124,6 +124,8 @@ const char *node_type_str(NodeType node_type) {...@@ -124,6 +124,8 @@ const char *node_type_str(NodeType node_type) {
124 return "Goto";124 return "Goto";
125 case NodeTypeBreak:125 case NodeTypeBreak:
126 return "Break";126 return "Break";
127 case NodeTypeContinue:
128 return "Continue";
127 case NodeTypeAsmExpr:129 case NodeTypeAsmExpr:
128 return "AsmExpr";130 return "AsmExpr";
129 case NodeTypeFieldAccessExpr:131 case NodeTypeFieldAccessExpr:
...@@ -341,6 +343,9 @@ void ast_print(AstNode *node, int indent) {...@@ -341,6 +343,9 @@ void ast_print(AstNode *node, int indent) {
341 case NodeTypeBreak:343 case NodeTypeBreak:
342 fprintf(stderr, "%s\n", node_type_str(node->type));344 fprintf(stderr, "%s\n", node_type_str(node->type));
343 break;345 break;
346 case NodeTypeContinue:
347 fprintf(stderr, "%s\n", node_type_str(node->type));
348 break;
344 case NodeTypeAsmExpr:349 case NodeTypeAsmExpr:
345 fprintf(stderr, "%s\n", node_type_str(node->type));350 fprintf(stderr, "%s\n", node_type_str(node->type));
346 break;351 break;
...@@ -1107,7 +1112,7 @@ static AstNode *ast_parse_struct_val_expr(ParseContext *pc, int *token_index) {...@@ -1107,7 +1112,7 @@ static AstNode *ast_parse_struct_val_expr(ParseContext *pc, int *token_index) {
1107}1112}
11081113
1109/*1114/*
1110PrimaryExpression : token(Number) | token(String) | KeywordLiteral | GroupedExpression | Goto | Break | BlockExpression | token(Symbol) | StructValueExpression1115PrimaryExpression : token(Number) | token(String) | KeywordLiteral | GroupedExpression | Goto | token(Break) | token(Continue) | BlockExpression | token(Symbol) | StructValueExpression
1111*/1116*/
1112static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool mandatory) {1117static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool mandatory) {
1113 Token *token = &pc->tokens->at(*token_index);1118 Token *token = &pc->tokens->at(*token_index);
...@@ -1165,6 +1170,10 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool...@@ -1165,6 +1170,10 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
1165 AstNode *node = ast_create_node(pc, NodeTypeBreak, token);1170 AstNode *node = ast_create_node(pc, NodeTypeBreak, token);
1166 *token_index += 1;1171 *token_index += 1;
1167 return node;1172 return node;
1173 } else if (token->id == TokenIdKeywordContinue) {
1174 AstNode *node = ast_create_node(pc, NodeTypeContinue, token);
1175 *token_index += 1;
1176 return node;
1168 }1177 }
11691178
1170 AstNode *grouped_expr_node = ast_parse_grouped_expr(pc, token_index, false);1179 AstNode *grouped_expr_node = ast_parse_grouped_expr(pc, token_index, false);
src/parser.hpp+1
...@@ -49,6 +49,7 @@ enum NodeType {...@@ -49,6 +49,7 @@ enum NodeType {
49 NodeTypeLabel,49 NodeTypeLabel,
50 NodeTypeGoto,50 NodeTypeGoto,
51 NodeTypeBreak,51 NodeTypeBreak,
52 NodeTypeContinue,
52 NodeTypeAsmExpr,53 NodeTypeAsmExpr,
53 NodeTypeStructDecl,54 NodeTypeStructDecl,
54 NodeTypeStructField,55 NodeTypeStructField,
test/run_tests.cpp+13-7
...@@ -659,17 +659,15 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {...@@ -659,17 +659,15 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
659}659}
660 )SOURCE", "loop\nloop\nloop\nloop\n");660 )SOURCE", "loop\nloop\nloop\nloop\n");
661661
662 add_simple_case("break out of while loop", R"SOURCE(662 add_simple_case("continue and break", R"SOURCE(
663use "std.zig";663use "std.zig";
664export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {664export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
665 var i : i32 = 0;665 var i : i32 = 0;
666 while true {666 while true {
667 while true {667 print_str("loop\n");
668 if i >= 4 {668 i += 1;
669 break;669 if i < 4 {
670 }670 continue;
671 print_str("loop\n");
672 i += 1;
673 }671 }
674 break;672 break;
675 }673 }
...@@ -678,6 +676,8 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {...@@ -678,6 +676,8 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
678 )SOURCE", "loop\nloop\nloop\nloop\n");676 )SOURCE", "loop\nloop\nloop\nloop\n");
679}677}
680678
679////////////////////////////////////////////////////////////////////////////////////
680
681static void add_compile_failure_test_cases(void) {681static void add_compile_failure_test_cases(void) {
682 add_compile_fail_case("multiple function definitions", R"SOURCE(682 add_compile_fail_case("multiple function definitions", R"SOURCE(
683fn a() {}683fn a() {}
...@@ -958,6 +958,12 @@ fn f() {...@@ -958,6 +958,12 @@ fn f() {
958 break;958 break;
959}959}
960 )SOURCE", 1, ".tmp_source.zig:3:5: error: 'break' expression not in loop");960 )SOURCE", 1, ".tmp_source.zig:3:5: error: 'break' expression not in loop");
961
962 add_compile_fail_case("invalid continue expression", R"SOURCE(
963fn f() {
964 continue;
965}
966 )SOURCE", 1, ".tmp_source.zig:3:5: error: 'continue' expression not in loop");
961}967}
962968
963static void print_compiler_invocation(TestCase *test_case) {969static void print_compiler_invocation(TestCase *test_case) {