authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-26 15:05:27-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-26 15:05:27-07:00
log1f8e3871ee11c71b7965e8b9e97fa37a8e994d68
tree130c237a692aad2f42217e221426a64830770ec2
parent5943f995106f9fc2c7c5b416c8d4a2ebba2b8315

parse if maybe expression


9 files changed, 176 insertions(+), 72 deletions(-)

README.md+3-2
...@@ -44,10 +44,11 @@ compromises backward compatibility....@@ -44,10 +44,11 @@ compromises backward compatibility.
4444
45### Current Status45### Current Status
4646
47 * Core language features are lacking such as structs, enums, loops.47 * Have a look in the examples/ folder to see some code examples.
48 * Some language features available such as loops, inline assembly, expressions,
49 literals, functions.
48 * Only Linux x86_64 is supported.50 * Only Linux x86_64 is supported.
49 * Only building for the native target is supported.51 * Only building for the native target is supported.
50 * Have a look in the examples/ folder to see some code examples.
51 * Optimized machine code that Zig produces is indistinguishable from52 * Optimized machine code that Zig produces is indistinguishable from
52 optimized machine code produced from equivalent C program.53 optimized machine code produced from equivalent C program.
53 * Zig can generate dynamic libraries, executables, object files, and C54 * Zig can generate dynamic libraries, executables, object files, and C
doc/langref.md+5-1
...@@ -102,7 +102,11 @@ BoolOrExpression : BoolAndExpression token(BoolOr) BoolOrExpression | BoolAndExp...@@ -102,7 +102,11 @@ BoolOrExpression : BoolAndExpression token(BoolOr) BoolOrExpression | BoolAndExp
102102
103ReturnExpression : token(Return) option(Expression)103ReturnExpression : token(Return) option(Expression)
104104
105IfExpression : token(If) Expression Block option(Else | ElseIf)105IfExpression : IfVarExpression | IfBoolExpression
106
107IfBoolExpression : token(If) option((token) Expression Block option(Else | ElseIf)
108
109IfVarExpression : token(If) (token(Const) | token(Var)) token(Symbol) option(token(Colon) Type) Token(MaybeAssign) Expression Block Option(Else | ElseIf)
106110
107ElseIf : token(Else) IfExpression111ElseIf : token(Else) IfExpression
108112
example/guess_number/main.zig+7-8
...@@ -12,17 +12,16 @@ fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {...@@ -12,17 +12,16 @@ fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
12 const answer = rand_int(&rand_state, 0, 100) + 1;12 const answer = rand_int(&rand_state, 0, 100) + 1;
1313
14 while true {14 while true {
15 Buffer line = readline("\nGuess a number between 1 and 100: ");15 line = readline("\nGuess a number between 1 and 100: ");
1616
17 (const err, const guess) = parse_number(line);17 if const guess ?= parse_number(line) {
18 if err == Error.None {18 if (guess > answer) {
19 if guess == answer {19 print_str("Guess lower.\n");
20 print_str("You win!\n");20 } else if (guess < answer) {
21 return 0;
22 } else if guess < answer {
23 print_str("Guess higher.\n");21 print_str("Guess higher.\n");
24 } else {22 } else {
25 print_str("Guess lower.\n");23 print_str("You win!\n");
24 return 0;
26 }25 }
27 } else {26 } else {
28 print_str("Invalid number format.\n");27 print_str("Invalid number format.\n");
src/analyze.cpp+47-29
...@@ -45,7 +45,8 @@ static AstNode *first_executing_node(AstNode *node) {...@@ -45,7 +45,8 @@ static AstNode *first_executing_node(AstNode *node) {
45 case NodeTypeUse:45 case NodeTypeUse:
46 case NodeTypeVoid:46 case NodeTypeVoid:
47 case NodeTypeBoolLiteral:47 case NodeTypeBoolLiteral:
48 case NodeTypeIfExpr:48 case NodeTypeIfBoolExpr:
49 case NodeTypeIfVarExpr:
49 case NodeTypeLabel:50 case NodeTypeLabel:
50 case NodeTypeGoto:51 case NodeTypeGoto:
51 case NodeTypeBreak:52 case NodeTypeBreak:
...@@ -528,7 +529,8 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,...@@ -528,7 +529,8 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
528 case NodeTypeSymbol:529 case NodeTypeSymbol:
529 case NodeTypeCastExpr:530 case NodeTypeCastExpr:
530 case NodeTypePrefixOpExpr:531 case NodeTypePrefixOpExpr:
531 case NodeTypeIfExpr:532 case NodeTypeIfBoolExpr:
533 case NodeTypeIfVarExpr:
532 case NodeTypeWhileExpr:534 case NodeTypeWhileExpr:
533 case NodeTypeLabel:535 case NodeTypeLabel:
534 case NodeTypeGoto:536 case NodeTypeGoto:
...@@ -598,7 +600,8 @@ static void preview_types(CodeGen *g, ImportTableEntry *import, AstNode *node) {...@@ -598,7 +600,8 @@ static void preview_types(CodeGen *g, ImportTableEntry *import, AstNode *node) {
598 case NodeTypeSymbol:600 case NodeTypeSymbol:
599 case NodeTypeCastExpr:601 case NodeTypeCastExpr:
600 case NodeTypePrefixOpExpr:602 case NodeTypePrefixOpExpr:
601 case NodeTypeIfExpr:603 case NodeTypeIfBoolExpr:
604 case NodeTypeIfVarExpr:
602 case NodeTypeWhileExpr:605 case NodeTypeWhileExpr:
603 case NodeTypeLabel:606 case NodeTypeLabel:
604 case NodeTypeGoto:607 case NodeTypeGoto:
...@@ -1394,6 +1397,39 @@ static TypeTableEntry *analyze_continue_expr(CodeGen *g, ImportTableEntry *impor...@@ -1394,6 +1397,39 @@ static TypeTableEntry *analyze_continue_expr(CodeGen *g, ImportTableEntry *impor
1394 return g->builtin_types.entry_unreachable;1397 return g->builtin_types.entry_unreachable;
1395}1398}
13961399
1400static TypeTableEntry *analyze_if_bool_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
1401 TypeTableEntry *expected_type, AstNode *node)
1402{
1403 analyze_expression(g, import, context, g->builtin_types.entry_bool, node->data.if_bool_expr.condition);
1404
1405 TypeTableEntry *then_type = analyze_expression(g, import, context, expected_type,
1406 node->data.if_bool_expr.then_block);
1407
1408 TypeTableEntry *else_type;
1409 if (node->data.if_bool_expr.else_node) {
1410 else_type = analyze_expression(g, import, context, expected_type, node->data.if_bool_expr.else_node);
1411 } else {
1412 else_type = g->builtin_types.entry_void;
1413 else_type = resolve_type_compatibility(g, context, node, expected_type, else_type);
1414 }
1415
1416
1417 if (expected_type) {
1418 return (then_type->id == TypeTableEntryIdUnreachable) ? else_type : then_type;
1419 } else {
1420 return resolve_peer_type_compatibility(g, context, node,
1421 node->data.if_bool_expr.then_block, node->data.if_bool_expr.else_node,
1422 then_type, else_type);
1423 }
1424}
1425
1426static TypeTableEntry *analyze_if_var_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
1427 TypeTableEntry *expected_type, AstNode *node)
1428{
1429 assert(node->type == NodeTypeIfVarExpr);
1430 zig_panic("TODO analyze_if_var_expr");
1431}
1432
1397static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,1433static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
1398 TypeTableEntry *expected_type, AstNode *node)1434 TypeTableEntry *expected_type, AstNode *node)
1399{1435{
...@@ -1651,31 +1687,12 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -1651,31 +1687,12 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
1651 }1687 }
1652 }1688 }
1653 break;1689 break;
1654 case NodeTypeIfExpr:1690 case NodeTypeIfBoolExpr:
1655 {1691 return_type = analyze_if_bool_expr(g, import, context, expected_type, node);
1656 analyze_expression(g, import, context, g->builtin_types.entry_bool, node->data.if_expr.condition);1692 break;
16571693 case NodeTypeIfVarExpr:
1658 TypeTableEntry *then_type = analyze_expression(g, import, context, expected_type,1694 return_type = analyze_if_var_expr(g, import, context, expected_type, node);
1659 node->data.if_expr.then_block);1695 break;
1660
1661 TypeTableEntry *else_type;
1662 if (node->data.if_expr.else_node) {
1663 else_type = analyze_expression(g, import, context, expected_type, node->data.if_expr.else_node);
1664 } else {
1665 else_type = g->builtin_types.entry_void;
1666 else_type = resolve_type_compatibility(g, context, node, expected_type, else_type);
1667 }
1668
1669
1670 if (expected_type) {
1671 return_type = (then_type->id == TypeTableEntryIdUnreachable) ? else_type : then_type;
1672 } else {
1673 return_type = resolve_peer_type_compatibility(g, context, node,
1674 node->data.if_expr.then_block, node->data.if_expr.else_node,
1675 then_type, else_type);
1676 }
1677 break;
1678 }
1679 case NodeTypeWhileExpr:1696 case NodeTypeWhileExpr:
1680 return_type = analyze_while_expr(g, import, context, expected_type, node);1697 return_type = analyze_while_expr(g, import, context, expected_type, node);
1681 break;1698 break;
...@@ -1828,7 +1845,8 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,...@@ -1828,7 +1845,8 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,
1828 case NodeTypeSymbol:1845 case NodeTypeSymbol:
1829 case NodeTypeCastExpr:1846 case NodeTypeCastExpr:
1830 case NodeTypePrefixOpExpr:1847 case NodeTypePrefixOpExpr:
1831 case NodeTypeIfExpr:1848 case NodeTypeIfBoolExpr:
1849 case NodeTypeIfVarExpr:
1832 case NodeTypeWhileExpr:1850 case NodeTypeWhileExpr:
1833 case NodeTypeLabel:1851 case NodeTypeLabel:
1834 case NodeTypeGoto:1852 case NodeTypeGoto:
src/codegen.cpp+22-15
...@@ -769,18 +769,18 @@ static LLVMValueRef gen_return_expr(CodeGen *g, AstNode *node) {...@@ -769,18 +769,18 @@ static LLVMValueRef gen_return_expr(CodeGen *g, AstNode *node) {
769 }769 }
770}770}
771771
772static LLVMValueRef gen_if_expr(CodeGen *g, AstNode *node) {772static LLVMValueRef gen_if_bool_expr(CodeGen *g, AstNode *node) {
773 assert(node->type == NodeTypeIfExpr);773 assert(node->type == NodeTypeIfBoolExpr);
774 assert(node->data.if_expr.condition);774 assert(node->data.if_bool_expr.condition);
775 assert(node->data.if_expr.then_block);775 assert(node->data.if_bool_expr.then_block);
776776
777 LLVMValueRef cond_value = gen_expr(g, node->data.if_expr.condition);777 LLVMValueRef cond_value = gen_expr(g, node->data.if_bool_expr.condition);
778778
779 TypeTableEntry *then_type = get_expr_type(node->data.if_expr.then_block);779 TypeTableEntry *then_type = get_expr_type(node->data.if_bool_expr.then_block);
780 bool use_expr_value = (then_type->id != TypeTableEntryIdUnreachable &&780 bool use_expr_value = (then_type->id != TypeTableEntryIdUnreachable &&
781 then_type->id != TypeTableEntryIdVoid);781 then_type->id != TypeTableEntryIdVoid);
782782
783 if (node->data.if_expr.else_node) {783 if (node->data.if_bool_expr.else_node) {
784 LLVMBasicBlockRef then_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "Then");784 LLVMBasicBlockRef then_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "Then");
785 LLVMBasicBlockRef else_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "Else");785 LLVMBasicBlockRef else_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "Else");
786 LLVMBasicBlockRef endif_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "EndIf");786 LLVMBasicBlockRef endif_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "EndIf");
...@@ -788,13 +788,13 @@ static LLVMValueRef gen_if_expr(CodeGen *g, AstNode *node) {...@@ -788,13 +788,13 @@ static LLVMValueRef gen_if_expr(CodeGen *g, AstNode *node) {
788 LLVMBuildCondBr(g->builder, cond_value, then_block, else_block);788 LLVMBuildCondBr(g->builder, cond_value, then_block, else_block);
789789
790 LLVMPositionBuilderAtEnd(g->builder, then_block);790 LLVMPositionBuilderAtEnd(g->builder, then_block);
791 LLVMValueRef then_expr_result = gen_expr(g, node->data.if_expr.then_block);791 LLVMValueRef then_expr_result = gen_expr(g, node->data.if_bool_expr.then_block);
792 if (get_expr_type(node->data.if_expr.then_block)->id != TypeTableEntryIdUnreachable)792 if (get_expr_type(node->data.if_bool_expr.then_block)->id != TypeTableEntryIdUnreachable)
793 LLVMBuildBr(g->builder, endif_block);793 LLVMBuildBr(g->builder, endif_block);
794794
795 LLVMPositionBuilderAtEnd(g->builder, else_block);795 LLVMPositionBuilderAtEnd(g->builder, else_block);
796 LLVMValueRef else_expr_result = gen_expr(g, node->data.if_expr.else_node);796 LLVMValueRef else_expr_result = gen_expr(g, node->data.if_bool_expr.else_node);
797 if (get_expr_type(node->data.if_expr.else_node)->id != TypeTableEntryIdUnreachable)797 if (get_expr_type(node->data.if_bool_expr.else_node)->id != TypeTableEntryIdUnreachable)
798 LLVMBuildBr(g->builder, endif_block);798 LLVMBuildBr(g->builder, endif_block);
799799
800 LLVMPositionBuilderAtEnd(g->builder, endif_block);800 LLVMPositionBuilderAtEnd(g->builder, endif_block);
...@@ -818,14 +818,19 @@ static LLVMValueRef gen_if_expr(CodeGen *g, AstNode *node) {...@@ -818,14 +818,19 @@ static LLVMValueRef gen_if_expr(CodeGen *g, AstNode *node) {
818 LLVMBuildCondBr(g->builder, cond_value, then_block, endif_block);818 LLVMBuildCondBr(g->builder, cond_value, then_block, endif_block);
819819
820 LLVMPositionBuilderAtEnd(g->builder, then_block);820 LLVMPositionBuilderAtEnd(g->builder, then_block);
821 gen_expr(g, node->data.if_expr.then_block);821 gen_expr(g, node->data.if_bool_expr.then_block);
822 if (get_expr_type(node->data.if_expr.then_block)->id != TypeTableEntryIdUnreachable)822 if (get_expr_type(node->data.if_bool_expr.then_block)->id != TypeTableEntryIdUnreachable)
823 LLVMBuildBr(g->builder, endif_block);823 LLVMBuildBr(g->builder, endif_block);
824824
825 LLVMPositionBuilderAtEnd(g->builder, endif_block);825 LLVMPositionBuilderAtEnd(g->builder, endif_block);
826 return nullptr;826 return nullptr;
827}827}
828828
829static LLVMValueRef gen_if_var_expr(CodeGen *g, AstNode *node) {
830 assert(node->type == NodeTypeIfVarExpr);
831 zig_panic("TODO gen_if_var_expr");
832}
833
829static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *implicit_return_type) {834static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *implicit_return_type) {
830 assert(block_node->type == NodeTypeBlock);835 assert(block_node->type == NodeTypeBlock);
831836
...@@ -1112,8 +1117,10 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {...@@ -1112,8 +1117,10 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
1112 return LLVMConstAllOnes(LLVMInt1Type());1117 return LLVMConstAllOnes(LLVMInt1Type());
1113 else1118 else
1114 return LLVMConstNull(LLVMInt1Type());1119 return LLVMConstNull(LLVMInt1Type());
1115 case NodeTypeIfExpr:1120 case NodeTypeIfBoolExpr:
1116 return gen_if_expr(g, node);1121 return gen_if_bool_expr(g, node);
1122 case NodeTypeIfVarExpr:
1123 return gen_if_var_expr(g, node);
1117 case NodeTypeWhileExpr:1124 case NodeTypeWhileExpr:
1118 return gen_while_expr(g, node);1125 return gen_while_expr(g, node);
1119 case NodeTypeAsmExpr:1126 case NodeTypeAsmExpr:
src/parser.cpp+57-14
...@@ -114,8 +114,10 @@ const char *node_type_str(NodeType node_type) {...@@ -114,8 +114,10 @@ const char *node_type_str(NodeType node_type) {
114 return "Void";114 return "Void";
115 case NodeTypeBoolLiteral:115 case NodeTypeBoolLiteral:
116 return "BoolLiteral";116 return "BoolLiteral";
117 case NodeTypeIfExpr:117 case NodeTypeIfBoolExpr:
118 return "IfExpr";118 return "IfBoolExpr";
119 case NodeTypeIfVarExpr:
120 return "IfVarExpr";
119 case NodeTypeWhileExpr:121 case NodeTypeWhileExpr:
120 return "WhileExpr";122 return "WhileExpr";
121 case NodeTypeLabel:123 case NodeTypeLabel:
...@@ -321,14 +323,27 @@ void ast_print(AstNode *node, int indent) {...@@ -321,14 +323,27 @@ void ast_print(AstNode *node, int indent) {
321 case NodeTypeBoolLiteral:323 case NodeTypeBoolLiteral:
322 fprintf(stderr, "%s '%s'\n", node_type_str(node->type), node->data.bool_literal ? "true" : "false");324 fprintf(stderr, "%s '%s'\n", node_type_str(node->type), node->data.bool_literal ? "true" : "false");
323 break;325 break;
324 case NodeTypeIfExpr:326 case NodeTypeIfBoolExpr:
325 fprintf(stderr, "%s\n", node_type_str(node->type));327 fprintf(stderr, "%s\n", node_type_str(node->type));
326 if (node->data.if_expr.condition)328 if (node->data.if_bool_expr.condition)
327 ast_print(node->data.if_expr.condition, indent + 2);329 ast_print(node->data.if_bool_expr.condition, indent + 2);
328 ast_print(node->data.if_expr.then_block, indent + 2);330 ast_print(node->data.if_bool_expr.then_block, indent + 2);
329 if (node->data.if_expr.else_node)331 if (node->data.if_bool_expr.else_node)
330 ast_print(node->data.if_expr.else_node, indent + 2);332 ast_print(node->data.if_bool_expr.else_node, indent + 2);
331 break;333 break;
334 case NodeTypeIfVarExpr:
335 {
336 Buf *name_buf = &node->data.if_var_expr.var_decl.symbol;
337 fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(name_buf));
338 if (node->data.if_var_expr.var_decl.type)
339 ast_print(node->data.if_var_expr.var_decl.type, indent + 2);
340 if (node->data.if_var_expr.var_decl.expr)
341 ast_print(node->data.if_var_expr.var_decl.expr, indent + 2);
342 ast_print(node->data.if_var_expr.then_block, indent + 2);
343 if (node->data.if_var_expr.else_node)
344 ast_print(node->data.if_var_expr.else_node, indent + 2);
345 break;
346 }
332 case NodeTypeWhileExpr:347 case NodeTypeWhileExpr:
333 fprintf(stderr, "%s\n", node_type_str(node->type));348 fprintf(stderr, "%s\n", node_type_str(node->type));
334 ast_print(node->data.while_expr.condition, indent + 2);349 ast_print(node->data.while_expr.condition, indent + 2);
...@@ -1644,7 +1659,9 @@ static AstNode *ast_parse_else_or_else_if(ParseContext *pc, int *token_index, bo...@@ -1644,7 +1659,9 @@ static AstNode *ast_parse_else_or_else_if(ParseContext *pc, int *token_index, bo
1644}1659}
16451660
1646/*1661/*
1647IfExpression : token(If) Expression Block option(Else | ElseIf)1662IfExpression : IfVarExpression | IfBoolExpression
1663IfBoolExpression : token(If) option((token) Expression Block option(Else | ElseIf)
1664IfVarExpression : token(If) (token(Const) | token(Var)) token(Symbol) option(token(Colon) Type) Token(Eq) Expression Block Option(Else | ElseIf)
1648*/1665*/
1649static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool mandatory) {1666static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool mandatory) {
1650 Token *if_tok = &pc->tokens->at(*token_index);1667 Token *if_tok = &pc->tokens->at(*token_index);
...@@ -1657,11 +1674,37 @@ static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool manda...@@ -1657,11 +1674,37 @@ static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool manda
1657 }1674 }
1658 *token_index += 1;1675 *token_index += 1;
16591676
1660 AstNode *node = ast_create_node(pc, NodeTypeIfExpr, if_tok);1677 Token *token = &pc->tokens->at(*token_index);
1661 node->data.if_expr.condition = ast_parse_expression(pc, token_index, true);1678 if (token->id == TokenIdKeywordConst || token->id == TokenIdKeywordVar) {
1662 node->data.if_expr.then_block = ast_parse_block(pc, token_index, true);1679 AstNode *node = ast_create_node(pc, NodeTypeIfVarExpr, if_tok);
1663 node->data.if_expr.else_node = ast_parse_else_or_else_if(pc, token_index, false);1680 node->data.if_var_expr.var_decl.is_const = (token->id == TokenIdKeywordConst);
1664 return node;1681 *token_index += 1;
1682
1683 Token *name_token = ast_eat_token(pc, token_index, TokenIdSymbol);
1684 ast_buf_from_token(pc, name_token, &node->data.if_var_expr.var_decl.symbol);
1685
1686 Token *eq_or_colon = &pc->tokens->at(*token_index);
1687 *token_index += 1;
1688 if (eq_or_colon->id == TokenIdMaybeAssign) {
1689 node->data.if_var_expr.var_decl.expr = ast_parse_expression(pc, token_index, true);
1690 } else if (eq_or_colon->id == TokenIdColon) {
1691 node->data.if_var_expr.var_decl.type = ast_parse_type(pc, token_index);
1692
1693 ast_eat_token(pc, token_index, TokenIdMaybeAssign);
1694 node->data.if_var_expr.var_decl.expr = ast_parse_expression(pc, token_index, true);
1695 } else {
1696 ast_invalid_token_error(pc, eq_or_colon);
1697 }
1698 node->data.if_var_expr.then_block = ast_parse_block(pc, token_index, true);
1699 node->data.if_var_expr.else_node = ast_parse_else_or_else_if(pc, token_index, false);
1700 return node;
1701 } else {
1702 AstNode *node = ast_create_node(pc, NodeTypeIfBoolExpr, if_tok);
1703 node->data.if_bool_expr.condition = ast_parse_expression(pc, token_index, true);
1704 node->data.if_bool_expr.then_block = ast_parse_block(pc, token_index, true);
1705 node->data.if_bool_expr.else_node = ast_parse_else_or_else_if(pc, token_index, false);
1706 return node;
1707 }
1665}1708}
16661709
1667/*1710/*
src/parser.hpp+11-3
...@@ -44,7 +44,8 @@ enum NodeType {...@@ -44,7 +44,8 @@ enum NodeType {
44 NodeTypeUse,44 NodeTypeUse,
45 NodeTypeVoid,45 NodeTypeVoid,
46 NodeTypeBoolLiteral,46 NodeTypeBoolLiteral,
47 NodeTypeIfExpr,47 NodeTypeIfBoolExpr,
48 NodeTypeIfVarExpr,
48 NodeTypeWhileExpr,49 NodeTypeWhileExpr,
49 NodeTypeLabel,50 NodeTypeLabel,
50 NodeTypeGoto,51 NodeTypeGoto,
...@@ -217,12 +218,18 @@ struct AstNodeUse {...@@ -217,12 +218,18 @@ struct AstNodeUse {
217 ZigList<AstNode *> *directives;218 ZigList<AstNode *> *directives;
218};219};
219220
220struct AstNodeIfExpr {221struct AstNodeIfBoolExpr {
221 AstNode *condition;222 AstNode *condition;
222 AstNode *then_block;223 AstNode *then_block;
223 AstNode *else_node; // null, block node, or other if expr node224 AstNode *else_node; // null, block node, or other if expr node
224};225};
225226
227struct AstNodeIfVarExpr {
228 AstNodeVariableDeclaration var_decl;
229 AstNode *then_block;
230 AstNode *else_node; // null, block node, or other if expr node
231};
232
226struct AstNodeWhileExpr {233struct AstNodeWhileExpr {
227 AstNode *condition;234 AstNode *condition;
228 AstNode *body;235 AstNode *body;
...@@ -341,7 +348,8 @@ struct AstNode {...@@ -341,7 +348,8 @@ struct AstNode {
341 AstNodeFnCallExpr fn_call_expr;348 AstNodeFnCallExpr fn_call_expr;
342 AstNodeArrayAccessExpr array_access_expr;349 AstNodeArrayAccessExpr array_access_expr;
343 AstNodeUse use;350 AstNodeUse use;
344 AstNodeIfExpr if_expr;351 AstNodeIfBoolExpr if_bool_expr;
352 AstNodeIfVarExpr if_var_expr;
345 AstNodeWhileExpr while_expr;353 AstNodeWhileExpr while_expr;
346 AstNodeLabel label;354 AstNodeLabel label;
347 AstNodeGoto go_to;355 AstNodeGoto go_to;
src/tokenizer.cpp+22
...@@ -125,6 +125,7 @@ enum TokenizeState {...@@ -125,6 +125,7 @@ enum TokenizeState {
125 TokenizeStateSawGreaterThanGreaterThan,125 TokenizeStateSawGreaterThanGreaterThan,
126 TokenizeStateSawDot,126 TokenizeStateSawDot,
127 TokenizeStateSawDotDot,127 TokenizeStateSawDotDot,
128 TokenizeStateSawQuestionMark,
128 TokenizeStateError,129 TokenizeStateError,
129};130};
130131
...@@ -402,10 +403,28 @@ void tokenize(Buf *buf, Tokenization *out) {...@@ -402,10 +403,28 @@ void tokenize(Buf *buf, Tokenization *out) {
402 begin_token(&t, TokenIdDot);403 begin_token(&t, TokenIdDot);
403 t.state = TokenizeStateSawDot;404 t.state = TokenizeStateSawDot;
404 break;405 break;
406 case '?':
407 begin_token(&t, TokenIdMaybe);
408 t.state = TokenizeStateSawQuestionMark;
409 break;
405 default:410 default:
406 tokenize_error(&t, "invalid character: '%c'", c);411 tokenize_error(&t, "invalid character: '%c'", c);
407 }412 }
408 break;413 break;
414 case TokenizeStateSawQuestionMark:
415 switch (c) {
416 case '=':
417 t.cur_tok->id = TokenIdMaybeAssign;
418 end_token(&t);
419 t.state = TokenizeStateStart;
420 break;
421 default:
422 t.pos -= 1;
423 end_token(&t);
424 t.state = TokenizeStateStart;
425 continue;
426 }
427 break;
409 case TokenizeStateSawDot:428 case TokenizeStateSawDot:
410 switch (c) {429 switch (c) {
411 case '.':430 case '.':
...@@ -917,6 +936,7 @@ void tokenize(Buf *buf, Tokenization *out) {...@@ -917,6 +936,7 @@ void tokenize(Buf *buf, Tokenization *out) {
917 case TokenizeStateSawGreaterThan:936 case TokenizeStateSawGreaterThan:
918 case TokenizeStateSawGreaterThanGreaterThan:937 case TokenizeStateSawGreaterThanGreaterThan:
919 case TokenizeStateSawDot:938 case TokenizeStateSawDot:
939 case TokenizeStateSawQuestionMark:
920 end_token(&t);940 end_token(&t);
921 break;941 break;
922 case TokenizeStateSawDotDot:942 case TokenizeStateSawDotDot:
...@@ -1012,6 +1032,8 @@ static const char * token_name(Token *token) {...@@ -1012,6 +1032,8 @@ static const char * token_name(Token *token) {
1012 case TokenIdPercent: return "Percent";1032 case TokenIdPercent: return "Percent";
1013 case TokenIdDot: return "Dot";1033 case TokenIdDot: return "Dot";
1014 case TokenIdEllipsis: return "Ellipsis";1034 case TokenIdEllipsis: return "Ellipsis";
1035 case TokenIdMaybe: return "Maybe";
1036 case TokenIdMaybeAssign: return "MaybeAssign";
1015 }1037 }
1016 return "(invalid token)";1038 return "(invalid token)";
1017}1039}
src/tokenizer.hpp+2
...@@ -83,6 +83,8 @@ enum TokenId {...@@ -83,6 +83,8 @@ enum TokenId {
83 TokenIdPercent,83 TokenIdPercent,
84 TokenIdDot,84 TokenIdDot,
85 TokenIdEllipsis,85 TokenIdEllipsis,
86 TokenIdMaybe,
87 TokenIdMaybeAssign,
86};88};
8789
88struct Token {90struct Token {