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.
4444
4545### 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.
4850 * Only Linux x86_64 is supported.
4951 * Only building for the native target is supported.
50 * Have a look in the examples/ folder to see some code examples.
5152 * Optimized machine code that Zig produces is indistinguishable from
5253 optimized machine code produced from equivalent C program.
5354 * 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
102102
103103ReturnExpression : 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
107111ElseIf : token(Else) IfExpression
108112
example/guess_number/main.zig+7-8
......@@ -12,17 +12,16 @@ fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
1212 const answer = rand_int(&rand_state, 0, 100) + 1;
1313
1414 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);
18 if err == Error.None {
19 if guess == answer {
20 print_str("You win!\n");
21 return 0;
22 } else if guess < answer {
17 if const guess ?= parse_number(line) {
18 if (guess > answer) {
19 print_str("Guess lower.\n");
20 } else if (guess < answer) {
2321 print_str("Guess higher.\n");
2422 } else {
25 print_str("Guess lower.\n");
23 print_str("You win!\n");
24 return 0;
2625 }
2726 } else {
2827 print_str("Invalid number format.\n");
src/analyze.cpp+47-29
......@@ -45,7 +45,8 @@ static AstNode *first_executing_node(AstNode *node) {
4545 case NodeTypeUse:
4646 case NodeTypeVoid:
4747 case NodeTypeBoolLiteral:
48 case NodeTypeIfExpr:
48 case NodeTypeIfBoolExpr:
49 case NodeTypeIfVarExpr:
4950 case NodeTypeLabel:
5051 case NodeTypeGoto:
5152 case NodeTypeBreak:
......@@ -528,7 +529,8 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
528529 case NodeTypeSymbol:
529530 case NodeTypeCastExpr:
530531 case NodeTypePrefixOpExpr:
531 case NodeTypeIfExpr:
532 case NodeTypeIfBoolExpr:
533 case NodeTypeIfVarExpr:
532534 case NodeTypeWhileExpr:
533535 case NodeTypeLabel:
534536 case NodeTypeGoto:
......@@ -598,7 +600,8 @@ static void preview_types(CodeGen *g, ImportTableEntry *import, AstNode *node) {
598600 case NodeTypeSymbol:
599601 case NodeTypeCastExpr:
600602 case NodeTypePrefixOpExpr:
601 case NodeTypeIfExpr:
603 case NodeTypeIfBoolExpr:
604 case NodeTypeIfVarExpr:
602605 case NodeTypeWhileExpr:
603606 case NodeTypeLabel:
604607 case NodeTypeGoto:
......@@ -1394,6 +1397,39 @@ static TypeTableEntry *analyze_continue_expr(CodeGen *g, ImportTableEntry *impor
13941397 return g->builtin_types.entry_unreachable;
13951398}
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
13971433static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
13981434 TypeTableEntry *expected_type, AstNode *node)
13991435{
......@@ -1651,31 +1687,12 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
16511687 }
16521688 }
16531689 break;
1654 case NodeTypeIfExpr:
1655 {
1656 analyze_expression(g, import, context, g->builtin_types.entry_bool, node->data.if_expr.condition);
1657
1658 TypeTableEntry *then_type = analyze_expression(g, import, context, expected_type,
1659 node->data.if_expr.then_block);
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 }
1690 case NodeTypeIfBoolExpr:
1691 return_type = analyze_if_bool_expr(g, import, context, expected_type, node);
1692 break;
1693 case NodeTypeIfVarExpr:
1694 return_type = analyze_if_var_expr(g, import, context, expected_type, node);
1695 break;
16791696 case NodeTypeWhileExpr:
16801697 return_type = analyze_while_expr(g, import, context, expected_type, node);
16811698 break;
......@@ -1828,7 +1845,8 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,
18281845 case NodeTypeSymbol:
18291846 case NodeTypeCastExpr:
18301847 case NodeTypePrefixOpExpr:
1831 case NodeTypeIfExpr:
1848 case NodeTypeIfBoolExpr:
1849 case NodeTypeIfVarExpr:
18321850 case NodeTypeWhileExpr:
18331851 case NodeTypeLabel:
18341852 case NodeTypeGoto:
src/codegen.cpp+22-15
......@@ -769,18 +769,18 @@ static LLVMValueRef gen_return_expr(CodeGen *g, AstNode *node) {
769769 }
770770}
771771
772static LLVMValueRef gen_if_expr(CodeGen *g, AstNode *node) {
773 assert(node->type == NodeTypeIfExpr);
774 assert(node->data.if_expr.condition);
775 assert(node->data.if_expr.then_block);
772static LLVMValueRef gen_if_bool_expr(CodeGen *g, AstNode *node) {
773 assert(node->type == NodeTypeIfBoolExpr);
774 assert(node->data.if_bool_expr.condition);
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);
780780 bool use_expr_value = (then_type->id != TypeTableEntryIdUnreachable &&
781781 then_type->id != TypeTableEntryIdVoid);
782782
783 if (node->data.if_expr.else_node) {
783 if (node->data.if_bool_expr.else_node) {
784784 LLVMBasicBlockRef then_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "Then");
785785 LLVMBasicBlockRef else_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "Else");
786786 LLVMBasicBlockRef endif_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "EndIf");
......@@ -788,13 +788,13 @@ static LLVMValueRef gen_if_expr(CodeGen *g, AstNode *node) {
788788 LLVMBuildCondBr(g->builder, cond_value, then_block, else_block);
789789
790790 LLVMPositionBuilderAtEnd(g->builder, then_block);
791 LLVMValueRef then_expr_result = gen_expr(g, node->data.if_expr.then_block);
792 if (get_expr_type(node->data.if_expr.then_block)->id != TypeTableEntryIdUnreachable)
791 LLVMValueRef then_expr_result = gen_expr(g, node->data.if_bool_expr.then_block);
792 if (get_expr_type(node->data.if_bool_expr.then_block)->id != TypeTableEntryIdUnreachable)
793793 LLVMBuildBr(g->builder, endif_block);
794794
795795 LLVMPositionBuilderAtEnd(g->builder, else_block);
796 LLVMValueRef else_expr_result = gen_expr(g, node->data.if_expr.else_node);
797 if (get_expr_type(node->data.if_expr.else_node)->id != TypeTableEntryIdUnreachable)
796 LLVMValueRef else_expr_result = gen_expr(g, node->data.if_bool_expr.else_node);
797 if (get_expr_type(node->data.if_bool_expr.else_node)->id != TypeTableEntryIdUnreachable)
798798 LLVMBuildBr(g->builder, endif_block);
799799
800800 LLVMPositionBuilderAtEnd(g->builder, endif_block);
......@@ -818,14 +818,19 @@ static LLVMValueRef gen_if_expr(CodeGen *g, AstNode *node) {
818818 LLVMBuildCondBr(g->builder, cond_value, then_block, endif_block);
819819
820820 LLVMPositionBuilderAtEnd(g->builder, then_block);
821 gen_expr(g, node->data.if_expr.then_block);
822 if (get_expr_type(node->data.if_expr.then_block)->id != TypeTableEntryIdUnreachable)
821 gen_expr(g, node->data.if_bool_expr.then_block);
822 if (get_expr_type(node->data.if_bool_expr.then_block)->id != TypeTableEntryIdUnreachable)
823823 LLVMBuildBr(g->builder, endif_block);
824824
825825 LLVMPositionBuilderAtEnd(g->builder, endif_block);
826826 return nullptr;
827827}
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
829834static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *implicit_return_type) {
830835 assert(block_node->type == NodeTypeBlock);
831836
......@@ -1112,8 +1117,10 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
11121117 return LLVMConstAllOnes(LLVMInt1Type());
11131118 else
11141119 return LLVMConstNull(LLVMInt1Type());
1115 case NodeTypeIfExpr:
1116 return gen_if_expr(g, node);
1120 case NodeTypeIfBoolExpr:
1121 return gen_if_bool_expr(g, node);
1122 case NodeTypeIfVarExpr:
1123 return gen_if_var_expr(g, node);
11171124 case NodeTypeWhileExpr:
11181125 return gen_while_expr(g, node);
11191126 case NodeTypeAsmExpr:
src/parser.cpp+57-14
......@@ -114,8 +114,10 @@ const char *node_type_str(NodeType node_type) {
114114 return "Void";
115115 case NodeTypeBoolLiteral:
116116 return "BoolLiteral";
117 case NodeTypeIfExpr:
118 return "IfExpr";
117 case NodeTypeIfBoolExpr:
118 return "IfBoolExpr";
119 case NodeTypeIfVarExpr:
120 return "IfVarExpr";
119121 case NodeTypeWhileExpr:
120122 return "WhileExpr";
121123 case NodeTypeLabel:
......@@ -321,14 +323,27 @@ void ast_print(AstNode *node, int indent) {
321323 case NodeTypeBoolLiteral:
322324 fprintf(stderr, "%s '%s'\n", node_type_str(node->type), node->data.bool_literal ? "true" : "false");
323325 break;
324 case NodeTypeIfExpr:
326 case NodeTypeIfBoolExpr:
325327 fprintf(stderr, "%s\n", node_type_str(node->type));
326 if (node->data.if_expr.condition)
327 ast_print(node->data.if_expr.condition, indent + 2);
328 ast_print(node->data.if_expr.then_block, indent + 2);
329 if (node->data.if_expr.else_node)
330 ast_print(node->data.if_expr.else_node, indent + 2);
328 if (node->data.if_bool_expr.condition)
329 ast_print(node->data.if_bool_expr.condition, indent + 2);
330 ast_print(node->data.if_bool_expr.then_block, indent + 2);
331 if (node->data.if_bool_expr.else_node)
332 ast_print(node->data.if_bool_expr.else_node, indent + 2);
331333 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 }
332347 case NodeTypeWhileExpr:
333348 fprintf(stderr, "%s\n", node_type_str(node->type));
334349 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
16441659}
16451660
16461661/*
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)
16481665*/
16491666static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool mandatory) {
16501667 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
16571674 }
16581675 *token_index += 1;
16591676
1660 AstNode *node = ast_create_node(pc, NodeTypeIfExpr, if_tok);
1661 node->data.if_expr.condition = ast_parse_expression(pc, token_index, true);
1662 node->data.if_expr.then_block = ast_parse_block(pc, token_index, true);
1663 node->data.if_expr.else_node = ast_parse_else_or_else_if(pc, token_index, false);
1664 return node;
1677 Token *token = &pc->tokens->at(*token_index);
1678 if (token->id == TokenIdKeywordConst || token->id == TokenIdKeywordVar) {
1679 AstNode *node = ast_create_node(pc, NodeTypeIfVarExpr, if_tok);
1680 node->data.if_var_expr.var_decl.is_const = (token->id == TokenIdKeywordConst);
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 }
16651708}
16661709
16671710/*
src/parser.hpp+11-3
......@@ -44,7 +44,8 @@ enum NodeType {
4444 NodeTypeUse,
4545 NodeTypeVoid,
4646 NodeTypeBoolLiteral,
47 NodeTypeIfExpr,
47 NodeTypeIfBoolExpr,
48 NodeTypeIfVarExpr,
4849 NodeTypeWhileExpr,
4950 NodeTypeLabel,
5051 NodeTypeGoto,
......@@ -217,12 +218,18 @@ struct AstNodeUse {
217218 ZigList<AstNode *> *directives;
218219};
219220
220struct AstNodeIfExpr {
221struct AstNodeIfBoolExpr {
221222 AstNode *condition;
222223 AstNode *then_block;
223224 AstNode *else_node; // null, block node, or other if expr node
224225};
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
226233struct AstNodeWhileExpr {
227234 AstNode *condition;
228235 AstNode *body;
......@@ -341,7 +348,8 @@ struct AstNode {
341348 AstNodeFnCallExpr fn_call_expr;
342349 AstNodeArrayAccessExpr array_access_expr;
343350 AstNodeUse use;
344 AstNodeIfExpr if_expr;
351 AstNodeIfBoolExpr if_bool_expr;
352 AstNodeIfVarExpr if_var_expr;
345353 AstNodeWhileExpr while_expr;
346354 AstNodeLabel label;
347355 AstNodeGoto go_to;
src/tokenizer.cpp+22
......@@ -125,6 +125,7 @@ enum TokenizeState {
125125 TokenizeStateSawGreaterThanGreaterThan,
126126 TokenizeStateSawDot,
127127 TokenizeStateSawDotDot,
128 TokenizeStateSawQuestionMark,
128129 TokenizeStateError,
129130};
130131
......@@ -402,10 +403,28 @@ void tokenize(Buf *buf, Tokenization *out) {
402403 begin_token(&t, TokenIdDot);
403404 t.state = TokenizeStateSawDot;
404405 break;
406 case '?':
407 begin_token(&t, TokenIdMaybe);
408 t.state = TokenizeStateSawQuestionMark;
409 break;
405410 default:
406411 tokenize_error(&t, "invalid character: '%c'", c);
407412 }
408413 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;
409428 case TokenizeStateSawDot:
410429 switch (c) {
411430 case '.':
......@@ -917,6 +936,7 @@ void tokenize(Buf *buf, Tokenization *out) {
917936 case TokenizeStateSawGreaterThan:
918937 case TokenizeStateSawGreaterThanGreaterThan:
919938 case TokenizeStateSawDot:
939 case TokenizeStateSawQuestionMark:
920940 end_token(&t);
921941 break;
922942 case TokenizeStateSawDotDot:
......@@ -1012,6 +1032,8 @@ static const char * token_name(Token *token) {
10121032 case TokenIdPercent: return "Percent";
10131033 case TokenIdDot: return "Dot";
10141034 case TokenIdEllipsis: return "Ellipsis";
1035 case TokenIdMaybe: return "Maybe";
1036 case TokenIdMaybeAssign: return "MaybeAssign";
10151037 }
10161038 return "(invalid token)";
10171039}
src/tokenizer.hpp+2
......@@ -83,6 +83,8 @@ enum TokenId {
8383 TokenIdPercent,
8484 TokenIdDot,
8585 TokenIdEllipsis,
86 TokenIdMaybe,
87 TokenIdMaybeAssign,
8688};
8789
8890struct Token {