Commit 5dbc21b511

Andrew Kelley <superjoe30@gmail.com>
2016-04-08 22:13:33
update cat example, refactor std
partial implementation of @err_name
1 parent f6edba4
example/cat/main.zig
@@ -1,58 +1,61 @@
-export executable "cat";
+use @import("std");
 
-import "std.zig";
-
-// Things to do to make this work:
-// * var args printing
-// * cast err type to string
-// * string equality
+// TODO var args printing
 
 pub fn main(args: [][]u8) -> %void {
     const exe = args[0];
     var catted_anything = false;
-    for (arg, args[1...]) {
-        if (arg == "-") {
+    for (args[1...]) |arg| {
+        if (str_eql(arg, "-")) {
             catted_anything = true;
-            cat_stream(stdin) %% |err| return err;
+            cat_stream(io.stdin) %% |err| return err;
         } else if (arg[0] == '-') {
             return usage(exe);
         } else {
-            var is = input_stream_open(arg, OpenReadOnly) %% |err| {
-                %%stderr.print("Unable to open file: {}", ([]u8)(err));
+            var is = io.InStream.open(arg) %% |err| {
+                %%io.stderr.write("Unable to open file: ");
+                %%io.stderr.write(@err_name(err));
+                %%io.stderr.write("\n");
                 return err;
             };
-            defer is.close();
+            defer %%is.close();
 
             catted_anything = true;
             cat_stream(is) %% |err| return err;
         }
     }
     if (!catted_anything) {
-        cat_stream(stdin) %% |err| return err;
+        cat_stream(io.stdin) %% |err| return err;
     }
 }
 
 fn usage(exe: []u8) -> %void {
-    %%stderr.print("Usage: {} [FILE]...\n", exe);
+    %%io.stderr.write("Usage: ");
+    %%io.stderr.write(exe);
+    %%io.stderr.write(" [FILE]...\n");
     return error.Invalid;
 }
 
-fn cat_stream(is: InputStream) -> %void {
+fn cat_stream(is: io.InStream) -> %void {
     var buf: [1024 * 4]u8 = undefined;
 
     while (true) {
         const bytes_read = is.read(buf) %% |err| {
-            %%stderr.print("Unable to read from stream: {}", ([]u8)(err));
+            %%io.stderr.write("Unable to read from stream: ");
+            %%io.stderr.write(@err_name(err));
+            %%io.stderr.write("\n");
             return err;
-        }
+        };
 
         if (bytes_read == 0) {
             break;
         }
 
-        stdout.write(buf[0...bytes_read]) %% |err| {
-            %%stderr.print("Unable to write to stdout: {}", ([]u8)(err));
+        io.stdout.write(buf[0...bytes_read]) %% |err| {
+            %%io.stderr.write("Unable to write to stdout: ");
+            %%io.stderr.write(@err_name(err));
+            %%io.stderr.write("\n");
             return err;
-        }
+        };
     }
 }
src/all_types.hpp
@@ -1044,6 +1044,7 @@ enum BuiltinFnId {
     BuiltinFnIdClz,
     BuiltinFnIdImport,
     BuiltinFnIdCImport,
+    BuiltinFnIdErrName,
 };
 
 struct BuiltinFnEntry {
@@ -1177,7 +1178,7 @@ struct CodeGen {
     LLVMValueRef trap_fn_val;
     bool error_during_imports;
     uint32_t next_node_index;
-    uint32_t error_value_count;
+    ZigList<AstNode *> error_decls;
     TypeTableEntry *err_tag_type;
     LLVMValueRef int_overflow_fns[2][3][4]; // [0-signed,1-unsigned][0-add,1-sub,2-mul][0-8,1-16,2-32,3-64]
     LLVMValueRef int_builtin_fns[2][4]; // [0-ctz,1-clz][0-8,1-16,2-32,3-64]
@@ -1189,6 +1190,8 @@ struct CodeGen {
     uint32_t test_fn_count;
 
     bool check_unused;
+
+    bool generate_error_name_table;
 };
 
 struct VariableTableEntry {
src/analyze.cpp
@@ -1415,9 +1415,10 @@ static void preview_error_value_decl(CodeGen *g, AstNode *node) {
         // duplicate error definitions allowed and they get the same value
         err->value = existing_entry->value->value;
     } else {
-        assert(g->error_value_count < (((uint32_t)1) << (uint32_t)g->err_tag_type->data.integral.bit_count));
-        err->value = g->error_value_count;
-        g->error_value_count += 1;
+        int error_value_count = g->error_decls.length;
+        assert(error_value_count < (((uint32_t)1) << (uint32_t)g->err_tag_type->data.integral.bit_count));
+        err->value = error_value_count;
+        g->error_decls.append(node);
         g->error_table.put(&err->name, err);
     }
 
@@ -4084,7 +4085,7 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B
         wanted_type->id == TypeTableEntryIdInt)
     {
         BigNum bn;
-        bignum_init_unsigned(&bn, g->error_value_count);
+        bignum_init_unsigned(&bn, g->error_decls.length);
         if (bignum_fits_in_bits(&bn, wanted_type->data.integral.bit_count,
                     wanted_type->data.integral.is_signed))
         {
@@ -4242,6 +4243,25 @@ static TypeTableEntry *analyze_c_import(CodeGen *g, ImportTableEntry *parent_imp
     return resolve_expr_const_val_as_import(g, node, child_import);
 }
 
+static TypeTableEntry *analyze_err_name(CodeGen *g, ImportTableEntry *import,
+        BlockContext *context, AstNode *node)
+{
+    assert(node->type == NodeTypeFnCallExpr);
+
+    AstNode *err_value = node->data.fn_call_expr.params.at(0);
+    TypeTableEntry *resolved_type = analyze_expression(g, import, context,
+            g->builtin_types.entry_pure_error, err_value);
+
+    if (resolved_type->id == TypeTableEntryIdInvalid) {
+        return resolved_type;
+    }
+
+    g->generate_error_name_table = true;
+
+    TypeTableEntry *str_type = get_slice_type(g, g->builtin_types.entry_u8, true);
+    return str_type;
+}
+
 static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
         TypeTableEntry *expected_type, AstNode *node)
 {
@@ -4570,7 +4590,8 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
             return analyze_import(g, import, context, node);
         case BuiltinFnIdCImport:
             return analyze_c_import(g, import, context, node);
-
+        case BuiltinFnIdErrName:
+            return analyze_err_name(g, import, context, node);
     }
     zig_unreachable();
 }
src/codegen.cpp
@@ -65,7 +65,9 @@ CodeGen *codegen_create(Buf *root_source_dir, const ZigTarget *target) {
     g->generic_table.init(16);
     g->is_release_build = false;
     g->is_test_build = false;
-    g->error_value_count = 1;
+
+    // the error.Ok value
+    g->error_decls.append(nullptr);
 
     g->root_package = new_package(buf_ptr(root_source_dir), "");
     g->std_package = new_package(ZIG_STD_DIR, "index.zig");
@@ -328,6 +330,14 @@ static LLVMValueRef get_handle_value(CodeGen *g, AstNode *source_node, LLVMValue
     }
 }
 
+static LLVMValueRef gen_err_name(CodeGen *g, AstNode *node) {
+    zig_panic("TODO");
+    //assert(node->type == NodeTypeFnCallExpr);
+    //AstNode *err_val_node = node->data.fn_call_expr.params.at(0);
+    //LLVMValueRef err_val = gen_expr(g, err_val_node);
+    //arg
+}
+
 static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
     assert(node->type == NodeTypeFnCallExpr);
     AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr;
@@ -467,6 +477,8 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
             zig_unreachable();
         case BuiltinFnIdCompileVar:
             return nullptr;
+        case BuiltinFnIdErrName:
+            return gen_err_name(g, node);
     }
     zig_unreachable();
 }
@@ -3739,6 +3751,7 @@ static void define_builtin_fns(CodeGen *g) {
     create_builtin_fn_with_arg_count(g, BuiltinFnIdClz, "clz", 2);
     create_builtin_fn_with_arg_count(g, BuiltinFnIdImport, "import", 1);
     create_builtin_fn_with_arg_count(g, BuiltinFnIdCImport, "c_import", 1);
+    create_builtin_fn_with_arg_count(g, BuiltinFnIdErrName, "err_name", 1);
 }
 
 static void init(CodeGen *g, Buf *source_path) {
std/index.zig
@@ -2,3 +2,24 @@ pub const Rand = @import("rand.zig").Rand;
 pub const io = @import("io.zig");
 pub const os = @import("os.zig");
 pub const math = @import("math.zig");
+
+pub fn assert(b: bool) {
+    if (!b) unreachable{}
+}
+
+pub const str_eql = slice_eql(u8);
+
+pub fn slice_eql(T: type)(a: []T, b: []T) -> bool {
+    if (a.len != b.len) return false;
+    for (a) |item, index| {
+        if (b[index] != item) return false;
+    }
+    return true;
+}
+
+#attribute("test")
+fn string_equality() {
+    assert(str_eql("abcd", "abcd"));
+    assert(!str_eql("abcdef", "abZdef"));
+    assert(!str_eql("abcdefg", "abcdef"));
+}
std/io.zig
@@ -39,37 +39,51 @@ pub error NoSpaceLeft;
 pub error BadPerm;
 pub error PipeFail;
 pub error BadFd;
+pub error IsDir;
+pub error NotDir;
+pub error SymLinkLoop;
+pub error ProcessFdQuotaExceeded;
+pub error SystemFdQuotaExceeded;
+pub error NameTooLong;
+pub error NoDevice;
+pub error PathNotFound;
+pub error NoMem;
 
 const buffer_size = 4 * 1024;
 const max_u64_base10_digits = 20;
 const max_f64_digits = 65;
 
+pub const OpenRead     = 0b0001;
+pub const OpenWrite    = 0b0010;
+pub const OpenCreate   = 0b0100;
+pub const OpenTruncate = 0b1000;
+
 pub struct OutStream {
     fd: isize,
     buffer: [buffer_size]u8,
     index: isize,
 
-    pub fn print_str(os: &OutStream, str: []const u8) -> %isize {
-        var src_bytes_left = str.len;
-        var src_index: @typeof(str.len) = 0;
+    pub fn write(os: &OutStream, bytes: []const u8) -> %isize {
+        var src_bytes_left = bytes.len;
+        var src_index: @typeof(bytes.len) = 0;
         const dest_space_left = os.buffer.len - os.index;
 
         while (src_bytes_left > 0) {
             const copy_amt = math.min_isize(dest_space_left, src_bytes_left);
-            @memcpy(&os.buffer[os.index], &str[src_index], copy_amt);
+            @memcpy(&os.buffer[os.index], &bytes[src_index], copy_amt);
             os.index += copy_amt;
             if (os.index == os.buffer.len) {
                 %return os.flush();
             }
             src_bytes_left -= copy_amt;
         }
-        return str.len;
+        return bytes.len;
     }
 
     /// Prints a byte buffer, flushes the buffer, then returns the number of
     /// bytes printed. The "f" is for "flush".
     pub fn printf(os: &OutStream, str: []const u8) -> %isize {
-        const byte_count = %return os.print_str(str);
+        const byte_count = %return os.write(str);
         %return os.flush();
         return byte_count;
     }
@@ -138,6 +152,33 @@ pub struct OutStream {
 pub struct InStream {
     fd: isize,
 
+    pub fn open(path: []u8) -> %InStream {
+        const fd = linux.open(path, linux.O_LARGEFILE|linux.O_RDONLY, 0);
+        if (fd < 0) {
+            return switch (-fd) {
+                errno.EFAULT => unreachable{},
+                errno.EINVAL => unreachable{},
+                errno.EACCES => error.BadPerm,
+                errno.EFBIG, errno.EOVERFLOW => error.FileTooBig,
+                errno.EINTR => error.SigInterrupt,
+                errno.EISDIR => error.IsDir,
+                errno.ELOOP => error.SymLinkLoop,
+                errno.EMFILE => error.ProcessFdQuotaExceeded,
+                errno.ENAMETOOLONG => error.NameTooLong,
+                errno.ENFILE => error.SystemFdQuotaExceeded,
+                errno.ENODEV => error.NoDevice,
+                errno.ENOENT => error.PathNotFound,
+                errno.ENOMEM => error.NoMem,
+                errno.ENOSPC => error.NoSpaceLeft,
+                errno.ENOTDIR => error.NotDir,
+                errno.EPERM => error.BadPerm,
+                else => error.Unexpected,
+            }
+        }
+
+        return InStream { .fd = fd, };
+    }
+
     pub fn read(is: &InStream, buf: []u8) -> %isize {
         const amt_read = linux.read(is.fd, &buf[0], buf.len);
         if (amt_read < 0) {
std/linux.zig
@@ -1,86 +1,6 @@
-const SYS_read = switch (@compile_var("arch")) {
-    x86_64 => 0,
-    i386 => 3,
-    else => unreachable{},
-};
-const SYS_write = switch (@compile_var("arch")) {
-    x86_64 => 1,
-    i386 => 4,
-    else => unreachable{},
-};
-const SYS_open = switch (@compile_var("arch")) {
-    x86_64 => 2,
-    i386 => 5,
-    else => unreachable{},
-};
-const SYS_close = switch (@compile_var("arch")) {
-    x86_64 => 3,
-    i386 => 6,
-    else => unreachable{},
-};
-const SYS_creat = switch (@compile_var("arch")) {
-    x86_64 => 85,
-    i386 => 8,
-    else => unreachable{},
-};
-const SYS_lseek = switch (@compile_var("arch")) {
-    x86_64 => 8,
-    i386 => 19,
-    else => unreachable{},
-};
-const SYS_mmap = switch (@compile_var("arch")) {
-    x86_64 => 9,
-    i386 => 90,
-    else => unreachable{},
-};
-const SYS_munmap = switch (@compile_var("arch")) {
-    x86_64 => 11,
-    i386 => 91,
-    else => unreachable{},
-};
-const SYS_rt_sigprocmask = switch (@compile_var("arch")) {
-    x86_64 => 14,
-    i386 => 175,
-    else => unreachable{},
-};
-const SYS_exit = switch (@compile_var("arch")) {
-    x86_64 => 60,
-    i386 => 1,
-    else => unreachable{},
-};
-const SYS_kill = switch (@compile_var("arch")) {
-    x86_64 => 62,
-    i386 => 37,
-    else => unreachable{},
-};
-const SYS_getgid = switch (@compile_var("arch")) {
-    x86_64 => 104,
-    i386 => 47,
-    else => unreachable{},
-};
-const SYS_gettid = switch (@compile_var("arch")) {
-    x86_64 => 186,
-    i386 => 224,
-    else => unreachable{},
-};
-const SYS_tkill = switch (@compile_var("arch")) {
-    x86_64 => 200,
-    i386 => 238,
-    else => unreachable{},
-};
-const SYS_tgkill = switch (@compile_var("arch")) {
-    x86_64 => 234,
-    i386 => 270,
-    else => unreachable{},
-};
-const SYS_openat = switch (@compile_var("arch")) {
-    x86_64 => 257,
-    i386 => 295,
-    else => unreachable{},
-};
-const SYS_getrandom = switch (@compile_var("arch")) {
-    x86_64 => 318,
-    i386 => 355,
+const arch = switch (@compile_var("arch")) {
+    x86_64 => @import("linux_x86_64.zig"),
+    i386 => @import("linux_i386.zig"),
     else => unreachable{},
 };
 
@@ -95,15 +15,6 @@ pub const MMAP_MAP_PRIVATE = 2;
 pub const MMAP_MAP_FIXED =   16;
 pub const MMAP_MAP_ANON =    32;
 
-pub const O_RDONLY  = 0x0;
-pub const O_WRONLY  = 0x1;
-pub const O_RDWR    = 0x2;
-pub const O_CREAT   = 0x40;
-pub const O_EXCL    = 0x80;
-pub const O_TRUNC   = 0x200;
-pub const O_APPEND  = 0x400;
-pub const O_SYNC    = 0x101000;
-
 pub const SIGHUP    = 1;
 pub const SIGINT    = 2;
 pub const SIGQUIT   = 3;
@@ -139,209 +50,93 @@ pub const SIGPWR    = 30;
 pub const SIGSYS    = 31;
 pub const SIGUNUSED = SIGSYS;
 
+pub const O_RDONLY = 0o0;
+pub const O_WRONLY = 0o1;
+pub const O_RDWR   = 0o2;
+
+pub const O_CREAT = arch.O_CREAT;
+pub const O_EXCL = arch.O_EXCL;
+pub const O_NOCTTY = arch.O_NOCTTY;
+pub const O_TRUNC = arch.O_TRUNC;
+pub const O_APPEND = arch.O_APPEND;
+pub const O_NONBLOCK = arch.O_NONBLOCK;
+pub const O_DSYNC = arch.O_DSYNC;
+pub const O_SYNC = arch.O_SYNC;
+pub const O_RSYNC = arch.O_RSYNC;
+pub const O_DIRECTORY = arch.O_DIRECTORY;
+pub const O_NOFOLLOW = arch.O_NOFOLLOW;
+pub const O_CLOEXEC = arch.O_CLOEXEC;
+
+pub const O_ASYNC = arch.O_ASYNC;
+pub const O_DIRECT = arch.O_DIRECT;
+pub const O_LARGEFILE = arch.O_LARGEFILE;
+pub const O_NOATIME = arch.O_NOATIME;
+pub const O_PATH = arch.O_PATH;
+pub const O_TMPFILE = arch.O_TMPFILE;
+pub const O_NDELAY = arch.O_NDELAY;
+
 const SIG_BLOCK   = 0;
 const SIG_UNBLOCK = 1;
 const SIG_SETMASK = 2;
 
-const syscall0 = switch (@compile_var("arch")) {
-    x86_64 => x86_64_syscall0,
-    i386 => i386_syscall0,
-    else => unreachable{},
-};
-const syscall1 = switch (@compile_var("arch")) {
-    x86_64 => x86_64_syscall1,
-    i386 => i386_syscall1,
-    else => unreachable{},
-};
-const syscall2 = switch (@compile_var("arch")) {
-    x86_64 => x86_64_syscall2,
-    i386 => i386_syscall2,
-    else => unreachable{},
-};
-const syscall3 = switch (@compile_var("arch")) {
-    x86_64 => x86_64_syscall3,
-    i386 => i386_syscall3,
-    else => unreachable{},
-};
-const syscall4 = switch (@compile_var("arch")) {
-    x86_64 => x86_64_syscall4,
-    i386 => i386_syscall4,
-    else => unreachable{},
-};
-const syscall6 = switch (@compile_var("arch")) {
-    x86_64 => x86_64_syscall6,
-    i386 => i386_syscall6,
-    else => unreachable{},
-};
-
-fn x86_64_syscall0(number: isize) -> isize {
-    asm volatile ("syscall"
-        : [ret] "={rax}" (-> isize)
-        : [number] "{rax}" (number)
-        : "rcx", "r11")
-}
-
-fn x86_64_syscall1(number: isize, arg1: isize) -> isize {
-    asm volatile ("syscall"
-        : [ret] "={rax}" (-> isize)
-        : [number] "{rax}" (number),
-            [arg1] "{rdi}" (arg1)
-        : "rcx", "r11")
-}
-
-fn x86_64_syscall2(number: isize, arg1: isize, arg2: isize) -> isize {
-    asm volatile ("syscall"
-        : [ret] "={rax}" (-> isize)
-        : [number] "{rax}" (number),
-            [arg1] "{rdi}" (arg1),
-            [arg2] "{rsi}" (arg2)
-        : "rcx", "r11")
-}
-
-fn x86_64_syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize {
-    asm volatile ("syscall"
-        : [ret] "={rax}" (-> isize)
-        : [number] "{rax}" (number),
-            [arg1] "{rdi}" (arg1),
-            [arg2] "{rsi}" (arg2),
-            [arg3] "{rdx}" (arg3)
-        : "rcx", "r11")
-}
-
-fn x86_64_syscall4(number: isize, arg1: isize, arg2: isize, arg3: isize, arg4: isize) -> isize {
-    asm volatile ("syscall"
-        : [ret] "={rax}" (-> isize)
-        : [number] "{rax}" (number),
-            [arg1] "{rdi}" (arg1),
-            [arg2] "{rsi}" (arg2),
-            [arg3] "{rdx}" (arg3),
-            [arg4] "{r10}" (arg4)
-        : "rcx", "r11")
-}
-
-fn x86_64_syscall6(number: isize, arg1: isize, arg2: isize, arg3: isize, arg4: isize, arg5: isize, arg6: isize) -> isize {
-    asm volatile ("syscall"
-        : [ret] "={rax}" (-> isize)
-        : [number] "{rax}" (number),
-            [arg1] "{rdi}" (arg1),
-            [arg2] "{rsi}" (arg2),
-            [arg3] "{rdx}" (arg3),
-            [arg4] "{r10}" (arg4),
-            [arg5] "{r8}" (arg5),
-            [arg6] "{r9}" (arg6)
-        : "rcx", "r11")
-}
-
-fn i386_syscall0(number: isize) -> isize {
-    asm volatile ("int $0x80"
-        : [ret] "={eax}" (-> isize)
-        : [number] "{eax}" (number))
-}
-
-fn i386_syscall1(number: isize, arg1: isize) -> isize {
-    asm volatile ("int $0x80"
-        : [ret] "={eax}" (-> isize)
-        : [number] "{eax}" (number),
-            [arg1] "{ebx}" (arg1))
-}
-
-fn i386_syscall2(number: isize, arg1: isize, arg2: isize) -> isize {
-    asm volatile ("int $0x80"
-        : [ret] "={eax}" (-> isize)
-        : [number] "{eax}" (number),
-            [arg1] "{ebx}" (arg1),
-            [arg2] "{ecx}" (arg2))
-}
-
-fn i386_syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize {
-    asm volatile ("int $0x80"
-        : [ret] "={eax}" (-> isize)
-        : [number] "{eax}" (number),
-            [arg1] "{ebx}" (arg1),
-            [arg2] "{ecx}" (arg2),
-            [arg3] "{edx}" (arg3))
-}
-
-fn i386_syscall4(number: isize, arg1: isize, arg2: isize, arg3: isize, arg4: isize) -> isize {
-    asm volatile ("int $0x80"
-        : [ret] "={eax}" (-> isize)
-        : [number] "{eax}" (number),
-            [arg1] "{ebx}" (arg1),
-            [arg2] "{ecx}" (arg2),
-            [arg3] "{edx}" (arg3),
-            [arg4] "{esi}" (arg4))
-}
-
-fn i386_syscall6(number: isize, arg1: isize, arg2: isize, arg3: isize, arg4: isize, arg5: isize, arg6: isize) -> isize {
-    asm volatile ("int $0x80"
-        : [ret] "={eax}" (-> isize)
-        : [number] "{eax}" (number),
-            [arg1] "{ebx}" (arg1),
-            [arg2] "{ecx}" (arg2),
-            [arg3] "{edx}" (arg3),
-            [arg4] "{esi}" (arg4),
-            [arg5] "{edi}" (arg5),
-            [arg6] "{ebp}" (arg6))
-}
-
 pub fn mmap(address: ?&u8, length: isize, prot: isize, flags: isize, fd: isize, offset: isize) -> isize {
     // TODO ability to cast maybe pointer to isize
     const addr = if (const unwrapped ?= address) isize(unwrapped) else 0;
-    syscall6(SYS_mmap, addr, length, prot, flags, fd, offset)
+    arch.syscall6(arch.SYS_mmap, addr, length, prot, flags, fd, offset)
 }
 
 pub fn munmap(address: &u8, length: isize) -> isize {
-    syscall2(SYS_munmap, isize(address), length)
+    arch.syscall2(arch.SYS_munmap, isize(address), length)
 }
 
 pub fn read(fd: isize, buf: &u8, count: isize) -> isize {
-    syscall3(SYS_read, isize(fd), isize(buf), count)
+    arch.syscall3(arch.SYS_read, isize(fd), isize(buf), count)
 }
 
 pub fn write(fd: isize, buf: &const u8, count: isize) -> isize {
-    syscall3(SYS_write, isize(fd), isize(buf), count)
+    arch.syscall3(arch.SYS_write, isize(fd), isize(buf), count)
 }
 
 pub fn open(path: []u8, flags: isize, perm: isize) -> isize {
     var buf: [path.len + 1]u8 = undefined;
     @memcpy(&buf[0], &path[0], path.len);
     buf[path.len] = 0;
-    syscall3(SYS_open, isize(&buf[0]), flags, perm)
+    arch.syscall3(arch.SYS_open, isize(&buf[0]), flags, perm)
 }
 
 pub fn create(path: []u8, perm: isize) -> isize {
     var buf: [path.len + 1]u8 = undefined;
     @memcpy(&buf[0], &path[0], path.len);
     buf[path.len] = 0;
-    syscall2(SYS_creat, isize(&buf[0]), perm)
+    arch.syscall2(arch.SYS_creat, isize(&buf[0]), perm)
 }
 
 pub fn openat(dirfd: isize, path: []u8, flags: isize, mode: isize) -> isize {
     var buf: [path.len + 1]u8 = undefined;
     @memcpy(&buf[0], &path[0], path.len);
     buf[path.len] = 0;
-    syscall4(SYS_openat, dirfd, isize(&buf[0]), flags, mode)
+    arch.syscall4(arch.SYS_openat, dirfd, isize(&buf[0]), flags, mode)
 }
 
 pub fn close(fd: isize) -> isize {
-    syscall1(SYS_close, fd)
+    arch.syscall1(arch.SYS_close, fd)
 }
 
 pub fn lseek(fd: isize, offset: isize, ref_pos: isize) -> isize {
-    syscall3(SYS_lseek, fd, offset, ref_pos)
+    arch.syscall3(arch.SYS_lseek, fd, offset, ref_pos)
 }
 
 pub fn exit(status: i32) -> unreachable {
-    syscall1(SYS_exit, isize(status));
+    arch.syscall1(arch.SYS_exit, isize(status));
     unreachable{}
 }
 
 pub fn getrandom(buf: &u8, count: isize, flags: u32) -> isize {
-    syscall3(SYS_getrandom, isize(buf), count, isize(flags))
+    arch.syscall3(arch.SYS_getrandom, isize(buf), count, isize(flags))
 }
 
 pub fn kill(pid: i32, sig: i32) -> i32 {
-    i32(syscall2(SYS_kill, pid, sig))
+    i32(arch.syscall2(arch.SYS_kill, pid, sig))
 }
 
 const NSIG = 65;
@@ -352,20 +147,20 @@ const app_mask = []u8 { 0xff, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xff, };
 pub fn raise(sig: i32) -> i32 {
     var set: sigset_t = undefined;
     block_app_signals(&set);
-    const tid = i32(syscall0(SYS_gettid));
-    const ret = i32(syscall2(SYS_tkill, tid, sig));
+    const tid = i32(arch.syscall0(arch.SYS_gettid));
+    const ret = i32(arch.syscall2(arch.SYS_tkill, tid, sig));
     restore_signals(&set);
     return ret;
 }
 
 fn block_all_signals(set: &sigset_t) {
-    syscall4(SYS_rt_sigprocmask, SIG_BLOCK, isize(&all_mask), isize(set), NSIG/8);
+    arch.syscall4(arch.SYS_rt_sigprocmask, SIG_BLOCK, isize(&all_mask), isize(set), NSIG/8);
 }
 
 fn block_app_signals(set: &sigset_t) {
-    syscall4(SYS_rt_sigprocmask, SIG_BLOCK, isize(&app_mask), isize(set), NSIG/8);
+    arch.syscall4(arch.SYS_rt_sigprocmask, SIG_BLOCK, isize(&app_mask), isize(set), NSIG/8);
 }
 
 fn restore_signals(set: &sigset_t) {
-    syscall4(SYS_rt_sigprocmask, SIG_SETMASK, isize(set), 0, NSIG/8);
+    arch.syscall4(arch.SYS_rt_sigprocmask, SIG_SETMASK, isize(set), 0, NSIG/8);
 }
std/linux_i386.zig
@@ -0,0 +1,92 @@
+pub const O_CREAT        = 0o100;
+pub const O_EXCL         = 0o200;
+pub const O_NOCTTY       = 0o400;
+pub const O_TRUNC       = 0o1000;
+pub const O_APPEND      = 0o2000;
+pub const O_NONBLOCK    = 0o4000;
+pub const O_DSYNC      = 0o10000;
+pub const O_SYNC     = 0o4010000;
+pub const O_RSYNC    = 0o4010000;
+pub const O_DIRECTORY = 0o200000;
+pub const O_NOFOLLOW  = 0o400000;
+pub const O_CLOEXEC  = 0o2000000;
+
+pub const O_ASYNC      = 0o20000;
+pub const O_DIRECT     = 0o40000;
+pub const O_LARGEFILE = 0o100000;
+pub const O_NOATIME  = 0o1000000;
+pub const O_PATH    = 0o10000000;
+pub const O_TMPFILE = 0o20200000;
+pub const O_NDELAY =  O_NONBLOCK;
+
+pub const F_DUPFD  = 0;
+pub const F_GETFD  = 1;
+pub const F_SETFD  = 2;
+pub const F_GETFL  = 3;
+pub const F_SETFL  = 4;
+
+pub const F_SETOWN = 8;
+pub const F_GETOWN = 9;
+pub const F_SETSIG = 10;
+pub const F_GETSIG = 11;
+
+pub const F_GETLK = 12;
+pub const F_SETLK = 13;
+pub const F_SETLKW = 14;
+
+pub const F_SETOWN_EX = 15;
+pub const F_GETOWN_EX = 16;
+
+pub const F_GETOWNER_UIDS = 17;
+
+pub fn syscall0(number: isize) -> isize {
+    asm volatile ("int $0x80"
+        : [ret] "={eax}" (-> isize)
+        : [number] "{eax}" (number))
+}
+
+pub fn syscall1(number: isize, arg1: isize) -> isize {
+    asm volatile ("int $0x80"
+        : [ret] "={eax}" (-> isize)
+        : [number] "{eax}" (number),
+            [arg1] "{ebx}" (arg1))
+}
+
+pub fn syscall2(number: isize, arg1: isize, arg2: isize) -> isize {
+    asm volatile ("int $0x80"
+        : [ret] "={eax}" (-> isize)
+        : [number] "{eax}" (number),
+            [arg1] "{ebx}" (arg1),
+            [arg2] "{ecx}" (arg2))
+}
+
+pub fn syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize {
+    asm volatile ("int $0x80"
+        : [ret] "={eax}" (-> isize)
+        : [number] "{eax}" (number),
+            [arg1] "{ebx}" (arg1),
+            [arg2] "{ecx}" (arg2),
+            [arg3] "{edx}" (arg3))
+}
+
+pub fn syscall4(number: isize, arg1: isize, arg2: isize, arg3: isize, arg4: isize) -> isize {
+    asm volatile ("int $0x80"
+        : [ret] "={eax}" (-> isize)
+        : [number] "{eax}" (number),
+            [arg1] "{ebx}" (arg1),
+            [arg2] "{ecx}" (arg2),
+            [arg3] "{edx}" (arg3),
+            [arg4] "{esi}" (arg4))
+}
+
+pub fn syscall6(number: isize, arg1: isize, arg2: isize, arg3: isize, arg4: isize, arg5: isize, arg6: isize) -> isize {
+    asm volatile ("int $0x80"
+        : [ret] "={eax}" (-> isize)
+        : [number] "{eax}" (number),
+            [arg1] "{ebx}" (arg1),
+            [arg2] "{ecx}" (arg2),
+            [arg3] "{edx}" (arg3),
+            [arg4] "{esi}" (arg4),
+            [arg5] "{edi}" (arg5),
+            [arg6] "{ebp}" (arg6))
+}
std/linux_x86_64.zig
@@ -0,0 +1,116 @@
+pub const SYS_read = 0;
+pub const SYS_write = 1;
+pub const SYS_open = 2;
+pub const SYS_close = 3;
+pub const SYS_creat = 85;
+pub const SYS_lseek = 8;
+pub const SYS_mmap = 9;
+pub const SYS_munmap = 11;
+pub const SYS_rt_sigprocmask = 14;
+pub const SYS_exit = 60;
+pub const SYS_kill = 62;
+pub const SYS_getgid = 104;
+pub const SYS_gettid = 186;
+pub const SYS_tkill = 200;
+pub const SYS_tgkill = 234;
+pub const SYS_openat = 257;
+pub const SYS_getrandom = 318;
+
+pub const O_CREAT =        0o100;
+pub const O_EXCL =         0o200;
+pub const O_NOCTTY =       0o400;
+pub const O_TRUNC =       0o1000;
+pub const O_APPEND =      0o2000;
+pub const O_NONBLOCK =    0o4000;
+pub const O_DSYNC =      0o10000;
+pub const O_SYNC =     0o4010000;
+pub const O_RSYNC =    0o4010000;
+pub const O_DIRECTORY = 0o200000;
+pub const O_NOFOLLOW =  0o400000;
+pub const O_CLOEXEC =  0o2000000;
+
+pub const O_ASYNC      = 0o20000;
+pub const O_DIRECT     = 0o40000;
+pub const O_LARGEFILE       =  0;
+pub const O_NOATIME  = 0o1000000;
+pub const O_PATH    = 0o10000000;
+pub const O_TMPFILE = 0o20200000;
+pub const O_NDELAY  = O_NONBLOCK;
+
+pub const F_DUPFD = 0;
+pub const F_GETFD = 1;
+pub const F_SETFD = 2;
+pub const F_GETFL = 3;
+pub const F_SETFL = 4;
+
+pub const F_SETOWN = 8;
+pub const F_GETOWN = 9;
+pub const F_SETSIG = 10;
+pub const F_GETSIG = 11;
+
+pub const F_GETLK = 5;
+pub const F_SETLK = 6;
+pub const F_SETLKW = 7;
+
+pub const F_SETOWN_EX = 15;
+pub const F_GETOWN_EX = 16;
+
+pub const F_GETOWNER_UIDS = 17;
+
+pub fn syscall0(number: isize) -> isize {
+    asm volatile ("syscall"
+        : [ret] "={rax}" (-> isize)
+        : [number] "{rax}" (number)
+        : "rcx", "r11")
+}
+
+pub fn syscall1(number: isize, arg1: isize) -> isize {
+    asm volatile ("syscall"
+        : [ret] "={rax}" (-> isize)
+        : [number] "{rax}" (number),
+            [arg1] "{rdi}" (arg1)
+        : "rcx", "r11")
+}
+
+pub fn syscall2(number: isize, arg1: isize, arg2: isize) -> isize {
+    asm volatile ("syscall"
+        : [ret] "={rax}" (-> isize)
+        : [number] "{rax}" (number),
+            [arg1] "{rdi}" (arg1),
+            [arg2] "{rsi}" (arg2)
+        : "rcx", "r11")
+}
+
+pub fn syscall3(number: isize, arg1: isize, arg2: isize, arg3: isize) -> isize {
+    asm volatile ("syscall"
+        : [ret] "={rax}" (-> isize)
+        : [number] "{rax}" (number),
+            [arg1] "{rdi}" (arg1),
+            [arg2] "{rsi}" (arg2),
+            [arg3] "{rdx}" (arg3)
+        : "rcx", "r11")
+}
+
+pub fn syscall4(number: isize, arg1: isize, arg2: isize, arg3: isize, arg4: isize) -> isize {
+    asm volatile ("syscall"
+        : [ret] "={rax}" (-> isize)
+        : [number] "{rax}" (number),
+            [arg1] "{rdi}" (arg1),
+            [arg2] "{rsi}" (arg2),
+            [arg3] "{rdx}" (arg3),
+            [arg4] "{r10}" (arg4)
+        : "rcx", "r11")
+}
+
+pub fn syscall6(number: isize, arg1: isize, arg2: isize, arg3: isize, arg4: isize, arg5: isize, arg6: isize) -> isize {
+    asm volatile ("syscall"
+        : [ret] "={rax}" (-> isize)
+        : [number] "{rax}" (number),
+            [arg1] "{rdi}" (arg1),
+            [arg2] "{rsi}" (arg2),
+            [arg3] "{rdx}" (arg3),
+            [arg4] "{r10}" (arg4),
+            [arg5] "{r8}" (arg5),
+            [arg6] "{r9}" (arg6)
+        : "rcx", "r11")
+}
std/test_runner.zig
@@ -9,19 +9,19 @@ extern var zig_test_fn_list: []TestFn;
 
 pub fn run_tests() -> %void {
     for (zig_test_fn_list) |test_fn, i| {
-        %%io.stderr.print_str("Test ");
+        %%io.stderr.write("Test ");
         %%io.stderr.print_i64(i + 1);
-        %%io.stderr.print_str("/");
+        %%io.stderr.write("/");
         %%io.stderr.print_i64(zig_test_fn_list.len);
-        %%io.stderr.print_str(" ");
-        %%io.stderr.print_str(test_fn.name);
-        %%io.stderr.print_str("...");
+        %%io.stderr.write(" ");
+        %%io.stderr.write(test_fn.name);
+        %%io.stderr.write("...");
         %%io.stderr.flush();
 
         test_fn.func();
 
 
-        %%io.stderr.print_str("OK\n");
+        %%io.stderr.write("OK\n");
         %%io.stderr.flush();
     }
 }
test/self_hosted.zig
@@ -1,5 +1,5 @@
 // test std library
-const std = @import("std");
+use @import("std");
 
 #attribute("test")
 fn empty_function() {}
@@ -554,14 +554,3 @@ fn mem_alloc(T: type)(n: isize) -> %[]T {
 fn mem_free(T: type)(mem: []T) { }
 
 
-fn assert(b: bool) {
-    if (!b) unreachable{}
-}
-
-fn str_eql(s1: []u8, s2: []u8) -> bool {
-    if (s1.len != s2.len) return false;
-    for (s1) |c, i| {
-        if (s2[i] != c) return false;
-    }
-    return true;
-}
CMakeLists.txt
@@ -198,6 +198,8 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/errno.zig" DESTINATION "${ZIG_STD_DEST}")
 install(FILES "${CMAKE_SOURCE_DIR}/std/rand.zig" DESTINATION "${ZIG_STD_DEST}")
 install(FILES "${CMAKE_SOURCE_DIR}/std/math.zig" DESTINATION "${ZIG_STD_DEST}")
 install(FILES "${CMAKE_SOURCE_DIR}/std/index.zig" DESTINATION "${ZIG_STD_DEST}")
+install(FILES "${CMAKE_SOURCE_DIR}/std/linux_x86_64.zig" DESTINATION "${ZIG_STD_DEST}")
+install(FILES "${CMAKE_SOURCE_DIR}/std/linux_i386.zig" DESTINATION "${ZIG_STD_DEST}")
 
 add_executable(run_tests ${TEST_SOURCES})
 target_link_libraries(run_tests)