authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-04 00:17:24-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-04 00:17:24-04:00
log72fb2443e0e5dd0c8c3a0265428832796b4ff548
treedd4cfda1e44784a80538ccd3c6d776c3fb664651
parentb46344fd01db28384b51d9898ef25c4825bb19b0

API for command line args

closes #300

11 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}")
223install(FILES "${CMAKE_SOURCE_DIR}/std/math.zig" DESTINATION "${ZIG_STD_DEST}")223install(FILES "${CMAKE_SOURCE_DIR}/std/math.zig" DESTINATION "${ZIG_STD_DEST}")
224install(FILES "${CMAKE_SOURCE_DIR}/std/mem.zig" DESTINATION "${ZIG_STD_DEST}")224install(FILES "${CMAKE_SOURCE_DIR}/std/mem.zig" DESTINATION "${ZIG_STD_DEST}")
225install(FILES "${CMAKE_SOURCE_DIR}/std/net.zig" DESTINATION "${ZIG_STD_DEST}")225install(FILES "${CMAKE_SOURCE_DIR}/std/net.zig" DESTINATION "${ZIG_STD_DEST}")
226install(FILES "${CMAKE_SOURCE_DIR}/std/os/child_process.zig" DESTINATION "${ZIG_STD_DEST}/os")
226install(FILES "${CMAKE_SOURCE_DIR}/std/os/darwin.zig" DESTINATION "${ZIG_STD_DEST}/os")227install(FILES "${CMAKE_SOURCE_DIR}/std/os/darwin.zig" DESTINATION "${ZIG_STD_DEST}/os")
227install(FILES "${CMAKE_SOURCE_DIR}/std/os/darwin_x86_64.zig" DESTINATION "${ZIG_STD_DEST}/os")228install(FILES "${CMAKE_SOURCE_DIR}/std/os/darwin_x86_64.zig" DESTINATION "${ZIG_STD_DEST}/os")
228install(FILES "${CMAKE_SOURCE_DIR}/std/os/errno.zig" DESTINATION "${ZIG_STD_DEST}/os")229install(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 @@
1const std = @import("std");1const std = @import("std");
2const io = std.io;2const io = std.io;
3const mem = std.mem;3const mem = std.mem;
4const os = std.os;
45
5pub fn main(args: [][]u8) -> %void {6pub 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();
2123
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}
3133
32fn usage(exe: []u8) -> %void {34fn 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;
4const Rand = std.rand.Rand;4const Rand = std.rand.Rand;
5const os = std.os;5const os = std.os;
66
7pub fn main(args: [][]u8) -> %void {7pub 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");
99
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 @@
1const io = @import("std").io;1const io = @import("std").io;
22
3pub fn main(args: [][]u8) -> %void {3pub 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 }
4141
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);
4444
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 }
9698
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 @@
1const io = @import("../io.zig");
2const os = @import("index.zig");
3const posix = os.posix;
4const mem = @import("../mem.zig");
5const Allocator = mem.Allocator;
6const errno = @import("errno.zig");
7const debug = @import("../debug.zig");
8const assert = debug.assert;
9
10pub 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
217fn 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
229fn 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.
236fn forkChildErrReport(fd: i32, err: error) -> noreturn {
237 _ = writeIntFd(fd, ErrInt(err));
238 posix.exit(1);
239}
240
241const ErrInt = @intType(false, @sizeOf(error) * 8);
242fn 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
261fn 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};
1010
11pub const max_noalloc_path_len = 1024;11pub const max_noalloc_path_len = 1024;
12pub const ChildProcess = @import("child_process.zig").ChildProcess;
1213
13const debug = @import("../debug.zig");14const debug = @import("../debug.zig");
14const assert = debug.assert;15const assert = debug.assert;
...@@ -20,7 +21,6 @@ const c = @import("../c/index.zig");...@@ -20,7 +21,6 @@ const c = @import("../c/index.zig");
20const mem = @import("../mem.zig");21const mem = @import("../mem.zig");
21const Allocator = mem.Allocator;22const Allocator = mem.Allocator;
2223
23const io = @import("../io.zig");
24const HashMap = @import("../hash_map.zig").HashMap;24const HashMap = @import("../hash_map.zig").HashMap;
25const cstr = @import("../cstr.zig");25const cstr = @import("../cstr.zig");
2626
...@@ -96,23 +96,6 @@ pub coldcc fn abort() -> noreturn {...@@ -96,23 +96,6 @@ pub coldcc fn abort() -> noreturn {
96 }96 }
97}97}
9898
99fn 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
111fn 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.
117pub fn posixClose(fd: i32) {100pub 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}
204187
205const ErrInt = @intType(false, @sizeOf(error) * 8);188pub fn posixDup2(old_fd: i32, new_fd: i32) -> %void {
206fn 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
225fn 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.
247fn forkChildErrReport(fd: i32, err: error) -> noreturn {
248 _ = writeIntFd(fd, ErrInt(err));
249 posix.exit(1);
250}
251
252fn 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}
266202
267pub 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 null204/// 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.
478fn execve(path: []const u8, argv: []const []const u8, env_map: &const EnvMap, allocator: &Allocator) -> %usize {207pub 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};
608352
609pub fn getEnvMap(allocator: &Allocator) -> %EnvMap {353pub 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}
643387
644fn hash_slice_u8(k: []const u8) -> u32 {388pub const args = struct {
645 // FNV 32-bit hash389 pub var raw: []&u8 = undefined;
646 var h: u32 = 2166136261;
647 for (k) |b| {
648 h = (h ^ b) *% 16777619;
649 }
650 return h;
651}
652390
653fn 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}
3939
40var args_data: [32][]u8 = undefined;
41fn callMain(argc: usize, argv: &&u8, envp: &?&u8) -> %void {40fn callMain(argc: usize, argv: &&u8, envp: &?&u8) -> %void {
42 // TODO create args API to make it work with > 32 args41 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 }
4842
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];
5246
53 return root.main(args);47 return root.main();
54}48}
5549
56export fn main(c_argc: i32, c_argv: &&u8, c_envp: &?&u8) -> i32 {50export 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 @@
1const root = @import("@build");1const root = @import("@build");
2const std = @import("std");2const std = @import("std");
3const io = std.io;3const io = std.io;
4const os = std.os;
4const Builder = std.build.Builder;5const Builder = std.build.Builder;
5const mem = std.mem;6const mem = std.mem;
67
7error InvalidArgs;8error InvalidArgs;
89
9pub fn main(args: [][]u8) -> %void {10pub 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;
1617
17 // TODO use a more general purpose allocator here18 // 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 {
2021
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 {
77
8extern var zig_test_fn_list: []TestFn;8extern var zig_test_fn_list: []TestFn;
99
10pub fn main(args: [][]u8) -> %void {10pub 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);
1313
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 {
215use @import("std").io;215use @import("std").io;
216use @import("foo.zig");216use @import("foo.zig");
217217
218pub fn main(args: [][]u8) -> %void {218pub 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() {
245use @import("foo.zig");245use @import("foo.zig");
246use @import("bar.zig");246use @import("bar.zig");
247247
248pub fn main(args: [][]u8) -> %void {248pub 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(
282use @import("a.zig");282use @import("a.zig");
283283
284pub fn main(args: [][]u8) -> %void {284pub 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(
310const io = @import("std").io;310const io = @import("std").io;
311311
312pub fn main(args: [][]u8) -> %void {312pub 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;
446const z = io.stdin_fileno;446const z = io.stdin_fileno;
447const x : @typeOf(y) = 1234;447const x : @typeOf(y) = 1234;
448const y : u16 = 5678;448const y : u16 = 5678;
449pub fn main(args: [][]u8) -> %void {449pub fn main() -> %void {
450 var x_local : i32 = print_ok(x);450 var x_local : i32 = print_ok(x);
451}451}
452fn print_ok(val: @typeOf(x)) -> @typeOf(foo) {452fn 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}
473473
474export fn main(args: c_int, argv: &&u8) -> c_int {474export 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 };
476476
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};
518518
519pub fn main(args: [][]u8) -> %void {519pub 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 {
532532
533 add_simple_case("defer with only fallthrough", R"SOURCE(533 add_simple_case("defer with only fallthrough", R"SOURCE(
534const io = @import("std").io;534const io = @import("std").io;
535pub fn main(args: [][]u8) -> %void {535pub 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 {
544544
545 add_simple_case("defer with return", R"SOURCE(545 add_simple_case("defer with return", R"SOURCE(
546const io = @import("std").io;546const io = @import("std").io;
547pub fn main(args: [][]u8) -> %void {547const os = @import("std").os;
548pub 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 {
557558
558 add_simple_case("%defer and it fails", R"SOURCE(559 add_simple_case("%defer and it fails", R"SOURCE(
559const io = @import("std").io;560const io = @import("std").io;
560pub fn main(args: [][]u8) -> %void {561pub fn main() -> %void {
561 do_test() %% return;562 do_test() %% return;
562}563}
563fn do_test() -> %void {564fn do_test() -> %void {
...@@ -577,7 +578,7 @@ fn its_gonna_fail() -> %void {...@@ -577,7 +578,7 @@ fn its_gonna_fail() -> %void {
577578
578 add_simple_case("%defer and it passes", R"SOURCE(579 add_simple_case("%defer and it passes", R"SOURCE(
579const io = @import("std").io;580const io = @import("std").io;
580pub fn main(args: [][]u8) -> %void {581pub fn main() -> %void {
581 do_test() %% return;582 do_test() %% return;
582}583}
583fn do_test() -> %void {584fn do_test() -> %void {
...@@ -597,7 +598,7 @@ fn its_gonna_pass() -> %void { }...@@ -597,7 +598,7 @@ fn its_gonna_pass() -> %void { }
597const foo_txt = @embedFile("foo.txt");598const foo_txt = @embedFile("foo.txt");
598const io = @import("std").io;599const io = @import("std").io;
599600
600pub fn main(args: [][]u8) -> %void {601pub 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'");
13891390
1390 add_compile_fail_case("wrong return type for main", R"SOURCE(1391 add_compile_fail_case("wrong return type for main", R"SOURCE(
1391pub fn main(args: [][]u8) { }1392pub 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'");
13931394
1395 add_compile_fail_case("double ?? on main return value", R"SOURCE(
1396pub fn main() -> ??void {
1397}
1398 )SOURCE", 1, ".tmp_source.zig:2:18: error: expected return type of main to be '%void', instead is '??void'");
13941399
1395 add_compile_fail_case("invalid pointer for var type", R"SOURCE(1400 add_compile_fail_case("invalid pointer for var type", R"SOURCE(
1396extern fn ext() -> usize;1401extern 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");
16911696
1692 add_compile_fail_case("double ?? on main return value", R"SOURCE(
1693pub 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(
1698const u2 = @intType(false, 2);1698const u2 = @intType(false, 2);
1699const u3 = @intType(false, 3);1699const 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}
1847pub fn main(args: [][]u8) -> %void {1847pub 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}
1859pub fn main(args: [][]u8) -> %void {1859pub 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}
1874error Whatever;1874error Whatever;
1875pub fn main(args: [][]u8) -> %void {1875pub 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}
1889error Whatever;1889error Whatever;
1890pub fn main(args: [][]u8) -> %void {1890pub 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}
1904error Whatever;1904error Whatever;
1905pub fn main(args: [][]u8) -> %void {1905pub 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}
1919error Whatever;1919error Whatever;
1920pub fn main(args: [][]u8) -> %void {1920pub 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}
1934error Whatever;1934error Whatever;
1935pub fn main(args: [][]u8) -> %void {1935pub 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}
1949error Whatever;1949error Whatever;
1950pub fn main(args: [][]u8) -> %void {1950pub 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}
1964error Whatever;1964error Whatever;
1965pub fn main(args: [][]u8) -> %void {1965pub 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}
1979error Whatever;1979error Whatever;
1980pub fn main(args: [][]u8) -> %void {1980pub fn main() -> %void {
1981 const x = div0(999, 0);1981 const x = div0(999, 0);
1982}1982}
1983fn div0(a: i32, b: i32) -> i32 {1983fn 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}
1993error Whatever;1993error Whatever;
1994pub fn main(args: [][]u8) -> %void {1994pub 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}
2008error Whatever;2008error Whatever;
2009pub fn main(args: [][]u8) -> %void {2009pub 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}
2023error Whatever;2023error Whatever;
2024pub fn main(args: [][]u8) -> %void {2024pub 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}
2038error Whatever;2038error Whatever;
2039pub fn main(args: [][]u8) -> %void {2039pub 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}
2053error Whatever;2053error Whatever;
2054pub fn main(args: [][]u8) -> %void {2054pub fn main() -> %void {
2055 %%bar();2055 %%bar();
2056}2056}
2057fn bar() -> %void {2057fn 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}
2067pub fn main(args: [][]u8) -> %void {2067pub fn main() -> %void {
2068 _ = bar(9999);2068 _ = bar(9999);
2069}2069}
2070fn bar(x: u32) -> error {2070fn 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}
25022502
2503static void run_all_tests(bool reverse) {2503static 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}
25312519
2532static int usage(const char *arg0) {2520static 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}
25362524
2537int main(int argc, char **argv) {2525int 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}