mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
parent
44ca5e19dc
commit
5943f99510
@ -146,7 +146,7 @@ ArrayAccessExpression : token(LBracket) Expression token(RBracket)
|
|||||||
|
|
||||||
PrefixOp : token(Not) | token(Dash) | token(Tilde) | (token(Ampersand) option(token(Const)))
|
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)
|
StructValueExpression : token(Type) token(LBrace) list(StructValueExpressionField, token(Comma)) token(RBrace)
|
||||||
|
|
||||||
@ -154,8 +154,6 @@ StructValueExpressionField : token(Dot) token(Symbol) token(Eq) Expression
|
|||||||
|
|
||||||
Goto: token(Goto) token(Symbol)
|
Goto: token(Goto) token(Symbol)
|
||||||
|
|
||||||
Break: token(Break)
|
|
||||||
|
|
||||||
GroupedExpression : token(LParen) Expression token(RParen)
|
GroupedExpression : token(LParen) Expression token(RParen)
|
||||||
|
|
||||||
KeywordLiteral : token(Unreachable) | token(Void) | token(True) | token(False)
|
KeywordLiteral : token(Unreachable) | token(Void) | token(True) | token(False)
|
||||||
|
|||||||
@ -49,6 +49,7 @@ static AstNode *first_executing_node(AstNode *node) {
|
|||||||
case NodeTypeLabel:
|
case NodeTypeLabel:
|
||||||
case NodeTypeGoto:
|
case NodeTypeGoto:
|
||||||
case NodeTypeBreak:
|
case NodeTypeBreak:
|
||||||
|
case NodeTypeContinue:
|
||||||
case NodeTypeAsmExpr:
|
case NodeTypeAsmExpr:
|
||||||
case NodeTypeFieldAccessExpr:
|
case NodeTypeFieldAccessExpr:
|
||||||
case NodeTypeStructDecl:
|
case NodeTypeStructDecl:
|
||||||
@ -532,6 +533,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
|
|||||||
case NodeTypeLabel:
|
case NodeTypeLabel:
|
||||||
case NodeTypeGoto:
|
case NodeTypeGoto:
|
||||||
case NodeTypeBreak:
|
case NodeTypeBreak:
|
||||||
|
case NodeTypeContinue:
|
||||||
case NodeTypeAsmExpr:
|
case NodeTypeAsmExpr:
|
||||||
case NodeTypeFieldAccessExpr:
|
case NodeTypeFieldAccessExpr:
|
||||||
case NodeTypeStructField:
|
case NodeTypeStructField:
|
||||||
@ -601,6 +603,7 @@ static void preview_types(CodeGen *g, ImportTableEntry *import, AstNode *node) {
|
|||||||
case NodeTypeLabel:
|
case NodeTypeLabel:
|
||||||
case NodeTypeGoto:
|
case NodeTypeGoto:
|
||||||
case NodeTypeBreak:
|
case NodeTypeBreak:
|
||||||
|
case NodeTypeContinue:
|
||||||
case NodeTypeAsmExpr:
|
case NodeTypeAsmExpr:
|
||||||
case NodeTypeFieldAccessExpr:
|
case NodeTypeFieldAccessExpr:
|
||||||
case NodeTypeStructField:
|
case NodeTypeStructField:
|
||||||
@ -1381,6 +1384,16 @@ static TypeTableEntry *analyze_break_expr(CodeGen *g, ImportTableEntry *import,
|
|||||||
return g->builtin_types.entry_unreachable;
|
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,
|
static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
|
||||||
TypeTableEntry *expected_type, AstNode *node)
|
TypeTableEntry *expected_type, AstNode *node)
|
||||||
{
|
{
|
||||||
@ -1463,6 +1476,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
|
|||||||
case NodeTypeBreak:
|
case NodeTypeBreak:
|
||||||
return_type = analyze_break_expr(g, import, context, expected_type, node);
|
return_type = analyze_break_expr(g, import, context, expected_type, node);
|
||||||
break;
|
break;
|
||||||
|
case NodeTypeContinue:
|
||||||
|
return_type = analyze_continue_expr(g, import, context, expected_type, node);
|
||||||
|
break;
|
||||||
case NodeTypeAsmExpr:
|
case NodeTypeAsmExpr:
|
||||||
{
|
{
|
||||||
node->data.asm_expr.return_count = 0;
|
node->data.asm_expr.return_count = 0;
|
||||||
@ -1817,6 +1833,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,
|
|||||||
case NodeTypeLabel:
|
case NodeTypeLabel:
|
||||||
case NodeTypeGoto:
|
case NodeTypeGoto:
|
||||||
case NodeTypeBreak:
|
case NodeTypeBreak:
|
||||||
|
case NodeTypeContinue:
|
||||||
case NodeTypeAsmExpr:
|
case NodeTypeAsmExpr:
|
||||||
case NodeTypeFieldAccessExpr:
|
case NodeTypeFieldAccessExpr:
|
||||||
case NodeTypeStructField:
|
case NodeTypeStructField:
|
||||||
|
|||||||
@ -197,6 +197,7 @@ struct CodeGen {
|
|||||||
LLVMBasicBlockRef cur_basic_block;
|
LLVMBasicBlockRef cur_basic_block;
|
||||||
BlockContext *cur_block_context;
|
BlockContext *cur_block_context;
|
||||||
ZigList<LLVMBasicBlockRef> break_block_stack;
|
ZigList<LLVMBasicBlockRef> break_block_stack;
|
||||||
|
ZigList<LLVMBasicBlockRef> continue_block_stack;
|
||||||
bool c_stdint_used;
|
bool c_stdint_used;
|
||||||
AstNode *root_export_decl;
|
AstNode *root_export_decl;
|
||||||
int version_major;
|
int version_major;
|
||||||
|
|||||||
@ -1025,8 +1025,10 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {
|
|||||||
|
|
||||||
LLVMPositionBuilderAtEnd(g->builder, body_block);
|
LLVMPositionBuilderAtEnd(g->builder, body_block);
|
||||||
g->break_block_stack.append(end_block);
|
g->break_block_stack.append(end_block);
|
||||||
|
g->continue_block_stack.append(cond_block);
|
||||||
gen_expr(g, node->data.while_expr.body);
|
gen_expr(g, node->data.while_expr.body);
|
||||||
g->break_block_stack.pop();
|
g->break_block_stack.pop();
|
||||||
|
g->continue_block_stack.pop();
|
||||||
if (get_expr_type(node->data.while_expr.body)->id != TypeTableEntryIdUnreachable) {
|
if (get_expr_type(node->data.while_expr.body)->id != TypeTableEntryIdUnreachable) {
|
||||||
LLVMBuildBr(g->builder, cond_block);
|
LLVMBuildBr(g->builder, cond_block);
|
||||||
}
|
}
|
||||||
@ -1043,6 +1045,14 @@ static LLVMValueRef gen_break(CodeGen *g, AstNode *node) {
|
|||||||
return LLVMBuildBr(g->builder, dest_block);
|
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) {
|
static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
|
||||||
switch (node->type) {
|
switch (node->type) {
|
||||||
case NodeTypeBinOpExpr:
|
case NodeTypeBinOpExpr:
|
||||||
@ -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);
|
return LLVMBuildBr(g->builder, node->codegen_node->data.label_entry->basic_block);
|
||||||
case NodeTypeBreak:
|
case NodeTypeBreak:
|
||||||
return gen_break(g, node);
|
return gen_break(g, node);
|
||||||
|
case NodeTypeContinue:
|
||||||
|
return gen_continue(g, node);
|
||||||
case NodeTypeLabel:
|
case NodeTypeLabel:
|
||||||
{
|
{
|
||||||
LabelTableEntry *label_entry = node->codegen_node->data.label_entry;
|
LabelTableEntry *label_entry = node->codegen_node->data.label_entry;
|
||||||
|
|||||||
@ -124,6 +124,8 @@ const char *node_type_str(NodeType node_type) {
|
|||||||
return "Goto";
|
return "Goto";
|
||||||
case NodeTypeBreak:
|
case NodeTypeBreak:
|
||||||
return "Break";
|
return "Break";
|
||||||
|
case NodeTypeContinue:
|
||||||
|
return "Continue";
|
||||||
case NodeTypeAsmExpr:
|
case NodeTypeAsmExpr:
|
||||||
return "AsmExpr";
|
return "AsmExpr";
|
||||||
case NodeTypeFieldAccessExpr:
|
case NodeTypeFieldAccessExpr:
|
||||||
@ -341,6 +343,9 @@ void ast_print(AstNode *node, int indent) {
|
|||||||
case NodeTypeBreak:
|
case NodeTypeBreak:
|
||||||
fprintf(stderr, "%s\n", node_type_str(node->type));
|
fprintf(stderr, "%s\n", node_type_str(node->type));
|
||||||
break;
|
break;
|
||||||
|
case NodeTypeContinue:
|
||||||
|
fprintf(stderr, "%s\n", node_type_str(node->type));
|
||||||
|
break;
|
||||||
case NodeTypeAsmExpr:
|
case NodeTypeAsmExpr:
|
||||||
fprintf(stderr, "%s\n", node_type_str(node->type));
|
fprintf(stderr, "%s\n", node_type_str(node->type));
|
||||||
break;
|
break;
|
||||||
@ -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) {
|
static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool mandatory) {
|
||||||
Token *token = &pc->tokens->at(*token_index);
|
Token *token = &pc->tokens->at(*token_index);
|
||||||
@ -1165,6 +1170,10 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
|
|||||||
AstNode *node = ast_create_node(pc, NodeTypeBreak, token);
|
AstNode *node = ast_create_node(pc, NodeTypeBreak, token);
|
||||||
*token_index += 1;
|
*token_index += 1;
|
||||||
return node;
|
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);
|
AstNode *grouped_expr_node = ast_parse_grouped_expr(pc, token_index, false);
|
||||||
|
|||||||
@ -49,6 +49,7 @@ enum NodeType {
|
|||||||
NodeTypeLabel,
|
NodeTypeLabel,
|
||||||
NodeTypeGoto,
|
NodeTypeGoto,
|
||||||
NodeTypeBreak,
|
NodeTypeBreak,
|
||||||
|
NodeTypeContinue,
|
||||||
NodeTypeAsmExpr,
|
NodeTypeAsmExpr,
|
||||||
NodeTypeStructDecl,
|
NodeTypeStructDecl,
|
||||||
NodeTypeStructField,
|
NodeTypeStructField,
|
||||||
|
|||||||
@ -659,17 +659,15 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
|
|||||||
}
|
}
|
||||||
)SOURCE", "loop\nloop\nloop\nloop\n");
|
)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";
|
use "std.zig";
|
||||||
export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
|
export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
|
||||||
var i : i32 = 0;
|
var i : i32 = 0;
|
||||||
while true {
|
while true {
|
||||||
while true {
|
print_str("loop\n");
|
||||||
if i >= 4 {
|
i += 1;
|
||||||
break;
|
if i < 4 {
|
||||||
}
|
continue;
|
||||||
print_str("loop\n");
|
|
||||||
i += 1;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -678,6 +676,8 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
|
|||||||
)SOURCE", "loop\nloop\nloop\nloop\n");
|
)SOURCE", "loop\nloop\nloop\nloop\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static void add_compile_failure_test_cases(void) {
|
static void add_compile_failure_test_cases(void) {
|
||||||
add_compile_fail_case("multiple function definitions", R"SOURCE(
|
add_compile_fail_case("multiple function definitions", R"SOURCE(
|
||||||
fn a() {}
|
fn a() {}
|
||||||
@ -958,6 +958,12 @@ fn f() {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
)SOURCE", 1, ".tmp_source.zig:3:5: error: 'break' expression not in loop");
|
)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) {
|
static void print_compiler_invocation(TestCase *test_case) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user