| author | |
| committer | |
| log | deb35868841fc3eb99228fe102a5b8ed1991d51f |
| tree | e84077cf298eec6f95cd3a75f1f05cd4cb0b501f |
| parent | c0dc0ca6c90649f157dfcb43c7ec69fa4b5f6b09 |
See #23
also make undefined constants use llvm undef value9 files changed, 54 insertions(+), 20 deletions(-)
README.md+2-2| ... | @@ -48,8 +48,8 @@ compromises backward compatibility. | ... | @@ -48,8 +48,8 @@ compromises backward compatibility. |
| 48 | ### Current Status | 48 | ### Current Status |
| 49 | 49 | ||
| 50 | * Have a look in the example/ folder to see some code examples. | 50 | * Have a look in the example/ folder to see some code examples. |
| 51 | * Basic language features available such as loops, inline assembly, | 51 | * Most language features are available, but many edge cases and errors are |
| 52 | expressions, literals, functions, importing, structs, tagged unions. | 52 | not yet implemented. |
| 53 | * Linux x86_64 is supported. | 53 | * Linux x86_64 is supported. |
| 54 | * Building for the native target is supported. | 54 | * Building for the native target is supported. |
| 55 | * Optimized machine code that Zig produces is indistinguishable from | 55 | * Optimized machine code that Zig produces is indistinguishable from |
doc/langref.md+2-2| ... | @@ -137,7 +137,7 @@ ContainerInitBody : list(StructLiteralField, ",") | list(Expression, ",") | ... | @@ -137,7 +137,7 @@ ContainerInitBody : list(StructLiteralField, ",") | list(Expression, ",") |
| 137 | 137 | ||
| 138 | StructLiteralField : "." "Symbol" "=" Expression | 138 | StructLiteralField : "." "Symbol" "=" Expression |
| 139 | 139 | ||
| 140 | PrefixOp : "!" | "-" | "~" | "*" | ("&" option("const")) | "?" | "%" | 140 | PrefixOp : "!" | "-" | "~" | "*" | ("&" option("const")) | "?" | "%" | "%%" |
| 141 | 141 | ||
| 142 | PrimaryExpression : "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | AsmExpression | ("error" "." "Symbol") | 142 | PrimaryExpression : "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | AsmExpression | ("error" "." "Symbol") |
| 143 | 143 | ||
| ... | @@ -154,7 +154,7 @@ KeywordLiteral : "true" | "false" | "null" | "break" | "continue" | "undefined" | ... | @@ -154,7 +154,7 @@ KeywordLiteral : "true" | "false" | "null" | "break" | "continue" | "undefined" |
| 154 | 154 | ||
| 155 | ``` | 155 | ``` |
| 156 | x() x[] x.y | 156 | x() x[] x.y |
| 157 | !x -x ~x *x &x ?x %x | 157 | !x -x ~x *x &x ?x %x %%x |
| 158 | x{} | 158 | x{} |
| 159 | * / % | 159 | * / % |
| 160 | + - | 160 | + - |
example/cat/main.zig+3-4| ... | @@ -5,7 +5,6 @@ import "std.zig"; | ... | @@ -5,7 +5,6 @@ import "std.zig"; |
| 5 | // Things to do to make this work: | 5 | // Things to do to make this work: |
| 6 | // * var args printing | 6 | // * var args printing |
| 7 | // * defer | 7 | // * defer |
| 8 | // * %% binary operator | ||
| 9 | // * %% prefix operator | 8 | // * %% prefix operator |
| 10 | // * cast err type to string | 9 | // * cast err type to string |
| 11 | // * string equality | 10 | // * string equality |
| ... | @@ -21,7 +20,7 @@ pub fn main(args: [][]u8) %void => { | ... | @@ -21,7 +20,7 @@ pub fn main(args: [][]u8) %void => { |
| 21 | return usage(exe); | 20 | return usage(exe); |
| 22 | } else { | 21 | } else { |
| 23 | var is: InputStream; | 22 | var is: InputStream; |
| 24 | is.open(arg, OpenReadOnly) %% (err) => { | 23 | is.open(arg, OpenReadOnly) %% |err| { |
| 25 | %%stderr.print("Unable to open file: {}", ([]u8])(err)); | 24 | %%stderr.print("Unable to open file: {}", ([]u8])(err)); |
| 26 | return err; | 25 | return err; |
| 27 | } | 26 | } |
| ... | @@ -45,7 +44,7 @@ fn cat_stream(is: InputStream) %void => { | ... | @@ -45,7 +44,7 @@ fn cat_stream(is: InputStream) %void => { |
| 45 | var buf: [1024 * 4]u8; | 44 | var buf: [1024 * 4]u8; |
| 46 | 45 | ||
| 47 | while (true) { | 46 | while (true) { |
| 48 | const bytes_read = is.read(buf) %% (err) => { | 47 | const bytes_read = is.read(buf) %% |err| { |
| 49 | %%stderr.print("Unable to read from stream: {}", ([]u8)(err)); | 48 | %%stderr.print("Unable to read from stream: {}", ([]u8)(err)); |
| 50 | return err; | 49 | return err; |
| 51 | } | 50 | } |
| ... | @@ -54,7 +53,7 @@ fn cat_stream(is: InputStream) %void => { | ... | @@ -54,7 +53,7 @@ fn cat_stream(is: InputStream) %void => { |
| 54 | break; | 53 | break; |
| 55 | } | 54 | } |
| 56 | 55 | ||
| 57 | stdout.write(buf[0...bytes_read]) %% (err) => { | 56 | stdout.write(buf[0...bytes_read]) %% |err| { |
| 58 | %%stderr.print("Unable to write to stdout: {}", ([]u8)(err)); | 57 | %%stderr.print("Unable to write to stdout: {}", ([]u8)(err)); |
| 59 | return err; | 58 | return err; |
| 60 | } | 59 | } |
example/guess_number/main.zig+8-8| ... | @@ -4,35 +4,35 @@ import "std.zig"; | ... | @@ -4,35 +4,35 @@ import "std.zig"; |
| 4 | import "rand.zig"; | 4 | import "rand.zig"; |
| 5 | 5 | ||
| 6 | pub fn main(args: [][]u8) %void => { | 6 | pub fn main(args: [][]u8) %void => { |
| 7 | stderr.print_str("Welcome to the Guess Number Game in Zig.\n"); | 7 | %%stderr.print_str("Welcome to the Guess Number Game in Zig.\n"); |
| 8 | 8 | ||
| 9 | var seed : u32; | 9 | var seed : u32; |
| 10 | const seed_bytes = (&u8)(&seed)[0...4]; | 10 | const seed_bytes = (&u8)(&seed)[0...4]; |
| 11 | os_get_random_bytes(seed_bytes) %% unreachable{}; | 11 | %%os_get_random_bytes(seed_bytes); |
| 12 | 12 | ||
| 13 | var rand = rand_new(seed); | 13 | var rand = rand_new(seed); |
| 14 | 14 | ||
| 15 | const answer = rand.range_u64(0, 100) + 1; | 15 | const answer = rand.range_u64(0, 100) + 1; |
| 16 | 16 | ||
| 17 | while (true) { | 17 | while (true) { |
| 18 | stderr.print_str("\nGuess a number between 1 and 100: "); | 18 | %%stderr.print_str("\nGuess a number between 1 and 100: "); |
| 19 | var line_buf : [20]u8; | 19 | var line_buf : [20]u8; |
| 20 | 20 | ||
| 21 | const line_len = stdin.read(line_buf) %% |err| { | 21 | const line_len = stdin.read(line_buf) %% |err| { |
| 22 | stderr.print_str("Unable to read from stdin.\n"); | 22 | %%stderr.print_str("Unable to read from stdin.\n"); |
| 23 | return err; | 23 | return err; |
| 24 | }; | 24 | }; |
| 25 | 25 | ||
| 26 | const guess = parse_u64(line_buf[0...line_len - 1], 10) %% { | 26 | const guess = parse_u64(line_buf[0...line_len - 1], 10) %% { |
| 27 | stderr.print_str("Invalid number.\n"); | 27 | %%stderr.print_str("Invalid number.\n"); |
| 28 | continue; | 28 | continue; |
| 29 | }; | 29 | }; |
| 30 | if (guess > answer) { | 30 | if (guess > answer) { |
| 31 | stderr.print_str("Guess lower.\n"); | 31 | %%stderr.print_str("Guess lower.\n"); |
| 32 | } else if (guess < answer) { | 32 | } else if (guess < answer) { |
| 33 | stderr.print_str("Guess higher.\n"); | 33 | %%stderr.print_str("Guess higher.\n"); |
| 34 | } else { | 34 | } else { |
| 35 | stderr.print_str("You win!\n"); | 35 | %%stderr.print_str("You win!\n"); |
| 36 | return; | 36 | return; |
| 37 | } | 37 | } |
| 38 | } | 38 | } |
src/all_types.hpp+1| ... | @@ -405,6 +405,7 @@ enum PrefixOp { | ... | @@ -405,6 +405,7 @@ enum PrefixOp { |
| 405 | PrefixOpDereference, | 405 | PrefixOpDereference, |
| 406 | PrefixOpMaybe, | 406 | PrefixOpMaybe, |
| 407 | PrefixOpError, | 407 | PrefixOpError, |
| 408 | PrefixOpUnwrapError, | ||
| 408 | }; | 409 | }; |
| 409 | 410 | ||
| 410 | struct AstNodePrefixOpExpr { | 411 | struct AstNodePrefixOpExpr { |
src/analyze.cpp+14| ... | @@ -3656,6 +3656,20 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo | ... | @@ -3656,6 +3656,20 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo |
| 3656 | } | 3656 | } |
| 3657 | 3657 | ||
| 3658 | } | 3658 | } |
| 3659 | case PrefixOpUnwrapError: | ||
| 3660 | { | ||
| 3661 | TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr, expr_node); | ||
| 3662 | |||
| 3663 | if (type_entry->id == TypeTableEntryIdInvalid) { | ||
| 3664 | return type_entry; | ||
| 3665 | } else if (type_entry->id == TypeTableEntryIdErrorUnion) { | ||
| 3666 | return type_entry->data.error.child_type; | ||
| 3667 | } else { | ||
| 3668 | add_node_error(g, expr_node, | ||
| 3669 | buf_sprintf("expected error type, got '%s'", buf_ptr(&type_entry->name))); | ||
| 3670 | return g->builtin_types.entry_invalid; | ||
| 3671 | } | ||
| 3672 | } | ||
| 3659 | } | 3673 | } |
| 3660 | zig_unreachable(); | 3674 | zig_unreachable(); |
| 3661 | } | 3675 | } |
src/codegen.cpp+19-1| ... | @@ -833,6 +833,24 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) { | ... | @@ -833,6 +833,24 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) { |
| 833 | { | 833 | { |
| 834 | zig_panic("TODO codegen PrefixOpError"); | 834 | zig_panic("TODO codegen PrefixOpError"); |
| 835 | } | 835 | } |
| 836 | case PrefixOpUnwrapError: | ||
| 837 | { | ||
| 838 | LLVMValueRef expr_val = gen_expr(g, expr_node); | ||
| 839 | TypeTableEntry *expr_type = get_expr_type(expr_node); | ||
| 840 | assert(expr_type->id == TypeTableEntryIdErrorUnion); | ||
| 841 | TypeTableEntry *child_type = expr_type->data.error.child_type; | ||
| 842 | // TODO in debug mode, put a panic here if the error is not 0 | ||
| 843 | if (child_type->size_in_bits > 0) { | ||
| 844 | LLVMValueRef child_val_ptr = LLVMBuildStructGEP(g->builder, expr_val, 1, ""); | ||
| 845 | if (handle_is_ptr(child_type)) { | ||
| 846 | return child_val_ptr; | ||
| 847 | } else { | ||
| 848 | return expr_val; | ||
| 849 | } | ||
| 850 | } else { | ||
| 851 | return nullptr; | ||
| 852 | } | ||
| 853 | } | ||
| 836 | } | 854 | } |
| 837 | zig_unreachable(); | 855 | zig_unreachable(); |
| 838 | } | 856 | } |
| ... | @@ -2219,7 +2237,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE | ... | @@ -2219,7 +2237,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE |
| 2219 | assert(const_val->ok); | 2237 | assert(const_val->ok); |
| 2220 | 2238 | ||
| 2221 | if (const_val->undef) { | 2239 | if (const_val->undef) { |
| 2222 | return LLVMConstNull(type_entry->type_ref); | 2240 | return LLVMGetUndef(type_entry->type_ref); |
| 2223 | } | 2241 | } |
| 2224 | 2242 | ||
| 2225 | if (type_entry->id == TypeTableEntryIdInt) { | 2243 | if (type_entry->id == TypeTableEntryIdInt) { |
src/parser.cpp+2| ... | @@ -64,6 +64,7 @@ static const char *prefix_op_str(PrefixOp prefix_op) { | ... | @@ -64,6 +64,7 @@ static const char *prefix_op_str(PrefixOp prefix_op) { |
| 64 | case PrefixOpDereference: return "*"; | 64 | case PrefixOpDereference: return "*"; |
| 65 | case PrefixOpMaybe: return "?"; | 65 | case PrefixOpMaybe: return "?"; |
| 66 | case PrefixOpError: return "%"; | 66 | case PrefixOpError: return "%"; |
| 67 | case PrefixOpUnwrapError: return "%%"; | ||
| 67 | } | 68 | } |
| 68 | zig_unreachable(); | 69 | zig_unreachable(); |
| 69 | } | 70 | } |
| ... | @@ -1664,6 +1665,7 @@ static PrefixOp tok_to_prefix_op(Token *token) { | ... | @@ -1664,6 +1665,7 @@ static PrefixOp tok_to_prefix_op(Token *token) { |
| 1664 | case TokenIdStar: return PrefixOpDereference; | 1665 | case TokenIdStar: return PrefixOpDereference; |
| 1665 | case TokenIdMaybe: return PrefixOpMaybe; | 1666 | case TokenIdMaybe: return PrefixOpMaybe; |
| 1666 | case TokenIdPercent: return PrefixOpError; | 1667 | case TokenIdPercent: return PrefixOpError; |
| 1668 | case TokenIdPercentPercent: return PrefixOpUnwrapError; | ||
| 1667 | case TokenIdBoolAnd: return PrefixOpAddressOf; | 1669 | case TokenIdBoolAnd: return PrefixOpAddressOf; |
| 1668 | default: return PrefixOpInvalid; | 1670 | default: return PrefixOpInvalid; |
| 1669 | } | 1671 | } |
std/bootstrap.zig+3-3| ... | @@ -3,9 +3,9 @@ import "syscall.zig"; | ... | @@ -3,9 +3,9 @@ import "syscall.zig"; |
| 3 | // The compiler treats this file special by implicitly importing the function `main` | 3 | // The compiler treats this file special by implicitly importing the function `main` |
| 4 | // from the root source file. | 4 | // from the root source file. |
| 5 | 5 | ||
| 6 | var argc: isize; | 6 | var argc: isize = undefined; |
| 7 | var argv: &&u8; | 7 | var argv: &&u8 = undefined; |
| 8 | var env: &&u8; | 8 | var env: &&u8 = undefined; |
| 9 | 9 | ||
| 10 | #attribute("naked") | 10 | #attribute("naked") |
| 11 | export fn _start() unreachable => { | 11 | export fn _start() unreachable => { |