authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-07 03:23:38-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-07 03:23:38-07:00
loga3c97081ca37a6f78732c9a5f2244cef5a11cb07
treeaec69a113eacaa084039364b65ef803d695e0dd5
parent9b9fd5ad23e37d1e2b37b05b168abcfd53f4629d

add ?? maybe unwrapping binary operator

add null literal fix number literal / maybe interactions

14 files changed, 287 insertions(+), 23 deletions(-)

CMakeLists.txt+1
...@@ -120,6 +120,7 @@ set(ZIG_STD_SRC...@@ -120,6 +120,7 @@ set(ZIG_STD_SRC
120 "${CMAKE_SOURCE_DIR}/std/builtin.zig"120 "${CMAKE_SOURCE_DIR}/std/builtin.zig"
121 "${CMAKE_SOURCE_DIR}/std/std.zig"121 "${CMAKE_SOURCE_DIR}/std/std.zig"
122 "${CMAKE_SOURCE_DIR}/std/syscall.zig"122 "${CMAKE_SOURCE_DIR}/std/syscall.zig"
123 "${CMAKE_SOURCE_DIR}/std/errno.zig"
123 "${CMAKE_SOURCE_DIR}/std/rand.zig"124 "${CMAKE_SOURCE_DIR}/std/rand.zig"
124)125)
125126
doc/langref.md+9-6
...@@ -98,7 +98,9 @@ AsmInputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token...@@ -98,7 +98,9 @@ AsmInputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token
9898
99AsmClobbers: token(Colon) list(token(String), token(Comma))99AsmClobbers: token(Colon) list(token(String), token(Comma))
100100
101AssignmentExpression : BoolOrExpression AssignmentOperator BoolOrExpression | BoolOrExpression101UnwrapMaybeExpression : BoolOrExpression token(DoubleQuestion) BoolOrExpression | BoolOrExpression
102
103AssignmentExpression : UnwrapMaybeExpression AssignmentOperator UnwrapMaybeExpression | UnwrapMaybeExpression
102104
103AssignmentOperator : 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) 105AssignmentOperator : 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)
104106
...@@ -166,7 +168,7 @@ Goto: token(Goto) token(Symbol)...@@ -166,7 +168,7 @@ Goto: token(Goto) token(Symbol)
166168
167GroupedExpression : token(LParen) Expression token(RParen)169GroupedExpression : token(LParen) Expression token(RParen)
168170
169KeywordLiteral : token(Unreachable) | token(Void) | token(True) | token(False)171KeywordLiteral : token(Unreachable) | token(Void) | token(True) | token(False) | token(Null)
170```172```
171173
172## Operator Precedence174## Operator Precedence
...@@ -184,6 +186,7 @@ as...@@ -184,6 +186,7 @@ as
184== != < > <= >=186== != < > <= >=
185&&187&&
186||188||
189??
187= *= /= %= += -= <<= >>= &= ^= |= &&= ||=190= *= /= %= += -= <<= >>= &= ^= |= &&= ||=
188```191```
189192
...@@ -192,7 +195,7 @@ as...@@ -192,7 +195,7 @@ as
192### Characters and Strings195### Characters and Strings
193196
194 | Example | Characters | Escapes | Null Term | Type197 | Example | Characters | Escapes | Null Term | Type
195---------------------------------------------------------------------------------198----------------|----------|-------------|----------------|-----------|----------
196 Byte | 'H' | All ASCII | Byte | No | u8199 Byte | 'H' | All ASCII | Byte | No | u8
197 UTF-8 Bytes | "hello" | All Unicode | Byte & Unicode | No | [5; u8]200 UTF-8 Bytes | "hello" | All Unicode | Byte & Unicode | No | [5; u8]
198 UTF-8 C string | c"hello" | All Unicode | Byte & Unicode | Yes | *const u8201 UTF-8 C string | c"hello" | All Unicode | Byte & Unicode | Yes | *const u8
...@@ -200,7 +203,7 @@ as...@@ -200,7 +203,7 @@ as
200### Byte Escapes203### Byte Escapes
201204
202 | Name205 | Name
203-----------------------------------------------206------|----------------------------------------
204 \x7F | 8-bit character code (exactly 2 digits)207 \x7F | 8-bit character code (exactly 2 digits)
205 \n | Newline208 \n | Newline
206 \r | Carriage return209 \r | Carriage return
...@@ -213,13 +216,13 @@ as...@@ -213,13 +216,13 @@ as
213### Unicode Escapes216### Unicode Escapes
214217
215 | Name218 | Name
216----------------------------------------------------------219----------|-----------------------------------------------
217 \u{7FFF} | 24-bit Unicode character code (up to 6 digits)220 \u{7FFF} | 24-bit Unicode character code (up to 6 digits)
218221
219### Numbers222### Numbers
220223
221 Number literals | Example | Exponentiation224 Number literals | Example | Exponentiation
222--------------------------------------------------225--------------------|-------------|---------------
223 Decimal integer | 98222 | N/A226 Decimal integer | 98222 | N/A
224 Hex integer | 0xff | N/A227 Hex integer | 0xff | N/A
225 Octal integer | 0o77 | N/A228 Octal integer | 0o77 | N/A
doc/vim/syntax/zig.vim+10
...@@ -14,6 +14,7 @@ syn keyword zigStatement goto break return continue asm...@@ -14,6 +14,7 @@ syn keyword zigStatement goto break return continue asm
14syn keyword zigConditional if else match14syn keyword zigConditional if else match
15syn keyword zigRepeat while for15syn keyword zigRepeat while for
1616
17syn keyword zigConstant null
17syn keyword zigKeyword fn unreachable use void18syn keyword zigKeyword fn unreachable use void
18syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128 string19syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128 string
1920
...@@ -28,6 +29,12 @@ syn match zigHexNumber display "\<0x[a-fA-F0-9_]\+\%([iu]\%(size\|8\|16\|32\|64\...@@ -28,6 +29,12 @@ syn match zigHexNumber display "\<0x[a-fA-F0-9_]\+\%([iu]\%(size\|8\|16\|32\|64\
28syn match zigOctNumber display "\<0o[0-7_]\+\%([iu]\%(size\|8\|16\|32\|64\)\)\="29syn match zigOctNumber display "\<0o[0-7_]\+\%([iu]\%(size\|8\|16\|32\|64\)\)\="
29syn match zigBinNumber display "\<0b[01_]\+\%([iu]\%(size\|8\|16\|32\|64\)\)\="30syn match zigBinNumber display "\<0b[01_]\+\%([iu]\%(size\|8\|16\|32\|64\)\)\="
3031
32
33syn match zigCharacterInvalid display contained /b\?'\zs[\n\r\t']\ze'/
34syn match zigCharacterInvalidUnicode display contained /b'\zs[^[:cntrl:][:graph:][:alnum:][:space:]]\ze'/
35syn match zigCharacter /b'\([^\\]\|\\\(.\|x\x\{2}\)\)'/ contains=zigEscape,zigEscapeError,zigCharacterInvalid,zigCharacterInvalidUnicode
36syn match zigCharacter /'\([^\\]\|\\\(.\|x\x\{2}\|u\x\{4}\|U\x\{8}\|u{\x\{1,6}}\)\)'/ contains=zigEscape,zigEscapeUnicode,zigEscapeError,zigCharacterInvalid
37
31syn match zigShebang /\%^#![^[].*/38syn match zigShebang /\%^#![^[].*/
3239
33syn region zigCommentLine start="//" end="$" contains=zigTodo,@Spell40syn region zigCommentLine start="//" end="$" contains=zigTodo,@Spell
...@@ -64,6 +71,9 @@ hi def link zigCommentBlockDoc zigCommentLineDoc...@@ -64,6 +71,9 @@ hi def link zigCommentBlockDoc zigCommentLineDoc
64hi def link zigTodo Todo71hi def link zigTodo Todo
65hi def link zigStringContinuation Special72hi def link zigStringContinuation Special
66hi def link zigString String73hi def link zigString String
74hi def link zigCharacterInvalid Error
75hi def link zigCharacterInvalidUnicode zigCharacterInvalid
76hi def link zigCharacter Character
67hi def link zigEscape Special77hi def link zigEscape Special
68hi def link zigEscapeUnicode zigEscape78hi def link zigEscapeUnicode zigEscape
69hi def link zigEscapeError Error79hi def link zigEscapeError Error
example/guess_number/main.zig+8-6
...@@ -14,7 +14,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {...@@ -14,7 +14,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
14 var err : isize;14 var err : isize;
15 if ({err = os_get_random_bytes(&seed as &u8, #sizeof(u32)); err != #sizeof(u32)}) {15 if ({err = os_get_random_bytes(&seed as &u8, #sizeof(u32)); err != #sizeof(u32)}) {
16 // TODO full error message16 // TODO full error message
17 fprint_str(stderr_fileno, "unable to get random bytes");17 fprint_str(stderr_fileno, "unable to get random bytes\n");
18 return 1;18 return 1;
19 }19 }
2020
...@@ -27,11 +27,14 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {...@@ -27,11 +27,14 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
27 print_u64(answer);27 print_u64(answer);
28 print_str("\n");28 print_str("\n");
2929
30 return 0;
31
32 /*
33 while (true) {30 while (true) {
34 const line = readline("\nGuess a number between 1 and 100: ");31 print_str("\nGuess a number between 1 and 100: ");
32 var line_buf : [20]u8;
33 const line = readline(line_buf) ?? {
34 // TODO full error message
35 fprint_str(stderr_fileno, "unable to read input\n");
36 return 1;
37 };
3538
36 if (const guess ?= parse_u64(line)) {39 if (const guess ?= parse_u64(line)) {
37 if (guess > answer) {40 if (guess > answer) {
...@@ -46,5 +49,4 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {...@@ -46,5 +49,4 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
46 print_str("Invalid number format.\n");49 print_str("Invalid number format.\n");
47 }50 }
48 }51 }
49 */
50}52}
example/maybe_type/main.zig+16
...@@ -15,5 +15,21 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {...@@ -15,5 +15,21 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
15 print_str("x is none\n");15 print_str("x is none\n");
16 }16 }
1717
18 const next_x : ?i32 = null;
19
20 const z = next_x ?? 1234;
21
22 if (z != 1234) {
23 print_str("BAD\n");
24 }
25
26 const final_x : ?i32 = 13;
27
28 const num = final_x ?? unreachable;
29
30 if (num != 13) {
31 print_str("BAD\n");
32 }
33
18 return 0;34 return 0;
19}35}
src/analyze.cpp+60-3
...@@ -48,6 +48,7 @@ static AstNode *first_executing_node(AstNode *node) {...@@ -48,6 +48,7 @@ static AstNode *first_executing_node(AstNode *node) {
48 case NodeTypeUse:48 case NodeTypeUse:
49 case NodeTypeVoid:49 case NodeTypeVoid:
50 case NodeTypeBoolLiteral:50 case NodeTypeBoolLiteral:
51 case NodeTypeNullLiteral:
51 case NodeTypeIfBoolExpr:52 case NodeTypeIfBoolExpr:
52 case NodeTypeIfVarExpr:53 case NodeTypeIfVarExpr:
53 case NodeTypeLabel:54 case NodeTypeLabel:
...@@ -358,6 +359,7 @@ static TypeTableEntry *eval_const_expr_bin_op(CodeGen *g, BlockContext *context,...@@ -358,6 +359,7 @@ static TypeTableEntry *eval_const_expr_bin_op(CodeGen *g, BlockContext *context,
358 case BinOpTypeSub:359 case BinOpTypeSub:
359 case BinOpTypeMult:360 case BinOpTypeMult:
360 case BinOpTypeDiv:361 case BinOpTypeDiv:
362 case BinOpTypeUnwrapMaybe:
361 return g->builtin_types.entry_invalid;363 return g->builtin_types.entry_invalid;
362 case BinOpTypeInvalid:364 case BinOpTypeInvalid:
363 case BinOpTypeAssign:365 case BinOpTypeAssign:
...@@ -388,6 +390,8 @@ static TypeTableEntry *eval_const_expr(CodeGen *g, BlockContext *context,...@@ -388,6 +390,8 @@ static TypeTableEntry *eval_const_expr(CodeGen *g, BlockContext *context,
388 case NodeTypeBoolLiteral:390 case NodeTypeBoolLiteral:
389 out_number_literal->data.x_uint = node->data.bool_literal ? 1 : 0;391 out_number_literal->data.x_uint = node->data.bool_literal ? 1 : 0;
390 return node->codegen_node->expr_node.type_entry;392 return node->codegen_node->expr_node.type_entry;
393 case NodeTypeNullLiteral:
394 return node->codegen_node->expr_node.type_entry;
391 case NodeTypeBinOpExpr:395 case NodeTypeBinOpExpr:
392 return eval_const_expr_bin_op(g, context, node, out_number_literal);396 return eval_const_expr_bin_op(g, context, node, out_number_literal);
393 case NodeTypeCompilerFnType:397 case NodeTypeCompilerFnType:
...@@ -877,6 +881,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,...@@ -877,6 +881,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
877 case NodeTypeUnreachable:881 case NodeTypeUnreachable:
878 case NodeTypeVoid:882 case NodeTypeVoid:
879 case NodeTypeBoolLiteral:883 case NodeTypeBoolLiteral:
884 case NodeTypeNullLiteral:
880 case NodeTypeSymbol:885 case NodeTypeSymbol:
881 case NodeTypeCastExpr:886 case NodeTypeCastExpr:
882 case NodeTypePrefixOpExpr:887 case NodeTypePrefixOpExpr:
...@@ -951,6 +956,7 @@ static void preview_types(CodeGen *g, ImportTableEntry *import, AstNode *node) {...@@ -951,6 +956,7 @@ static void preview_types(CodeGen *g, ImportTableEntry *import, AstNode *node) {
951 case NodeTypeUnreachable:956 case NodeTypeUnreachable:
952 case NodeTypeVoid:957 case NodeTypeVoid:
953 case NodeTypeBoolLiteral:958 case NodeTypeBoolLiteral:
959 case NodeTypeNullLiteral:
954 case NodeTypeSymbol:960 case NodeTypeSymbol:
955 case NodeTypeCastExpr:961 case NodeTypeCastExpr:
956 case NodeTypePrefixOpExpr:962 case NodeTypePrefixOpExpr:
...@@ -1018,7 +1024,7 @@ static bool num_lit_fits_in_other_type(CodeGen *g, TypeTableEntry *literal_type,...@@ -1018,7 +1024,7 @@ static bool num_lit_fits_in_other_type(CodeGen *g, TypeTableEntry *literal_type,
1018 return false;1024 return false;
1019 }1025 }
1020 case TypeTableEntryIdMaybe:1026 case TypeTableEntryIdMaybe:
1021 return num_lit_fits_in_other_type(g, literal_type, other_type->data.maybe.child_type);1027 return false;
1022 }1028 }
1023 zig_unreachable();1029 zig_unreachable();
1024}1030}
...@@ -1133,6 +1139,9 @@ static TypeTableEntry *resolve_type_compatibility(CodeGen *g, BlockContext *cont...@@ -1133,6 +1139,9 @@ static TypeTableEntry *resolve_type_compatibility(CodeGen *g, BlockContext *cont
1133 if (actual_type->id == TypeTableEntryIdNumberLiteral &&1139 if (actual_type->id == TypeTableEntryIdNumberLiteral &&
1134 num_lit_fits_in_other_type(g, actual_type, expected_type))1140 num_lit_fits_in_other_type(g, actual_type, expected_type))
1135 {1141 {
1142 assert(!node->codegen_node->data.num_lit_node.resolved_type ||
1143 node->codegen_node->data.num_lit_node.resolved_type == expected_type);
1144 node->codegen_node->data.num_lit_node.resolved_type = expected_type;
1136 return expected_type;1145 return expected_type;
1137 }1146 }
11381147
...@@ -1419,6 +1428,7 @@ static bool is_op_allowed(TypeTableEntry *type, BinOpType op) {...@@ -1419,6 +1428,7 @@ static bool is_op_allowed(TypeTableEntry *type, BinOpType op) {
1419 case BinOpTypeMult:1428 case BinOpTypeMult:
1420 case BinOpTypeDiv:1429 case BinOpTypeDiv:
1421 case BinOpTypeMod:1430 case BinOpTypeMod:
1431 case BinOpTypeUnwrapMaybe:
1422 zig_unreachable();1432 zig_unreachable();
1423 }1433 }
1424 zig_unreachable();1434 zig_unreachable();
...@@ -1619,6 +1629,24 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import,...@@ -1619,6 +1629,24 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import,
16191629
1620 return resolve_peer_type_compatibility(g, context, node, op1, op2, lhs_type, rhs_type);1630 return resolve_peer_type_compatibility(g, context, node, op1, op2, lhs_type, rhs_type);
1621 }1631 }
1632 case BinOpTypeUnwrapMaybe:
1633 {
1634 AstNode *op1 = node->data.bin_op_expr.op1;
1635 AstNode *op2 = node->data.bin_op_expr.op2;
1636 TypeTableEntry *lhs_type = analyze_expression(g, import, context, nullptr, op1);
1637
1638 if (lhs_type->id == TypeTableEntryIdInvalid) {
1639 return lhs_type;
1640 } else if (lhs_type->id == TypeTableEntryIdMaybe) {
1641 TypeTableEntry *child_type = lhs_type->data.maybe.child_type;
1642 analyze_expression(g, import, context, child_type, op2);
1643 return child_type;
1644 } else {
1645 add_node_error(g, op1,
1646 buf_sprintf("expected maybe type, got '%s'",
1647 buf_ptr(&lhs_type->name)));
1648 }
1649 }
1622 case BinOpTypeInvalid:1650 case BinOpTypeInvalid:
1623 zig_unreachable();1651 zig_unreachable();
1624 }1652 }
...@@ -1695,6 +1723,27 @@ static VariableTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableE...@@ -1695,6 +1723,27 @@ static VariableTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableE
1695 return analyze_variable_declaration_raw(g, import, context, node, variable_declaration, false);1723 return analyze_variable_declaration_raw(g, import, context, node, variable_declaration, false);
1696}1724}
16971725
1726static TypeTableEntry *analyze_null_literal_expr(CodeGen *g, ImportTableEntry *import,
1727 BlockContext *block_context, TypeTableEntry *expected_type, AstNode *node)
1728{
1729 assert(node->type == NodeTypeNullLiteral);
1730
1731 if (expected_type) {
1732 assert(expected_type->id == TypeTableEntryIdMaybe);
1733
1734 assert(node->codegen_node);
1735 node->codegen_node->data.struct_val_expr_node.type_entry = expected_type;
1736 node->codegen_node->data.struct_val_expr_node.source_node = node;
1737 block_context->struct_val_expr_alloca_list.append(&node->codegen_node->data.struct_val_expr_node);
1738
1739 return expected_type;
1740 } else {
1741 add_node_error(g, node,
1742 buf_sprintf("unable to determine null type"));
1743 return g->builtin_types.entry_invalid;
1744 }
1745}
1746
1698static TypeTableEntry *analyze_number_literal_expr(CodeGen *g, ImportTableEntry *import,1747static TypeTableEntry *analyze_number_literal_expr(CodeGen *g, ImportTableEntry *import,
1699 BlockContext *block_context, TypeTableEntry *expected_type, AstNode *node)1748 BlockContext *block_context, TypeTableEntry *expected_type, AstNode *node)
1700{1749{
...@@ -1706,8 +1755,11 @@ static TypeTableEntry *analyze_number_literal_expr(CodeGen *g, ImportTableEntry...@@ -1706,8 +1755,11 @@ static TypeTableEntry *analyze_number_literal_expr(CodeGen *g, ImportTableEntry
1706 } else if (expected_type) {1755 } else if (expected_type) {
1707 NumberLiteralNode *codegen_num_lit = &node->codegen_node->data.num_lit_node;1756 NumberLiteralNode *codegen_num_lit = &node->codegen_node->data.num_lit_node;
1708 assert(!codegen_num_lit->resolved_type);1757 assert(!codegen_num_lit->resolved_type);
1709 codegen_num_lit->resolved_type = resolve_type_compatibility(g, block_context, node, expected_type, num_lit_type);1758 TypeTableEntry *after_implicit_cast_resolved_type =
1710 return codegen_num_lit->resolved_type;1759 resolve_type_compatibility(g, block_context, node, expected_type, num_lit_type);
1760 assert(codegen_num_lit->resolved_type ||
1761 after_implicit_cast_resolved_type->id == TypeTableEntryIdInvalid);
1762 return after_implicit_cast_resolved_type;
1711 } else {1763 } else {
1712 return num_lit_type;1764 return num_lit_type;
1713 }1765 }
...@@ -2174,6 +2226,10 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -2174,6 +2226,10 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
2174 return_type = g->builtin_types.entry_bool;2226 return_type = g->builtin_types.entry_bool;
2175 break;2227 break;
21762228
2229 case NodeTypeNullLiteral:
2230 return_type = analyze_null_literal_expr(g, import, context, expected_type, node);
2231 break;
2232
2177 case NodeTypeSymbol:2233 case NodeTypeSymbol:
2178 {2234 {
2179 return_type = analyze_variable_name(g, import, context, node, &node->data.symbol);2235 return_type = analyze_variable_name(g, import, context, node, &node->data.symbol);
...@@ -2491,6 +2547,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,...@@ -2491,6 +2547,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,
2491 case NodeTypeUnreachable:2547 case NodeTypeUnreachable:
2492 case NodeTypeVoid:2548 case NodeTypeVoid:
2493 case NodeTypeBoolLiteral:2549 case NodeTypeBoolLiteral:
2550 case NodeTypeNullLiteral:
2494 case NodeTypeSymbol:2551 case NodeTypeSymbol:
2495 case NodeTypeCastExpr:2552 case NodeTypeCastExpr:
2496 case NodeTypePrefixOpExpr:2553 case NodeTypePrefixOpExpr:
src/codegen.cpp+86-4
...@@ -613,6 +613,7 @@ static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g, AstNode *source_node,...@@ -613,6 +613,7 @@ static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g, AstNode *source_node,
613 case BinOpTypeAssign:613 case BinOpTypeAssign:
614 case BinOpTypeAssignBoolAnd:614 case BinOpTypeAssignBoolAnd:
615 case BinOpTypeAssignBoolOr:615 case BinOpTypeAssignBoolOr:
616 case BinOpTypeUnwrapMaybe:
616 zig_unreachable();617 zig_unreachable();
617 }618 }
618 zig_unreachable();619 zig_unreachable();
...@@ -814,6 +815,70 @@ static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {...@@ -814,6 +815,70 @@ static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {
814 return gen_assign_raw(g, node, node->data.bin_op_expr.bin_op, target_ref, value, op1_type, op2_type);815 return gen_assign_raw(g, node, node->data.bin_op_expr.bin_op, target_ref, value, op1_type, op2_type);
815}816}
816817
818static LLVMValueRef gen_unwrap_maybe(CodeGen *g, AstNode *node, LLVMValueRef maybe_struct_ref) {
819 add_debug_source_node(g, node);
820 LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_struct_ref, 0, "");
821 // TODO if it's a struct we might not want to load the pointer
822 return LLVMBuildLoad(g->builder, maybe_field_ptr, "");
823}
824
825static LLVMValueRef gen_unwrap_maybe_expr(CodeGen *g, AstNode *node) {
826 assert(node->type == NodeTypeBinOpExpr);
827 assert(node->data.bin_op_expr.bin_op == BinOpTypeUnwrapMaybe);
828
829 AstNode *op1_node = node->data.bin_op_expr.op1;
830 AstNode *op2_node = node->data.bin_op_expr.op2;
831
832 LLVMValueRef maybe_struct_ref = gen_expr(g, op1_node);
833
834 add_debug_source_node(g, node);
835 LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_struct_ref, 1, "");
836 LLVMValueRef cond_value = LLVMBuildLoad(g->builder, maybe_field_ptr, "");
837
838 LLVMBasicBlockRef non_null_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeNonNull");
839 LLVMBasicBlockRef null_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeNull");
840 LLVMBasicBlockRef end_block;
841
842 bool non_null_reachable = get_expr_type(op1_node)->id != TypeTableEntryIdUnreachable;
843 bool null_reachable = get_expr_type(op2_node)->id != TypeTableEntryIdUnreachable;
844 bool end_reachable = non_null_reachable || null_reachable;
845 if (end_reachable) {
846 end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeEnd");
847 }
848
849 LLVMBuildCondBr(g->builder, cond_value, non_null_block, null_block);
850
851 LLVMPositionBuilderAtEnd(g->builder, non_null_block);
852 LLVMValueRef non_null_result = gen_unwrap_maybe(g, op1_node, maybe_struct_ref);
853 if (non_null_reachable) {
854 add_debug_source_node(g, node);
855 LLVMBuildBr(g->builder, end_block);
856 }
857
858 LLVMPositionBuilderAtEnd(g->builder, null_block);
859 LLVMValueRef null_result = gen_expr(g, op2_node);
860 if (null_reachable) {
861 add_debug_source_node(g, node);
862 LLVMBuildBr(g->builder, end_block);
863 }
864
865 if (end_reachable) {
866 LLVMPositionBuilderAtEnd(g->builder, end_block);
867 if (null_reachable) {
868 add_debug_source_node(g, node);
869 LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMTypeOf(non_null_result), "");
870 LLVMValueRef incoming_values[2] = {non_null_result, null_result};
871 LLVMBasicBlockRef incoming_blocks[2] = {non_null_block, null_block};
872 LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2);
873 return phi;
874 } else {
875 return non_null_result;
876 }
877 }
878
879 return nullptr;
880}
881
817static LLVMValueRef gen_bin_op_expr(CodeGen *g, AstNode *node) {882static LLVMValueRef gen_bin_op_expr(CodeGen *g, AstNode *node) {
818 switch (node->data.bin_op_expr.bin_op) {883 switch (node->data.bin_op_expr.bin_op) {
819 case BinOpTypeInvalid:884 case BinOpTypeInvalid:
...@@ -843,6 +908,8 @@ static LLVMValueRef gen_bin_op_expr(CodeGen *g, AstNode *node) {...@@ -843,6 +908,8 @@ static LLVMValueRef gen_bin_op_expr(CodeGen *g, AstNode *node) {
843 case BinOpTypeCmpLessOrEq:908 case BinOpTypeCmpLessOrEq:
844 case BinOpTypeCmpGreaterOrEq:909 case BinOpTypeCmpGreaterOrEq:
845 return gen_cmp_expr(g, node);910 return gen_cmp_expr(g, node);
911 case BinOpTypeUnwrapMaybe:
912 return gen_unwrap_maybe_expr(g, node);
846 case BinOpTypeBinOr:913 case BinOpTypeBinOr:
847 case BinOpTypeBinXor:914 case BinOpTypeBinXor:
848 case BinOpTypeBinAnd:915 case BinOpTypeBinAnd:
...@@ -1124,6 +1191,22 @@ static LLVMValueRef gen_asm_expr(CodeGen *g, AstNode *node) {...@@ -1124,6 +1191,22 @@ static LLVMValueRef gen_asm_expr(CodeGen *g, AstNode *node) {
1124 return LLVMBuildCall(g->builder, asm_fn, param_values, input_and_output_count, "");1191 return LLVMBuildCall(g->builder, asm_fn, param_values, input_and_output_count, "");
1125}1192}
11261193
1194static LLVMValueRef gen_null_literal(CodeGen *g, AstNode *node) {
1195 assert(node->type == NodeTypeNullLiteral);
1196
1197 TypeTableEntry *type_entry = get_expr_type(node);
1198 assert(type_entry->id == TypeTableEntryIdMaybe);
1199
1200 LLVMValueRef tmp_struct_ptr = node->codegen_node->data.struct_val_expr_node.ptr;
1201
1202 add_debug_source_node(g, node);
1203 LLVMValueRef field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 1, "");
1204 LLVMValueRef null_value = LLVMConstNull(LLVMInt1Type());
1205 LLVMBuildStore(g->builder, null_value, field_ptr);
1206
1207 return tmp_struct_ptr;
1208}
1209
1127static LLVMValueRef gen_struct_val_expr(CodeGen *g, AstNode *node) {1210static LLVMValueRef gen_struct_val_expr(CodeGen *g, AstNode *node) {
1128 assert(node->type == NodeTypeStructValueExpr);1211 assert(node->type == NodeTypeStructValueExpr);
11291212
...@@ -1242,10 +1325,7 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa...@@ -1242,10 +1325,7 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa
1242 LLVMValueRef value;1325 LLVMValueRef value;
1243 if (unwrap_maybe) {1326 if (unwrap_maybe) {
1244 assert(var_decl->expr);1327 assert(var_decl->expr);
1245 add_debug_source_node(g, source_node);1328 value = gen_unwrap_maybe(g, source_node, *init_value);
1246 LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, *init_value, 0, "");
1247 // TODO if it's a struct we might not want to load the pointer
1248 value = LLVMBuildLoad(g->builder, maybe_field_ptr, "");
1249 } else {1329 } else {
1250 value = *init_value;1330 value = *init_value;
1251 }1331 }
...@@ -1375,6 +1455,8 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {...@@ -1375,6 +1455,8 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
1375 return LLVMConstAllOnes(LLVMInt1Type());1455 return LLVMConstAllOnes(LLVMInt1Type());
1376 else1456 else
1377 return LLVMConstNull(LLVMInt1Type());1457 return LLVMConstNull(LLVMInt1Type());
1458 case NodeTypeNullLiteral:
1459 return gen_null_literal(g, node);
1378 case NodeTypeIfBoolExpr:1460 case NodeTypeIfBoolExpr:
1379 return gen_if_bool_expr(g, node);1461 return gen_if_bool_expr(g, node);
1380 case NodeTypeIfVarExpr:1462 case NodeTypeIfVarExpr:
src/parser.cpp+40-3
...@@ -48,6 +48,7 @@ static const char *bin_op_str(BinOpType bin_op) {...@@ -48,6 +48,7 @@ static const char *bin_op_str(BinOpType bin_op) {
48 case BinOpTypeAssignBitOr: return "|=";48 case BinOpTypeAssignBitOr: return "|=";
49 case BinOpTypeAssignBoolAnd: return "&&=";49 case BinOpTypeAssignBoolAnd: return "&&=";
50 case BinOpTypeAssignBoolOr: return "||=";50 case BinOpTypeAssignBoolOr: return "||=";
51 case BinOpTypeUnwrapMaybe: return "??";
51 }52 }
52 zig_unreachable();53 zig_unreachable();
53}54}
...@@ -117,6 +118,8 @@ const char *node_type_str(NodeType node_type) {...@@ -117,6 +118,8 @@ const char *node_type_str(NodeType node_type) {
117 return "Void";118 return "Void";
118 case NodeTypeBoolLiteral:119 case NodeTypeBoolLiteral:
119 return "BoolLiteral";120 return "BoolLiteral";
121 case NodeTypeNullLiteral:
122 return "NullLiteral";
120 case NodeTypeIfBoolExpr:123 case NodeTypeIfBoolExpr:
121 return "IfBoolExpr";124 return "IfBoolExpr";
122 case NodeTypeIfVarExpr:125 case NodeTypeIfVarExpr:
...@@ -349,6 +352,9 @@ void ast_print(AstNode *node, int indent) {...@@ -349,6 +352,9 @@ void ast_print(AstNode *node, int indent) {
349 case NodeTypeBoolLiteral:352 case NodeTypeBoolLiteral:
350 fprintf(stderr, "%s '%s'\n", node_type_str(node->type), node->data.bool_literal ? "true" : "false");353 fprintf(stderr, "%s '%s'\n", node_type_str(node->type), node->data.bool_literal ? "true" : "false");
351 break;354 break;
355 case NodeTypeNullLiteral:
356 fprintf(stderr, "%s\n", node_type_str(node->type));
357 break;
352 case NodeTypeIfBoolExpr:358 case NodeTypeIfBoolExpr:
353 fprintf(stderr, "%s\n", node_type_str(node->type));359 fprintf(stderr, "%s\n", node_type_str(node->type));
354 if (node->data.if_bool_expr.condition)360 if (node->data.if_bool_expr.condition)
...@@ -1280,6 +1286,7 @@ static AstNode *ast_parse_struct_val_expr(ParseContext *pc, int *token_index) {...@@ -1280,6 +1286,7 @@ static AstNode *ast_parse_struct_val_expr(ParseContext *pc, int *token_index) {
12801286
1281/*1287/*
1282PrimaryExpression : token(Number) | token(String) | token(CharLiteral) | KeywordLiteral | GroupedExpression | Goto | token(Break) | token(Continue) | BlockExpression | token(Symbol) | StructValueExpression | CompilerFnType1288PrimaryExpression : token(Number) | token(String) | token(CharLiteral) | KeywordLiteral | GroupedExpression | Goto | token(Break) | token(Continue) | BlockExpression | token(Symbol) | StructValueExpression | CompilerFnType
1289KeywordLiteral : token(Unreachable) | token(Void) | token(True) | token(False) | token(Null)
1283*/1290*/
1284static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool mandatory) {1291static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool mandatory) {
1285 Token *token = &pc->tokens->at(*token_index);1292 Token *token = &pc->tokens->at(*token_index);
...@@ -1317,6 +1324,10 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool...@@ -1317,6 +1324,10 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
1317 node->data.bool_literal = false;1324 node->data.bool_literal = false;
1318 *token_index += 1;1325 *token_index += 1;
1319 return node;1326 return node;
1327 } else if (token->id == TokenIdKeywordNull) {
1328 AstNode *node = ast_create_node(pc, NodeTypeNullLiteral, token);
1329 *token_index += 1;
1330 return node;
1320 } else if (token->id == TokenIdSymbol) {1331 } else if (token->id == TokenIdSymbol) {
1321 Token *next_token = &pc->tokens->at(*token_index + 1);1332 Token *next_token = &pc->tokens->at(*token_index + 1);
13221333
...@@ -2045,19 +2056,45 @@ static BinOpType ast_parse_ass_op(ParseContext *pc, int *token_index, bool manda...@@ -2045,19 +2056,45 @@ static BinOpType ast_parse_ass_op(ParseContext *pc, int *token_index, bool manda
2045}2056}
20462057
2047/*2058/*
2048AssignmentExpression : BoolOrExpression AssignmentOperator BoolOrExpression | BoolOrExpression2059UnwrapMaybeExpression : BoolOrExpression token(DoubleQuestion) BoolOrExpression | BoolOrExpression
2049*/2060*/
2050static AstNode *ast_parse_ass_expr(ParseContext *pc, int *token_index, bool mandatory) {2061static AstNode *ast_parse_unwrap_maybe_expr(ParseContext *pc, int *token_index, bool mandatory) {
2051 AstNode *lhs = ast_parse_bool_or_expr(pc, token_index, mandatory);2062 AstNode *lhs = ast_parse_bool_or_expr(pc, token_index, mandatory);
2052 if (!lhs)2063 if (!lhs)
2053 return nullptr;2064 return nullptr;
20542065
2066 Token *token = &pc->tokens->at(*token_index);
2067
2068 if (token->id != TokenIdDoubleQuestion) {
2069 return lhs;
2070 }
2071
2072 *token_index += 1;
2073
2074 AstNode *rhs = ast_parse_bool_or_expr(pc, token_index, true);
2075
2076 AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token);
2077 node->data.bin_op_expr.op1 = lhs;
2078 node->data.bin_op_expr.bin_op = BinOpTypeUnwrapMaybe;
2079 node->data.bin_op_expr.op2 = rhs;
2080
2081 return node;
2082}
2083
2084/*
2085AssignmentExpression : UnwrapMaybeExpression AssignmentOperator UnwrapMaybeExpression | UnwrapMaybeExpression
2086*/
2087static AstNode *ast_parse_ass_expr(ParseContext *pc, int *token_index, bool mandatory) {
2088 AstNode *lhs = ast_parse_unwrap_maybe_expr(pc, token_index, mandatory);
2089 if (!lhs)
2090 return nullptr;
2091
2055 Token *token = &pc->tokens->at(*token_index);2092 Token *token = &pc->tokens->at(*token_index);
2056 BinOpType ass_op = ast_parse_ass_op(pc, token_index, false);2093 BinOpType ass_op = ast_parse_ass_op(pc, token_index, false);
2057 if (ass_op == BinOpTypeInvalid)2094 if (ass_op == BinOpTypeInvalid)
2058 return lhs;2095 return lhs;
20592096
2060 AstNode *rhs = ast_parse_bool_or_expr(pc, token_index, true);2097 AstNode *rhs = ast_parse_unwrap_maybe_expr(pc, token_index, true);
20612098
2062 AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token);2099 AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token);
2063 node->data.bin_op_expr.op1 = lhs;2100 node->data.bin_op_expr.op1 = lhs;
src/parser.hpp+2
...@@ -45,6 +45,7 @@ enum NodeType {...@@ -45,6 +45,7 @@ enum NodeType {
45 NodeTypeUse,45 NodeTypeUse,
46 NodeTypeVoid,46 NodeTypeVoid,
47 NodeTypeBoolLiteral,47 NodeTypeBoolLiteral,
48 NodeTypeNullLiteral,
48 NodeTypeIfBoolExpr,49 NodeTypeIfBoolExpr,
49 NodeTypeIfVarExpr,50 NodeTypeIfVarExpr,
50 NodeTypeWhileExpr,51 NodeTypeWhileExpr,
...@@ -161,6 +162,7 @@ enum BinOpType {...@@ -161,6 +162,7 @@ enum BinOpType {
161 BinOpTypeMult,162 BinOpTypeMult,
162 BinOpTypeDiv,163 BinOpTypeDiv,
163 BinOpTypeMod,164 BinOpTypeMod,
165 BinOpTypeUnwrapMaybe,
164};166};
165167
166struct AstNodeBinOpExpr {168struct AstNodeBinOpExpr {
src/tokenizer.cpp+9
...@@ -241,6 +241,8 @@ static void end_token(Tokenize *t) {...@@ -241,6 +241,8 @@ static void end_token(Tokenize *t) {
241 t->cur_tok->id = TokenIdKeywordContinue;241 t->cur_tok->id = TokenIdKeywordContinue;
242 } else if (mem_eql_str(token_mem, token_len, "break")) {242 } else if (mem_eql_str(token_mem, token_len, "break")) {
243 t->cur_tok->id = TokenIdKeywordBreak;243 t->cur_tok->id = TokenIdKeywordBreak;
244 } else if (mem_eql_str(token_mem, token_len, "null")) {
245 t->cur_tok->id = TokenIdKeywordNull;
244 }246 }
245247
246 t->cur_tok = nullptr;248 t->cur_tok = nullptr;
...@@ -418,6 +420,11 @@ void tokenize(Buf *buf, Tokenization *out) {...@@ -418,6 +420,11 @@ void tokenize(Buf *buf, Tokenization *out) {
418 break;420 break;
419 case TokenizeStateSawQuestionMark:421 case TokenizeStateSawQuestionMark:
420 switch (c) {422 switch (c) {
423 case '?':
424 t.cur_tok->id = TokenIdDoubleQuestion;
425 end_token(&t);
426 t.state = TokenizeStateStart;
427 break;
421 case '=':428 case '=':
422 t.cur_tok->id = TokenIdMaybeAssign;429 t.cur_tok->id = TokenIdMaybeAssign;
423 end_token(&t);430 end_token(&t);
...@@ -1002,6 +1009,7 @@ static const char * token_name(Token *token) {...@@ -1002,6 +1009,7 @@ static const char * token_name(Token *token) {
1002 case TokenIdKeywordWhile: return "While";1009 case TokenIdKeywordWhile: return "While";
1003 case TokenIdKeywordContinue: return "Continue";1010 case TokenIdKeywordContinue: return "Continue";
1004 case TokenIdKeywordBreak: return "Break";1011 case TokenIdKeywordBreak: return "Break";
1012 case TokenIdKeywordNull: return "Null";
1005 case TokenIdLParen: return "LParen";1013 case TokenIdLParen: return "LParen";
1006 case TokenIdRParen: return "RParen";1014 case TokenIdRParen: return "RParen";
1007 case TokenIdComma: return "Comma";1015 case TokenIdComma: return "Comma";
...@@ -1052,6 +1060,7 @@ static const char * token_name(Token *token) {...@@ -1052,6 +1060,7 @@ static const char * token_name(Token *token) {
1052 case TokenIdDot: return "Dot";1060 case TokenIdDot: return "Dot";
1053 case TokenIdEllipsis: return "Ellipsis";1061 case TokenIdEllipsis: return "Ellipsis";
1054 case TokenIdMaybe: return "Maybe";1062 case TokenIdMaybe: return "Maybe";
1063 case TokenIdDoubleQuestion: return "DoubleQuestion";
1055 case TokenIdMaybeAssign: return "MaybeAssign";1064 case TokenIdMaybeAssign: return "MaybeAssign";
1056 }1065 }
1057 return "(invalid token)";1066 return "(invalid token)";
src/tokenizer.hpp+2
...@@ -35,6 +35,7 @@ enum TokenId {...@@ -35,6 +35,7 @@ enum TokenId {
35 TokenIdKeywordWhile,35 TokenIdKeywordWhile,
36 TokenIdKeywordContinue,36 TokenIdKeywordContinue,
37 TokenIdKeywordBreak,37 TokenIdKeywordBreak,
38 TokenIdKeywordNull,
38 TokenIdLParen,39 TokenIdLParen,
39 TokenIdRParen,40 TokenIdRParen,
40 TokenIdComma,41 TokenIdComma,
...@@ -85,6 +86,7 @@ enum TokenId {...@@ -85,6 +86,7 @@ enum TokenId {
85 TokenIdDot,86 TokenIdDot,
86 TokenIdEllipsis,87 TokenIdEllipsis,
87 TokenIdMaybe,88 TokenIdMaybe,
89 TokenIdDoubleQuestion,
88 TokenIdMaybeAssign,90 TokenIdMaybeAssign,
89};91};
9092
std/std.zig+21
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1use "syscall.zig";1use "syscall.zig";
22
3const stdin_fileno : isize = 0;
3const stdout_fileno : isize = 1;4const stdout_fileno : isize = 1;
4const stderr_fileno : isize = 2;5const stderr_fileno : isize = 2;
56
...@@ -38,6 +39,26 @@ pub fn print_i64(x: i64) -> isize {...@@ -38,6 +39,26 @@ pub fn print_i64(x: i64) -> isize {
38 return write(stdout_fileno, buf.ptr, len);39 return write(stdout_fileno, buf.ptr, len);
39}40}
4041
42/*
43// TODO error handling
44pub fn readline(buf: []u8) -> ?[]u8 {
45 var index = 0;
46 while (index < buf.len) {
47 // TODO unknown size array indexing operator
48 const err = read(stdin_fileno, &buf.ptr[index], 1);
49 if (err != 0) {
50 return null;
51 }
52 // TODO unknown size array indexing operator
53 if (buf.ptr[index] == '\n') {
54 return buf[0...index + 1];
55 }
56 index += 1;
57 }
58 return null;
59}
60*/
61
41fn digit_to_char(digit: u64) -> u8 {62fn digit_to_char(digit: u64) -> u8 {
42 '0' + (digit as u8)63 '0' + (digit as u8)
43}64}
std/syscall.zig+5
...@@ -1,3 +1,4 @@...@@ -1,3 +1,4 @@
1const SYS_read : usize = 0;
1const SYS_write : usize = 1;2const SYS_write : usize = 1;
2const SYS_exit : usize = 60;3const SYS_exit : usize = 60;
3const SYS_getrandom : usize = 318;4const SYS_getrandom : usize = 318;
...@@ -16,6 +17,10 @@ fn syscall3(number: usize, arg1: usize, arg2: usize, arg3: usize) -> usize {...@@ -16,6 +17,10 @@ fn syscall3(number: usize, arg1: usize, arg2: usize, arg3: usize) -> usize {
16 : "rcx", "r11")17 : "rcx", "r11")
17}18}
1819
20pub fn read(fd: isize, buf: &u8, count: usize) -> isize {
21 syscall3(SYS_read, fd as usize, buf as usize, count) as isize
22}
23
19pub fn write(fd: isize, buf: &const u8, count: usize) -> isize {24pub fn write(fd: isize, buf: &const u8, count: usize) -> isize {
20 syscall3(SYS_write, fd as usize, buf as usize, count) as isize25 syscall3(SYS_write, fd as usize, buf as usize, count) as isize
21}26}
test/run_tests.cpp+18-1
...@@ -710,7 +710,7 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {...@@ -710,7 +710,7 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
710710
711 add_simple_case("maybe type", R"SOURCE(711 add_simple_case("maybe type", R"SOURCE(
712use "std.zig";712use "std.zig";
713pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {713pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
714 const x : ?bool = true;714 const x : ?bool = true;
715715
716 if (const y ?= x) {716 if (const y ?= x) {
...@@ -722,6 +722,23 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {...@@ -722,6 +722,23 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
722 } else {722 } else {
723 print_str("x is none\n");723 print_str("x is none\n");
724 }724 }
725
726 const next_x : ?i32 = null;
727
728 const z = next_x ?? 1234;
729
730 if (z != 1234) {
731 print_str("BAD\n");
732 }
733
734 const final_x : ?i32 = 13;
735
736 const num = final_x ?? unreachable;
737
738 if (num != 13) {
739 print_str("BAD\n");
740 }
741
725 return 0;742 return 0;
726}743}
727 )SOURCE", "x is true\n");744 )SOURCE", "x is true\n");