Commit deb3586884

Andrew Kelley <superjoe30@gmail.com>
2016-01-25 23:45:05
implement %% prefix operator
See #23 also make undefined constants use llvm undef value
1 parent c0dc0ca
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{}
 * / %
 + -
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;
         }
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;
         }
     }
src/all_types.hpp
@@ -405,6 +405,7 @@ enum PrefixOp {
     PrefixOpDereference,
     PrefixOpMaybe,
     PrefixOpError,
+    PrefixOpUnwrapError,
 };
 
 struct AstNodePrefixOpExpr {
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();
 }
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) {
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;
     }
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 => {
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