diff --git a/README.md b/README.md index 9b6a72cc72..df069cf979 100644 --- a/README.md +++ b/README.md @@ -48,8 +48,8 @@ compromises backward compatibility. ### Current Status * Have a look in the example/ folder to see some code examples. - * Basic language features available such as loops, inline assembly, - expressions, literals, functions, importing, structs, tagged unions. + * Most language features are available, but many edge cases and errors are + not yet implemented. * Linux x86_64 is supported. * Building for the native target is supported. * Optimized machine code that Zig produces is indistinguishable from diff --git a/doc/langref.md b/doc/langref.md index f329d22b27..3747ca7113 100644 --- a/doc/langref.md +++ b/doc/langref.md @@ -137,7 +137,7 @@ ContainerInitBody : list(StructLiteralField, ",") | list(Expression, ",") StructLiteralField : "." "Symbol" "=" Expression -PrefixOp : "!" | "-" | "~" | "*" | ("&" option("const")) | "?" | "%" +PrefixOp : "!" | "-" | "~" | "*" | ("&" option("const")) | "?" | "%" | "%%" PrimaryExpression : "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | AsmExpression | ("error" "." "Symbol") @@ -154,7 +154,7 @@ KeywordLiteral : "true" | "false" | "null" | "break" | "continue" | "undefined" ``` x() x[] x.y -!x -x ~x *x &x ?x %x +!x -x ~x *x &x ?x %x %%x x{} * / % + - diff --git a/example/cat/main.zig b/example/cat/main.zig index 2651f0dc3f..e08db393d6 100644 --- a/example/cat/main.zig +++ b/example/cat/main.zig @@ -5,7 +5,6 @@ import "std.zig"; // Things to do to make this work: // * var args printing // * defer -// * %% binary operator // * %% prefix operator // * cast err type to string // * string equality @@ -21,7 +20,7 @@ pub fn main(args: [][]u8) %void => { return usage(exe); } else { var is: InputStream; - is.open(arg, OpenReadOnly) %% (err) => { + is.open(arg, OpenReadOnly) %% |err| { %%stderr.print("Unable to open file: {}", ([]u8])(err)); return err; } @@ -45,7 +44,7 @@ fn cat_stream(is: InputStream) %void => { var buf: [1024 * 4]u8; while (true) { - const bytes_read = is.read(buf) %% (err) => { + const bytes_read = is.read(buf) %% |err| { %%stderr.print("Unable to read from stream: {}", ([]u8)(err)); return err; } @@ -54,7 +53,7 @@ fn cat_stream(is: InputStream) %void => { break; } - stdout.write(buf[0...bytes_read]) %% (err) => { + stdout.write(buf[0...bytes_read]) %% |err| { %%stderr.print("Unable to write to stdout: {}", ([]u8)(err)); return err; } diff --git a/example/guess_number/main.zig b/example/guess_number/main.zig index 10295718df..8d4c7c8874 100644 --- a/example/guess_number/main.zig +++ b/example/guess_number/main.zig @@ -4,35 +4,35 @@ import "std.zig"; import "rand.zig"; pub fn main(args: [][]u8) %void => { - stderr.print_str("Welcome to the Guess Number Game in Zig.\n"); + %%stderr.print_str("Welcome to the Guess Number Game in Zig.\n"); var seed : u32; const seed_bytes = (&u8)(&seed)[0...4]; - os_get_random_bytes(seed_bytes) %% unreachable{}; + %%os_get_random_bytes(seed_bytes); var rand = rand_new(seed); const answer = rand.range_u64(0, 100) + 1; while (true) { - stderr.print_str("\nGuess a number between 1 and 100: "); + %%stderr.print_str("\nGuess a number between 1 and 100: "); var line_buf : [20]u8; const line_len = stdin.read(line_buf) %% |err| { - stderr.print_str("Unable to read from stdin.\n"); + %%stderr.print_str("Unable to read from stdin.\n"); return err; }; const guess = parse_u64(line_buf[0...line_len - 1], 10) %% { - stderr.print_str("Invalid number.\n"); + %%stderr.print_str("Invalid number.\n"); continue; }; if (guess > answer) { - stderr.print_str("Guess lower.\n"); + %%stderr.print_str("Guess lower.\n"); } else if (guess < answer) { - stderr.print_str("Guess higher.\n"); + %%stderr.print_str("Guess higher.\n"); } else { - stderr.print_str("You win!\n"); + %%stderr.print_str("You win!\n"); return; } } diff --git a/src/all_types.hpp b/src/all_types.hpp index 5218b59d0c..d7f633b765 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -405,6 +405,7 @@ enum PrefixOp { PrefixOpDereference, PrefixOpMaybe, PrefixOpError, + PrefixOpUnwrapError, }; struct AstNodePrefixOpExpr { diff --git a/src/analyze.cpp b/src/analyze.cpp index b43d7dfe30..9556b32089 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -3656,6 +3656,20 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo } } + case PrefixOpUnwrapError: + { + TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr, expr_node); + + if (type_entry->id == TypeTableEntryIdInvalid) { + return type_entry; + } else if (type_entry->id == TypeTableEntryIdErrorUnion) { + return type_entry->data.error.child_type; + } else { + add_node_error(g, expr_node, + buf_sprintf("expected error type, got '%s'", buf_ptr(&type_entry->name))); + return g->builtin_types.entry_invalid; + } + } } zig_unreachable(); } diff --git a/src/codegen.cpp b/src/codegen.cpp index b86f3b3b5a..6d26793013 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -833,6 +833,24 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) { { zig_panic("TODO codegen PrefixOpError"); } + case PrefixOpUnwrapError: + { + LLVMValueRef expr_val = gen_expr(g, expr_node); + TypeTableEntry *expr_type = get_expr_type(expr_node); + assert(expr_type->id == TypeTableEntryIdErrorUnion); + TypeTableEntry *child_type = expr_type->data.error.child_type; + // TODO in debug mode, put a panic here if the error is not 0 + if (child_type->size_in_bits > 0) { + LLVMValueRef child_val_ptr = LLVMBuildStructGEP(g->builder, expr_val, 1, ""); + if (handle_is_ptr(child_type)) { + return child_val_ptr; + } else { + return expr_val; + } + } else { + return nullptr; + } + } } zig_unreachable(); } @@ -2219,7 +2237,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE assert(const_val->ok); if (const_val->undef) { - return LLVMConstNull(type_entry->type_ref); + return LLVMGetUndef(type_entry->type_ref); } if (type_entry->id == TypeTableEntryIdInt) { diff --git a/src/parser.cpp b/src/parser.cpp index 425651a4a2..b34d76aba3 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -64,6 +64,7 @@ static const char *prefix_op_str(PrefixOp prefix_op) { case PrefixOpDereference: return "*"; case PrefixOpMaybe: return "?"; case PrefixOpError: return "%"; + case PrefixOpUnwrapError: return "%%"; } zig_unreachable(); } @@ -1664,6 +1665,7 @@ static PrefixOp tok_to_prefix_op(Token *token) { case TokenIdStar: return PrefixOpDereference; case TokenIdMaybe: return PrefixOpMaybe; case TokenIdPercent: return PrefixOpError; + case TokenIdPercentPercent: return PrefixOpUnwrapError; case TokenIdBoolAnd: return PrefixOpAddressOf; default: return PrefixOpInvalid; } diff --git a/std/bootstrap.zig b/std/bootstrap.zig index 10afb0addc..306da3529e 100644 --- a/std/bootstrap.zig +++ b/std/bootstrap.zig @@ -3,9 +3,9 @@ import "syscall.zig"; // The compiler treats this file special by implicitly importing the function `main` // from the root source file. -var argc: isize; -var argv: &&u8; -var env: &&u8; +var argc: isize = undefined; +var argv: &&u8 = undefined; +var env: &&u8 = undefined; #attribute("naked") export fn _start() unreachable => {