Commit 5ceaae288c

Andrew Kelley <superjoe30@gmail.com>
2015-12-24 23:09:35
add break expression
1 parent ffc593b
doc/langref.md
@@ -146,7 +146,7 @@ ArrayAccessExpression : token(LBracket) Expression token(RBracket)
 
 PrefixOp : token(Not) | token(Dash) | token(Tilde) | (token(Ampersand) option(token(Const)))
 
-PrimaryExpression : token(Number) | token(String) | KeywordLiteral | GroupedExpression | Goto | BlockExpression | token(Symbol) | StructValueExpression
+PrimaryExpression : token(Number) | token(String) | KeywordLiteral | GroupedExpression | Goto | Break | BlockExpression | token(Symbol) | StructValueExpression
 
 StructValueExpression : token(Type) token(LBrace) list(StructValueExpressionField, token(Comma)) token(RBrace)
 
@@ -154,6 +154,8 @@ StructValueExpressionField : token(Dot) token(Symbol) token(Eq) Expression
 
 Goto: token(Goto) token(Symbol)
 
+Break: token(Break)
+
 GroupedExpression : token(LParen) Expression token(RParen)
 
 KeywordLiteral : token(Unreachable) | token(Void) | token(True) | token(False)
src/analyze.cpp
@@ -48,6 +48,7 @@ static AstNode *first_executing_node(AstNode *node) {
         case NodeTypeIfExpr:
         case NodeTypeLabel:
         case NodeTypeGoto:
+        case NodeTypeBreak:
         case NodeTypeAsmExpr:
         case NodeTypeFieldAccessExpr:
         case NodeTypeStructDecl:
@@ -530,6 +531,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
         case NodeTypeWhileExpr:
         case NodeTypeLabel:
         case NodeTypeGoto:
+        case NodeTypeBreak:
         case NodeTypeAsmExpr:
         case NodeTypeFieldAccessExpr:
         case NodeTypeStructField:
@@ -598,6 +600,7 @@ static void preview_types(CodeGen *g, ImportTableEntry *import, AstNode *node) {
         case NodeTypeWhileExpr:
         case NodeTypeLabel:
         case NodeTypeGoto:
+        case NodeTypeBreak:
         case NodeTypeAsmExpr:
         case NodeTypeFieldAccessExpr:
         case NodeTypeStructField:
@@ -1360,6 +1363,12 @@ static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import,
     return g->builtin_types.entry_void;
 }
 
+static TypeTableEntry *analyze_break_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
+        TypeTableEntry *expected_type, AstNode *node)
+{
+    return g->builtin_types.entry_unreachable;
+}
+
 static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
         TypeTableEntry *expected_type, AstNode *node)
 {
@@ -1439,6 +1448,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
                 return_type = g->builtin_types.entry_unreachable;
                 break;
             }
+        case NodeTypeBreak:
+            return_type = analyze_break_expr(g, import, context, expected_type, node);
+            break;
         case NodeTypeAsmExpr:
             {
                 node->data.asm_expr.return_count = 0;
@@ -1792,6 +1804,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,
         case NodeTypeWhileExpr:
         case NodeTypeLabel:
         case NodeTypeGoto:
+        case NodeTypeBreak:
         case NodeTypeAsmExpr:
         case NodeTypeFieldAccessExpr:
         case NodeTypeStructField:
src/analyze.hpp
@@ -196,6 +196,7 @@ struct CodeGen {
     FnTableEntry *cur_fn;
     LLVMBasicBlockRef cur_basic_block;
     BlockContext *cur_block_context;
+    LLVMBasicBlockRef cur_break_block;
     bool c_stdint_used;
     AstNode *root_export_decl;
     int version_major;
src/codegen.cpp
@@ -1024,13 +1024,23 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {
     LLVMBuildCondBr(g->builder, cond_val, body_block, end_block);
 
     LLVMPositionBuilderAtEnd(g->builder, body_block);
+    g->cur_break_block = end_block;
     gen_expr(g, node->data.while_expr.body);
+    g->cur_break_block = nullptr;
     LLVMBuildBr(g->builder, cond_block);
 
     LLVMPositionBuilderAtEnd(g->builder, end_block);
     return nullptr;
 }
 
+static LLVMValueRef gen_break(CodeGen *g, AstNode *node) {
+    assert(node->type == NodeTypeBreak);
+    assert(g->cur_break_block);
+
+    add_debug_source_node(g, node);
+    return LLVMBuildBr(g->builder, g->cur_break_block);
+}
+
 static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
     switch (node->type) {
         case NodeTypeBinOpExpr:
@@ -1160,6 +1170,8 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
         case NodeTypeGoto:
             add_debug_source_node(g, node);
             return LLVMBuildBr(g->builder, node->codegen_node->data.label_entry->basic_block);
+        case NodeTypeBreak:
+            return gen_break(g, node);
         case NodeTypeLabel:
             {
                 LabelTableEntry *label_entry = node->codegen_node->data.label_entry;
src/parser.cpp
@@ -122,6 +122,8 @@ const char *node_type_str(NodeType node_type) {
             return "Label";
         case NodeTypeGoto:
             return "Goto";
+        case NodeTypeBreak:
+            return "Break";
         case NodeTypeAsmExpr:
             return "AsmExpr";
         case NodeTypeFieldAccessExpr:
@@ -336,6 +338,9 @@ void ast_print(AstNode *node, int indent) {
         case NodeTypeGoto:
             fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.go_to.name));
             break;
+        case NodeTypeBreak:
+            fprintf(stderr, "%s\n", node_type_str(node->type));
+            break;
         case NodeTypeAsmExpr:
             fprintf(stderr, "%s\n", node_type_str(node->type));
             break;
@@ -1102,7 +1107,7 @@ static AstNode *ast_parse_struct_val_expr(ParseContext *pc, int *token_index) {
 }
 
 /*
-PrimaryExpression : token(Number) | token(String) | KeywordLiteral | GroupedExpression | Goto | BlockExpression | token(Symbol) | StructValueExpression
+PrimaryExpression : token(Number) | token(String) | KeywordLiteral | GroupedExpression | Goto | Break | BlockExpression | token(Symbol) | StructValueExpression
 */
 static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool mandatory) {
     Token *token = &pc->tokens->at(*token_index);
@@ -1156,6 +1161,10 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
 
         ast_buf_from_token(pc, dest_symbol, &node->data.go_to.name);
         return node;
+    } else if (token->id == TokenIdKeywordBreak) {
+        AstNode *node = ast_create_node(pc, NodeTypeBreak, token);
+        *token_index += 1;
+        return node;
     }
 
     AstNode *grouped_expr_node = ast_parse_grouped_expr(pc, token_index, false);
src/parser.hpp
@@ -48,6 +48,7 @@ enum NodeType {
     NodeTypeWhileExpr,
     NodeTypeLabel,
     NodeTypeGoto,
+    NodeTypeBreak,
     NodeTypeAsmExpr,
     NodeTypeStructDecl,
     NodeTypeStructField,
test/run_tests.cpp
@@ -656,6 +656,21 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
         i += 1;
     }
     return 0;
+}
+    )SOURCE", "loop\nloop\nloop\nloop\n");
+
+    add_simple_case("break out of while loop", R"SOURCE(
+use "std.zig";
+export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
+    var i : i32 = 0;
+    while true {
+        if i >= 4 {
+            break;
+        }
+        print_str("loop\n");
+        i += 1;
+    }
+    return 0;
 }
     )SOURCE", "loop\nloop\nloop\nloop\n");
 }