authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-31 16:04:13-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-31 16:04:13-07:00
logb3ac5c16ecc8dd9da661dcb9d15a6c36a8e4167b
tree4539ac7b88906ef03540639f19e2f37ce0bf319f
parent7ba99e9715c1fa3cd00fe6d9ac74b9a15eeac706

block expressions require parens

closes #39

7 files changed, 141 insertions(+), 73 deletions(-)

doc/langref.md+7-7
......@@ -60,10 +60,12 @@ ParamDeclList : token(LParen) list(ParamDecl, token(Comma)) token(RParen)
6060
6161ParamDecl : token(Symbol) token(Colon) Type | token(Ellipsis)
6262
63Type : token(Symbol) | token(Unreachable) | token(Void) | PointerType | ArrayType
63Type : token(Symbol) | token(Unreachable) | token(Void) | PointerType | ArrayType | MaybeType
6464
6565PointerType : token(Ampersand) option(token(Const)) Type
6666
67MaybeType : token(Question) Type
68
6769ArrayType : token(LBracket) Type token(Semicolon) Expression token(RBracket)
6870
6971Block : token(LBrace) list(option(Statement), token(Semicolon)) token(RBrace)
......@@ -96,7 +98,7 @@ AssignmentOperator : token(Eq) | token(TimesEq) | token(DivEq) | token(ModEq) |
9698
9799BlockExpression : IfExpression | Block | WhileExpression
98100
99WhileExpression : token(While) Expression Block
101WhileExpression : token(While) token(LParen) Expression token(RParen) Expression
100102
101103BoolOrExpression : BoolAndExpression token(BoolOr) BoolOrExpression | BoolAndExpression
102104
......@@ -104,13 +106,11 @@ ReturnExpression : token(Return) option(Expression)
104106
105107IfExpression : IfVarExpression | IfBoolExpression
106108
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)
109IfBoolExpression : token(If) token(LParen) Expression token(RParen) Expression option(Else)
110110
111ElseIf : token(Else) IfExpression
111IfVarExpression : token(If) token(LParen) (token(Const) | token(Var)) token(Symbol) option(token(Colon) Type) Token(MaybeAssign) Expression token(RParen) Expression Option(Else)
112112
113Else : token(Else) Block
113Else : token(Else) Expression
114114
115115BoolAndExpression : ComparisonExpression token(BoolAnd) BoolAndExpression | ComparisonExpression
116116
example/maybe_type/main.zig created+19
......@@ -0,0 +1,19 @@
1export executable "maybe_type";
2
3use "std.zig";
4
5fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
6 const x : ?bool = true;
7
8 if (const y ?= x) {
9 if (y) {
10 print_str("x is true\n");
11 } else {
12 print_str("x is false\n");
13 }
14 } else {
15 print_str("x is none\n");
16 }
17
18 return 0;
19}
src/analyze.cpp+34
......@@ -132,6 +132,26 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool
132132 }
133133}
134134
135static TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {
136 if (child_type->maybe_parent) {
137 return child_type->maybe_parent;
138 } else {
139 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdMaybe);
140 // TODO entry->type_ref
141 buf_resize(&entry->name, 0);
142 buf_appendf(&entry->name, "?%s", buf_ptr(&child_type->name));
143 // TODO entry->size_in_bits
144 // TODO entry->align_in_bits
145 assert(child_type->di_type);
146 // TODO entry->di_type
147 entry->data.maybe.child_type = child_type;
148
149 g->type_table.put(&entry->name, entry);
150 child_type->maybe_parent = entry;
151 return entry;
152 }
153}
154
135155static TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t array_size) {
136156 auto existing_entry = child_type->arrays_by_size.maybe_get(array_size);
137157 if (existing_entry) {
......@@ -208,6 +228,20 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node) {
208228 }
209229 return type_node->entry;
210230 }
231 case AstNodeTypeTypeMaybe:
232 {
233 resolve_type(g, node->data.type.child_type);
234 TypeTableEntry *child_type = node->data.type.child_type->codegen_node->data.type_node.entry;
235 assert(child_type);
236 if (child_type->id == TypeTableEntryIdUnreachable) {
237 add_node_error(g, node,
238 buf_create_from_str("maybe unreachable type not allowed"));
239 } else if (child_type->id == TypeTableEntryIdInvalid) {
240 return child_type;
241 }
242 type_node->entry = get_maybe_type(g, child_type);
243 return type_node->entry;
244 }
211245 }
212246 zig_unreachable();
213247}
src/analyze.hpp+1
......@@ -96,6 +96,7 @@ struct TypeTableEntry {
9696 TypeTableEntry *pointer_const_parent;
9797 TypeTableEntry *pointer_mut_parent;
9898 HashMap<uint64_t, TypeTableEntry *, uint64_hash, uint64_eq> arrays_by_size;
99 TypeTableEntry *maybe_parent;
99100
100101};
101102
src/parser.cpp+30-17
......@@ -225,6 +225,12 @@ void ast_print(AstNode *node, int indent) {
225225 ast_print(node->data.type.array_size, indent + 2);
226226 break;
227227 }
228 case AstNodeTypeTypeMaybe:
229 {
230 fprintf(stderr, "MaybeType\n");
231 ast_print(node->data.type.child_type, indent + 2);
232 break;
233 }
228234 }
229235 break;
230236 case NodeTypeReturnExpr:
......@@ -920,7 +926,7 @@ static void ast_parse_type_assume_amp(ParseContext *pc, int *token_index, AstNod
920926}
921927
922928/*
923Type : token(Symbol) | token(Unreachable) | token(Void) | PointerType | ArrayType
929Type : token(Symbol) | token(Unreachable) | token(Void) | PointerType | ArrayType | MaybeType
924930PointerType : token(Ampersand) option(token(Const)) Type
925931ArrayType : token(LBracket) Type token(Semicolon) token(Number) token(RBracket)
926932*/
......@@ -941,6 +947,9 @@ static AstNode *ast_parse_type(ParseContext *pc, int *token_index) {
941947 ast_buf_from_token(pc, token, &node->data.type.primitive_name);
942948 } else if (token->id == TokenIdAmpersand) {
943949 ast_parse_type_assume_amp(pc, token_index, node);
950 } else if (token->id == TokenIdMaybe) {
951 node->data.type.type = AstNodeTypeTypeMaybe;
952 node->data.type.child_type = ast_parse_type(pc, token_index);
944953 } else if (token->id == TokenIdBoolAnd) {
945954 // Pretend that we got 2 ampersand tokens
946955 node->data.type.type = AstNodeTypeTypePointer;
......@@ -1636,10 +1645,9 @@ static AstNode *ast_parse_bool_and_expr(ParseContext *pc, int *token_index, bool
16361645}
16371646
16381647/*
1639ElseIf : token(Else) IfExpression
1640Else : token(Else) Block
1648Else : token(Else) Expression
16411649*/
1642static AstNode *ast_parse_else_or_else_if(ParseContext *pc, int *token_index, bool mandatory) {
1650static AstNode *ast_parse_else(ParseContext *pc, int *token_index, bool mandatory) {
16431651 Token *else_token = &pc->tokens->at(*token_index);
16441652
16451653 if (else_token->id != TokenIdKeywordElse) {
......@@ -1651,17 +1659,13 @@ static AstNode *ast_parse_else_or_else_if(ParseContext *pc, int *token_index, bo
16511659 }
16521660 *token_index += 1;
16531661
1654 AstNode *if_expr = ast_parse_if_expr(pc, token_index, false);
1655 if (if_expr)
1656 return if_expr;
1657
1658 return ast_parse_block(pc, token_index, true);
1662 return ast_parse_expression(pc, token_index, true);
16591663}
16601664
16611665/*
16621666IfExpression : 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)
1667IfBoolExpression : token(If) token(LParen) Expression token(RParen) Expression option(Else)
1668IfVarExpression : token(If) token(LParen) (token(Const) | token(Var)) token(Symbol) option(token(Colon) Type) Token(MaybeAssign) Expression token(RParen) Expression Option(Else)
16651669*/
16661670static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool mandatory) {
16671671 Token *if_tok = &pc->tokens->at(*token_index);
......@@ -1674,6 +1678,8 @@ static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool manda
16741678 }
16751679 *token_index += 1;
16761680
1681 ast_eat_token(pc, token_index, TokenIdLParen);
1682
16771683 Token *token = &pc->tokens->at(*token_index);
16781684 if (token->id == TokenIdKeywordConst || token->id == TokenIdKeywordVar) {
16791685 AstNode *node = ast_create_node(pc, NodeTypeIfVarExpr, if_tok);
......@@ -1695,14 +1701,16 @@ static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool manda
16951701 } else {
16961702 ast_invalid_token_error(pc, eq_or_colon);
16971703 }
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);
1704 ast_eat_token(pc, token_index, TokenIdRParen);
1705 node->data.if_var_expr.then_block = ast_parse_expression(pc, token_index, true);
1706 node->data.if_var_expr.else_node = ast_parse_else(pc, token_index, false);
17001707 return node;
17011708 } else {
17021709 AstNode *node = ast_create_node(pc, NodeTypeIfBoolExpr, if_tok);
17031710 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);
1711 ast_eat_token(pc, token_index, TokenIdRParen);
1712 node->data.if_bool_expr.then_block = ast_parse_expression(pc, token_index, true);
1713 node->data.if_bool_expr.else_node = ast_parse_else(pc, token_index, false);
17061714 return node;
17071715 }
17081716}
......@@ -1795,7 +1803,7 @@ static AstNode *ast_parse_bool_or_expr(ParseContext *pc, int *token_index, bool
17951803}
17961804
17971805/*
1798WhileExpression : token(While) Expression Block
1806WhileExpression : token(While) token(LParen) Expression token(RParen) Expression
17991807*/
18001808static AstNode *ast_parse_while_expr(ParseContext *pc, int *token_index, bool mandatory) {
18011809 Token *token = &pc->tokens->at(*token_index);
......@@ -1811,8 +1819,13 @@ static AstNode *ast_parse_while_expr(ParseContext *pc, int *token_index, bool ma
18111819
18121820 AstNode *node = ast_create_node(pc, NodeTypeWhileExpr, token);
18131821
1822 ast_eat_token(pc, token_index, TokenIdLParen);
18141823 node->data.while_expr.condition = ast_parse_expression(pc, token_index, true);
1815 node->data.while_expr.body = ast_parse_block(pc, token_index, true);
1824 ast_eat_token(pc, token_index, TokenIdRParen);
1825
1826 node->data.while_expr.body = ast_parse_expression(pc, token_index, true);
1827
1828
18161829
18171830 return node;
18181831}
src/parser.hpp+1
......@@ -95,6 +95,7 @@ enum AstNodeTypeType {
9595 AstNodeTypeTypePrimitive,
9696 AstNodeTypeTypePointer,
9797 AstNodeTypeTypeArray,
98 AstNodeTypeTypeMaybe,
9899};
99100
100101struct AstNodeType {
test/run_tests.cpp+49-49
......@@ -184,17 +184,17 @@ static void add_compiling_test_cases(void) {
184184 use "std.zig";
185185
186186 pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
187 if 1 != 0 {
187 if (1 != 0) {
188188 print_str("1 is true\n");
189189 } else {
190190 print_str("1 is false\n");
191191 }
192 if 0 != 0 {
192 if (0 != 0) {
193193 print_str("0 is true\n");
194 } else if 1 - 1 != 0 {
194 } else if (1 - 1 != 0) {
195195 print_str("1 - 1 is true\n");
196196 }
197 if !(0 != 0) {
197 if (!(0 != 0)) {
198198 print_str("!0 is true\n");
199199 }
200200 return 0;
......@@ -209,7 +209,7 @@ static void add_compiling_test_cases(void) {
209209 }
210210
211211 pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
212 if add(22, 11) == 33 {
212 if (add(22, 11) == 33) {
213213 print_str("pass\n");
214214 }
215215 return 0;
......@@ -220,7 +220,7 @@ static void add_compiling_test_cases(void) {
220220 use "std.zig";
221221
222222 fn loop(a : i32) {
223 if a == 0 {
223 if (a == 0) {
224224 goto done;
225225 }
226226 print_str("loop\n");
......@@ -304,7 +304,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
304304
305305 var i = 0 as i32;
306306loop_start:
307 if i == 3 {
307 if (i == 3) {
308308 goto done;
309309 }
310310 print_str("loop\n");
......@@ -323,7 +323,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
323323
324324 var i : i32 = 0;
325325loop_start:
326 if i == 5 {
326 if (i == 5) {
327327 goto loop_end;
328328 }
329329 array[i] = i + 1;
......@@ -335,7 +335,7 @@ loop_end:
335335 i = 0;
336336 var accumulator = 0 as i32;
337337loop_2_start:
338 if i == 5 {
338 if (i == 5) {
339339 goto loop_2_end;
340340 }
341341
......@@ -345,7 +345,7 @@ loop_2_start:
345345 goto loop_2_start;
346346loop_2_end:
347347
348 if accumulator == 15 {
348 if (accumulator == 15) {
349349 print_str("OK\n");
350350 }
351351
......@@ -368,18 +368,18 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
368368use "std.zig";
369369
370370export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
371 if false || false || false { print_str("BAD 1\n"); }
372 if true && true && false { print_str("BAD 2\n"); }
373 if 1 | 2 | 4 != 7 { print_str("BAD 3\n"); }
374 if 3 ^ 6 ^ 8 != 13 { print_str("BAD 4\n"); }
375 if 7 & 14 & 28 != 4 { print_str("BAD 5\n"); }
376 if 9 << 1 << 2 != 9 << 3 { print_str("BAD 6\n"); }
377 if 90 >> 1 >> 2 != 90 >> 3 { print_str("BAD 7\n"); }
378 if 100 - 1 + 1000 != 1099 { print_str("BAD 8\n"); }
379 if 5 * 4 / 2 % 3 != 1 { print_str("BAD 9\n"); }
380 if 5 as i32 as i32 != 5 { print_str("BAD 10\n"); }
381 if !!false { print_str("BAD 11\n"); }
382 if 7 != --7 { print_str("BAD 12\n"); }
371 if (false || false || false) { print_str("BAD 1\n"); }
372 if (true && true && false) { print_str("BAD 2\n"); }
373 if (1 | 2 | 4 != 7) { print_str("BAD 3\n"); }
374 if (3 ^ 6 ^ 8 != 13) { print_str("BAD 4\n"); }
375 if (7 & 14 & 28 != 4) { print_str("BAD 5\n"); }
376 if (9 << 1 << 2 != 9 << 3) { print_str("BAD 6\n"); }
377 if (90 >> 1 >> 2 != 90 >> 3) { print_str("BAD 7\n"); }
378 if (100 - 1 + 1000 != 1099) { print_str("BAD 8\n"); }
379 if (5 * 4 / 2 % 3 != 1) { print_str("BAD 9\n"); }
380 if (5 as i32 as i32 != 5) { print_str("BAD 10\n"); }
381 if (!!false) { print_str("BAD 11\n"); }
382 if (7 != --7) { print_str("BAD 12\n"); }
383383
384384 print_str("OK\n");
385385 return 0;
......@@ -390,17 +390,17 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
390390use "std.zig";
391391
392392export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
393 if true || { print_str("BAD 1\n"); false } {
393 if (true || { print_str("BAD 1\n"); false }) {
394394 print_str("OK 1\n");
395395 }
396 if false || { print_str("OK 2\n"); false } {
396 if (false || { print_str("OK 2\n"); false }) {
397397 print_str("BAD 2\n");
398398 }
399399
400 if true && { print_str("OK 3\n"); false } {
400 if (true && { print_str("OK 3\n"); false }) {
401401 print_str("BAD 3\n");
402402 }
403 if false && { print_str("BAD 4\n"); false } {
403 if (false && { print_str("BAD 4\n"); false }) {
404404 } else {
405405 print_str("OK 4\n");
406406 }
......@@ -414,18 +414,18 @@ use "std.zig";
414414
415415export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
416416 var i : i32 = 0;
417 i += 5; if i != 5 { print_str("BAD +=\n"); }
418 i -= 2; if i != 3 { print_str("BAD -=\n"); }
419 i *= 20; if i != 60 { print_str("BAD *=\n"); }
420 i /= 3; if i != 20 { print_str("BAD /=\n"); }
421 i %= 11; if i != 9 { print_str("BAD %=\n"); }
422 i <<= 1; if i != 18 { print_str("BAD <<=\n"); }
423 i >>= 2; if i != 4 { print_str("BAD >>=\n"); }
417 i += 5; if (i != 5) { print_str("BAD +=\n"); }
418 i -= 2; if (i != 3) { print_str("BAD -=\n"); }
419 i *= 20; if (i != 60) { print_str("BAD *=\n"); }
420 i /= 3; if (i != 20) { print_str("BAD /=\n"); }
421 i %= 11; if (i != 9) { print_str("BAD %=\n"); }
422 i <<= 1; if (i != 18) { print_str("BAD <<=\n"); }
423 i >>= 2; if (i != 4) { print_str("BAD >>=\n"); }
424424 i = 6;
425 i &= 5; if i != 4 { print_str("BAD &=\n"); }
426 i ^= 6; if i != 2 { print_str("BAD ^=\n"); }
425 i &= 5; if (i != 4) { print_str("BAD &=\n"); }
426 i ^= 6; if (i != 2) { print_str("BAD ^=\n"); }
427427 i = 6;
428 i |= 3; if i != 7 { print_str("BAD |=\n"); }
428 i |= 3; if (i != 7) { print_str("BAD |=\n"); }
429429
430430 print_str("OK\n");
431431 return 0;
......@@ -570,7 +570,7 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
570570 foo.b = foo.a == 1;
571571 test_foo(foo);
572572 test_mutation(&foo);
573 if foo.c != 100 {
573 if (foo.c != 100) {
574574 print_str("BAD\n");
575575 }
576576 test_point_to_self();
......@@ -585,7 +585,7 @@ struct Foo {
585585 c : f32,
586586}
587587fn test_foo(foo : Foo) {
588 if !foo.b {
588 if (!foo.b) {
589589 print_str("BAD\n");
590590 }
591591}
......@@ -610,7 +610,7 @@ fn test_point_to_self() {
610610
611611 root.next = &node;
612612
613 if node.next.next.next.val.x != 1 {
613 if (node.next.next.next.val.x != 1) {
614614 print_str("BAD\n");
615615 }
616616}
......@@ -620,15 +620,15 @@ fn test_byval_assign() {
620620
621621 foo1.a = 1234;
622622
623 if foo2.a != 0 { print_str("BAD\n"); }
623 if (foo2.a != 0) { print_str("BAD\n"); }
624624
625625 foo2 = foo1;
626626
627 if foo2.a != 1234 { print_str("BAD - byval assignment failed\n"); }
627 if (foo2.a != 1234) { print_str("BAD - byval assignment failed\n"); }
628628}
629629fn test_initializer() {
630630 const val = Val { .x = 42 };
631 if val.x != 42 { print_str("BAD\n"); }
631 if (val.x != 42) { print_str("BAD\n"); }
632632}
633633 )SOURCE", "OK\n");
634634
......@@ -639,9 +639,9 @@ const g1 : i32 = 1233 + 1;
639639var g2 : i32;
640640
641641export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
642 if g2 != 0 { print_str("BAD\n"); }
642 if (g2 != 0) { print_str("BAD\n"); }
643643 g2 = g1;
644 if g2 != 1234 { print_str("BAD\n"); }
644 if (g2 != 1234) { print_str("BAD\n"); }
645645 print_str("OK\n");
646646 return 0;
647647}
......@@ -651,7 +651,7 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
651651use "std.zig";
652652export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
653653 var i : i32 = 0;
654 while i < 4 {
654 while (i < 4) {
655655 print_str("loop\n");
656656 i += 1;
657657 }
......@@ -663,10 +663,10 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
663663use "std.zig";
664664export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
665665 var i : i32 = 0;
666 while true {
666 while (true) {
667667 print_str("loop\n");
668668 i += 1;
669 if i < 4 {
669 if (i < 4) {
670670 continue;
671671 }
672672 break;
......@@ -871,8 +871,8 @@ fn f() {
871871
872872 add_compile_fail_case("missing else clause", R"SOURCE(
873873fn f() {
874 const x : i32 = if true { 1 };
875 const y = if true { 1 as i32 };
874 const x : i32 = if (true) { 1 };
875 const y = if (true) { 1 as i32 };
876876}
877877 )SOURCE", 2, ".tmp_source.zig:3:21: error: expected type 'i32', got 'void'",
878878 ".tmp_source.zig:4:15: error: incompatible types: 'i32' and 'void'");