| 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 | 48 | ### Current Status |
| 49 | 49 | |
| 50 | 50 | * Have a look in the example/ folder to see some code examples. |
| 51 | * Basic language features available such as loops, inline assembly, | |
| 52 | expressions, literals, functions, importing, structs, tagged unions. | |
| 51 | * Most language features are available, but many edge cases and errors are | |
| 52 | not yet implemented. | |
| 53 | 53 | * Linux x86_64 is supported. |
| 54 | 54 | * Building for the native target is supported. |
| 55 | 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 | 137 | |
| 138 | 138 | StructLiteralField : "." "Symbol" "=" Expression |
| 139 | 139 | |
| 140 | PrefixOp : "!" | "-" | "~" | "*" | ("&" option("const")) | "?" | "%" | |
| 140 | PrefixOp : "!" | "-" | "~" | "*" | ("&" option("const")) | "?" | "%" | "%%" | |
| 141 | 141 | |
| 142 | 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 | 154 | |
| 155 | 155 | ``` |
| 156 | 156 | x() x[] x.y |
| 157 | !x -x ~x *x &x ?x %x | |
| 157 | !x -x ~x *x &x ?x %x %%x | |
| 158 | 158 | x{} |
| 159 | 159 | * / % |
| 160 | 160 | + - |
example/cat/main.zig+3-4| ... | ... | @@ -5,7 +5,6 @@ import "std.zig"; |
| 5 | 5 | // Things to do to make this work: |
| 6 | 6 | // * var args printing |
| 7 | 7 | // * defer |
| 8 | // * %% binary operator | |
| 9 | 8 | // * %% prefix operator |
| 10 | 9 | // * cast err type to string |
| 11 | 10 | // * string equality |
| ... | ... | @@ -21,7 +20,7 @@ pub fn main(args: [][]u8) %void => { |
| 21 | 20 | return usage(exe); |
| 22 | 21 | } else { |
| 23 | 22 | var is: InputStream; |
| 24 | is.open(arg, OpenReadOnly) %% (err) => { | |
| 23 | is.open(arg, OpenReadOnly) %% |err| { | |
| 25 | 24 | %%stderr.print("Unable to open file: {}", ([]u8])(err)); |
| 26 | 25 | return err; |
| 27 | 26 | } |
| ... | ... | @@ -45,7 +44,7 @@ fn cat_stream(is: InputStream) %void => { |
| 45 | 44 | var buf: [1024 * 4]u8; |
| 46 | 45 | |
| 47 | 46 | while (true) { |
| 48 | const bytes_read = is.read(buf) %% (err) => { | |
| 47 | const bytes_read = is.read(buf) %% |err| { | |
| 49 | 48 | %%stderr.print("Unable to read from stream: {}", ([]u8)(err)); |
| 50 | 49 | return err; |
| 51 | 50 | } |
| ... | ... | @@ -54,7 +53,7 @@ fn cat_stream(is: InputStream) %void => { |
| 54 | 53 | break; |
| 55 | 54 | } |
| 56 | 55 | |
| 57 | stdout.write(buf[0...bytes_read]) %% (err) => { | |
| 56 | stdout.write(buf[0...bytes_read]) %% |err| { | |
| 58 | 57 | %%stderr.print("Unable to write to stdout: {}", ([]u8)(err)); |
| 59 | 58 | return err; |
| 60 | 59 | } |
example/guess_number/main.zig+8-8| ... | ... | @@ -4,35 +4,35 @@ import "std.zig"; |
| 4 | 4 | import "rand.zig"; |
| 5 | 5 | |
| 6 | 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 | 9 | var seed : u32; |
| 10 | 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 | 13 | var rand = rand_new(seed); |
| 14 | 14 | |
| 15 | 15 | const answer = rand.range_u64(0, 100) + 1; |
| 16 | 16 | |
| 17 | 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 | 19 | var line_buf : [20]u8; |
| 20 | 20 | |
| 21 | 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 | 23 | return err; |
| 24 | 24 | }; |
| 25 | 25 | |
| 26 | 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 | 28 | continue; |
| 29 | 29 | }; |
| 30 | 30 | if (guess > answer) { |
| 31 | stderr.print_str("Guess lower.\n"); | |
| 31 | %%stderr.print_str("Guess lower.\n"); | |
| 32 | 32 | } else if (guess < answer) { |
| 33 | stderr.print_str("Guess higher.\n"); | |
| 33 | %%stderr.print_str("Guess higher.\n"); | |
| 34 | 34 | } else { |
| 35 | stderr.print_str("You win!\n"); | |
| 35 | %%stderr.print_str("You win!\n"); | |
| 36 | 36 | return; |
| 37 | 37 | } |
| 38 | 38 | } |
src/all_types.hpp+1| ... | ... | @@ -405,6 +405,7 @@ enum PrefixOp { |
| 405 | 405 | PrefixOpDereference, |
| 406 | 406 | PrefixOpMaybe, |
| 407 | 407 | PrefixOpError, |
| 408 | PrefixOpUnwrapError, | |
| 408 | 409 | }; |
| 409 | 410 | |
| 410 | 411 | struct AstNodePrefixOpExpr { |
src/analyze.cpp+14| ... | ... | @@ -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 | 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 | 833 | { |
| 834 | 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 | 855 | zig_unreachable(); |
| 838 | 856 | } |
| ... | ... | @@ -2219,7 +2237,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE |
| 2219 | 2237 | assert(const_val->ok); |
| 2220 | 2238 | |
| 2221 | 2239 | if (const_val->undef) { |
| 2222 | return LLVMConstNull(type_entry->type_ref); | |
| 2240 | return LLVMGetUndef(type_entry->type_ref); | |
| 2223 | 2241 | } |
| 2224 | 2242 | |
| 2225 | 2243 | if (type_entry->id == TypeTableEntryIdInt) { |
src/parser.cpp+2| ... | ... | @@ -64,6 +64,7 @@ static const char *prefix_op_str(PrefixOp prefix_op) { |
| 64 | 64 | case PrefixOpDereference: return "*"; |
| 65 | 65 | case PrefixOpMaybe: return "?"; |
| 66 | 66 | case PrefixOpError: return "%"; |
| 67 | case PrefixOpUnwrapError: return "%%"; | |
| 67 | 68 | } |
| 68 | 69 | zig_unreachable(); |
| 69 | 70 | } |
| ... | ... | @@ -1664,6 +1665,7 @@ static PrefixOp tok_to_prefix_op(Token *token) { |
| 1664 | 1665 | case TokenIdStar: return PrefixOpDereference; |
| 1665 | 1666 | case TokenIdMaybe: return PrefixOpMaybe; |
| 1666 | 1667 | case TokenIdPercent: return PrefixOpError; |
| 1668 | case TokenIdPercentPercent: return PrefixOpUnwrapError; | |
| 1667 | 1669 | case TokenIdBoolAnd: return PrefixOpAddressOf; |
| 1668 | 1670 | default: return PrefixOpInvalid; |
| 1669 | 1671 | } |
std/bootstrap.zig+3-3| ... | ... | @@ -3,9 +3,9 @@ import "syscall.zig"; |
| 3 | 3 | // The compiler treats this file special by implicitly importing the function `main` |
| 4 | 4 | // from the root source file. |
| 5 | 5 | |
| 6 | var argc: isize; | |
| 7 | var argv: &&u8; | |
| 8 | var env: &&u8; | |
| 6 | var argc: isize = undefined; | |
| 7 | var argv: &&u8 = undefined; | |
| 8 | var env: &&u8 = undefined; | |
| 9 | 9 | |
| 10 | 10 | #attribute("naked") |
| 11 | 11 | export fn _start() unreachable => { |