| author | |
| committer | |
| log | a030b60aebaf6b0e0c07fd5faa1e132ff7e55bbc |
| tree | dd904751b8dc721fac9449c1887850b6371b55f1 |
| parent | 2e74889c3ce61aae8e9e461d1f49a9b5cb79edc2 |
7 files changed, 99 insertions(+), 2 deletions(-)
doc/langref.md+3-1| ... | @@ -94,7 +94,9 @@ AssignmentExpression : BoolOrExpression AssignmentOperator BoolOrExpression | Bo | ... | @@ -94,7 +94,9 @@ AssignmentExpression : BoolOrExpression AssignmentOperator BoolOrExpression | Bo |
| 94 | 94 | ||
| 95 | 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) | 95 | 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) |
| 96 | 96 | ||
| 97 | BlockExpression : IfExpression | Block | 97 | BlockExpression : IfExpression | Block | WhileExpression |
| 98 | |||
| 99 | WhileExpression : token(While) Expression Block | ||
| 98 | 100 | ||
| 99 | BoolOrExpression : BoolAndExpression token(BoolOr) BoolOrExpression | BoolAndExpression | 101 | BoolOrExpression : BoolAndExpression token(BoolOr) BoolOrExpression | BoolAndExpression |
| 100 | 102 |
src/analyze.cpp+15| ... | @@ -54,6 +54,7 @@ static AstNode *first_executing_node(AstNode *node) { | ... | @@ -54,6 +54,7 @@ static AstNode *first_executing_node(AstNode *node) { |
| 54 | case NodeTypeStructField: | 54 | case NodeTypeStructField: |
| 55 | case NodeTypeStructValueExpr: | 55 | case NodeTypeStructValueExpr: |
| 56 | case NodeTypeStructValueField: | 56 | case NodeTypeStructValueField: |
| 57 | case NodeTypeWhileExpr: | ||
| 57 | return node; | 58 | return node; |
| 58 | } | 59 | } |
| 59 | zig_panic("unreachable"); | 60 | zig_panic("unreachable"); |
| ... | @@ -526,6 +527,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, | ... | @@ -526,6 +527,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, |
| 526 | case NodeTypeCastExpr: | 527 | case NodeTypeCastExpr: |
| 527 | case NodeTypePrefixOpExpr: | 528 | case NodeTypePrefixOpExpr: |
| 528 | case NodeTypeIfExpr: | 529 | case NodeTypeIfExpr: |
| 530 | case NodeTypeWhileExpr: | ||
| 529 | case NodeTypeLabel: | 531 | case NodeTypeLabel: |
| 530 | case NodeTypeGoto: | 532 | case NodeTypeGoto: |
| 531 | case NodeTypeAsmExpr: | 533 | case NodeTypeAsmExpr: |
| ... | @@ -593,6 +595,7 @@ static void preview_types(CodeGen *g, ImportTableEntry *import, AstNode *node) { | ... | @@ -593,6 +595,7 @@ static void preview_types(CodeGen *g, ImportTableEntry *import, AstNode *node) { |
| 593 | case NodeTypeCastExpr: | 595 | case NodeTypeCastExpr: |
| 594 | case NodeTypePrefixOpExpr: | 596 | case NodeTypePrefixOpExpr: |
| 595 | case NodeTypeIfExpr: | 597 | case NodeTypeIfExpr: |
| 598 | case NodeTypeWhileExpr: | ||
| 596 | case NodeTypeLabel: | 599 | case NodeTypeLabel: |
| 597 | case NodeTypeGoto: | 600 | case NodeTypeGoto: |
| 598 | case NodeTypeAsmExpr: | 601 | case NodeTypeAsmExpr: |
| ... | @@ -1349,6 +1352,14 @@ static TypeTableEntry *analyze_struct_val_expr(CodeGen *g, ImportTableEntry *imp | ... | @@ -1349,6 +1352,14 @@ static TypeTableEntry *analyze_struct_val_expr(CodeGen *g, ImportTableEntry *imp |
| 1349 | return type_entry; | 1352 | return type_entry; |
| 1350 | } | 1353 | } |
| 1351 | 1354 | ||
| 1355 | static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | ||
| 1356 | TypeTableEntry *expected_type, AstNode *node) | ||
| 1357 | { | ||
| 1358 | analyze_expression(g, import, context, g->builtin_types.entry_bool, node->data.while_expr.condition); | ||
| 1359 | analyze_expression(g, import, context, g->builtin_types.entry_void, node->data.while_expr.body); | ||
| 1360 | return g->builtin_types.entry_void; | ||
| 1361 | } | ||
| 1362 | |||
| 1352 | static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 1363 | static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 1353 | TypeTableEntry *expected_type, AstNode *node) | 1364 | TypeTableEntry *expected_type, AstNode *node) |
| 1354 | { | 1365 | { |
| ... | @@ -1625,6 +1636,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, | ... | @@ -1625,6 +1636,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 1625 | } | 1636 | } |
| 1626 | break; | 1637 | break; |
| 1627 | } | 1638 | } |
| 1639 | case NodeTypeWhileExpr: | ||
| 1640 | return_type = analyze_while_expr(g, import, context, expected_type, node); | ||
| 1641 | break; | ||
| 1628 | case NodeTypeStructValueExpr: | 1642 | case NodeTypeStructValueExpr: |
| 1629 | return_type = analyze_struct_val_expr(g, import, context, expected_type, node); | 1643 | return_type = analyze_struct_val_expr(g, import, context, expected_type, node); |
| 1630 | break; | 1644 | break; |
| ... | @@ -1775,6 +1789,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, | ... | @@ -1775,6 +1789,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import, |
| 1775 | case NodeTypeCastExpr: | 1789 | case NodeTypeCastExpr: |
| 1776 | case NodeTypePrefixOpExpr: | 1790 | case NodeTypePrefixOpExpr: |
| 1777 | case NodeTypeIfExpr: | 1791 | case NodeTypeIfExpr: |
| 1792 | case NodeTypeWhileExpr: | ||
| 1778 | case NodeTypeLabel: | 1793 | case NodeTypeLabel: |
| 1779 | case NodeTypeGoto: | 1794 | case NodeTypeGoto: |
| 1780 | case NodeTypeAsmExpr: | 1795 | case NodeTypeAsmExpr: |
src/codegen.cpp+27| ... | @@ -1006,6 +1006,31 @@ static LLVMValueRef gen_struct_val_expr(CodeGen *g, AstNode *node) { | ... | @@ -1006,6 +1006,31 @@ static LLVMValueRef gen_struct_val_expr(CodeGen *g, AstNode *node) { |
| 1006 | return tmp_struct_ptr; | 1006 | return tmp_struct_ptr; |
| 1007 | } | 1007 | } |
| 1008 | 1008 | ||
| 1009 | static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) { | ||
| 1010 | assert(node->type == NodeTypeWhileExpr); | ||
| 1011 | assert(node->data.while_expr.condition); | ||
| 1012 | assert(node->data.while_expr.body); | ||
| 1013 | |||
| 1014 | LLVMBasicBlockRef cond_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileCond"); | ||
| 1015 | LLVMBasicBlockRef body_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileBody"); | ||
| 1016 | LLVMBasicBlockRef end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileEnd"); | ||
| 1017 | |||
| 1018 | add_debug_source_node(g, node); | ||
| 1019 | LLVMBuildBr(g->builder, cond_block); | ||
| 1020 | |||
| 1021 | LLVMPositionBuilderAtEnd(g->builder, cond_block); | ||
| 1022 | LLVMValueRef cond_val = gen_expr(g, node->data.while_expr.condition); | ||
| 1023 | add_debug_source_node(g, node->data.while_expr.condition); | ||
| 1024 | LLVMBuildCondBr(g->builder, cond_val, body_block, end_block); | ||
| 1025 | |||
| 1026 | LLVMPositionBuilderAtEnd(g->builder, body_block); | ||
| 1027 | gen_expr(g, node->data.while_expr.body); | ||
| 1028 | LLVMBuildBr(g->builder, cond_block); | ||
| 1029 | |||
| 1030 | LLVMPositionBuilderAtEnd(g->builder, end_block); | ||
| 1031 | return nullptr; | ||
| 1032 | } | ||
| 1033 | |||
| 1009 | static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) { | 1034 | static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) { |
| 1010 | switch (node->type) { | 1035 | switch (node->type) { |
| 1011 | case NodeTypeBinOpExpr: | 1036 | case NodeTypeBinOpExpr: |
| ... | @@ -1067,6 +1092,8 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) { | ... | @@ -1067,6 +1092,8 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) { |
| 1067 | return LLVMConstNull(LLVMInt1Type()); | 1092 | return LLVMConstNull(LLVMInt1Type()); |
| 1068 | case NodeTypeIfExpr: | 1093 | case NodeTypeIfExpr: |
| 1069 | return gen_if_expr(g, node); | 1094 | return gen_if_expr(g, node); |
| 1095 | case NodeTypeWhileExpr: | ||
| 1096 | return gen_while_expr(g, node); | ||
| 1070 | case NodeTypeAsmExpr: | 1097 | case NodeTypeAsmExpr: |
| 1071 | return gen_asm_expr(g, node); | 1098 | return gen_asm_expr(g, node); |
| 1072 | case NodeTypeNumberLiteral: | 1099 | case NodeTypeNumberLiteral: |
src/parser.cpp+35-1| ... | @@ -116,6 +116,8 @@ const char *node_type_str(NodeType node_type) { | ... | @@ -116,6 +116,8 @@ const char *node_type_str(NodeType node_type) { |
| 116 | return "BoolLiteral"; | 116 | return "BoolLiteral"; |
| 117 | case NodeTypeIfExpr: | 117 | case NodeTypeIfExpr: |
| 118 | return "IfExpr"; | 118 | return "IfExpr"; |
| 119 | case NodeTypeWhileExpr: | ||
| 120 | return "WhileExpr"; | ||
| 119 | case NodeTypeLabel: | 121 | case NodeTypeLabel: |
| 120 | return "Label"; | 122 | return "Label"; |
| 121 | case NodeTypeGoto: | 123 | case NodeTypeGoto: |
| ... | @@ -323,6 +325,11 @@ void ast_print(AstNode *node, int indent) { | ... | @@ -323,6 +325,11 @@ void ast_print(AstNode *node, int indent) { |
| 323 | if (node->data.if_expr.else_node) | 325 | if (node->data.if_expr.else_node) |
| 324 | ast_print(node->data.if_expr.else_node, indent + 2); | 326 | ast_print(node->data.if_expr.else_node, indent + 2); |
| 325 | break; | 327 | break; |
| 328 | case NodeTypeWhileExpr: | ||
| 329 | fprintf(stderr, "%s\n", node_type_str(node->type)); | ||
| 330 | ast_print(node->data.while_expr.condition, indent + 2); | ||
| 331 | ast_print(node->data.while_expr.body, indent + 2); | ||
| 332 | break; | ||
| 326 | case NodeTypeLabel: | 333 | case NodeTypeLabel: |
| 327 | fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.label.name)); | 334 | fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.label.name)); |
| 328 | break; | 335 | break; |
| ... | @@ -1727,7 +1734,30 @@ static AstNode *ast_parse_bool_or_expr(ParseContext *pc, int *token_index, bool | ... | @@ -1727,7 +1734,30 @@ static AstNode *ast_parse_bool_or_expr(ParseContext *pc, int *token_index, bool |
| 1727 | } | 1734 | } |
| 1728 | 1735 | ||
| 1729 | /* | 1736 | /* |
| 1730 | BlockExpression : IfExpression | Block | 1737 | WhileExpression : token(While) Expression Block |
| 1738 | */ | ||
| 1739 | static AstNode *ast_parse_while_expr(ParseContext *pc, int *token_index, bool mandatory) { | ||
| 1740 | Token *token = &pc->tokens->at(*token_index); | ||
| 1741 | |||
| 1742 | if (token->id != TokenIdKeywordWhile) { | ||
| 1743 | if (mandatory) { | ||
| 1744 | ast_invalid_token_error(pc, token); | ||
| 1745 | } else { | ||
| 1746 | return nullptr; | ||
| 1747 | } | ||
| 1748 | } | ||
| 1749 | *token_index += 1; | ||
| 1750 | |||
| 1751 | AstNode *node = ast_create_node(pc, NodeTypeWhileExpr, token); | ||
| 1752 | |||
| 1753 | node->data.while_expr.condition = ast_parse_expression(pc, token_index, true); | ||
| 1754 | node->data.while_expr.body = ast_parse_block(pc, token_index, true); | ||
| 1755 | |||
| 1756 | return node; | ||
| 1757 | } | ||
| 1758 | |||
| 1759 | /* | ||
| 1760 | BlockExpression : IfExpression | Block | WhileExpression | ||
| 1731 | */ | 1761 | */ |
| 1732 | static AstNode *ast_parse_block_expr(ParseContext *pc, int *token_index, bool mandatory) { | 1762 | static AstNode *ast_parse_block_expr(ParseContext *pc, int *token_index, bool mandatory) { |
| 1733 | Token *token = &pc->tokens->at(*token_index); | 1763 | Token *token = &pc->tokens->at(*token_index); |
| ... | @@ -1740,6 +1770,10 @@ static AstNode *ast_parse_block_expr(ParseContext *pc, int *token_index, bool ma | ... | @@ -1740,6 +1770,10 @@ static AstNode *ast_parse_block_expr(ParseContext *pc, int *token_index, bool ma |
| 1740 | if (block) | 1770 | if (block) |
| 1741 | return block; | 1771 | return block; |
| 1742 | 1772 | ||
| 1773 | AstNode *while_expr = ast_parse_while_expr(pc, token_index, false); | ||
| 1774 | if (while_expr) | ||
| 1775 | return while_expr; | ||
| 1776 | |||
| 1743 | if (mandatory) | 1777 | if (mandatory) |
| 1744 | ast_invalid_token_error(pc, token); | 1778 | ast_invalid_token_error(pc, token); |
| 1745 | 1779 |
src/parser.hpp+7| ... | @@ -45,6 +45,7 @@ enum NodeType { | ... | @@ -45,6 +45,7 @@ enum NodeType { |
| 45 | NodeTypeVoid, | 45 | NodeTypeVoid, |
| 46 | NodeTypeBoolLiteral, | 46 | NodeTypeBoolLiteral, |
| 47 | NodeTypeIfExpr, | 47 | NodeTypeIfExpr, |
| 48 | NodeTypeWhileExpr, | ||
| 48 | NodeTypeLabel, | 49 | NodeTypeLabel, |
| 49 | NodeTypeGoto, | 50 | NodeTypeGoto, |
| 50 | NodeTypeAsmExpr, | 51 | NodeTypeAsmExpr, |
| ... | @@ -220,6 +221,11 @@ struct AstNodeIfExpr { | ... | @@ -220,6 +221,11 @@ struct AstNodeIfExpr { |
| 220 | AstNode *else_node; // null, block node, or other if expr node | 221 | AstNode *else_node; // null, block node, or other if expr node |
| 221 | }; | 222 | }; |
| 222 | 223 | ||
| 224 | struct AstNodeWhileExpr { | ||
| 225 | AstNode *condition; | ||
| 226 | AstNode *body; | ||
| 227 | }; | ||
| 228 | |||
| 223 | struct AstNodeLabel { | 229 | struct AstNodeLabel { |
| 224 | Buf name; | 230 | Buf name; |
| 225 | }; | 231 | }; |
| ... | @@ -334,6 +340,7 @@ struct AstNode { | ... | @@ -334,6 +340,7 @@ struct AstNode { |
| 334 | AstNodeArrayAccessExpr array_access_expr; | 340 | AstNodeArrayAccessExpr array_access_expr; |
| 335 | AstNodeUse use; | 341 | AstNodeUse use; |
| 336 | AstNodeIfExpr if_expr; | 342 | AstNodeIfExpr if_expr; |
| 343 | AstNodeWhileExpr while_expr; | ||
| 337 | AstNodeLabel label; | 344 | AstNodeLabel label; |
| 338 | AstNodeGoto go_to; | 345 | AstNodeGoto go_to; |
| 339 | AstNodeAsmExpr asm_expr; | 346 | AstNodeAsmExpr asm_expr; |
src/tokenizer.cpp+9| ... | @@ -233,6 +233,12 @@ static void end_token(Tokenize *t) { | ... | @@ -233,6 +233,12 @@ static void end_token(Tokenize *t) { |
| 233 | t->cur_tok->id = TokenIdKeywordAsm; | 233 | t->cur_tok->id = TokenIdKeywordAsm; |
| 234 | } else if (mem_eql_str(token_mem, token_len, "struct")) { | 234 | } else if (mem_eql_str(token_mem, token_len, "struct")) { |
| 235 | t->cur_tok->id = TokenIdKeywordStruct; | 235 | t->cur_tok->id = TokenIdKeywordStruct; |
| 236 | } else if (mem_eql_str(token_mem, token_len, "while")) { | ||
| 237 | t->cur_tok->id = TokenIdKeywordWhile; | ||
| 238 | } else if (mem_eql_str(token_mem, token_len, "continue")) { | ||
| 239 | t->cur_tok->id = TokenIdKeywordContinue; | ||
| 240 | } else if (mem_eql_str(token_mem, token_len, "break")) { | ||
| 241 | t->cur_tok->id = TokenIdKeywordBreak; | ||
| 236 | } | 242 | } |
| 237 | 243 | ||
| 238 | t->cur_tok = nullptr; | 244 | t->cur_tok = nullptr; |
| ... | @@ -955,6 +961,9 @@ static const char * token_name(Token *token) { | ... | @@ -955,6 +961,9 @@ static const char * token_name(Token *token) { |
| 955 | case TokenIdKeywordVolatile: return "Volatile"; | 961 | case TokenIdKeywordVolatile: return "Volatile"; |
| 956 | case TokenIdKeywordAsm: return "Asm"; | 962 | case TokenIdKeywordAsm: return "Asm"; |
| 957 | case TokenIdKeywordStruct: return "Struct"; | 963 | case TokenIdKeywordStruct: return "Struct"; |
| 964 | case TokenIdKeywordWhile: return "While"; | ||
| 965 | case TokenIdKeywordContinue: return "Continue"; | ||
| 966 | case TokenIdKeywordBreak: return "Break"; | ||
| 958 | case TokenIdLParen: return "LParen"; | 967 | case TokenIdLParen: return "LParen"; |
| 959 | case TokenIdRParen: return "RParen"; | 968 | case TokenIdRParen: return "RParen"; |
| 960 | case TokenIdComma: return "Comma"; | 969 | case TokenIdComma: return "Comma"; |
src/tokenizer.hpp+3| ... | @@ -32,6 +32,9 @@ enum TokenId { | ... | @@ -32,6 +32,9 @@ enum TokenId { |
| 32 | TokenIdKeywordAsm, | 32 | TokenIdKeywordAsm, |
| 33 | TokenIdKeywordVolatile, | 33 | TokenIdKeywordVolatile, |
| 34 | TokenIdKeywordStruct, | 34 | TokenIdKeywordStruct, |
| 35 | TokenIdKeywordWhile, | ||
| 36 | TokenIdKeywordContinue, | ||
| 37 | TokenIdKeywordBreak, | ||
| 35 | TokenIdLParen, | 38 | TokenIdLParen, |
| 36 | TokenIdRParen, | 39 | TokenIdRParen, |
| 37 | TokenIdComma, | 40 | TokenIdComma, |