From a030b60aebaf6b0e0c07fd5faa1e132ff7e55bbc Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 24 Dec 2015 14:37:43 -0700 Subject: [PATCH] add while loop --- doc/langref.md | 4 +++- src/analyze.cpp | 15 +++++++++++++++ src/codegen.cpp | 27 +++++++++++++++++++++++++++ src/parser.cpp | 36 +++++++++++++++++++++++++++++++++++- src/parser.hpp | 7 +++++++ src/tokenizer.cpp | 9 +++++++++ src/tokenizer.hpp | 3 +++ 7 files changed, 99 insertions(+), 2 deletions(-) diff --git a/doc/langref.md b/doc/langref.md index a39e16c135..42a09cdacf 100644 --- a/doc/langref.md +++ b/doc/langref.md @@ -94,7 +94,9 @@ AssignmentExpression : BoolOrExpression AssignmentOperator BoolOrExpression | Bo AssignmentOperator : token(Eq) | token(TimesEq) | token(DivEq) | token(ModEq) | token(PlusEq) | token(MinusEq) | token(BitShiftLeftEq) | token(BitShiftRightEq) | token(BitAndEq) | token(BitXorEq) | token(BitOrEq) | token(BoolAndEq) | token(BoolOrEq) -BlockExpression : IfExpression | Block +BlockExpression : IfExpression | Block | WhileExpression + +WhileExpression : token(While) Expression Block BoolOrExpression : BoolAndExpression token(BoolOr) BoolOrExpression | BoolAndExpression diff --git a/src/analyze.cpp b/src/analyze.cpp index 41ce9d49c0..bd9eaa7f2d 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -54,6 +54,7 @@ static AstNode *first_executing_node(AstNode *node) { case NodeTypeStructField: case NodeTypeStructValueExpr: case NodeTypeStructValueField: + case NodeTypeWhileExpr: return node; } zig_panic("unreachable"); @@ -526,6 +527,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, case NodeTypeCastExpr: case NodeTypePrefixOpExpr: case NodeTypeIfExpr: + case NodeTypeWhileExpr: case NodeTypeLabel: case NodeTypeGoto: case NodeTypeAsmExpr: @@ -593,6 +595,7 @@ static void preview_types(CodeGen *g, ImportTableEntry *import, AstNode *node) { case NodeTypeCastExpr: case NodeTypePrefixOpExpr: case NodeTypeIfExpr: + case NodeTypeWhileExpr: case NodeTypeLabel: case NodeTypeGoto: case NodeTypeAsmExpr: @@ -1349,6 +1352,14 @@ static TypeTableEntry *analyze_struct_val_expr(CodeGen *g, ImportTableEntry *imp return type_entry; } +static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, + TypeTableEntry *expected_type, AstNode *node) +{ + analyze_expression(g, import, context, g->builtin_types.entry_bool, node->data.while_expr.condition); + analyze_expression(g, import, context, g->builtin_types.entry_void, node->data.while_expr.body); + return g->builtin_types.entry_void; +} + static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, TypeTableEntry *expected_type, AstNode *node) { @@ -1625,6 +1636,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, } break; } + case NodeTypeWhileExpr: + return_type = analyze_while_expr(g, import, context, expected_type, node); + break; case NodeTypeStructValueExpr: return_type = analyze_struct_val_expr(g, import, context, expected_type, node); break; @@ -1775,6 +1789,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, case NodeTypeCastExpr: case NodeTypePrefixOpExpr: case NodeTypeIfExpr: + case NodeTypeWhileExpr: case NodeTypeLabel: case NodeTypeGoto: case NodeTypeAsmExpr: diff --git a/src/codegen.cpp b/src/codegen.cpp index 26573e6179..2c0ed2efed 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1006,6 +1006,31 @@ static LLVMValueRef gen_struct_val_expr(CodeGen *g, AstNode *node) { return tmp_struct_ptr; } +static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) { + assert(node->type == NodeTypeWhileExpr); + assert(node->data.while_expr.condition); + assert(node->data.while_expr.body); + + LLVMBasicBlockRef cond_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileCond"); + LLVMBasicBlockRef body_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileBody"); + LLVMBasicBlockRef end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileEnd"); + + add_debug_source_node(g, node); + LLVMBuildBr(g->builder, cond_block); + + LLVMPositionBuilderAtEnd(g->builder, cond_block); + LLVMValueRef cond_val = gen_expr(g, node->data.while_expr.condition); + add_debug_source_node(g, node->data.while_expr.condition); + LLVMBuildCondBr(g->builder, cond_val, body_block, end_block); + + LLVMPositionBuilderAtEnd(g->builder, body_block); + gen_expr(g, node->data.while_expr.body); + LLVMBuildBr(g->builder, cond_block); + + LLVMPositionBuilderAtEnd(g->builder, end_block); + return nullptr; +} + static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) { switch (node->type) { case NodeTypeBinOpExpr: @@ -1067,6 +1092,8 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) { return LLVMConstNull(LLVMInt1Type()); case NodeTypeIfExpr: return gen_if_expr(g, node); + case NodeTypeWhileExpr: + return gen_while_expr(g, node); case NodeTypeAsmExpr: return gen_asm_expr(g, node); case NodeTypeNumberLiteral: diff --git a/src/parser.cpp b/src/parser.cpp index 3af9a677b3..5a5486e713 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -116,6 +116,8 @@ const char *node_type_str(NodeType node_type) { return "BoolLiteral"; case NodeTypeIfExpr: return "IfExpr"; + case NodeTypeWhileExpr: + return "WhileExpr"; case NodeTypeLabel: return "Label"; case NodeTypeGoto: @@ -323,6 +325,11 @@ void ast_print(AstNode *node, int indent) { if (node->data.if_expr.else_node) ast_print(node->data.if_expr.else_node, indent + 2); break; + case NodeTypeWhileExpr: + fprintf(stderr, "%s\n", node_type_str(node->type)); + ast_print(node->data.while_expr.condition, indent + 2); + ast_print(node->data.while_expr.body, indent + 2); + break; case NodeTypeLabel: fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.label.name)); break; @@ -1727,7 +1734,30 @@ static AstNode *ast_parse_bool_or_expr(ParseContext *pc, int *token_index, bool } /* -BlockExpression : IfExpression | Block +WhileExpression : token(While) Expression Block +*/ +static AstNode *ast_parse_while_expr(ParseContext *pc, int *token_index, bool mandatory) { + Token *token = &pc->tokens->at(*token_index); + + if (token->id != TokenIdKeywordWhile) { + if (mandatory) { + ast_invalid_token_error(pc, token); + } else { + return nullptr; + } + } + *token_index += 1; + + AstNode *node = ast_create_node(pc, NodeTypeWhileExpr, token); + + node->data.while_expr.condition = ast_parse_expression(pc, token_index, true); + node->data.while_expr.body = ast_parse_block(pc, token_index, true); + + return node; +} + +/* +BlockExpression : IfExpression | Block | WhileExpression */ static AstNode *ast_parse_block_expr(ParseContext *pc, int *token_index, bool mandatory) { Token *token = &pc->tokens->at(*token_index); @@ -1740,6 +1770,10 @@ static AstNode *ast_parse_block_expr(ParseContext *pc, int *token_index, bool ma if (block) return block; + AstNode *while_expr = ast_parse_while_expr(pc, token_index, false); + if (while_expr) + return while_expr; + if (mandatory) ast_invalid_token_error(pc, token); diff --git a/src/parser.hpp b/src/parser.hpp index d36d5d883f..af24b29131 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -45,6 +45,7 @@ enum NodeType { NodeTypeVoid, NodeTypeBoolLiteral, NodeTypeIfExpr, + NodeTypeWhileExpr, NodeTypeLabel, NodeTypeGoto, NodeTypeAsmExpr, @@ -220,6 +221,11 @@ struct AstNodeIfExpr { AstNode *else_node; // null, block node, or other if expr node }; +struct AstNodeWhileExpr { + AstNode *condition; + AstNode *body; +}; + struct AstNodeLabel { Buf name; }; @@ -334,6 +340,7 @@ struct AstNode { AstNodeArrayAccessExpr array_access_expr; AstNodeUse use; AstNodeIfExpr if_expr; + AstNodeWhileExpr while_expr; AstNodeLabel label; AstNodeGoto go_to; AstNodeAsmExpr asm_expr; diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 5678fa9df5..93301f4655 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -233,6 +233,12 @@ static void end_token(Tokenize *t) { t->cur_tok->id = TokenIdKeywordAsm; } else if (mem_eql_str(token_mem, token_len, "struct")) { t->cur_tok->id = TokenIdKeywordStruct; + } else if (mem_eql_str(token_mem, token_len, "while")) { + t->cur_tok->id = TokenIdKeywordWhile; + } else if (mem_eql_str(token_mem, token_len, "continue")) { + t->cur_tok->id = TokenIdKeywordContinue; + } else if (mem_eql_str(token_mem, token_len, "break")) { + t->cur_tok->id = TokenIdKeywordBreak; } t->cur_tok = nullptr; @@ -955,6 +961,9 @@ static const char * token_name(Token *token) { case TokenIdKeywordVolatile: return "Volatile"; case TokenIdKeywordAsm: return "Asm"; case TokenIdKeywordStruct: return "Struct"; + case TokenIdKeywordWhile: return "While"; + case TokenIdKeywordContinue: return "Continue"; + case TokenIdKeywordBreak: return "Break"; case TokenIdLParen: return "LParen"; case TokenIdRParen: return "RParen"; case TokenIdComma: return "Comma"; diff --git a/src/tokenizer.hpp b/src/tokenizer.hpp index e96a51256c..2686cd9ce8 100644 --- a/src/tokenizer.hpp +++ b/src/tokenizer.hpp @@ -32,6 +32,9 @@ enum TokenId { TokenIdKeywordAsm, TokenIdKeywordVolatile, TokenIdKeywordStruct, + TokenIdKeywordWhile, + TokenIdKeywordContinue, + TokenIdKeywordBreak, TokenIdLParen, TokenIdRParen, TokenIdComma,