1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
|
export type status = enum {
SUCCESS,
USER,
LEX,
PARSE,
CHECK,
ABNORMAL = 255,
};
fn strstatus(status: int) str = {
switch (status) {
case status::SUCCESS =>
return "success (0)";
case status::USER =>
return "user (1)";
case status::LEX =>
return "lex (2)";
case status::PARSE =>
return "parse (3)";
case status::CHECK =>
return "check (4)";
case status::ABNORMAL =>
return "abnormal (255)";
case =>
return itos(status: int);
};
};
export type error = !void;
// Runs the Hare compiler and returns the exit status.
export fn compile(
expected: (status | void),
src: str,
flags: str...
) (void | error) = {
let wstatus = 0;
let pipefd = [-1, -1];
assert(pipe2(&pipefd, 0) == 0);
const child = fork();
if (child == 0) {
close(pipefd[1]);
dup2(pipefd[0], 0);
close(1);
close(2);
let argv: []nullable *const u8 = [];
defer for (let i = 0z; i < len(argv); i += 1) {
free(argv[i]);
};
// FIXME use $BINOUT variable
append(argv, alloc_constchar("./.bin/harec"));
for (let i = 0z; i < len(flags); i += 1) {
append(argv, alloc_constchar(flags[i]));
};
append(argv, alloc_constchar("-o/dev/null"));
append(argv, alloc_constchar("-"));
append(argv, null);
execve(constchar("./.bin/harec\0"), *(&argv: **[*]nullable *const u8), envp);
abort();
} else {
assert(child != -1, "fork(2) failed");
close(pipefd[0]);
const buf = constchar(src): *const [*]u8;
for (let n = 0z; n < len(src)) {
let m = write(pipefd[1], &buf[n], len(src) - n): size;
assert(m > 0, "write(2) failed");
n += m;
};
close(pipefd[1]);
wait4(child, &wstatus, 0, null);
};
if (!wifexited(wstatus)) {
assert(wifsignaled(wstatus));
let s = "signaled ";
write(2, constchar(s), len(s));
s = itos(wtermsig(wstatus));
write(2, constchar(s), len(s));
write(2, constchar("\n"), 1);
return error;
};
match (expected) {
case void =>
const status = wexitstatus(wstatus);
if (status == status::SUCCESS) {
let s = "expected any failure, got success\n";
write(2, constchar(s), len(s));
return error;
};
case let expected: status =>
const status = wexitstatus(wstatus);
if (status != expected) {
let s = "expected ";
write(2, constchar(s), len(s));
s = strstatus(expected);
write(2, constchar(s), len(s));
s = ", got ";
write(2, constchar(s), len(s));
s = strstatus(status);
write(2, constchar(s), len(s));
write(2, constchar("\n"), 1);
return error;
};
};
};
|