Skip to content

Commit

Permalink
implement continue expression
Browse files Browse the repository at this point in the history
closes #6
  • Loading branch information
andrewrk committed Dec 24, 2015
1 parent 44ca5e1 commit 5943f99
Show file tree
Hide file tree
Showing 7 changed files with 55 additions and 11 deletions.
4 changes: 1 addition & 3 deletions doc/langref.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,16 +146,14 @@ 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 | Break | BlockExpression | token(Symbol) | StructValueExpression
PrimaryExpression : token(Number) | token(String) | KeywordLiteral | GroupedExpression | Goto | token(Break) | token(Continue) | BlockExpression | token(Symbol) | StructValueExpression
StructValueExpression : token(Type) token(LBrace) list(StructValueExpressionField, token(Comma)) token(RBrace)
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)
Expand Down
17 changes: 17 additions & 0 deletions src/analyze.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ static AstNode *first_executing_node(AstNode *node) {
case NodeTypeLabel:
case NodeTypeGoto:
case NodeTypeBreak:
case NodeTypeContinue:
case NodeTypeAsmExpr:
case NodeTypeFieldAccessExpr:
case NodeTypeStructDecl:
Expand Down Expand Up @@ -532,6 +533,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
case NodeTypeLabel:
case NodeTypeGoto:
case NodeTypeBreak:
case NodeTypeContinue:
case NodeTypeAsmExpr:
case NodeTypeFieldAccessExpr:
case NodeTypeStructField:
Expand Down Expand Up @@ -601,6 +603,7 @@ static void preview_types(CodeGen *g, ImportTableEntry *import, AstNode *node) {
case NodeTypeLabel:
case NodeTypeGoto:
case NodeTypeBreak:
case NodeTypeContinue:
case NodeTypeAsmExpr:
case NodeTypeFieldAccessExpr:
case NodeTypeStructField:
Expand Down Expand Up @@ -1381,6 +1384,16 @@ static TypeTableEntry *analyze_break_expr(CodeGen *g, ImportTableEntry *import,
return g->builtin_types.entry_unreachable;
}

static TypeTableEntry *analyze_continue_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
TypeTableEntry *expected_type, AstNode *node)
{
if (!context->break_allowed) {
add_node_error(g, node,
buf_sprintf("'continue' expression not in loop"));
}
return g->builtin_types.entry_unreachable;
}

static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
TypeTableEntry *expected_type, AstNode *node)
{
Expand Down Expand Up @@ -1463,6 +1476,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
case NodeTypeBreak:
return_type = analyze_break_expr(g, import, context, expected_type, node);
break;
case NodeTypeContinue:
return_type = analyze_continue_expr(g, import, context, expected_type, node);
break;
case NodeTypeAsmExpr:
{
node->data.asm_expr.return_count = 0;
Expand Down Expand Up @@ -1817,6 +1833,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,
case NodeTypeLabel:
case NodeTypeGoto:
case NodeTypeBreak:
case NodeTypeContinue:
case NodeTypeAsmExpr:
case NodeTypeFieldAccessExpr:
case NodeTypeStructField:
Expand Down
1 change: 1 addition & 0 deletions src/analyze.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ struct CodeGen {
LLVMBasicBlockRef cur_basic_block;
BlockContext *cur_block_context;
ZigList<LLVMBasicBlockRef> break_block_stack;
ZigList<LLVMBasicBlockRef> continue_block_stack;
bool c_stdint_used;
AstNode *root_export_decl;
int version_major;
Expand Down
12 changes: 12 additions & 0 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1025,8 +1025,10 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {

LLVMPositionBuilderAtEnd(g->builder, body_block);
g->break_block_stack.append(end_block);
g->continue_block_stack.append(cond_block);
gen_expr(g, node->data.while_expr.body);
g->break_block_stack.pop();
g->continue_block_stack.pop();
if (get_expr_type(node->data.while_expr.body)->id != TypeTableEntryIdUnreachable) {
LLVMBuildBr(g->builder, cond_block);
}
Expand All @@ -1043,6 +1045,14 @@ static LLVMValueRef gen_break(CodeGen *g, AstNode *node) {
return LLVMBuildBr(g->builder, dest_block);
}

static LLVMValueRef gen_continue(CodeGen *g, AstNode *node) {
assert(node->type == NodeTypeContinue);
LLVMBasicBlockRef dest_block = g->continue_block_stack.last();

add_debug_source_node(g, node);
return LLVMBuildBr(g->builder, dest_block);
}

static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
switch (node->type) {
case NodeTypeBinOpExpr:
Expand Down Expand Up @@ -1174,6 +1184,8 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
return LLVMBuildBr(g->builder, node->codegen_node->data.label_entry->basic_block);
case NodeTypeBreak:
return gen_break(g, node);
case NodeTypeContinue:
return gen_continue(g, node);
case NodeTypeLabel:
{
LabelTableEntry *label_entry = node->codegen_node->data.label_entry;
Expand Down
11 changes: 10 additions & 1 deletion src/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ const char *node_type_str(NodeType node_type) {
return "Goto";
case NodeTypeBreak:
return "Break";
case NodeTypeContinue:
return "Continue";
case NodeTypeAsmExpr:
return "AsmExpr";
case NodeTypeFieldAccessExpr:
Expand Down Expand Up @@ -341,6 +343,9 @@ void ast_print(AstNode *node, int indent) {
case NodeTypeBreak:
fprintf(stderr, "%s\n", node_type_str(node->type));
break;
case NodeTypeContinue:
fprintf(stderr, "%s\n", node_type_str(node->type));
break;
case NodeTypeAsmExpr:
fprintf(stderr, "%s\n", node_type_str(node->type));
break;
Expand Down Expand Up @@ -1107,7 +1112,7 @@ static AstNode *ast_parse_struct_val_expr(ParseContext *pc, int *token_index) {
}

/*
PrimaryExpression : token(Number) | token(String) | KeywordLiteral | GroupedExpression | Goto | Break | BlockExpression | token(Symbol) | StructValueExpression
PrimaryExpression : token(Number) | token(String) | KeywordLiteral | GroupedExpression | Goto | token(Break) | token(Continue) | BlockExpression | token(Symbol) | StructValueExpression
*/
static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool mandatory) {
Token *token = &pc->tokens->at(*token_index);
Expand Down Expand Up @@ -1165,6 +1170,10 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
AstNode *node = ast_create_node(pc, NodeTypeBreak, token);
*token_index += 1;
return node;
} else if (token->id == TokenIdKeywordContinue) {
AstNode *node = ast_create_node(pc, NodeTypeContinue, token);
*token_index += 1;
return node;
}

AstNode *grouped_expr_node = ast_parse_grouped_expr(pc, token_index, false);
Expand Down
1 change: 1 addition & 0 deletions src/parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ enum NodeType {
NodeTypeLabel,
NodeTypeGoto,
NodeTypeBreak,
NodeTypeContinue,
NodeTypeAsmExpr,
NodeTypeStructDecl,
NodeTypeStructField,
Expand Down
20 changes: 13 additions & 7 deletions test/run_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -659,17 +659,15 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
}
)SOURCE", "loop\nloop\nloop\nloop\n");

add_simple_case("break out of while loop", R"SOURCE(
add_simple_case("continue and break", R"SOURCE(
use "std.zig";
export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
var i : i32 = 0;
while true {
while true {
if i >= 4 {
break;
}
print_str("loop\n");
i += 1;
print_str("loop\n");
i += 1;
if i < 4 {
continue;
}
break;
}
Expand All @@ -678,6 +676,8 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
)SOURCE", "loop\nloop\nloop\nloop\n");
}

////////////////////////////////////////////////////////////////////////////////////

static void add_compile_failure_test_cases(void) {
add_compile_fail_case("multiple function definitions", R"SOURCE(
fn a() {}
Expand Down Expand Up @@ -958,6 +958,12 @@ fn f() {
break;
}
)SOURCE", 1, ".tmp_source.zig:3:5: error: 'break' expression not in loop");

add_compile_fail_case("invalid continue expression", R"SOURCE(
fn f() {
continue;
}
)SOURCE", 1, ".tmp_source.zig:3:5: error: 'continue' expression not in loop");
}

static void print_compiler_invocation(TestCase *test_case) {
Expand Down

0 comments on commit 5943f99

Please sign in to comment.