| author | |
| committer | |
| log | 72fb2443e0e5dd0c8c3a0265428832796b4ff548 |
| tree | dd4cfda1e44784a80538ccd3c6d776c3fb664651 |
| parent | b46344fd01db28384b51d9898ef25c4825bb19b0 |
closes #30011 files changed, 381 insertions(+), 374 deletions(-)
CMakeLists.txt+1| ... | @@ -223,6 +223,7 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/list.zig" DESTINATION "${ZIG_STD_DEST}") | ... | @@ -223,6 +223,7 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/list.zig" DESTINATION "${ZIG_STD_DEST}") |
| 223 | install(FILES "${CMAKE_SOURCE_DIR}/std/math.zig" DESTINATION "${ZIG_STD_DEST}") | 223 | install(FILES "${CMAKE_SOURCE_DIR}/std/math.zig" DESTINATION "${ZIG_STD_DEST}") |
| 224 | install(FILES "${CMAKE_SOURCE_DIR}/std/mem.zig" DESTINATION "${ZIG_STD_DEST}") | 224 | install(FILES "${CMAKE_SOURCE_DIR}/std/mem.zig" DESTINATION "${ZIG_STD_DEST}") |
| 225 | install(FILES "${CMAKE_SOURCE_DIR}/std/net.zig" DESTINATION "${ZIG_STD_DEST}") | 225 | install(FILES "${CMAKE_SOURCE_DIR}/std/net.zig" DESTINATION "${ZIG_STD_DEST}") |
| 226 | install(FILES "${CMAKE_SOURCE_DIR}/std/os/child_process.zig" DESTINATION "${ZIG_STD_DEST}/os") | ||
| 226 | install(FILES "${CMAKE_SOURCE_DIR}/std/os/darwin.zig" DESTINATION "${ZIG_STD_DEST}/os") | 227 | install(FILES "${CMAKE_SOURCE_DIR}/std/os/darwin.zig" DESTINATION "${ZIG_STD_DEST}/os") |
| 227 | install(FILES "${CMAKE_SOURCE_DIR}/std/os/darwin_x86_64.zig" DESTINATION "${ZIG_STD_DEST}/os") | 228 | install(FILES "${CMAKE_SOURCE_DIR}/std/os/darwin_x86_64.zig" DESTINATION "${ZIG_STD_DEST}/os") |
| 228 | install(FILES "${CMAKE_SOURCE_DIR}/std/os/errno.zig" DESTINATION "${ZIG_STD_DEST}/os") | 229 | install(FILES "${CMAKE_SOURCE_DIR}/std/os/errno.zig" DESTINATION "${ZIG_STD_DEST}/os") |
example/cat/main.zig+9-7| ... | @@ -1,23 +1,25 @@ | ... | @@ -1,23 +1,25 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const io = std.io; | 2 | const io = std.io; |
| 3 | const mem = std.mem; | 3 | const mem = std.mem; |
| 4 | const os = std.os; | ||
| 4 | 5 | ||
| 5 | pub fn main(args: [][]u8) -> %void { | 6 | pub fn main() -> %void { |
| 6 | const exe = args[0]; | 7 | const exe = os.args.at(0); |
| 7 | var catted_anything = false; | 8 | var catted_anything = false; |
| 8 | for (args[1...]) |arg| { | 9 | var arg_i: usize = 1; |
| 10 | while (arg_i < os.args.count(); arg_i += 1) { | ||
| 11 | const arg = os.args.at(arg_i); | ||
| 9 | if (mem.eql(u8, arg, "-")) { | 12 | if (mem.eql(u8, arg, "-")) { |
| 10 | catted_anything = true; | 13 | catted_anything = true; |
| 11 | %return cat_stream(&io.stdin); | 14 | %return cat_stream(&io.stdin); |
| 12 | } else if (arg[0] == '-') { | 15 | } else if (arg[0] == '-') { |
| 13 | return usage(exe); | 16 | return usage(exe); |
| 14 | } else { | 17 | } else { |
| 15 | var is: io.InStream = undefined; | 18 | var is = io.InStream.open(arg, null) %% |err| { |
| 16 | is.open(arg) %% |err| { | ||
| 17 | %%io.stderr.printf("Unable to open file: {}\n", @errorName(err)); | 19 | %%io.stderr.printf("Unable to open file: {}\n", @errorName(err)); |
| 18 | return err; | 20 | return err; |
| 19 | }; | 21 | }; |
| 20 | defer %%is.close(); | 22 | defer is.close(); |
| 21 | 23 | ||
| 22 | catted_anything = true; | 24 | catted_anything = true; |
| 23 | %return cat_stream(&is); | 25 | %return cat_stream(&is); |
| ... | @@ -29,7 +31,7 @@ pub fn main(args: [][]u8) -> %void { | ... | @@ -29,7 +31,7 @@ pub fn main(args: [][]u8) -> %void { |
| 29 | %return io.stdout.flush(); | 31 | %return io.stdout.flush(); |
| 30 | } | 32 | } |
| 31 | 33 | ||
| 32 | fn usage(exe: []u8) -> %void { | 34 | fn usage(exe: []const u8) -> %void { |
| 33 | %%io.stderr.printf("Usage: {} [FILE]...\n", exe); | 35 | %%io.stderr.printf("Usage: {} [FILE]...\n", exe); |
| 34 | return error.Invalid; | 36 | return error.Invalid; |
| 35 | } | 37 | } |
example/guess_number/main.zig+1-1| ... | @@ -4,7 +4,7 @@ const fmt = std.fmt; | ... | @@ -4,7 +4,7 @@ const fmt = std.fmt; |
| 4 | const Rand = std.rand.Rand; | 4 | const Rand = std.rand.Rand; |
| 5 | const os = std.os; | 5 | const os = std.os; |
| 6 | 6 | ||
| 7 | pub fn main(args: [][]u8) -> %void { | 7 | pub fn main() -> %void { |
| 8 | %%io.stdout.printf("Welcome to the Guess Number Game in Zig.\n"); | 8 | %%io.stdout.printf("Welcome to the Guess Number Game in Zig.\n"); |
| 9 | 9 | ||
| 10 | var seed_bytes: [@sizeOf(usize)]u8 = undefined; | 10 | var seed_bytes: [@sizeOf(usize)]u8 = undefined; |
example/hello_world/hello.zig+1-1| ... | @@ -1,5 +1,5 @@ | ... | @@ -1,5 +1,5 @@ |
| 1 | const io = @import("std").io; | 1 | const io = @import("std").io; |
| 2 | 2 | ||
| 3 | pub fn main(args: [][]u8) -> %void { | 3 | pub fn main() -> %void { |
| 4 | %%io.stdout.printf("Hello, world!\n"); | 4 | %%io.stdout.printf("Hello, world!\n"); |
| 5 | } | 5 | } |
std/build.zig+6-3| ... | @@ -39,11 +39,13 @@ pub const Builder = struct { | ... | @@ -39,11 +39,13 @@ pub const Builder = struct { |
| 39 | return exe; | 39 | return exe; |
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | pub fn make(self: &Builder, cli_args: []const []const u8) -> %void { | 42 | pub fn make(self: &Builder, leftover_arg_index: usize) -> %void { |
| 43 | var env_map = %return os.getEnvMap(self.allocator); | 43 | var env_map = %return os.getEnvMap(self.allocator); |
| 44 | 44 | ||
| 45 | var verbose = false; | 45 | var verbose = false; |
| 46 | for (cli_args) |arg| { | 46 | var arg_i: usize = leftover_arg_index; |
| 47 | while (arg_i < os.args.count(); arg_i += 1) { | ||
| 48 | const arg = os.args.at(arg_i); | ||
| 47 | if (mem.eql(u8, arg, "--verbose")) { | 49 | if (mem.eql(u8, arg, "--verbose")) { |
| 48 | verbose = true; | 50 | verbose = true; |
| 49 | } else { | 51 | } else { |
| ... | @@ -95,7 +97,8 @@ pub const Builder = struct { | ... | @@ -95,7 +97,8 @@ pub const Builder = struct { |
| 95 | } | 97 | } |
| 96 | 98 | ||
| 97 | printInvocation(self.zig_exe, zig_args); | 99 | printInvocation(self.zig_exe, zig_args); |
| 98 | var child = %return os.ChildProcess.spawn(self.zig_exe, zig_args.toSliceConst(), env_map, | 100 | // TODO issue #301 |
| 101 | var child = %return os.ChildProcess.spawn(self.zig_exe, zig_args.toSliceConst(), &env_map, | ||
| 99 | StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, self.allocator); | 102 | StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, self.allocator); |
| 100 | const term = %return child.wait(); | 103 | const term = %return child.wait(); |
| 101 | switch (term) { | 104 | switch (term) { |
std/os/child_process.zig created+280| ... | @@ -0,0 +1,280 @@ | ||
| 1 | const io = @import("../io.zig"); | ||
| 2 | const os = @import("index.zig"); | ||
| 3 | const posix = os.posix; | ||
| 4 | const mem = @import("../mem.zig"); | ||
| 5 | const Allocator = mem.Allocator; | ||
| 6 | const errno = @import("errno.zig"); | ||
| 7 | const debug = @import("../debug.zig"); | ||
| 8 | const assert = debug.assert; | ||
| 9 | |||
| 10 | pub const ChildProcess = struct { | ||
| 11 | pid: i32, | ||
| 12 | err_pipe: [2]i32, | ||
| 13 | |||
| 14 | stdin: ?io.OutStream, | ||
| 15 | stdout: ?io.InStream, | ||
| 16 | stderr: ?io.InStream, | ||
| 17 | |||
| 18 | pub const Term = enum { | ||
| 19 | Clean: i32, | ||
| 20 | Signal: i32, | ||
| 21 | Stopped: i32, | ||
| 22 | Unknown: i32, | ||
| 23 | }; | ||
| 24 | |||
| 25 | pub const StdIo = enum { | ||
| 26 | Inherit, | ||
| 27 | Ignore, | ||
| 28 | Pipe, | ||
| 29 | Close, | ||
| 30 | }; | ||
| 31 | |||
| 32 | pub fn spawn(exe_path: []const u8, args: []const []const u8, env_map: &const os.EnvMap, | ||
| 33 | stdin: StdIo, stdout: StdIo, stderr: StdIo, allocator: &Allocator) -> %ChildProcess | ||
| 34 | { | ||
| 35 | switch (@compileVar("os")) { | ||
| 36 | Os.linux, Os.macosx, Os.ios, Os.darwin => { | ||
| 37 | return spawnPosix(exe_path, args, env_map, stdin, stdout, stderr, allocator); | ||
| 38 | }, | ||
| 39 | else => @compileError("Unsupported OS"), | ||
| 40 | } | ||
| 41 | } | ||
| 42 | |||
| 43 | pub fn wait(self: &ChildProcess) -> %Term { | ||
| 44 | defer { | ||
| 45 | os.posixClose(self.err_pipe[0]); | ||
| 46 | os.posixClose(self.err_pipe[1]); | ||
| 47 | }; | ||
| 48 | |||
| 49 | var status: i32 = undefined; | ||
| 50 | while (true) { | ||
| 51 | const err = posix.getErrno(posix.waitpid(self.pid, &status, 0)); | ||
| 52 | if (err > 0) { | ||
| 53 | switch (err) { | ||
| 54 | errno.EINVAL, errno.ECHILD => unreachable, | ||
| 55 | errno.EINTR => continue, | ||
| 56 | else => { | ||
| 57 | if (const *stdin ?= self.stdin) { stdin.close(); } | ||
| 58 | if (const *stdout ?= self.stdin) { stdout.close(); } | ||
| 59 | if (const *stderr ?= self.stdin) { stderr.close(); } | ||
| 60 | return error.Unexpected; | ||
| 61 | }, | ||
| 62 | } | ||
| 63 | } | ||
| 64 | break; | ||
| 65 | } | ||
| 66 | |||
| 67 | if (const *stdin ?= self.stdin) { stdin.close(); } | ||
| 68 | if (const *stdout ?= self.stdin) { stdout.close(); } | ||
| 69 | if (const *stderr ?= self.stdin) { stderr.close(); } | ||
| 70 | |||
| 71 | // Write @maxValue(ErrInt) to the write end of the err_pipe. This is after | ||
| 72 | // waitpid, so this write is guaranteed to be after the child | ||
| 73 | // pid potentially wrote an error. This way we can do a blocking | ||
| 74 | // read on the error pipe and either get @maxValue(ErrInt) (no error) or | ||
| 75 | // an error code. | ||
| 76 | %return writeIntFd(self.err_pipe[1], @maxValue(ErrInt)); | ||
| 77 | const err_int = %return readIntFd(self.err_pipe[0]); | ||
| 78 | // Here we potentially return the fork child's error | ||
| 79 | // from the parent pid. | ||
| 80 | if (err_int != @maxValue(ErrInt)) { | ||
| 81 | return error(err_int); | ||
| 82 | } | ||
| 83 | |||
| 84 | return statusToTerm(status); | ||
| 85 | } | ||
| 86 | |||
| 87 | fn statusToTerm(status: i32) -> Term { | ||
| 88 | return if (posix.WIFEXITED(status)) { | ||
| 89 | Term.Clean { posix.WEXITSTATUS(status) } | ||
| 90 | } else if (posix.WIFSIGNALED(status)) { | ||
| 91 | Term.Signal { posix.WTERMSIG(status) } | ||
| 92 | } else if (posix.WIFSTOPPED(status)) { | ||
| 93 | Term.Stopped { posix.WSTOPSIG(status) } | ||
| 94 | } else { | ||
| 95 | Term.Unknown { status } | ||
| 96 | }; | ||
| 97 | } | ||
| 98 | |||
| 99 | fn spawnPosix(exe_path: []const u8, args: []const []const u8, env_map: &const os.EnvMap, | ||
| 100 | stdin: StdIo, stdout: StdIo, stderr: StdIo, allocator: &Allocator) -> %ChildProcess | ||
| 101 | { | ||
| 102 | // TODO issue #295 | ||
| 103 | //const stdin_pipe = if (stdin == StdIo.Pipe) %return makePipe() else undefined; | ||
| 104 | var stdin_pipe: [2]i32 = undefined; | ||
| 105 | if (stdin == StdIo.Pipe) | ||
| 106 | stdin_pipe = %return makePipe(); | ||
| 107 | %defer if (stdin == StdIo.Pipe) { destroyPipe(stdin_pipe); }; | ||
| 108 | |||
| 109 | // TODO issue #295 | ||
| 110 | //const stdout_pipe = if (stdout == StdIo.Pipe) %return makePipe() else undefined; | ||
| 111 | var stdout_pipe: [2]i32 = undefined; | ||
| 112 | if (stdout == StdIo.Pipe) | ||
| 113 | stdout_pipe = %return makePipe(); | ||
| 114 | %defer if (stdout == StdIo.Pipe) { destroyPipe(stdout_pipe); }; | ||
| 115 | |||
| 116 | // TODO issue #295 | ||
| 117 | //const stderr_pipe = if (stderr == StdIo.Pipe) %return makePipe() else undefined; | ||
| 118 | var stderr_pipe: [2]i32 = undefined; | ||
| 119 | if (stderr == StdIo.Pipe) | ||
| 120 | stderr_pipe = %return makePipe(); | ||
| 121 | %defer if (stderr == StdIo.Pipe) { destroyPipe(stderr_pipe); }; | ||
| 122 | |||
| 123 | const any_ignore = (stdin == StdIo.Ignore or stdout == StdIo.Ignore or stderr == StdIo.Ignore); | ||
| 124 | // TODO issue #295 | ||
| 125 | //const dev_null_fd = if (any_ignore) { | ||
| 126 | // %return os.posixOpen("/dev/null", posix.O_RDWR, 0, null) | ||
| 127 | //} else { | ||
| 128 | // undefined | ||
| 129 | //}; | ||
| 130 | var dev_null_fd: i32 = undefined; | ||
| 131 | if (any_ignore) | ||
| 132 | dev_null_fd = %return os.posixOpen("/dev/null", posix.O_RDWR, 0, null); | ||
| 133 | |||
| 134 | // This pipe is used to communicate errors between the time of fork | ||
| 135 | // and execve from the child process to the parent process. | ||
| 136 | const err_pipe = %return makePipe(); | ||
| 137 | %defer destroyPipe(err_pipe); | ||
| 138 | |||
| 139 | const pid = posix.fork(); | ||
| 140 | const pid_err = posix.getErrno(pid); | ||
| 141 | if (pid_err > 0) { | ||
| 142 | return switch (pid_err) { | ||
| 143 | errno.EAGAIN, errno.ENOMEM, errno.ENOSYS => error.SysResources, | ||
| 144 | else => error.Unexpected, | ||
| 145 | }; | ||
| 146 | } | ||
| 147 | if (pid == 0) { | ||
| 148 | // we are the child | ||
| 149 | setUpChildIo(stdin, stdin_pipe[0], posix.STDIN_FILENO, dev_null_fd) %% | ||
| 150 | |err| forkChildErrReport(err_pipe[1], err); | ||
| 151 | setUpChildIo(stdout, stdout_pipe[1], posix.STDOUT_FILENO, dev_null_fd) %% | ||
| 152 | |err| forkChildErrReport(err_pipe[1], err); | ||
| 153 | setUpChildIo(stderr, stderr_pipe[1], posix.STDERR_FILENO, dev_null_fd) %% | ||
| 154 | |err| forkChildErrReport(err_pipe[1], err); | ||
| 155 | |||
| 156 | const err = posix.getErrno(%return os.posixExecve(exe_path, args, env_map, allocator)); | ||
| 157 | assert(err > 0); | ||
| 158 | forkChildErrReport(err_pipe[1], switch (err) { | ||
| 159 | errno.EFAULT => unreachable, | ||
| 160 | errno.E2BIG, errno.EMFILE, errno.ENAMETOOLONG, errno.ENFILE, errno.ENOMEM => error.SysResources, | ||
| 161 | errno.EACCES, errno.EPERM => error.AccessDenied, | ||
| 162 | errno.EINVAL, errno.ENOEXEC => error.InvalidExe, | ||
| 163 | errno.EIO, errno.ELOOP => error.FileSystem, | ||
| 164 | errno.EISDIR => error.IsDir, | ||
| 165 | errno.ENOENT, errno.ENOTDIR => error.FileNotFound, | ||
| 166 | errno.ETXTBSY => error.FileBusy, | ||
| 167 | else => error.Unexpected, | ||
| 168 | }); | ||
| 169 | } | ||
| 170 | |||
| 171 | // we are the parent | ||
| 172 | if (stdin == StdIo.Pipe) { os.posixClose(stdin_pipe[0]); } | ||
| 173 | if (stdout == StdIo.Pipe) { os.posixClose(stdout_pipe[1]); } | ||
| 174 | if (stderr == StdIo.Pipe) { os.posixClose(stderr_pipe[1]); } | ||
| 175 | if (any_ignore) { os.posixClose(dev_null_fd); } | ||
| 176 | |||
| 177 | return ChildProcess { | ||
| 178 | .pid = i32(pid), | ||
| 179 | .err_pipe = err_pipe, | ||
| 180 | |||
| 181 | .stdin = if (stdin == StdIo.Pipe) { | ||
| 182 | io.OutStream { | ||
| 183 | .fd = stdin_pipe[1], | ||
| 184 | .buffer = undefined, | ||
| 185 | .index = 0, | ||
| 186 | } | ||
| 187 | } else { | ||
| 188 | null | ||
| 189 | }, | ||
| 190 | .stdout = if (stdout == StdIo.Pipe) { | ||
| 191 | io.InStream { | ||
| 192 | .fd = stdout_pipe[0], | ||
| 193 | } | ||
| 194 | } else { | ||
| 195 | null | ||
| 196 | }, | ||
| 197 | .stderr = if (stderr == StdIo.Pipe) { | ||
| 198 | io.InStream { | ||
| 199 | .fd = stderr_pipe[0], | ||
| 200 | } | ||
| 201 | } else { | ||
| 202 | null | ||
| 203 | }, | ||
| 204 | }; | ||
| 205 | } | ||
| 206 | |||
| 207 | fn setUpChildIo(stdio: StdIo, pipe_fd: i32, std_fileno: i32, dev_null_fd: i32) -> %void { | ||
| 208 | switch (stdio) { | ||
| 209 | StdIo.Pipe => %return os.posixDup2(pipe_fd, std_fileno), | ||
| 210 | StdIo.Close => os.posixClose(std_fileno), | ||
| 211 | StdIo.Inherit => {}, | ||
| 212 | StdIo.Ignore => %return os.posixDup2(dev_null_fd, std_fileno), | ||
| 213 | } | ||
| 214 | } | ||
| 215 | }; | ||
| 216 | |||
| 217 | fn makePipe() -> %[2]i32 { | ||
| 218 | var fds: [2]i32 = undefined; | ||
| 219 | const err = posix.getErrno(posix.pipe(&fds)); | ||
| 220 | if (err > 0) { | ||
| 221 | return switch (err) { | ||
| 222 | errno.EMFILE, errno.ENFILE => error.SysResources, | ||
| 223 | else => error.Unexpected, | ||
| 224 | } | ||
| 225 | } | ||
| 226 | return fds; | ||
| 227 | } | ||
| 228 | |||
| 229 | fn destroyPipe(pipe: &const [2]i32) { | ||
| 230 | os.posixClose((*pipe)[0]); | ||
| 231 | os.posixClose((*pipe)[1]); | ||
| 232 | } | ||
| 233 | |||
| 234 | // Child of fork calls this to report an error to the fork parent. | ||
| 235 | // Then the child exits. | ||
| 236 | fn forkChildErrReport(fd: i32, err: error) -> noreturn { | ||
| 237 | _ = writeIntFd(fd, ErrInt(err)); | ||
| 238 | posix.exit(1); | ||
| 239 | } | ||
| 240 | |||
| 241 | const ErrInt = @intType(false, @sizeOf(error) * 8); | ||
| 242 | fn writeIntFd(fd: i32, value: ErrInt) -> %void { | ||
| 243 | var bytes: [@sizeOf(ErrInt)]u8 = undefined; | ||
| 244 | mem.writeInt(bytes[0...], value, true); | ||
| 245 | |||
| 246 | var index: usize = 0; | ||
| 247 | while (index < bytes.len) { | ||
| 248 | const amt_written = posix.write(fd, &bytes[index], bytes.len - index); | ||
| 249 | const err = posix.getErrno(amt_written); | ||
| 250 | if (err > 0) { | ||
| 251 | switch (err) { | ||
| 252 | errno.EINTR => continue, | ||
| 253 | errno.EINVAL => unreachable, | ||
| 254 | else => return error.SysResources, | ||
| 255 | } | ||
| 256 | } | ||
| 257 | index += amt_written; | ||
| 258 | } | ||
| 259 | } | ||
| 260 | |||
| 261 | fn readIntFd(fd: i32) -> %ErrInt { | ||
| 262 | var bytes: [@sizeOf(ErrInt)]u8 = undefined; | ||
| 263 | |||
| 264 | var index: usize = 0; | ||
| 265 | while (index < bytes.len) { | ||
| 266 | const amt_written = posix.read(fd, &bytes[index], bytes.len - index); | ||
| 267 | const err = posix.getErrno(amt_written); | ||
| 268 | if (err > 0) { | ||
| 269 | switch (err) { | ||
| 270 | errno.EINTR => continue, | ||
| 271 | errno.EINVAL => unreachable, | ||
| 272 | else => return error.SysResources, | ||
| 273 | } | ||
| 274 | } | ||
| 275 | index += amt_written; | ||
| 276 | } | ||
| 277 | |||
| 278 | return mem.readInt(bytes[0...], ErrInt, true); | ||
| 279 | } | ||
| 280 | |||
std/os/index.zig+28-285| ... | @@ -9,6 +9,7 @@ pub const posix = switch(@compileVar("os")) { | ... | @@ -9,6 +9,7 @@ pub const posix = switch(@compileVar("os")) { |
| 9 | }; | 9 | }; |
| 10 | 10 | ||
| 11 | pub const max_noalloc_path_len = 1024; | 11 | pub const max_noalloc_path_len = 1024; |
| 12 | pub const ChildProcess = @import("child_process.zig").ChildProcess; | ||
| 12 | 13 | ||
| 13 | const debug = @import("../debug.zig"); | 14 | const debug = @import("../debug.zig"); |
| 14 | const assert = debug.assert; | 15 | const assert = debug.assert; |
| ... | @@ -20,7 +21,6 @@ const c = @import("../c/index.zig"); | ... | @@ -20,7 +21,6 @@ const c = @import("../c/index.zig"); |
| 20 | const mem = @import("../mem.zig"); | 21 | const mem = @import("../mem.zig"); |
| 21 | const Allocator = mem.Allocator; | 22 | const Allocator = mem.Allocator; |
| 22 | 23 | ||
| 23 | const io = @import("../io.zig"); | ||
| 24 | const HashMap = @import("../hash_map.zig").HashMap; | 24 | const HashMap = @import("../hash_map.zig").HashMap; |
| 25 | const cstr = @import("../cstr.zig"); | 25 | const cstr = @import("../cstr.zig"); |
| 26 | 26 | ||
| ... | @@ -96,23 +96,6 @@ pub coldcc fn abort() -> noreturn { | ... | @@ -96,23 +96,6 @@ pub coldcc fn abort() -> noreturn { |
| 96 | } | 96 | } |
| 97 | } | 97 | } |
| 98 | 98 | ||
| 99 | fn makePipe() -> %[2]i32 { | ||
| 100 | var fds: [2]i32 = undefined; | ||
| 101 | const err = posix.getErrno(posix.pipe(&fds)); | ||
| 102 | if (err > 0) { | ||
| 103 | return switch (err) { | ||
| 104 | errno.EMFILE, errno.ENFILE => error.SysResources, | ||
| 105 | else => error.Unexpected, | ||
| 106 | } | ||
| 107 | } | ||
| 108 | return fds; | ||
| 109 | } | ||
| 110 | |||
| 111 | fn destroyPipe(pipe: &const [2]i32) { | ||
| 112 | posixClose((*pipe)[0]); | ||
| 113 | posixClose((*pipe)[1]); | ||
| 114 | } | ||
| 115 | |||
| 116 | /// Calls POSIX close, and keeps trying if it gets interrupted. | 99 | /// Calls POSIX close, and keeps trying if it gets interrupted. |
| 117 | pub fn posixClose(fd: i32) { | 100 | pub fn posixClose(fd: i32) { |
| 118 | while (true) { | 101 | while (true) { |
| ... | @@ -202,54 +185,7 @@ pub fn posixOpen(path: []const u8, flags: usize, perm: usize, allocator: ?&Alloc | ... | @@ -202,54 +185,7 @@ pub fn posixOpen(path: []const u8, flags: usize, perm: usize, allocator: ?&Alloc |
| 202 | } | 185 | } |
| 203 | } | 186 | } |
| 204 | 187 | ||
| 205 | const ErrInt = @intType(false, @sizeOf(error) * 8); | 188 | pub fn posixDup2(old_fd: i32, new_fd: i32) -> %void { |
| 206 | fn writeIntFd(fd: i32, value: ErrInt) -> %void { | ||
| 207 | var bytes: [@sizeOf(ErrInt)]u8 = undefined; | ||
| 208 | mem.writeInt(bytes[0...], value, true); | ||
| 209 | |||
| 210 | var index: usize = 0; | ||
| 211 | while (index < bytes.len) { | ||
| 212 | const amt_written = posix.write(fd, &bytes[index], bytes.len - index); | ||
| 213 | const err = posix.getErrno(amt_written); | ||
| 214 | if (err > 0) { | ||
| 215 | switch (err) { | ||
| 216 | errno.EINTR => continue, | ||
| 217 | errno.EINVAL => unreachable, | ||
| 218 | else => return error.SysResources, | ||
| 219 | } | ||
| 220 | } | ||
| 221 | index += amt_written; | ||
| 222 | } | ||
| 223 | } | ||
| 224 | |||
| 225 | fn readIntFd(fd: i32) -> %ErrInt { | ||
| 226 | var bytes: [@sizeOf(ErrInt)]u8 = undefined; | ||
| 227 | |||
| 228 | var index: usize = 0; | ||
| 229 | while (index < bytes.len) { | ||
| 230 | const amt_written = posix.read(fd, &bytes[index], bytes.len - index); | ||
| 231 | const err = posix.getErrno(amt_written); | ||
| 232 | if (err > 0) { | ||
| 233 | switch (err) { | ||
| 234 | errno.EINTR => continue, | ||
| 235 | errno.EINVAL => unreachable, | ||
| 236 | else => return error.SysResources, | ||
| 237 | } | ||
| 238 | } | ||
| 239 | index += amt_written; | ||
| 240 | } | ||
| 241 | |||
| 242 | return mem.readInt(bytes[0...], ErrInt, true); | ||
| 243 | } | ||
| 244 | |||
| 245 | // Child of fork calls this to report an error to the fork parent. | ||
| 246 | // Then the child exits. | ||
| 247 | fn forkChildErrReport(fd: i32, err: error) -> noreturn { | ||
| 248 | _ = writeIntFd(fd, ErrInt(err)); | ||
| 249 | posix.exit(1); | ||
| 250 | } | ||
| 251 | |||
| 252 | fn dup2NoIntr(old_fd: i32, new_fd: i32) -> %void { | ||
| 253 | while (true) { | 189 | while (true) { |
| 254 | const err = posix.getErrno(posix.dup2(old_fd, new_fd)); | 190 | const err = posix.getErrno(posix.dup2(old_fd, new_fd)); |
| 255 | if (err > 0) { | 191 | if (err > 0) { |
| ... | @@ -264,218 +200,13 @@ fn dup2NoIntr(old_fd: i32, new_fd: i32) -> %void { | ... | @@ -264,218 +200,13 @@ fn dup2NoIntr(old_fd: i32, new_fd: i32) -> %void { |
| 264 | } | 200 | } |
| 265 | } | 201 | } |
| 266 | 202 | ||
| 267 | pub const ChildProcess = struct { | ||
| 268 | pid: i32, | ||
| 269 | err_pipe: [2]i32, | ||
| 270 | |||
| 271 | stdin: ?io.OutStream, | ||
| 272 | stdout: ?io.InStream, | ||
| 273 | stderr: ?io.InStream, | ||
| 274 | |||
| 275 | pub const Term = enum { | ||
| 276 | Clean: i32, | ||
| 277 | Signal: i32, | ||
| 278 | Stopped: i32, | ||
| 279 | Unknown: i32, | ||
| 280 | }; | ||
| 281 | |||
| 282 | pub const StdIo = enum { | ||
| 283 | Inherit, | ||
| 284 | Ignore, | ||
| 285 | Pipe, | ||
| 286 | Close, | ||
| 287 | }; | ||
| 288 | |||
| 289 | pub fn spawn(exe_path: []const u8, args: []const []const u8, env_map: &const EnvMap, | ||
| 290 | stdin: StdIo, stdout: StdIo, stderr: StdIo, allocator: &Allocator) -> %ChildProcess | ||
| 291 | { | ||
| 292 | switch (@compileVar("os")) { | ||
| 293 | Os.linux, Os.macosx, Os.ios, Os.darwin => { | ||
| 294 | return spawnPosix(exe_path, args, env_map, stdin, stdout, stderr, allocator); | ||
| 295 | }, | ||
| 296 | else => @compileError("Unsupported OS"), | ||
| 297 | } | ||
| 298 | } | ||
| 299 | |||
| 300 | pub fn wait(self: &ChildProcess) -> %Term { | ||
| 301 | defer { | ||
| 302 | posixClose(self.err_pipe[0]); | ||
| 303 | posixClose(self.err_pipe[1]); | ||
| 304 | }; | ||
| 305 | |||
| 306 | var status: i32 = undefined; | ||
| 307 | while (true) { | ||
| 308 | const err = posix.getErrno(posix.waitpid(self.pid, &status, 0)); | ||
| 309 | if (err > 0) { | ||
| 310 | switch (err) { | ||
| 311 | errno.EINVAL, errno.ECHILD => unreachable, | ||
| 312 | errno.EINTR => continue, | ||
| 313 | else => { | ||
| 314 | if (const *stdin ?= self.stdin) { stdin.close(); } | ||
| 315 | if (const *stdout ?= self.stdin) { stdout.close(); } | ||
| 316 | if (const *stderr ?= self.stdin) { stderr.close(); } | ||
| 317 | return error.Unexpected; | ||
| 318 | }, | ||
| 319 | } | ||
| 320 | } | ||
| 321 | break; | ||
| 322 | } | ||
| 323 | |||
| 324 | if (const *stdin ?= self.stdin) { stdin.close(); } | ||
| 325 | if (const *stdout ?= self.stdin) { stdout.close(); } | ||
| 326 | if (const *stderr ?= self.stdin) { stderr.close(); } | ||
| 327 | |||
| 328 | // Write @maxValue(ErrInt) to the write end of the err_pipe. This is after | ||
| 329 | // waitpid, so this write is guaranteed to be after the child | ||
| 330 | // pid potentially wrote an error. This way we can do a blocking | ||
| 331 | // read on the error pipe and either get @maxValue(ErrInt) (no error) or | ||
| 332 | // an error code. | ||
| 333 | %return writeIntFd(self.err_pipe[1], @maxValue(ErrInt)); | ||
| 334 | const err_int = %return readIntFd(self.err_pipe[0]); | ||
| 335 | // Here we potentially return the fork child's error | ||
| 336 | // from the parent pid. | ||
| 337 | if (err_int != @maxValue(ErrInt)) { | ||
| 338 | return error(err_int); | ||
| 339 | } | ||
| 340 | |||
| 341 | return statusToTerm(status); | ||
| 342 | } | ||
| 343 | |||
| 344 | fn statusToTerm(status: i32) -> Term { | ||
| 345 | return if (posix.WIFEXITED(status)) { | ||
| 346 | Term.Clean { posix.WEXITSTATUS(status) } | ||
| 347 | } else if (posix.WIFSIGNALED(status)) { | ||
| 348 | Term.Signal { posix.WTERMSIG(status) } | ||
| 349 | } else if (posix.WIFSTOPPED(status)) { | ||
| 350 | Term.Stopped { posix.WSTOPSIG(status) } | ||
| 351 | } else { | ||
| 352 | Term.Unknown { status } | ||
| 353 | }; | ||
| 354 | } | ||
| 355 | |||
| 356 | fn spawnPosix(exe_path: []const u8, args: []const []const u8, env_map: &const EnvMap, | ||
| 357 | stdin: StdIo, stdout: StdIo, stderr: StdIo, allocator: &Allocator) -> %ChildProcess | ||
| 358 | { | ||
| 359 | // TODO issue #295 | ||
| 360 | //const stdin_pipe = if (stdin == StdIo.Pipe) %return makePipe() else undefined; | ||
| 361 | var stdin_pipe: [2]i32 = undefined; | ||
| 362 | if (stdin == StdIo.Pipe) | ||
| 363 | stdin_pipe = %return makePipe(); | ||
| 364 | %defer if (stdin == StdIo.Pipe) { destroyPipe(stdin_pipe); }; | ||
| 365 | |||
| 366 | // TODO issue #295 | ||
| 367 | //const stdout_pipe = if (stdout == StdIo.Pipe) %return makePipe() else undefined; | ||
| 368 | var stdout_pipe: [2]i32 = undefined; | ||
| 369 | if (stdout == StdIo.Pipe) | ||
| 370 | stdout_pipe = %return makePipe(); | ||
| 371 | %defer if (stdout == StdIo.Pipe) { destroyPipe(stdout_pipe); }; | ||
| 372 | |||
| 373 | // TODO issue #295 | ||
| 374 | //const stderr_pipe = if (stderr == StdIo.Pipe) %return makePipe() else undefined; | ||
| 375 | var stderr_pipe: [2]i32 = undefined; | ||
| 376 | if (stderr == StdIo.Pipe) | ||
| 377 | stderr_pipe = %return makePipe(); | ||
| 378 | %defer if (stderr == StdIo.Pipe) { destroyPipe(stderr_pipe); }; | ||
| 379 | |||
| 380 | const any_ignore = (stdin == StdIo.Ignore or stdout == StdIo.Ignore or stderr == StdIo.Ignore); | ||
| 381 | // TODO issue #295 | ||
| 382 | //const dev_null_fd = if (any_ignore) { | ||
| 383 | // %return posixOpen("/dev/null", posix.O_RDWR, 0, null) | ||
| 384 | //} else { | ||
| 385 | // undefined | ||
| 386 | //}; | ||
| 387 | var dev_null_fd: i32 = undefined; | ||
| 388 | if (any_ignore) | ||
| 389 | dev_null_fd = %return posixOpen("/dev/null", posix.O_RDWR, 0, null); | ||
| 390 | |||
| 391 | // This pipe is used to communicate errors between the time of fork | ||
| 392 | // and execve from the child process to the parent process. | ||
| 393 | const err_pipe = %return makePipe(); | ||
| 394 | %defer destroyPipe(err_pipe); | ||
| 395 | |||
| 396 | const pid = posix.fork(); | ||
| 397 | const pid_err = linux.getErrno(pid); | ||
| 398 | if (pid_err > 0) { | ||
| 399 | return switch (pid_err) { | ||
| 400 | errno.EAGAIN, errno.ENOMEM, errno.ENOSYS => error.SysResources, | ||
| 401 | else => error.Unexpected, | ||
| 402 | }; | ||
| 403 | } | ||
| 404 | if (pid == 0) { | ||
| 405 | // we are the child | ||
| 406 | setUpChildIo(stdin, stdin_pipe[0], posix.STDIN_FILENO, dev_null_fd) %% | ||
| 407 | |err| forkChildErrReport(err_pipe[1], err); | ||
| 408 | setUpChildIo(stdout, stdout_pipe[1], posix.STDOUT_FILENO, dev_null_fd) %% | ||
| 409 | |err| forkChildErrReport(err_pipe[1], err); | ||
| 410 | setUpChildIo(stderr, stderr_pipe[1], posix.STDERR_FILENO, dev_null_fd) %% | ||
| 411 | |err| forkChildErrReport(err_pipe[1], err); | ||
| 412 | |||
| 413 | const err = posix.getErrno(%return execve(exe_path, args, env_map, allocator)); | ||
| 414 | assert(err > 0); | ||
| 415 | forkChildErrReport(err_pipe[1], switch (err) { | ||
| 416 | errno.EFAULT => unreachable, | ||
| 417 | errno.E2BIG, errno.EMFILE, errno.ENAMETOOLONG, errno.ENFILE, errno.ENOMEM => error.SysResources, | ||
| 418 | errno.EACCES, errno.EPERM => error.AccessDenied, | ||
| 419 | errno.EINVAL, errno.ENOEXEC => error.InvalidExe, | ||
| 420 | errno.EIO, errno.ELOOP => error.FileSystem, | ||
| 421 | errno.EISDIR => error.IsDir, | ||
| 422 | errno.ENOENT, errno.ENOTDIR => error.FileNotFound, | ||
| 423 | errno.ETXTBSY => error.FileBusy, | ||
| 424 | else => error.Unexpected, | ||
| 425 | }); | ||
| 426 | } | ||
| 427 | |||
| 428 | // we are the parent | ||
| 429 | if (stdin == StdIo.Pipe) { posixClose(stdin_pipe[0]); } | ||
| 430 | if (stdout == StdIo.Pipe) { posixClose(stdout_pipe[1]); } | ||
| 431 | if (stderr == StdIo.Pipe) { posixClose(stderr_pipe[1]); } | ||
| 432 | if (any_ignore) { posixClose(dev_null_fd); } | ||
| 433 | |||
| 434 | return ChildProcess { | ||
| 435 | .pid = i32(pid), | ||
| 436 | .err_pipe = err_pipe, | ||
| 437 | |||
| 438 | .stdin = if (stdin == StdIo.Pipe) { | ||
| 439 | io.OutStream { | ||
| 440 | .fd = stdin_pipe[1], | ||
| 441 | .buffer = undefined, | ||
| 442 | .index = 0, | ||
| 443 | } | ||
| 444 | } else { | ||
| 445 | null | ||
| 446 | }, | ||
| 447 | .stdout = if (stdout == StdIo.Pipe) { | ||
| 448 | io.InStream { | ||
| 449 | .fd = stdout_pipe[0], | ||
| 450 | } | ||
| 451 | } else { | ||
| 452 | null | ||
| 453 | }, | ||
| 454 | .stderr = if (stderr == StdIo.Pipe) { | ||
| 455 | io.InStream { | ||
| 456 | .fd = stderr_pipe[0], | ||
| 457 | } | ||
| 458 | } else { | ||
| 459 | null | ||
| 460 | }, | ||
| 461 | }; | ||
| 462 | } | ||
| 463 | |||
| 464 | fn setUpChildIo(stdio: StdIo, pipe_fd: i32, std_fileno: i32, dev_null_fd: i32) -> %void { | ||
| 465 | switch (stdio) { | ||
| 466 | StdIo.Pipe => %return dup2NoIntr(pipe_fd, std_fileno), | ||
| 467 | StdIo.Close => posixClose(std_fileno), | ||
| 468 | StdIo.Inherit => {}, | ||
| 469 | StdIo.Ignore => %return dup2NoIntr(dev_null_fd, std_fileno), | ||
| 470 | } | ||
| 471 | } | ||
| 472 | }; | ||
| 473 | |||
| 474 | /// This function must allocate memory to add a null terminating bytes on path and each arg. | 203 | /// This function must allocate memory to add a null terminating bytes on path and each arg. |
| 475 | /// It must also convert to KEY=VALUE\0 format for environment variables, and include null | 204 | /// It must also convert to KEY=VALUE\0 format for environment variables, and include null |
| 476 | /// pointers after the args and after the environment variables. | 205 | /// pointers after the args and after the environment variables. |
| 477 | /// Also make the first arg equal to path. | 206 | /// Also make the first arg equal to path. |
| 478 | fn execve(path: []const u8, argv: []const []const u8, env_map: &const EnvMap, allocator: &Allocator) -> %usize { | 207 | pub fn posixExecve(path: []const u8, argv: []const []const u8, env_map: &const EnvMap, |
| 208 | allocator: &Allocator) -> %usize | ||
| 209 | { | ||
| 479 | const path_buf = %return allocator.alloc(u8, path.len + 1); | 210 | const path_buf = %return allocator.alloc(u8, path.len + 1); |
| 480 | defer allocator.free(path_buf); | 211 | defer allocator.free(path_buf); |
| 481 | @memcpy(&path_buf[0], &path[0], path.len); | 212 | @memcpy(&path_buf[0], &path[0], path.len); |
| ... | @@ -604,6 +335,19 @@ pub const EnvMap = struct { | ... | @@ -604,6 +335,19 @@ pub const EnvMap = struct { |
| 604 | mem.copy(u8, result, value); | 335 | mem.copy(u8, result, value); |
| 605 | return result; | 336 | return result; |
| 606 | } | 337 | } |
| 338 | |||
| 339 | fn hash_slice_u8(k: []const u8) -> u32 { | ||
| 340 | // FNV 32-bit hash | ||
| 341 | var h: u32 = 2166136261; | ||
| 342 | for (k) |b| { | ||
| 343 | h = (h ^ b) *% 16777619; | ||
| 344 | } | ||
| 345 | return h; | ||
| 346 | } | ||
| 347 | |||
| 348 | fn eql_slice_u8(a: []const u8, b: []const u8) -> bool { | ||
| 349 | return mem.eql(u8, a, b); | ||
| 350 | } | ||
| 607 | }; | 351 | }; |
| 608 | 352 | ||
| 609 | pub fn getEnvMap(allocator: &Allocator) -> %EnvMap { | 353 | pub fn getEnvMap(allocator: &Allocator) -> %EnvMap { |
| ... | @@ -641,15 +385,14 @@ pub fn getEnv(key: []const u8) -> ?[]const u8 { | ... | @@ -641,15 +385,14 @@ pub fn getEnv(key: []const u8) -> ?[]const u8 { |
| 641 | return null; | 385 | return null; |
| 642 | } | 386 | } |
| 643 | 387 | ||
| 644 | fn hash_slice_u8(k: []const u8) -> u32 { | 388 | pub const args = struct { |
| 645 | // FNV 32-bit hash | 389 | pub var raw: []&u8 = undefined; |
| 646 | var h: u32 = 2166136261; | ||
| 647 | for (k) |b| { | ||
| 648 | h = (h ^ b) *% 16777619; | ||
| 649 | } | ||
| 650 | return h; | ||
| 651 | } | ||
| 652 | 390 | ||
| 653 | fn eql_slice_u8(a: []const u8, b: []const u8) -> bool { | 391 | pub fn count() -> usize { |
| 654 | return mem.eql(u8, a, b); | 392 | return raw.len; |
| 655 | } | 393 | } |
| 394 | pub fn at(i: usize) -> []const u8 { | ||
| 395 | const s = raw[i]; | ||
| 396 | return s[0...cstr.len(s)]; | ||
| 397 | } | ||
| 398 | }; |
std/special/bootstrap.zig+2-8| ... | @@ -37,20 +37,14 @@ fn callMainAndExit() -> noreturn { | ... | @@ -37,20 +37,14 @@ fn callMainAndExit() -> noreturn { |
| 37 | exit(0); | 37 | exit(0); |
| 38 | } | 38 | } |
| 39 | 39 | ||
| 40 | var args_data: [32][]u8 = undefined; | ||
| 41 | fn callMain(argc: usize, argv: &&u8, envp: &?&u8) -> %void { | 40 | fn callMain(argc: usize, argv: &&u8, envp: &?&u8) -> %void { |
| 42 | // TODO create args API to make it work with > 32 args | 41 | std.os.args.raw = argv[0...argc]; |
| 43 | const args = args_data[0...argc]; | ||
| 44 | for (args) |_, i| { | ||
| 45 | const ptr = argv[i]; | ||
| 46 | args[i] = ptr[0...std.cstr.len(ptr)]; | ||
| 47 | } | ||
| 48 | 42 | ||
| 49 | var env_count: usize = 0; | 43 | var env_count: usize = 0; |
| 50 | while (envp[env_count] != null; env_count += 1) {} | 44 | while (envp[env_count] != null; env_count += 1) {} |
| 51 | std.os.environ_raw = @ptrcast(&&u8, envp)[0...env_count]; | 45 | std.os.environ_raw = @ptrcast(&&u8, envp)[0...env_count]; |
| 52 | 46 | ||
| 53 | return root.main(args); | 47 | return root.main(); |
| 54 | } | 48 | } |
| 55 | 49 | ||
| 56 | export fn main(c_argc: i32, c_argv: &&u8, c_envp: &?&u8) -> i32 { | 50 | export fn main(c_argc: i32, c_argv: &&u8, c_envp: &?&u8) -> i32 { |
std/special/build_runner.zig+6-5| ... | @@ -1,18 +1,19 @@ | ... | @@ -1,18 +1,19 @@ |
| 1 | const root = @import("@build"); | 1 | const root = @import("@build"); |
| 2 | const std = @import("std"); | 2 | const std = @import("std"); |
| 3 | const io = std.io; | 3 | const io = std.io; |
| 4 | const os = std.os; | ||
| 4 | const Builder = std.build.Builder; | 5 | const Builder = std.build.Builder; |
| 5 | const mem = std.mem; | 6 | const mem = std.mem; |
| 6 | 7 | ||
| 7 | error InvalidArgs; | 8 | error InvalidArgs; |
| 8 | 9 | ||
| 9 | pub fn main(args: [][]u8) -> %void { | 10 | pub fn main() -> %void { |
| 10 | if (args.len < 2) { | 11 | if (os.args.count() < 2) { |
| 11 | %%io.stderr.printf("Expected first argument to be path to zig compiler\n"); | 12 | %%io.stderr.printf("Expected first argument to be path to zig compiler\n"); |
| 12 | return error.InvalidArgs; | 13 | return error.InvalidArgs; |
| 13 | } | 14 | } |
| 14 | const zig_exe = args[1]; | 15 | const zig_exe = os.args.at(1); |
| 15 | const leftover_args = args[2...]; | 16 | const leftover_arg_index = 2; |
| 16 | 17 | ||
| 17 | // TODO use a more general purpose allocator here | 18 | // TODO use a more general purpose allocator here |
| 18 | var inc_allocator = %%mem.IncrementingAllocator.init(10 * 1024 * 1024); | 19 | var inc_allocator = %%mem.IncrementingAllocator.init(10 * 1024 * 1024); |
| ... | @@ -20,5 +21,5 @@ pub fn main(args: [][]u8) -> %void { | ... | @@ -20,5 +21,5 @@ pub fn main(args: [][]u8) -> %void { |
| 20 | 21 | ||
| 21 | var builder = Builder.init(zig_exe, &inc_allocator.allocator); | 22 | var builder = Builder.init(zig_exe, &inc_allocator.allocator); |
| 22 | root.build(&builder); | 23 | root.build(&builder); |
| 23 | %return builder.make(leftover_args); | 24 | %return builder.make(leftover_arg_index); |
| 24 | } | 25 | } |
std/special/test_runner.zig+1-1| ... | @@ -7,7 +7,7 @@ const TestFn = struct { | ... | @@ -7,7 +7,7 @@ const TestFn = struct { |
| 7 | 7 | ||
| 8 | extern var zig_test_fn_list: []TestFn; | 8 | extern var zig_test_fn_list: []TestFn; |
| 9 | 9 | ||
| 10 | pub fn main(args: [][]u8) -> %void { | 10 | pub fn main() -> %void { |
| 11 | for (zig_test_fn_list) |testFn, i| { | 11 | for (zig_test_fn_list) |testFn, i| { |
| 12 | %%io.stderr.printf("Test {}/{} {}...", i + 1, zig_test_fn_list.len, testFn.name); | 12 | %%io.stderr.printf("Test {}/{} {}...", i + 1, zig_test_fn_list.len, testFn.name); |
| 13 | 13 |
test/run_tests.cpp+46-63| ... | @@ -215,7 +215,7 @@ export fn main(argc: c_int, argv: &&u8) -> c_int { | ... | @@ -215,7 +215,7 @@ export fn main(argc: c_int, argv: &&u8) -> c_int { |
| 215 | use @import("std").io; | 215 | use @import("std").io; |
| 216 | use @import("foo.zig"); | 216 | use @import("foo.zig"); |
| 217 | 217 | ||
| 218 | pub fn main(args: [][]u8) -> %void { | 218 | pub fn main() -> %void { |
| 219 | privateFunction(); | 219 | privateFunction(); |
| 220 | %%stdout.printf("OK 2\n"); | 220 | %%stdout.printf("OK 2\n"); |
| 221 | } | 221 | } |
| ... | @@ -245,7 +245,7 @@ pub fn printText() { | ... | @@ -245,7 +245,7 @@ pub fn printText() { |
| 245 | use @import("foo.zig"); | 245 | use @import("foo.zig"); |
| 246 | use @import("bar.zig"); | 246 | use @import("bar.zig"); |
| 247 | 247 | ||
| 248 | pub fn main(args: [][]u8) -> %void { | 248 | pub fn main() -> %void { |
| 249 | foo_function(); | 249 | foo_function(); |
| 250 | bar_function(); | 250 | bar_function(); |
| 251 | } | 251 | } |
| ... | @@ -281,7 +281,7 @@ pub fn foo_function() -> bool { | ... | @@ -281,7 +281,7 @@ pub fn foo_function() -> bool { |
| 281 | TestCase *tc = add_simple_case("two files use import each other", R"SOURCE( | 281 | TestCase *tc = add_simple_case("two files use import each other", R"SOURCE( |
| 282 | use @import("a.zig"); | 282 | use @import("a.zig"); |
| 283 | 283 | ||
| 284 | pub fn main(args: [][]u8) -> %void { | 284 | pub fn main() -> %void { |
| 285 | ok(); | 285 | ok(); |
| 286 | } | 286 | } |
| 287 | )SOURCE", "OK\n"); | 287 | )SOURCE", "OK\n"); |
| ... | @@ -309,7 +309,7 @@ pub const b_text = a_text; | ... | @@ -309,7 +309,7 @@ pub const b_text = a_text; |
| 309 | add_simple_case("hello world without libc", R"SOURCE( | 309 | add_simple_case("hello world without libc", R"SOURCE( |
| 310 | const io = @import("std").io; | 310 | const io = @import("std").io; |
| 311 | 311 | ||
| 312 | pub fn main(args: [][]u8) -> %void { | 312 | pub fn main() -> %void { |
| 313 | %%io.stdout.printf("Hello, world!\n{d4} {x3} {c}\n", u32(12), u16(0x12), u8('a')); | 313 | %%io.stdout.printf("Hello, world!\n{d4} {x3} {c}\n", u32(12), u16(0x12), u8('a')); |
| 314 | } | 314 | } |
| 315 | )SOURCE", "Hello, world!\n0012 012 a\n"); | 315 | )SOURCE", "Hello, world!\n0012 012 a\n"); |
| ... | @@ -446,7 +446,7 @@ const io = @import("std").io; | ... | @@ -446,7 +446,7 @@ const io = @import("std").io; |
| 446 | const z = io.stdin_fileno; | 446 | const z = io.stdin_fileno; |
| 447 | const x : @typeOf(y) = 1234; | 447 | const x : @typeOf(y) = 1234; |
| 448 | const y : u16 = 5678; | 448 | const y : u16 = 5678; |
| 449 | pub fn main(args: [][]u8) -> %void { | 449 | pub fn main() -> %void { |
| 450 | var x_local : i32 = print_ok(x); | 450 | var x_local : i32 = print_ok(x); |
| 451 | } | 451 | } |
| 452 | fn print_ok(val: @typeOf(x)) -> @typeOf(foo) { | 452 | fn print_ok(val: @typeOf(x)) -> @typeOf(foo) { |
| ... | @@ -471,7 +471,7 @@ export fn compare_fn(a: ?&const c_void, b: ?&const c_void) -> c_int { | ... | @@ -471,7 +471,7 @@ export fn compare_fn(a: ?&const c_void, b: ?&const c_void) -> c_int { |
| 471 | } | 471 | } |
| 472 | } | 472 | } |
| 473 | 473 | ||
| 474 | export fn main(args: c_int, argv: &&u8) -> c_int { | 474 | export fn main() -> c_int { |
| 475 | var array = []u32 { 1, 7, 3, 2, 0, 9, 4, 8, 6, 5 }; | 475 | var array = []u32 { 1, 7, 3, 2, 0, 9, 4, 8, 6, 5 }; |
| 476 | 476 | ||
| 477 | c.qsort(@ptrcast(&c_void, &array[0]), c_ulong(array.len), @sizeOf(i32), compare_fn); | 477 | c.qsort(@ptrcast(&c_void, &array[0]), c_ulong(array.len), @sizeOf(i32), compare_fn); |
| ... | @@ -516,7 +516,7 @@ const Bar = struct { | ... | @@ -516,7 +516,7 @@ const Bar = struct { |
| 516 | fn method(b: &const Bar) -> bool { true } | 516 | fn method(b: &const Bar) -> bool { true } |
| 517 | }; | 517 | }; |
| 518 | 518 | ||
| 519 | pub fn main(args: [][]u8) -> %void { | 519 | pub fn main() -> %void { |
| 520 | const bar = Bar {.field2 = 13,}; | 520 | const bar = Bar {.field2 = 13,}; |
| 521 | const foo = Foo {.field1 = bar,}; | 521 | const foo = Foo {.field1 = bar,}; |
| 522 | if (!foo.method()) { | 522 | if (!foo.method()) { |
| ... | @@ -532,7 +532,7 @@ pub fn main(args: [][]u8) -> %void { | ... | @@ -532,7 +532,7 @@ pub fn main(args: [][]u8) -> %void { |
| 532 | 532 | ||
| 533 | add_simple_case("defer with only fallthrough", R"SOURCE( | 533 | add_simple_case("defer with only fallthrough", R"SOURCE( |
| 534 | const io = @import("std").io; | 534 | const io = @import("std").io; |
| 535 | pub fn main(args: [][]u8) -> %void { | 535 | pub fn main() -> %void { |
| 536 | %%io.stdout.printf("before\n"); | 536 | %%io.stdout.printf("before\n"); |
| 537 | defer %%io.stdout.printf("defer1\n"); | 537 | defer %%io.stdout.printf("defer1\n"); |
| 538 | defer %%io.stdout.printf("defer2\n"); | 538 | defer %%io.stdout.printf("defer2\n"); |
| ... | @@ -544,11 +544,12 @@ pub fn main(args: [][]u8) -> %void { | ... | @@ -544,11 +544,12 @@ pub fn main(args: [][]u8) -> %void { |
| 544 | 544 | ||
| 545 | add_simple_case("defer with return", R"SOURCE( | 545 | add_simple_case("defer with return", R"SOURCE( |
| 546 | const io = @import("std").io; | 546 | const io = @import("std").io; |
| 547 | pub fn main(args: [][]u8) -> %void { | 547 | const os = @import("std").os; |
| 548 | pub fn main() -> %void { | ||
| 548 | %%io.stdout.printf("before\n"); | 549 | %%io.stdout.printf("before\n"); |
| 549 | defer %%io.stdout.printf("defer1\n"); | 550 | defer %%io.stdout.printf("defer1\n"); |
| 550 | defer %%io.stdout.printf("defer2\n"); | 551 | defer %%io.stdout.printf("defer2\n"); |
| 551 | if (args.len == 1) return; | 552 | if (os.args.count() == 1) return; |
| 552 | defer %%io.stdout.printf("defer3\n"); | 553 | defer %%io.stdout.printf("defer3\n"); |
| 553 | %%io.stdout.printf("after\n"); | 554 | %%io.stdout.printf("after\n"); |
| 554 | } | 555 | } |
| ... | @@ -557,7 +558,7 @@ pub fn main(args: [][]u8) -> %void { | ... | @@ -557,7 +558,7 @@ pub fn main(args: [][]u8) -> %void { |
| 557 | 558 | ||
| 558 | add_simple_case("%defer and it fails", R"SOURCE( | 559 | add_simple_case("%defer and it fails", R"SOURCE( |
| 559 | const io = @import("std").io; | 560 | const io = @import("std").io; |
| 560 | pub fn main(args: [][]u8) -> %void { | 561 | pub fn main() -> %void { |
| 561 | do_test() %% return; | 562 | do_test() %% return; |
| 562 | } | 563 | } |
| 563 | fn do_test() -> %void { | 564 | fn do_test() -> %void { |
| ... | @@ -577,7 +578,7 @@ fn its_gonna_fail() -> %void { | ... | @@ -577,7 +578,7 @@ fn its_gonna_fail() -> %void { |
| 577 | 578 | ||
| 578 | add_simple_case("%defer and it passes", R"SOURCE( | 579 | add_simple_case("%defer and it passes", R"SOURCE( |
| 579 | const io = @import("std").io; | 580 | const io = @import("std").io; |
| 580 | pub fn main(args: [][]u8) -> %void { | 581 | pub fn main() -> %void { |
| 581 | do_test() %% return; | 582 | do_test() %% return; |
| 582 | } | 583 | } |
| 583 | fn do_test() -> %void { | 584 | fn do_test() -> %void { |
| ... | @@ -597,7 +598,7 @@ fn its_gonna_pass() -> %void { } | ... | @@ -597,7 +598,7 @@ fn its_gonna_pass() -> %void { } |
| 597 | const foo_txt = @embedFile("foo.txt"); | 598 | const foo_txt = @embedFile("foo.txt"); |
| 598 | const io = @import("std").io; | 599 | const io = @import("std").io; |
| 599 | 600 | ||
| 600 | pub fn main(args: [][]u8) -> %void { | 601 | pub fn main() -> %void { |
| 601 | %%io.stdout.printf(foo_txt); | 602 | %%io.stdout.printf(foo_txt); |
| 602 | } | 603 | } |
| 603 | )SOURCE", "1234\nabcd\n"); | 604 | )SOURCE", "1234\nabcd\n"); |
| ... | @@ -1388,9 +1389,13 @@ fn something() -> %void { } | ... | @@ -1388,9 +1389,13 @@ fn something() -> %void { } |
| 1388 | ".tmp_source.zig:3:5: error: expected type 'void', found 'error'"); | 1389 | ".tmp_source.zig:3:5: error: expected type 'void', found 'error'"); |
| 1389 | 1390 | ||
| 1390 | add_compile_fail_case("wrong return type for main", R"SOURCE( | 1391 | add_compile_fail_case("wrong return type for main", R"SOURCE( |
| 1391 | pub fn main(args: [][]u8) { } | 1392 | pub fn main() { } |
| 1392 | )SOURCE", 1, ".tmp_source.zig:2:27: error: expected return type of main to be '%void', instead is 'void'"); | 1393 | )SOURCE", 1, ".tmp_source.zig:2:15: error: expected return type of main to be '%void', instead is 'void'"); |
| 1393 | 1394 | ||
| 1395 | add_compile_fail_case("double ?? on main return value", R"SOURCE( | ||
| 1396 | pub fn main() -> ??void { | ||
| 1397 | } | ||
| 1398 | )SOURCE", 1, ".tmp_source.zig:2:18: error: expected return type of main to be '%void', instead is '??void'"); | ||
| 1394 | 1399 | ||
| 1395 | add_compile_fail_case("invalid pointer for var type", R"SOURCE( | 1400 | add_compile_fail_case("invalid pointer for var type", R"SOURCE( |
| 1396 | extern fn ext() -> usize; | 1401 | extern fn ext() -> usize; |
| ... | @@ -1689,11 +1694,6 @@ fn bar(a: i32, b: []const u8) { | ... | @@ -1689,11 +1694,6 @@ fn bar(a: i32, b: []const u8) { |
| 1689 | ".tmp_source.zig:8:5: error: found compile log statement", | 1694 | ".tmp_source.zig:8:5: error: found compile log statement", |
| 1690 | ".tmp_source.zig:3:17: note: called from here"); | 1695 | ".tmp_source.zig:3:17: note: called from here"); |
| 1691 | 1696 | ||
| 1692 | add_compile_fail_case("double ?? on main return value", R"SOURCE( | ||
| 1693 | pub fn main(args: [][]u8) -> ??void { | ||
| 1694 | } | ||
| 1695 | )SOURCE", 1, ".tmp_source.zig:2:30: error: expected return type of main to be '%void', instead is '??void'"); | ||
| 1696 | |||
| 1697 | add_compile_fail_case("casting bit offset pointer to regular pointer", R"SOURCE( | 1697 | add_compile_fail_case("casting bit offset pointer to regular pointer", R"SOURCE( |
| 1698 | const u2 = @intType(false, 2); | 1698 | const u2 = @intType(false, 2); |
| 1699 | const u3 = @intType(false, 3); | 1699 | const u3 = @intType(false, 3); |
| ... | @@ -1844,7 +1844,7 @@ pub fn panic(message: []const u8) -> noreturn { | ... | @@ -1844,7 +1844,7 @@ pub fn panic(message: []const u8) -> noreturn { |
| 1844 | @breakpoint(); | 1844 | @breakpoint(); |
| 1845 | while (true) {} | 1845 | while (true) {} |
| 1846 | } | 1846 | } |
| 1847 | pub fn main(args: [][]u8) -> %void { | 1847 | pub fn main() -> %void { |
| 1848 | if (!@compileVar("is_release")) { | 1848 | if (!@compileVar("is_release")) { |
| 1849 | @panic("oh no"); | 1849 | @panic("oh no"); |
| 1850 | } | 1850 | } |
| ... | @@ -1856,7 +1856,7 @@ pub fn panic(message: []const u8) -> noreturn { | ... | @@ -1856,7 +1856,7 @@ pub fn panic(message: []const u8) -> noreturn { |
| 1856 | @breakpoint(); | 1856 | @breakpoint(); |
| 1857 | while (true) {} | 1857 | while (true) {} |
| 1858 | } | 1858 | } |
| 1859 | pub fn main(args: [][]u8) -> %void { | 1859 | pub fn main() -> %void { |
| 1860 | const a = []i32{1, 2, 3, 4}; | 1860 | const a = []i32{1, 2, 3, 4}; |
| 1861 | baz(bar(a)); | 1861 | baz(bar(a)); |
| 1862 | } | 1862 | } |
| ... | @@ -1872,7 +1872,7 @@ pub fn panic(message: []const u8) -> noreturn { | ... | @@ -1872,7 +1872,7 @@ pub fn panic(message: []const u8) -> noreturn { |
| 1872 | while (true) {} | 1872 | while (true) {} |
| 1873 | } | 1873 | } |
| 1874 | error Whatever; | 1874 | error Whatever; |
| 1875 | pub fn main(args: [][]u8) -> %void { | 1875 | pub fn main() -> %void { |
| 1876 | const x = add(65530, 10); | 1876 | const x = add(65530, 10); |
| 1877 | if (x == 0) return error.Whatever; | 1877 | if (x == 0) return error.Whatever; |
| 1878 | } | 1878 | } |
| ... | @@ -1887,7 +1887,7 @@ pub fn panic(message: []const u8) -> noreturn { | ... | @@ -1887,7 +1887,7 @@ pub fn panic(message: []const u8) -> noreturn { |
| 1887 | while (true) {} | 1887 | while (true) {} |
| 1888 | } | 1888 | } |
| 1889 | error Whatever; | 1889 | error Whatever; |
| 1890 | pub fn main(args: [][]u8) -> %void { | 1890 | pub fn main() -> %void { |
| 1891 | const x = sub(10, 20); | 1891 | const x = sub(10, 20); |
| 1892 | if (x == 0) return error.Whatever; | 1892 | if (x == 0) return error.Whatever; |
| 1893 | } | 1893 | } |
| ... | @@ -1902,7 +1902,7 @@ pub fn panic(message: []const u8) -> noreturn { | ... | @@ -1902,7 +1902,7 @@ pub fn panic(message: []const u8) -> noreturn { |
| 1902 | while (true) {} | 1902 | while (true) {} |
| 1903 | } | 1903 | } |
| 1904 | error Whatever; | 1904 | error Whatever; |
| 1905 | pub fn main(args: [][]u8) -> %void { | 1905 | pub fn main() -> %void { |
| 1906 | const x = mul(300, 6000); | 1906 | const x = mul(300, 6000); |
| 1907 | if (x == 0) return error.Whatever; | 1907 | if (x == 0) return error.Whatever; |
| 1908 | } | 1908 | } |
| ... | @@ -1917,7 +1917,7 @@ pub fn panic(message: []const u8) -> noreturn { | ... | @@ -1917,7 +1917,7 @@ pub fn panic(message: []const u8) -> noreturn { |
| 1917 | while (true) {} | 1917 | while (true) {} |
| 1918 | } | 1918 | } |
| 1919 | error Whatever; | 1919 | error Whatever; |
| 1920 | pub fn main(args: [][]u8) -> %void { | 1920 | pub fn main() -> %void { |
| 1921 | const x = neg(-32768); | 1921 | const x = neg(-32768); |
| 1922 | if (x == 32767) return error.Whatever; | 1922 | if (x == 32767) return error.Whatever; |
| 1923 | } | 1923 | } |
| ... | @@ -1932,7 +1932,7 @@ pub fn panic(message: []const u8) -> noreturn { | ... | @@ -1932,7 +1932,7 @@ pub fn panic(message: []const u8) -> noreturn { |
| 1932 | while (true) {} | 1932 | while (true) {} |
| 1933 | } | 1933 | } |
| 1934 | error Whatever; | 1934 | error Whatever; |
| 1935 | pub fn main(args: [][]u8) -> %void { | 1935 | pub fn main() -> %void { |
| 1936 | const x = div(-32768, -1); | 1936 | const x = div(-32768, -1); |
| 1937 | if (x == 32767) return error.Whatever; | 1937 | if (x == 32767) return error.Whatever; |
| 1938 | } | 1938 | } |
| ... | @@ -1947,7 +1947,7 @@ pub fn panic(message: []const u8) -> noreturn { | ... | @@ -1947,7 +1947,7 @@ pub fn panic(message: []const u8) -> noreturn { |
| 1947 | while (true) {} | 1947 | while (true) {} |
| 1948 | } | 1948 | } |
| 1949 | error Whatever; | 1949 | error Whatever; |
| 1950 | pub fn main(args: [][]u8) -> %void { | 1950 | pub fn main() -> %void { |
| 1951 | const x = shl(-16385, 1); | 1951 | const x = shl(-16385, 1); |
| 1952 | if (x == 0) return error.Whatever; | 1952 | if (x == 0) return error.Whatever; |
| 1953 | } | 1953 | } |
| ... | @@ -1962,7 +1962,7 @@ pub fn panic(message: []const u8) -> noreturn { | ... | @@ -1962,7 +1962,7 @@ pub fn panic(message: []const u8) -> noreturn { |
| 1962 | while (true) {} | 1962 | while (true) {} |
| 1963 | } | 1963 | } |
| 1964 | error Whatever; | 1964 | error Whatever; |
| 1965 | pub fn main(args: [][]u8) -> %void { | 1965 | pub fn main() -> %void { |
| 1966 | const x = shl(0b0010111111111111, 3); | 1966 | const x = shl(0b0010111111111111, 3); |
| 1967 | if (x == 0) return error.Whatever; | 1967 | if (x == 0) return error.Whatever; |
| 1968 | } | 1968 | } |
| ... | @@ -1977,7 +1977,7 @@ pub fn panic(message: []const u8) -> noreturn { | ... | @@ -1977,7 +1977,7 @@ pub fn panic(message: []const u8) -> noreturn { |
| 1977 | while (true) {} | 1977 | while (true) {} |
| 1978 | } | 1978 | } |
| 1979 | error Whatever; | 1979 | error Whatever; |
| 1980 | pub fn main(args: [][]u8) -> %void { | 1980 | pub fn main() -> %void { |
| 1981 | const x = div0(999, 0); | 1981 | const x = div0(999, 0); |
| 1982 | } | 1982 | } |
| 1983 | fn div0(a: i32, b: i32) -> i32 { | 1983 | fn div0(a: i32, b: i32) -> i32 { |
| ... | @@ -1991,7 +1991,7 @@ pub fn panic(message: []const u8) -> noreturn { | ... | @@ -1991,7 +1991,7 @@ pub fn panic(message: []const u8) -> noreturn { |
| 1991 | while (true) {} | 1991 | while (true) {} |
| 1992 | } | 1992 | } |
| 1993 | error Whatever; | 1993 | error Whatever; |
| 1994 | pub fn main(args: [][]u8) -> %void { | 1994 | pub fn main() -> %void { |
| 1995 | const x = divExact(10, 3); | 1995 | const x = divExact(10, 3); |
| 1996 | if (x == 0) return error.Whatever; | 1996 | if (x == 0) return error.Whatever; |
| 1997 | } | 1997 | } |
| ... | @@ -2006,7 +2006,7 @@ pub fn panic(message: []const u8) -> noreturn { | ... | @@ -2006,7 +2006,7 @@ pub fn panic(message: []const u8) -> noreturn { |
| 2006 | while (true) {} | 2006 | while (true) {} |
| 2007 | } | 2007 | } |
| 2008 | error Whatever; | 2008 | error Whatever; |
| 2009 | pub fn main(args: [][]u8) -> %void { | 2009 | pub fn main() -> %void { |
| 2010 | const x = widenSlice([]u8{1, 2, 3, 4, 5}); | 2010 | const x = widenSlice([]u8{1, 2, 3, 4, 5}); |
| 2011 | if (x.len == 0) return error.Whatever; | 2011 | if (x.len == 0) return error.Whatever; |
| 2012 | } | 2012 | } |
| ... | @@ -2021,7 +2021,7 @@ pub fn panic(message: []const u8) -> noreturn { | ... | @@ -2021,7 +2021,7 @@ pub fn panic(message: []const u8) -> noreturn { |
| 2021 | while (true) {} | 2021 | while (true) {} |
| 2022 | } | 2022 | } |
| 2023 | error Whatever; | 2023 | error Whatever; |
| 2024 | pub fn main(args: [][]u8) -> %void { | 2024 | pub fn main() -> %void { |
| 2025 | const x = shorten_cast(200); | 2025 | const x = shorten_cast(200); |
| 2026 | if (x == 0) return error.Whatever; | 2026 | if (x == 0) return error.Whatever; |
| 2027 | } | 2027 | } |
| ... | @@ -2036,7 +2036,7 @@ pub fn panic(message: []const u8) -> noreturn { | ... | @@ -2036,7 +2036,7 @@ pub fn panic(message: []const u8) -> noreturn { |
| 2036 | while (true) {} | 2036 | while (true) {} |
| 2037 | } | 2037 | } |
| 2038 | error Whatever; | 2038 | error Whatever; |
| 2039 | pub fn main(args: [][]u8) -> %void { | 2039 | pub fn main() -> %void { |
| 2040 | const x = unsigned_cast(-10); | 2040 | const x = unsigned_cast(-10); |
| 2041 | if (x == 0) return error.Whatever; | 2041 | if (x == 0) return error.Whatever; |
| 2042 | } | 2042 | } |
| ... | @@ -2051,7 +2051,7 @@ pub fn panic(message: []const u8) -> noreturn { | ... | @@ -2051,7 +2051,7 @@ pub fn panic(message: []const u8) -> noreturn { |
| 2051 | while (true) {} | 2051 | while (true) {} |
| 2052 | } | 2052 | } |
| 2053 | error Whatever; | 2053 | error Whatever; |
| 2054 | pub fn main(args: [][]u8) -> %void { | 2054 | pub fn main() -> %void { |
| 2055 | %%bar(); | 2055 | %%bar(); |
| 2056 | } | 2056 | } |
| 2057 | fn bar() -> %void { | 2057 | fn bar() -> %void { |
| ... | @@ -2064,7 +2064,7 @@ pub fn panic(message: []const u8) -> noreturn { | ... | @@ -2064,7 +2064,7 @@ pub fn panic(message: []const u8) -> noreturn { |
| 2064 | @breakpoint(); | 2064 | @breakpoint(); |
| 2065 | while (true) {} | 2065 | while (true) {} |
| 2066 | } | 2066 | } |
| 2067 | pub fn main(args: [][]u8) -> %void { | 2067 | pub fn main() -> %void { |
| 2068 | _ = bar(9999); | 2068 | _ = bar(9999); |
| 2069 | } | 2069 | } |
| 2070 | fn bar(x: u32) -> error { | 2070 | fn bar(x: u32) -> error { |
| ... | @@ -2500,25 +2500,13 @@ static void run_test(TestCase *test_case) { | ... | @@ -2500,25 +2500,13 @@ static void run_test(TestCase *test_case) { |
| 2500 | } | 2500 | } |
| 2501 | } | 2501 | } |
| 2502 | 2502 | ||
| 2503 | static void run_all_tests(bool reverse) { | 2503 | static void run_all_tests(void) { |
| 2504 | if (reverse) { | 2504 | for (size_t i = 0; i < test_cases.length; i += 1) { |
| 2505 | for (size_t i = test_cases.length;;) { | 2505 | TestCase *test_case = test_cases.at(i); |
| 2506 | TestCase *test_case = test_cases.at(i); | 2506 | printf("Test %zu/%zu %s...", i + 1, test_cases.length, test_case->case_name); |
| 2507 | printf("Test %zu/%zu %s...", i + 1, test_cases.length, test_case->case_name); | 2507 | fflush(stdout); |
| 2508 | fflush(stdout); | 2508 | run_test(test_case); |
| 2509 | run_test(test_case); | 2509 | printf("OK\n"); |
| 2510 | printf("OK\n"); | ||
| 2511 | if (i == 0) break; | ||
| 2512 | i -= 1; | ||
| 2513 | } | ||
| 2514 | } else { | ||
| 2515 | for (size_t i = 0; i < test_cases.length; i += 1) { | ||
| 2516 | TestCase *test_case = test_cases.at(i); | ||
| 2517 | printf("Test %zu/%zu %s...", i + 1, test_cases.length, test_case->case_name); | ||
| 2518 | fflush(stdout); | ||
| 2519 | run_test(test_case); | ||
| 2520 | printf("OK\n"); | ||
| 2521 | } | ||
| 2522 | } | 2510 | } |
| 2523 | printf("%zu tests passed.\n", test_cases.length); | 2511 | printf("%zu tests passed.\n", test_cases.length); |
| 2524 | } | 2512 | } |
| ... | @@ -2530,18 +2518,13 @@ static void cleanup(void) { | ... | @@ -2530,18 +2518,13 @@ static void cleanup(void) { |
| 2530 | } | 2518 | } |
| 2531 | 2519 | ||
| 2532 | static int usage(const char *arg0) { | 2520 | static int usage(const char *arg0) { |
| 2533 | fprintf(stderr, "Usage: %s [--reverse]\n", arg0); | 2521 | fprintf(stderr, "Usage: %s\n", arg0); |
| 2534 | return 1; | 2522 | return 1; |
| 2535 | } | 2523 | } |
| 2536 | 2524 | ||
| 2537 | int main(int argc, char **argv) { | 2525 | int main(int argc, char **argv) { |
| 2538 | bool reverse = false; | ||
| 2539 | for (int i = 1; i < argc; i += 1) { | 2526 | for (int i = 1; i < argc; i += 1) { |
| 2540 | if (strcmp(argv[i], "--reverse") == 0) { | 2527 | return usage(argv[0]); |
| 2541 | reverse = true; | ||
| 2542 | } else { | ||
| 2543 | return usage(argv[0]); | ||
| 2544 | } | ||
| 2545 | } | 2528 | } |
| 2546 | add_compiling_test_cases(); | 2529 | add_compiling_test_cases(); |
| 2547 | add_debug_safety_test_cases(); | 2530 | add_debug_safety_test_cases(); |
| ... | @@ -2549,6 +2532,6 @@ int main(int argc, char **argv) { | ... | @@ -2549,6 +2532,6 @@ int main(int argc, char **argv) { |
| 2549 | add_parseh_test_cases(); | 2532 | add_parseh_test_cases(); |
| 2550 | add_self_hosted_tests(); | 2533 | add_self_hosted_tests(); |
| 2551 | add_std_lib_tests(); | 2534 | add_std_lib_tests(); |
| 2552 | run_all_tests(reverse); | 2535 | run_all_tests(); |
| 2553 | cleanup(); | 2536 | cleanup(); |
| 2554 | } | 2537 | } |