update cat example, refactor std

partial implementation of @err_name
This commit is contained in:
Andrew Kelley 2016-04-08 13:13:33 -07:00
parent f6edba4a87
commit 5dbc21b511
12 changed files with 398 additions and 302 deletions

View File

@ -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/rand.zig" DESTINATION "${ZIG_STD_DEST}")
install(FILES "${CMAKE_SOURCE_DIR}/std/math.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/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}) add_executable(run_tests ${TEST_SOURCES})
target_link_libraries(run_tests) target_link_libraries(run_tests)

View File

@ -1,58 +1,61 @@
export executable "cat"; use @import("std");
import "std.zig"; // TODO var args printing
// Things to do to make this work:
// * var args printing
// * cast err type to string
// * string equality
pub fn main(args: [][]u8) -> %void { pub fn main(args: [][]u8) -> %void {
const exe = args[0]; const exe = args[0];
var catted_anything = false; var catted_anything = false;
for (arg, args[1...]) { for (args[1...]) |arg| {
if (arg == "-") { if (str_eql(arg, "-")) {
catted_anything = true; catted_anything = true;
cat_stream(stdin) %% |err| return err; cat_stream(io.stdin) %% |err| return err;
} else if (arg[0] == '-') { } else if (arg[0] == '-') {
return usage(exe); return usage(exe);
} else { } else {
var is = input_stream_open(arg, OpenReadOnly) %% |err| { var is = io.InStream.open(arg) %% |err| {
%%stderr.print("Unable to open file: {}", ([]u8)(err)); %%io.stderr.write("Unable to open file: ");
%%io.stderr.write(@err_name(err));
%%io.stderr.write("\n");
return err; return err;
}; };
defer is.close(); defer %%is.close();
catted_anything = true; catted_anything = true;
cat_stream(is) %% |err| return err; cat_stream(is) %% |err| return err;
} }
} }
if (!catted_anything) { if (!catted_anything) {
cat_stream(stdin) %% |err| return err; cat_stream(io.stdin) %% |err| return err;
} }
} }
fn usage(exe: []u8) -> %void { 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; return error.Invalid;
} }
fn cat_stream(is: InputStream) -> %void { fn cat_stream(is: io.InStream) -> %void {
var buf: [1024 * 4]u8 = undefined; var buf: [1024 * 4]u8 = undefined;
while (true) { 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)); %%io.stderr.write("Unable to read from stream: ");
%%io.stderr.write(@err_name(err));
%%io.stderr.write("\n");
return err; return err;
} };
if (bytes_read == 0) { if (bytes_read == 0) {
break; break;
} }
stdout.write(buf[0...bytes_read]) %% |err| { io.stdout.write(buf[0...bytes_read]) %% |err| {
%%stderr.print("Unable to write to stdout: {}", ([]u8)(err)); %%io.stderr.write("Unable to write to stdout: ");
%%io.stderr.write(@err_name(err));
%%io.stderr.write("\n");
return err; return err;
} };
} }
} }

View File

@ -1044,6 +1044,7 @@ enum BuiltinFnId {
BuiltinFnIdClz, BuiltinFnIdClz,
BuiltinFnIdImport, BuiltinFnIdImport,
BuiltinFnIdCImport, BuiltinFnIdCImport,
BuiltinFnIdErrName,
}; };
struct BuiltinFnEntry { struct BuiltinFnEntry {
@ -1177,7 +1178,7 @@ struct CodeGen {
LLVMValueRef trap_fn_val; LLVMValueRef trap_fn_val;
bool error_during_imports; bool error_during_imports;
uint32_t next_node_index; uint32_t next_node_index;
uint32_t error_value_count; ZigList<AstNode *> error_decls;
TypeTableEntry *err_tag_type; 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_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] 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; uint32_t test_fn_count;
bool check_unused; bool check_unused;
bool generate_error_name_table;
}; };
struct VariableTableEntry { struct VariableTableEntry {

View File

@ -1415,9 +1415,10 @@ static void preview_error_value_decl(CodeGen *g, AstNode *node) {
// duplicate error definitions allowed and they get the same value // duplicate error definitions allowed and they get the same value
err->value = existing_entry->value->value; err->value = existing_entry->value->value;
} else { } else {
assert(g->error_value_count < (((uint32_t)1) << (uint32_t)g->err_tag_type->data.integral.bit_count)); int error_value_count = g->error_decls.length;
err->value = g->error_value_count; assert(error_value_count < (((uint32_t)1) << (uint32_t)g->err_tag_type->data.integral.bit_count));
g->error_value_count += 1; err->value = error_value_count;
g->error_decls.append(node);
g->error_table.put(&err->name, err); 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) wanted_type->id == TypeTableEntryIdInt)
{ {
BigNum bn; 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, if (bignum_fits_in_bits(&bn, wanted_type->data.integral.bit_count,
wanted_type->data.integral.is_signed)) 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); 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, static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
TypeTableEntry *expected_type, AstNode *node) 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); return analyze_import(g, import, context, node);
case BuiltinFnIdCImport: case BuiltinFnIdCImport:
return analyze_c_import(g, import, context, node); return analyze_c_import(g, import, context, node);
case BuiltinFnIdErrName:
return analyze_err_name(g, import, context, node);
} }
zig_unreachable(); zig_unreachable();
} }

View File

@ -65,7 +65,9 @@ CodeGen *codegen_create(Buf *root_source_dir, const ZigTarget *target) {
g->generic_table.init(16); g->generic_table.init(16);
g->is_release_build = false; g->is_release_build = false;
g->is_test_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->root_package = new_package(buf_ptr(root_source_dir), "");
g->std_package = new_package(ZIG_STD_DIR, "index.zig"); 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) { static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
assert(node->type == NodeTypeFnCallExpr); assert(node->type == NodeTypeFnCallExpr);
AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr; 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(); zig_unreachable();
case BuiltinFnIdCompileVar: case BuiltinFnIdCompileVar:
return nullptr; return nullptr;
case BuiltinFnIdErrName:
return gen_err_name(g, node);
} }
zig_unreachable(); 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, BuiltinFnIdClz, "clz", 2);
create_builtin_fn_with_arg_count(g, BuiltinFnIdImport, "import", 1); 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, BuiltinFnIdCImport, "c_import", 1);
create_builtin_fn_with_arg_count(g, BuiltinFnIdErrName, "err_name", 1);
} }
static void init(CodeGen *g, Buf *source_path) { static void init(CodeGen *g, Buf *source_path) {

View File

@ -2,3 +2,24 @@ pub const Rand = @import("rand.zig").Rand;
pub const io = @import("io.zig"); pub const io = @import("io.zig");
pub const os = @import("os.zig"); pub const os = @import("os.zig");
pub const math = @import("math.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"));
}

View File

@ -39,37 +39,51 @@ pub error NoSpaceLeft;
pub error BadPerm; pub error BadPerm;
pub error PipeFail; pub error PipeFail;
pub error BadFd; 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 buffer_size = 4 * 1024;
const max_u64_base10_digits = 20; const max_u64_base10_digits = 20;
const max_f64_digits = 65; const max_f64_digits = 65;
pub const OpenRead = 0b0001;
pub const OpenWrite = 0b0010;
pub const OpenCreate = 0b0100;
pub const OpenTruncate = 0b1000;
pub struct OutStream { pub struct OutStream {
fd: isize, fd: isize,
buffer: [buffer_size]u8, buffer: [buffer_size]u8,
index: isize, index: isize,
pub fn print_str(os: &OutStream, str: []const u8) -> %isize { pub fn write(os: &OutStream, bytes: []const u8) -> %isize {
var src_bytes_left = str.len; var src_bytes_left = bytes.len;
var src_index: @typeof(str.len) = 0; var src_index: @typeof(bytes.len) = 0;
const dest_space_left = os.buffer.len - os.index; const dest_space_left = os.buffer.len - os.index;
while (src_bytes_left > 0) { while (src_bytes_left > 0) {
const copy_amt = math.min_isize(dest_space_left, src_bytes_left); 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; os.index += copy_amt;
if (os.index == os.buffer.len) { if (os.index == os.buffer.len) {
%return os.flush(); %return os.flush();
} }
src_bytes_left -= copy_amt; src_bytes_left -= copy_amt;
} }
return str.len; return bytes.len;
} }
/// Prints a byte buffer, flushes the buffer, then returns the number of /// Prints a byte buffer, flushes the buffer, then returns the number of
/// bytes printed. The "f" is for "flush". /// bytes printed. The "f" is for "flush".
pub fn printf(os: &OutStream, str: []const u8) -> %isize { 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 os.flush();
return byte_count; return byte_count;
} }
@ -138,6 +152,33 @@ pub struct OutStream {
pub struct InStream { pub struct InStream {
fd: isize, 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 { pub fn read(is: &InStream, buf: []u8) -> %isize {
const amt_read = linux.read(is.fd, &buf[0], buf.len); const amt_read = linux.read(is.fd, &buf[0], buf.len);
if (amt_read < 0) { if (amt_read < 0) {

View File

@ -1,86 +1,6 @@
const SYS_read = switch (@compile_var("arch")) { const arch = switch (@compile_var("arch")) {
x86_64 => 0, x86_64 => @import("linux_x86_64.zig"),
i386 => 3, i386 => @import("linux_i386.zig"),
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,
else => unreachable{}, else => unreachable{},
}; };
@ -95,15 +15,6 @@ pub const MMAP_MAP_PRIVATE = 2;
pub const MMAP_MAP_FIXED = 16; pub const MMAP_MAP_FIXED = 16;
pub const MMAP_MAP_ANON = 32; 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 SIGHUP = 1;
pub const SIGINT = 2; pub const SIGINT = 2;
pub const SIGQUIT = 3; pub const SIGQUIT = 3;
@ -139,209 +50,93 @@ pub const SIGPWR = 30;
pub const SIGSYS = 31; pub const SIGSYS = 31;
pub const SIGUNUSED = SIGSYS; 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_BLOCK = 0;
const SIG_UNBLOCK = 1; const SIG_UNBLOCK = 1;
const SIG_SETMASK = 2; 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 { pub fn mmap(address: ?&u8, length: isize, prot: isize, flags: isize, fd: isize, offset: isize) -> isize {
// TODO ability to cast maybe pointer to isize // TODO ability to cast maybe pointer to isize
const addr = if (const unwrapped ?= address) isize(unwrapped) else 0; 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 { 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 { 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 { 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 { pub fn open(path: []u8, flags: isize, perm: isize) -> isize {
var buf: [path.len + 1]u8 = undefined; var buf: [path.len + 1]u8 = undefined;
@memcpy(&buf[0], &path[0], path.len); @memcpy(&buf[0], &path[0], path.len);
buf[path.len] = 0; 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 { pub fn create(path: []u8, perm: isize) -> isize {
var buf: [path.len + 1]u8 = undefined; var buf: [path.len + 1]u8 = undefined;
@memcpy(&buf[0], &path[0], path.len); @memcpy(&buf[0], &path[0], path.len);
buf[path.len] = 0; 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 { pub fn openat(dirfd: isize, path: []u8, flags: isize, mode: isize) -> isize {
var buf: [path.len + 1]u8 = undefined; var buf: [path.len + 1]u8 = undefined;
@memcpy(&buf[0], &path[0], path.len); @memcpy(&buf[0], &path[0], path.len);
buf[path.len] = 0; 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 { 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 { 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 { pub fn exit(status: i32) -> unreachable {
syscall1(SYS_exit, isize(status)); arch.syscall1(arch.SYS_exit, isize(status));
unreachable{} unreachable{}
} }
pub fn getrandom(buf: &u8, count: isize, flags: u32) -> isize { 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 { 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; 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 { pub fn raise(sig: i32) -> i32 {
var set: sigset_t = undefined; var set: sigset_t = undefined;
block_app_signals(&set); block_app_signals(&set);
const tid = i32(syscall0(SYS_gettid)); const tid = i32(arch.syscall0(arch.SYS_gettid));
const ret = i32(syscall2(SYS_tkill, tid, sig)); const ret = i32(arch.syscall2(arch.SYS_tkill, tid, sig));
restore_signals(&set); restore_signals(&set);
return ret; return ret;
} }
fn block_all_signals(set: &sigset_t) { 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) { 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) { 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);
} }

92
std/linux_i386.zig Normal file
View File

@ -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))
}

116
std/linux_x86_64.zig Normal file
View File

@ -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")
}

View File

@ -9,19 +9,19 @@ extern var zig_test_fn_list: []TestFn;
pub fn run_tests() -> %void { pub fn run_tests() -> %void {
for (zig_test_fn_list) |test_fn, i| { 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_i64(i + 1);
%%io.stderr.print_str("/"); %%io.stderr.write("/");
%%io.stderr.print_i64(zig_test_fn_list.len); %%io.stderr.print_i64(zig_test_fn_list.len);
%%io.stderr.print_str(" "); %%io.stderr.write(" ");
%%io.stderr.print_str(test_fn.name); %%io.stderr.write(test_fn.name);
%%io.stderr.print_str("..."); %%io.stderr.write("...");
%%io.stderr.flush(); %%io.stderr.flush();
test_fn.func(); test_fn.func();
%%io.stderr.print_str("OK\n"); %%io.stderr.write("OK\n");
%%io.stderr.flush(); %%io.stderr.flush();
} }
} }

View File

@ -1,5 +1,5 @@
// test std library // test std library
const std = @import("std"); use @import("std");
#attribute("test") #attribute("test")
fn empty_function() {} fn empty_function() {}
@ -554,14 +554,3 @@ fn mem_alloc(T: type)(n: isize) -> %[]T {
fn mem_free(T: type)(mem: []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;
}