diff --git a/lib/os/os.ww b/lib/os/os.ww index 0b68988a..0b09306f 100644 --- a/lib/os/os.ww +++ b/lib/os/os.ww @@ -34,17 +34,23 @@ def SYS_UNLINK: i64 = 87; def SYS_GETCWD: i64 = 79; def SYS_GETDENTS64: i64 = 217; -// open(2) flags. Linux values, matching . -def O_RDONLY: i32 = 0; -def O_WRONLY: i32 = 1; -def O_RDWR: i32 = 2; -def O_CREAT: i32 = 64; // 0x40 -def O_TRUNC: i32 = 512; // 0x200 +// open(2) flags. Linux values, matching . Hare names them +// `fs::flag::RDONLY` etc; we use the same leaf names so callers say +// `os.flag.RDONLY` and `os.flag.WRONLY | os.flag.CREATE`. +export type flag = enum i32 { + RDONLY = 0, + WRONLY = 1, + RDWR = 2, + CREATE = 64, // 0x40 + TRUNC = 512, // 0x200 +}; -// lseek(2) whence. -def SEEK_SET: i32 = 0; -def SEEK_CUR: i32 = 1; -def SEEK_END: i32 = 2; +// lseek(2) whence. Hare names it `io::whence`. +export type whence = enum i32 { + SET = 0, + CUR = 1, + END = 2, +}; export fn exit(code: i32) void = { syscall1(SYS_EXIT, code: i64); @@ -92,11 +98,11 @@ export fn trywrite(fd: i32, buf: *u8, n: u64) (i64 | oserror) = { // `str` must ensure the bytes are followed by a 0 byte (literals are, // arena-copied paths usually are by construction). Returns -errno on // failure, fd otherwise. Higher-level callers prefer `tryopen`. -export fn open(path: *u8, flags: i32, mode: i32) i32 = { - return syscall3(SYS_OPEN, path: i64, flags: i64, mode: i64): i32; +export fn open(path: *u8, flags: flag, mode: i32) i32 = { + return syscall3(SYS_OPEN, path: i64, (flags as i32): i64, mode: i64): i32; }; -export fn tryopen(path: *u8, flags: i32, mode: i32) (i32 | oserror) = { +export fn tryopen(path: *u8, flags: flag, mode: i32) (i32 | oserror) = { let fd: i32 = open(path, flags, mode); if (fd < 0) { return fd: i64: oserror; }; return fd; @@ -105,8 +111,8 @@ export fn tryopen(path: *u8, flags: i32, mode: i32) (i32 | oserror) = { // lseek — set/inspect the fd's position. Returns the new offset or // a negative errno. We use this for fstat-free file-size discovery // (open ⇒ lseek to end ⇒ lseek back). -export fn lseek(fd: i32, off: i64, whence: i32) i64 = { - return syscall3(SYS_LSEEK, fd: i64, off, whence: i64); +export fn lseek(fd: i32, off: i64, w: whence) i64 = { + return syscall3(SYS_LSEEK, fd: i64, off, (w as i32): i64); }; // oserror — the underlying errno from a failed syscall, as a @@ -118,9 +124,9 @@ export type oserror = !i64; // filesize — byte length of an open fd via lseek-to-end-and-back. export fn filesize(fd: i32) (i64 | oserror) = { - let end: i64 = lseek(fd, 0i64, SEEK_END); + let end: i64 = lseek(fd, 0i64, whence.END); if (end < 0) { return end: oserror; }; - let r: i64 = lseek(fd, 0i64, SEEK_SET); + let r: i64 = lseek(fd, 0i64, whence.SET); if (r < 0) { return r: oserror; }; return end; }; diff --git a/selfhost/cmd/w6a/main.combined.ww b/selfhost/cmd/w6a/main.combined.ww index aec6ca50..a8dd469e 100644 --- a/selfhost/cmd/w6a/main.combined.ww +++ b/selfhost/cmd/w6a/main.combined.ww @@ -35,17 +35,23 @@ def SYS_UNLINK: i64 = 87; def SYS_GETCWD: i64 = 79; def SYS_GETDENTS64: i64 = 217; -// open(2) flags. Linux values, matching . -def O_RDONLY: i32 = 0; -def O_WRONLY: i32 = 1; -def O_RDWR: i32 = 2; -def O_CREAT: i32 = 64; // 0x40 -def O_TRUNC: i32 = 512; // 0x200 +// open(2) flags. Linux values, matching . Hare names them +// `fs::flag::RDONLY` etc; we use the same leaf names so callers say +// `os.flag.RDONLY` and `os.flag.WRONLY | os.flag.CREATE`. +export type flag = enum i32 { + RDONLY = 0, + WRONLY = 1, + RDWR = 2, + CREATE = 64, // 0x40 + TRUNC = 512, // 0x200 +}; -// lseek(2) whence. -def SEEK_SET: i32 = 0; -def SEEK_CUR: i32 = 1; -def SEEK_END: i32 = 2; +// lseek(2) whence. Hare names it `io::whence`. +export type whence = enum i32 { + SET = 0, + CUR = 1, + END = 2, +}; export fn exit(code: i32) void = { syscall1(SYS_EXIT, code: i64); @@ -93,11 +99,11 @@ export fn trywrite(fd: i32, buf: *u8, n: u64) (i64 | oserror) = { // `str` must ensure the bytes are followed by a 0 byte (literals are, // arena-copied paths usually are by construction). Returns -errno on // failure, fd otherwise. Higher-level callers prefer `tryopen`. -export fn open(path: *u8, flags: i32, mode: i32) i32 = { - return syscall3(SYS_OPEN, path: i64, flags: i64, mode: i64): i32; +export fn open(path: *u8, flags: flag, mode: i32) i32 = { + return syscall3(SYS_OPEN, path: i64, (flags as i32): i64, mode: i64): i32; }; -export fn tryopen(path: *u8, flags: i32, mode: i32) (i32 | oserror) = { +export fn tryopen(path: *u8, flags: flag, mode: i32) (i32 | oserror) = { let fd: i32 = open(path, flags, mode); if (fd < 0) { return fd: i64: oserror; }; return fd; @@ -106,8 +112,8 @@ export fn tryopen(path: *u8, flags: i32, mode: i32) (i32 | oserror) = { // lseek — set/inspect the fd's position. Returns the new offset or // a negative errno. We use this for fstat-free file-size discovery // (open ⇒ lseek to end ⇒ lseek back). -export fn lseek(fd: i32, off: i64, whence: i32) i64 = { - return syscall3(SYS_LSEEK, fd: i64, off, whence: i64); +export fn lseek(fd: i32, off: i64, w: whence) i64 = { + return syscall3(SYS_LSEEK, fd: i64, off, (w as i32): i64); }; // oserror — the underlying errno from a failed syscall, as a @@ -119,9 +125,9 @@ export type oserror = !i64; // filesize — byte length of an open fd via lseek-to-end-and-back. export fn filesize(fd: i32) (i64 | oserror) = { - let end: i64 = lseek(fd, 0i64, SEEK_END); + let end: i64 = lseek(fd, 0i64, whence.END); if (end < 0) { return end: oserror; }; - let r: i64 = lseek(fd, 0i64, SEEK_SET); + let r: i64 = lseek(fd, 0i64, whence.SET); if (r < 0) { return r: oserror; }; return end; }; @@ -2189,7 +2195,7 @@ fn cstrlen(p: *u8) u64 = { // Slurp the whole file into a fresh buffer. fn slurp(path: *u8) (*u8, u64) = { - let fd: i32 = os.open(path, os.O_RDONLY, 0i32); + let fd: i32 = os.open(path, os.flag.RDONLY, 0i32); if (fd < 0) { return nil, 0u64; }; let szr: (i64 | os.oserror) = os.filesize(fd); let n: i64 = 0i64; @@ -2265,7 +2271,7 @@ export fn main(argc: i32, argv: **u8) i32 = { if (encode(&asm) != 0) { return 1; }; // Open output for write. - let fd: i32 = os.open(out, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 420i32); // 0o644 + let fd: i32 = os.open(out, os.flag.WRONLY | os.flag.CREATE | os.flag.TRUNC, 420i32); // 0o644 if (fd < 0) { os.write(2, "w6a: cannot open output\n".ptr, 23u64); return 1; diff --git a/selfhost/cmd/w6a/main.ww b/selfhost/cmd/w6a/main.ww index d69c24ff..ee4b6df2 100644 --- a/selfhost/cmd/w6a/main.ww +++ b/selfhost/cmd/w6a/main.ww @@ -32,7 +32,7 @@ fn cstrlen(p: *u8) u64 = { // Slurp the whole file into a fresh buffer. fn slurp(path: *u8) (*u8, u64) = { - let fd: i32 = os.open(path, os.O_RDONLY, 0i32); + let fd: i32 = os.open(path, os.flag.RDONLY, 0i32); if (fd < 0) { return nil, 0u64; }; let szr: (i64 | os.oserror) = os.filesize(fd); let n: i64 = 0i64; @@ -108,7 +108,7 @@ export fn main(argc: i32, argv: **u8) i32 = { if (encode(&asm) != 0) { return 1; }; // Open output for write. - let fd: i32 = os.open(out, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 420i32); // 0o644 + let fd: i32 = os.open(out, os.flag.WRONLY | os.flag.CREATE | os.flag.TRUNC, 420i32); // 0o644 if (fd < 0) { os.write(2, "w6a: cannot open output\n".ptr, 23u64); return 1; diff --git a/selfhost/cmd/w6c/main.combined.ww b/selfhost/cmd/w6c/main.combined.ww index 362a536f..5c120999 100644 --- a/selfhost/cmd/w6c/main.combined.ww +++ b/selfhost/cmd/w6c/main.combined.ww @@ -35,17 +35,23 @@ def SYS_UNLINK: i64 = 87; def SYS_GETCWD: i64 = 79; def SYS_GETDENTS64: i64 = 217; -// open(2) flags. Linux values, matching . -def O_RDONLY: i32 = 0; -def O_WRONLY: i32 = 1; -def O_RDWR: i32 = 2; -def O_CREAT: i32 = 64; // 0x40 -def O_TRUNC: i32 = 512; // 0x200 +// open(2) flags. Linux values, matching . Hare names them +// `fs::flag::RDONLY` etc; we use the same leaf names so callers say +// `os.flag.RDONLY` and `os.flag.WRONLY | os.flag.CREATE`. +export type flag = enum i32 { + RDONLY = 0, + WRONLY = 1, + RDWR = 2, + CREATE = 64, // 0x40 + TRUNC = 512, // 0x200 +}; -// lseek(2) whence. -def SEEK_SET: i32 = 0; -def SEEK_CUR: i32 = 1; -def SEEK_END: i32 = 2; +// lseek(2) whence. Hare names it `io::whence`. +export type whence = enum i32 { + SET = 0, + CUR = 1, + END = 2, +}; export fn exit(code: i32) void = { syscall1(SYS_EXIT, code: i64); @@ -93,11 +99,11 @@ export fn trywrite(fd: i32, buf: *u8, n: u64) (i64 | oserror) = { // `str` must ensure the bytes are followed by a 0 byte (literals are, // arena-copied paths usually are by construction). Returns -errno on // failure, fd otherwise. Higher-level callers prefer `tryopen`. -export fn open(path: *u8, flags: i32, mode: i32) i32 = { - return syscall3(SYS_OPEN, path: i64, flags: i64, mode: i64): i32; +export fn open(path: *u8, flags: flag, mode: i32) i32 = { + return syscall3(SYS_OPEN, path: i64, (flags as i32): i64, mode: i64): i32; }; -export fn tryopen(path: *u8, flags: i32, mode: i32) (i32 | oserror) = { +export fn tryopen(path: *u8, flags: flag, mode: i32) (i32 | oserror) = { let fd: i32 = open(path, flags, mode); if (fd < 0) { return fd: i64: oserror; }; return fd; @@ -106,8 +112,8 @@ export fn tryopen(path: *u8, flags: i32, mode: i32) (i32 | oserror) = { // lseek — set/inspect the fd's position. Returns the new offset or // a negative errno. We use this for fstat-free file-size discovery // (open ⇒ lseek to end ⇒ lseek back). -export fn lseek(fd: i32, off: i64, whence: i32) i64 = { - return syscall3(SYS_LSEEK, fd: i64, off, whence: i64); +export fn lseek(fd: i32, off: i64, w: whence) i64 = { + return syscall3(SYS_LSEEK, fd: i64, off, (w as i32): i64); }; // oserror — the underlying errno from a failed syscall, as a @@ -119,9 +125,9 @@ export type oserror = !i64; // filesize — byte length of an open fd via lseek-to-end-and-back. export fn filesize(fd: i32) (i64 | oserror) = { - let end: i64 = lseek(fd, 0i64, SEEK_END); + let end: i64 = lseek(fd, 0i64, whence.END); if (end < 0) { return end: oserror; }; - let r: i64 = lseek(fd, 0i64, SEEK_SET); + let r: i64 = lseek(fd, 0i64, whence.SET); if (r < 0) { return r: oserror; }; return end; }; @@ -9265,7 +9271,7 @@ fn cstrlen(p: *u8) u64 = { }; fn slurp(path: *u8) (*u8, u64) = { - let fd: i32 = os.open(path, os.O_RDONLY, 0i32); + let fd: i32 = os.open(path, os.flag.RDONLY, 0i32); if (fd < 0) { return nil, 0u64; }; let szr: (i64 | os.oserror) = os.filesize(fd); let n: i64 = 0i64; @@ -9332,7 +9338,7 @@ export fn main(argc: i32, argv: **u8) i32 = { // threading a file descriptor through the emit helpers. if (out != nil) { let ofd: i32 = os.open(out, - os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 420i32); // 0o644 + os.flag.WRONLY | os.flag.CREATE | os.flag.TRUNC, 420i32); // 0o644 if (ofd < 0) { os.write(2, "w6c: cannot open output\n".ptr, 23u64); return 1; diff --git a/selfhost/cmd/w6c/main.ww b/selfhost/cmd/w6c/main.ww index a210687f..c2b83a2a 100644 --- a/selfhost/cmd/w6c/main.ww +++ b/selfhost/cmd/w6c/main.ww @@ -40,7 +40,7 @@ fn cstrlen(p: *u8) u64 = { }; fn slurp(path: *u8) (*u8, u64) = { - let fd: i32 = os.open(path, os.O_RDONLY, 0i32); + let fd: i32 = os.open(path, os.flag.RDONLY, 0i32); if (fd < 0) { return nil, 0u64; }; let szr: (i64 | os.oserror) = os.filesize(fd); let n: i64 = 0i64; @@ -107,7 +107,7 @@ export fn main(argc: i32, argv: **u8) i32 = { // threading a file descriptor through the emit helpers. if (out != nil) { let ofd: i32 = os.open(out, - os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 420i32); // 0o644 + os.flag.WRONLY | os.flag.CREATE | os.flag.TRUNC, 420i32); // 0o644 if (ofd < 0) { os.write(2, "w6c: cannot open output\n".ptr, 23u64); return 1; diff --git a/selfhost/cmd/w6l/dyn.ww b/selfhost/cmd/w6l/dyn.ww index e223b222..17c7926b 100644 --- a/selfhost/cmd/w6l/dyn.ww +++ b/selfhost/cmd/w6l/dyn.ww @@ -124,7 +124,7 @@ fn dbasename(p: *u8) *u8 = { // ---- file slurp -------------------------------------------------------- fn slurpso(path: *u8) (*u8, u64) = { - let fd: i32 = os.open(path, os.O_RDONLY, 0i32); + let fd: i32 = os.open(path, os.flag.RDONLY, 0i32); if (fd < 0) { return nil, 0u64; }; let szr: (i64 | os.oserror) = os.filesize(fd); let n: i64 = 0i64; diff --git a/selfhost/cmd/w6l/main.combined.ww b/selfhost/cmd/w6l/main.combined.ww index 253705f8..e194abd1 100644 --- a/selfhost/cmd/w6l/main.combined.ww +++ b/selfhost/cmd/w6l/main.combined.ww @@ -35,17 +35,23 @@ def SYS_UNLINK: i64 = 87; def SYS_GETCWD: i64 = 79; def SYS_GETDENTS64: i64 = 217; -// open(2) flags. Linux values, matching . -def O_RDONLY: i32 = 0; -def O_WRONLY: i32 = 1; -def O_RDWR: i32 = 2; -def O_CREAT: i32 = 64; // 0x40 -def O_TRUNC: i32 = 512; // 0x200 +// open(2) flags. Linux values, matching . Hare names them +// `fs::flag::RDONLY` etc; we use the same leaf names so callers say +// `os.flag.RDONLY` and `os.flag.WRONLY | os.flag.CREATE`. +export type flag = enum i32 { + RDONLY = 0, + WRONLY = 1, + RDWR = 2, + CREATE = 64, // 0x40 + TRUNC = 512, // 0x200 +}; -// lseek(2) whence. -def SEEK_SET: i32 = 0; -def SEEK_CUR: i32 = 1; -def SEEK_END: i32 = 2; +// lseek(2) whence. Hare names it `io::whence`. +export type whence = enum i32 { + SET = 0, + CUR = 1, + END = 2, +}; export fn exit(code: i32) void = { syscall1(SYS_EXIT, code: i64); @@ -93,11 +99,11 @@ export fn trywrite(fd: i32, buf: *u8, n: u64) (i64 | oserror) = { // `str` must ensure the bytes are followed by a 0 byte (literals are, // arena-copied paths usually are by construction). Returns -errno on // failure, fd otherwise. Higher-level callers prefer `tryopen`. -export fn open(path: *u8, flags: i32, mode: i32) i32 = { - return syscall3(SYS_OPEN, path: i64, flags: i64, mode: i64): i32; +export fn open(path: *u8, flags: flag, mode: i32) i32 = { + return syscall3(SYS_OPEN, path: i64, (flags as i32): i64, mode: i64): i32; }; -export fn tryopen(path: *u8, flags: i32, mode: i32) (i32 | oserror) = { +export fn tryopen(path: *u8, flags: flag, mode: i32) (i32 | oserror) = { let fd: i32 = open(path, flags, mode); if (fd < 0) { return fd: i64: oserror; }; return fd; @@ -106,8 +112,8 @@ export fn tryopen(path: *u8, flags: i32, mode: i32) (i32 | oserror) = { // lseek — set/inspect the fd's position. Returns the new offset or // a negative errno. We use this for fstat-free file-size discovery // (open ⇒ lseek to end ⇒ lseek back). -export fn lseek(fd: i32, off: i64, whence: i32) i64 = { - return syscall3(SYS_LSEEK, fd: i64, off, whence: i64); +export fn lseek(fd: i32, off: i64, w: whence) i64 = { + return syscall3(SYS_LSEEK, fd: i64, off, (w as i32): i64); }; // oserror — the underlying errno from a failed syscall, as a @@ -119,9 +125,9 @@ export type oserror = !i64; // filesize — byte length of an open fd via lseek-to-end-and-back. export fn filesize(fd: i32) (i64 | oserror) = { - let end: i64 = lseek(fd, 0i64, SEEK_END); + let end: i64 = lseek(fd, 0i64, whence.END); if (end < 0) { return end: oserror; }; - let r: i64 = lseek(fd, 0i64, SEEK_SET); + let r: i64 = lseek(fd, 0i64, whence.SET); if (r < 0) { return r: oserror; }; return end; }; @@ -505,7 +511,7 @@ def RELA_ADDEND: u64 = 16u64; // ---- file slurp -------------------------------------------------------- fn slurp(path: *u8) (*u8, u64) = { - let fd: i32 = os.open(path, os.O_RDONLY, 0i32); + let fd: i32 = os.open(path, os.flag.RDONLY, 0i32); if (fd < 0) { return nil, 0u64; }; let szr: (i64 | os.oserror) = os.filesize(fd); let n: i64 = 0i64; @@ -1050,7 +1056,7 @@ fn dbasename(p: *u8) *u8 = { // ---- file slurp -------------------------------------------------------- fn slurpso(path: *u8) (*u8, u64) = { - let fd: i32 = os.open(path, os.O_RDONLY, 0i32); + let fd: i32 = os.open(path, os.flag.RDONLY, 0i32); if (fd < 0) { return nil, 0u64; }; let szr: (i64 | os.oserror) = os.filesize(fd); let n: i64 = 0i64; @@ -2393,7 +2399,7 @@ fn buildpathv(dst: *u8, dir: *u8, name: *u8, v: u64) u64 = { // islinkable: read first 8 bytes; require !\n or \x7fELF. fn islinkable(path: *u8) bool = { - let fd: i32 = os.open(path, os.O_RDONLY, 0i32); + let fd: i32 = os.open(path, os.flag.RDONLY, 0i32); if (fd < 0) { return false; }; let mp: *u8 = os.alloc(8u64): *u8; let n: i64 = os.read(fd, mp, 8u64); @@ -2462,7 +2468,7 @@ fn resolvelib(a: *arena, name: *u8, libdirs: **u8, nlibdirs: i32) *u8 = { // Read first 20 bytes; return 1 for ET_DYN .so, 0 for ar/.o. fn isso(path: *u8) i32 = { - let fd: i32 = os.open(path, os.O_RDONLY, 0i32); + let fd: i32 = os.open(path, os.flag.RDONLY, 0i32); if (fd < 0) { return 0; }; let mp: *u8 = os.alloc(20u64): *u8; let n: i64 = os.read(fd, mp, 20u64); @@ -2606,7 +2612,7 @@ export fn main(argc: i32, argv: **u8) i32 = { return 1; }; - let flags: i32 = os.O_WRONLY | os.O_CREAT | os.O_TRUNC; + let flags: os.flag = os.flag.WRONLY | os.flag.CREATE | os.flag.TRUNC; let fd: i32 = os.open(outpath, flags, 493i32); // 0o755 if (fd < 0) { os.write(2, "w6l: cannot open output\n".ptr, 23u64); diff --git a/selfhost/cmd/w6l/main.ww b/selfhost/cmd/w6l/main.ww index 57ac898d..db103b05 100644 --- a/selfhost/cmd/w6l/main.ww +++ b/selfhost/cmd/w6l/main.ww @@ -99,7 +99,7 @@ fn buildpathv(dst: *u8, dir: *u8, name: *u8, v: u64) u64 = { // islinkable: read first 8 bytes; require !\n or \x7fELF. fn islinkable(path: *u8) bool = { - let fd: i32 = os.open(path, os.O_RDONLY, 0i32); + let fd: i32 = os.open(path, os.flag.RDONLY, 0i32); if (fd < 0) { return false; }; let mp: *u8 = os.alloc(8u64): *u8; let n: i64 = os.read(fd, mp, 8u64); @@ -168,7 +168,7 @@ fn resolvelib(a: *arena, name: *u8, libdirs: **u8, nlibdirs: i32) *u8 = { // Read first 20 bytes; return 1 for ET_DYN .so, 0 for ar/.o. fn isso(path: *u8) i32 = { - let fd: i32 = os.open(path, os.O_RDONLY, 0i32); + let fd: i32 = os.open(path, os.flag.RDONLY, 0i32); if (fd < 0) { return 0; }; let mp: *u8 = os.alloc(20u64): *u8; let n: i64 = os.read(fd, mp, 20u64); @@ -312,7 +312,7 @@ export fn main(argc: i32, argv: **u8) i32 = { return 1; }; - let flags: i32 = os.O_WRONLY | os.O_CREAT | os.O_TRUNC; + let flags: os.flag = os.flag.WRONLY | os.flag.CREATE | os.flag.TRUNC; let fd: i32 = os.open(outpath, flags, 493i32); // 0o755 if (fd < 0) { os.write(2, "w6l: cannot open output\n".ptr, 23u64); diff --git a/selfhost/cmd/w6l/obj.ww b/selfhost/cmd/w6l/obj.ww index 624072e5..f4a13a81 100644 --- a/selfhost/cmd/w6l/obj.ww +++ b/selfhost/cmd/w6l/obj.ww @@ -76,7 +76,7 @@ def RELA_ADDEND: u64 = 16u64; // ---- file slurp -------------------------------------------------------- fn slurp(path: *u8) (*u8, u64) = { - let fd: i32 = os.open(path, os.O_RDONLY, 0i32); + let fd: i32 = os.open(path, os.flag.RDONLY, 0i32); if (fd < 0) { return nil, 0u64; }; let szr: (i64 | os.oserror) = os.filesize(fd); let n: i64 = 0i64; diff --git a/selfhost/cmd/ww/main.combined.ww b/selfhost/cmd/ww/main.combined.ww index 84edc88b..c6f25415 100644 --- a/selfhost/cmd/ww/main.combined.ww +++ b/selfhost/cmd/ww/main.combined.ww @@ -35,17 +35,23 @@ def SYS_UNLINK: i64 = 87; def SYS_GETCWD: i64 = 79; def SYS_GETDENTS64: i64 = 217; -// open(2) flags. Linux values, matching . -def O_RDONLY: i32 = 0; -def O_WRONLY: i32 = 1; -def O_RDWR: i32 = 2; -def O_CREAT: i32 = 64; // 0x40 -def O_TRUNC: i32 = 512; // 0x200 +// open(2) flags. Linux values, matching . Hare names them +// `fs::flag::RDONLY` etc; we use the same leaf names so callers say +// `os.flag.RDONLY` and `os.flag.WRONLY | os.flag.CREATE`. +export type flag = enum i32 { + RDONLY = 0, + WRONLY = 1, + RDWR = 2, + CREATE = 64, // 0x40 + TRUNC = 512, // 0x200 +}; -// lseek(2) whence. -def SEEK_SET: i32 = 0; -def SEEK_CUR: i32 = 1; -def SEEK_END: i32 = 2; +// lseek(2) whence. Hare names it `io::whence`. +export type whence = enum i32 { + SET = 0, + CUR = 1, + END = 2, +}; export fn exit(code: i32) void = { syscall1(SYS_EXIT, code: i64); @@ -93,11 +99,11 @@ export fn trywrite(fd: i32, buf: *u8, n: u64) (i64 | oserror) = { // `str` must ensure the bytes are followed by a 0 byte (literals are, // arena-copied paths usually are by construction). Returns -errno on // failure, fd otherwise. Higher-level callers prefer `tryopen`. -export fn open(path: *u8, flags: i32, mode: i32) i32 = { - return syscall3(SYS_OPEN, path: i64, flags: i64, mode: i64): i32; +export fn open(path: *u8, flags: flag, mode: i32) i32 = { + return syscall3(SYS_OPEN, path: i64, (flags as i32): i64, mode: i64): i32; }; -export fn tryopen(path: *u8, flags: i32, mode: i32) (i32 | oserror) = { +export fn tryopen(path: *u8, flags: flag, mode: i32) (i32 | oserror) = { let fd: i32 = open(path, flags, mode); if (fd < 0) { return fd: i64: oserror; }; return fd; @@ -106,8 +112,8 @@ export fn tryopen(path: *u8, flags: i32, mode: i32) (i32 | oserror) = { // lseek — set/inspect the fd's position. Returns the new offset or // a negative errno. We use this for fstat-free file-size discovery // (open ⇒ lseek to end ⇒ lseek back). -export fn lseek(fd: i32, off: i64, whence: i32) i64 = { - return syscall3(SYS_LSEEK, fd: i64, off, whence: i64); +export fn lseek(fd: i32, off: i64, w: whence) i64 = { + return syscall3(SYS_LSEEK, fd: i64, off, (w as i32): i64); }; // oserror — the underlying errno from a failed syscall, as a @@ -119,9 +125,9 @@ export type oserror = !i64; // filesize — byte length of an open fd via lseek-to-end-and-back. export fn filesize(fd: i32) (i64 | oserror) = { - let end: i64 = lseek(fd, 0i64, SEEK_END); + let end: i64 = lseek(fd, 0i64, whence.END); if (end < 0) { return end: oserror; }; - let r: i64 = lseek(fd, 0i64, SEEK_SET); + let r: i64 = lseek(fd, 0i64, whence.SET); if (r < 0) { return r: oserror; }; return end; }; @@ -607,7 +613,7 @@ fn locateimport(a: *arena, dirs: *u8, name: *u8, namelen: u64) *u8 = { // ---- file slurp ------------------------------------------------------- fn slurp(pathcs: *u8) (*u8, u64) = { - let fd: i32 = os.open(pathcs, os.O_RDONLY, 0i32); + let fd: i32 = os.open(pathcs, os.flag.RDONLY, 0i32); if (fd < 0) { return nil, 0u64; }; let szr: (i64 | os.oserror) = os.filesize(fd); let n: i64 = 0i64; @@ -862,7 +868,7 @@ fn buildone(selfdir: *u8, src: *u8, out: *u8, incs: *u8, lf: *lflags) i32 = { }; // Step 1: expand `use`s into the combined file. - let cf: i32 = os.open(combined, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 420i32); // 0o644 + let cf: i32 = os.open(combined, os.flag.WRONLY | os.flag.CREATE | os.flag.TRUNC, 420i32); // 0o644 if (cf < 0) { os.write(2, "ww: cannot open combined\n".ptr, 25u64); return 1; @@ -1402,7 +1408,7 @@ fn runsingletest(selfdir: *u8, src: *u8) i32 = { }; fn rundirtests(selfdir: *u8, dir: *u8) i32 = { - let fd: i32 = os.open(dir, os.O_RDONLY, 0i32); + let fd: i32 = os.open(dir, os.flag.RDONLY, 0i32); if (fd < 0) { os.write(2, "ww test: cannot open directory\n".ptr, 31u64); return 1; diff --git a/selfhost/cmd/ww/main.ww b/selfhost/cmd/ww/main.ww index b5e6a3e0..ae0077ac 100644 --- a/selfhost/cmd/ww/main.ww +++ b/selfhost/cmd/ww/main.ww @@ -281,7 +281,7 @@ fn locateimport(a: *arena, dirs: *u8, name: *u8, namelen: u64) *u8 = { // ---- file slurp ------------------------------------------------------- fn slurp(pathcs: *u8) (*u8, u64) = { - let fd: i32 = os.open(pathcs, os.O_RDONLY, 0i32); + let fd: i32 = os.open(pathcs, os.flag.RDONLY, 0i32); if (fd < 0) { return nil, 0u64; }; let szr: (i64 | os.oserror) = os.filesize(fd); let n: i64 = 0i64; @@ -536,7 +536,7 @@ fn buildone(selfdir: *u8, src: *u8, out: *u8, incs: *u8, lf: *lflags) i32 = { }; // Step 1: expand `use`s into the combined file. - let cf: i32 = os.open(combined, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 420i32); // 0o644 + let cf: i32 = os.open(combined, os.flag.WRONLY | os.flag.CREATE | os.flag.TRUNC, 420i32); // 0o644 if (cf < 0) { os.write(2, "ww: cannot open combined\n".ptr, 25u64); return 1; @@ -1076,7 +1076,7 @@ fn runsingletest(selfdir: *u8, src: *u8) i32 = { }; fn rundirtests(selfdir: *u8, dir: *u8) i32 = { - let fd: i32 = os.open(dir, os.O_RDONLY, 0i32); + let fd: i32 = os.open(dir, os.flag.RDONLY, 0i32); if (fd < 0) { os.write(2, "ww test: cannot open directory\n".ptr, 31u64); return 1; diff --git a/selfhost/cmd/wwdump/main.combined.ww b/selfhost/cmd/wwdump/main.combined.ww index e4450fdb..4a8bb209 100644 --- a/selfhost/cmd/wwdump/main.combined.ww +++ b/selfhost/cmd/wwdump/main.combined.ww @@ -35,17 +35,23 @@ def SYS_UNLINK: i64 = 87; def SYS_GETCWD: i64 = 79; def SYS_GETDENTS64: i64 = 217; -// open(2) flags. Linux values, matching . -def O_RDONLY: i32 = 0; -def O_WRONLY: i32 = 1; -def O_RDWR: i32 = 2; -def O_CREAT: i32 = 64; // 0x40 -def O_TRUNC: i32 = 512; // 0x200 +// open(2) flags. Linux values, matching . Hare names them +// `fs::flag::RDONLY` etc; we use the same leaf names so callers say +// `os.flag.RDONLY` and `os.flag.WRONLY | os.flag.CREATE`. +export type flag = enum i32 { + RDONLY = 0, + WRONLY = 1, + RDWR = 2, + CREATE = 64, // 0x40 + TRUNC = 512, // 0x200 +}; -// lseek(2) whence. -def SEEK_SET: i32 = 0; -def SEEK_CUR: i32 = 1; -def SEEK_END: i32 = 2; +// lseek(2) whence. Hare names it `io::whence`. +export type whence = enum i32 { + SET = 0, + CUR = 1, + END = 2, +}; export fn exit(code: i32) void = { syscall1(SYS_EXIT, code: i64); @@ -93,11 +99,11 @@ export fn trywrite(fd: i32, buf: *u8, n: u64) (i64 | oserror) = { // `str` must ensure the bytes are followed by a 0 byte (literals are, // arena-copied paths usually are by construction). Returns -errno on // failure, fd otherwise. Higher-level callers prefer `tryopen`. -export fn open(path: *u8, flags: i32, mode: i32) i32 = { - return syscall3(SYS_OPEN, path: i64, flags: i64, mode: i64): i32; +export fn open(path: *u8, flags: flag, mode: i32) i32 = { + return syscall3(SYS_OPEN, path: i64, (flags as i32): i64, mode: i64): i32; }; -export fn tryopen(path: *u8, flags: i32, mode: i32) (i32 | oserror) = { +export fn tryopen(path: *u8, flags: flag, mode: i32) (i32 | oserror) = { let fd: i32 = open(path, flags, mode); if (fd < 0) { return fd: i64: oserror; }; return fd; @@ -106,8 +112,8 @@ export fn tryopen(path: *u8, flags: i32, mode: i32) (i32 | oserror) = { // lseek — set/inspect the fd's position. Returns the new offset or // a negative errno. We use this for fstat-free file-size discovery // (open ⇒ lseek to end ⇒ lseek back). -export fn lseek(fd: i32, off: i64, whence: i32) i64 = { - return syscall3(SYS_LSEEK, fd: i64, off, whence: i64); +export fn lseek(fd: i32, off: i64, w: whence) i64 = { + return syscall3(SYS_LSEEK, fd: i64, off, (w as i32): i64); }; // oserror — the underlying errno from a failed syscall, as a @@ -119,9 +125,9 @@ export type oserror = !i64; // filesize — byte length of an open fd via lseek-to-end-and-back. export fn filesize(fd: i32) (i64 | oserror) = { - let end: i64 = lseek(fd, 0i64, SEEK_END); + let end: i64 = lseek(fd, 0i64, whence.END); if (end < 0) { return end: oserror; }; - let r: i64 = lseek(fd, 0i64, SEEK_SET); + let r: i64 = lseek(fd, 0i64, whence.SET); if (r < 0) { return r: oserror; }; return end; }; @@ -9299,7 +9305,7 @@ export fn main(argc: i32, argv: **u8) i32 = { return 2; }; - let fdorerr: (i32 | os.oserror) = os.tryopen(path, os.O_RDONLY, 0i32); + let fdorerr: (i32 | os.oserror) = os.tryopen(path, os.flag.RDONLY, 0i32); let fd: i32 = -1; match (fdorerr) { case let v: i32 => fd = v; diff --git a/selfhost/cmd/wwdump/main.ww b/selfhost/cmd/wwdump/main.ww index 22fa2685..43db3de7 100644 --- a/selfhost/cmd/wwdump/main.ww +++ b/selfhost/cmd/wwdump/main.ww @@ -74,7 +74,7 @@ export fn main(argc: i32, argv: **u8) i32 = { return 2; }; - let fdorerr: (i32 | os.oserror) = os.tryopen(path, os.O_RDONLY, 0i32); + let fdorerr: (i32 | os.oserror) = os.tryopen(path, os.flag.RDONLY, 0i32); let fd: i32 = -1; match (fdorerr) { case let v: i32 => fd = v; diff --git a/selfhost/test/smoke.combined.ww b/selfhost/test/smoke.combined.ww index 96819efb..8487549e 100644 --- a/selfhost/test/smoke.combined.ww +++ b/selfhost/test/smoke.combined.ww @@ -35,17 +35,23 @@ def SYS_UNLINK: i64 = 87; def SYS_GETCWD: i64 = 79; def SYS_GETDENTS64: i64 = 217; -// open(2) flags. Linux values, matching . -def O_RDONLY: i32 = 0; -def O_WRONLY: i32 = 1; -def O_RDWR: i32 = 2; -def O_CREAT: i32 = 64; // 0x40 -def O_TRUNC: i32 = 512; // 0x200 +// open(2) flags. Linux values, matching . Hare names them +// `fs::flag::RDONLY` etc; we use the same leaf names so callers say +// `os.flag.RDONLY` and `os.flag.WRONLY | os.flag.CREATE`. +export type flag = enum i32 { + RDONLY = 0, + WRONLY = 1, + RDWR = 2, + CREATE = 64, // 0x40 + TRUNC = 512, // 0x200 +}; -// lseek(2) whence. -def SEEK_SET: i32 = 0; -def SEEK_CUR: i32 = 1; -def SEEK_END: i32 = 2; +// lseek(2) whence. Hare names it `io::whence`. +export type whence = enum i32 { + SET = 0, + CUR = 1, + END = 2, +}; export fn exit(code: i32) void = { syscall1(SYS_EXIT, code: i64); @@ -93,11 +99,11 @@ export fn trywrite(fd: i32, buf: *u8, n: u64) (i64 | oserror) = { // `str` must ensure the bytes are followed by a 0 byte (literals are, // arena-copied paths usually are by construction). Returns -errno on // failure, fd otherwise. Higher-level callers prefer `tryopen`. -export fn open(path: *u8, flags: i32, mode: i32) i32 = { - return syscall3(SYS_OPEN, path: i64, flags: i64, mode: i64): i32; +export fn open(path: *u8, flags: flag, mode: i32) i32 = { + return syscall3(SYS_OPEN, path: i64, (flags as i32): i64, mode: i64): i32; }; -export fn tryopen(path: *u8, flags: i32, mode: i32) (i32 | oserror) = { +export fn tryopen(path: *u8, flags: flag, mode: i32) (i32 | oserror) = { let fd: i32 = open(path, flags, mode); if (fd < 0) { return fd: i64: oserror; }; return fd; @@ -106,8 +112,8 @@ export fn tryopen(path: *u8, flags: i32, mode: i32) (i32 | oserror) = { // lseek — set/inspect the fd's position. Returns the new offset or // a negative errno. We use this for fstat-free file-size discovery // (open ⇒ lseek to end ⇒ lseek back). -export fn lseek(fd: i32, off: i64, whence: i32) i64 = { - return syscall3(SYS_LSEEK, fd: i64, off, whence: i64); +export fn lseek(fd: i32, off: i64, w: whence) i64 = { + return syscall3(SYS_LSEEK, fd: i64, off, (w as i32): i64); }; // oserror — the underlying errno from a failed syscall, as a @@ -119,9 +125,9 @@ export type oserror = !i64; // filesize — byte length of an open fd via lseek-to-end-and-back. export fn filesize(fd: i32) (i64 | oserror) = { - let end: i64 = lseek(fd, 0i64, SEEK_END); + let end: i64 = lseek(fd, 0i64, whence.END); if (end < 0) { return end: oserror; }; - let r: i64 = lseek(fd, 0i64, SEEK_SET); + let r: i64 = lseek(fd, 0i64, whence.SET); if (r < 0) { return r: oserror; }; return end; }; @@ -576,8 +582,11 @@ export fn main() i32 = { // Use raw os.open here (returns i32 with -errno) for the same // reason as os.read below: probe 6 in 990_selfhost compiles // smoke.ww standalone (no `use` expansion), so cross-module type - // references like `os.oserror` don't resolve at that step. - let fd: i32 = os.open(path.ptr, os.O_RDONLY, 0i32); + // references like `os.oserror` and `os.flag` don't resolve at + // that step. RDONLY is 0; passing the literal keeps the call + // site standalone-compilable to byte-identical asm on both + // compilers. + let fd: i32 = os.open(path.ptr, 0, 0i32); if (fd < 0) { return 21; }; let rbuf: [128]u8; // Use raw os.read here (single syscall, plain i64) instead of diff --git a/selfhost/test/smoke.ww b/selfhost/test/smoke.ww index 68b1561b..1c8ddb4c 100644 --- a/selfhost/test/smoke.ww +++ b/selfhost/test/smoke.ww @@ -155,8 +155,11 @@ export fn main() i32 = { // Use raw os.open here (returns i32 with -errno) for the same // reason as os.read below: probe 6 in 990_selfhost compiles // smoke.ww standalone (no `use` expansion), so cross-module type - // references like `os.oserror` don't resolve at that step. - let fd: i32 = os.open(path.ptr, os.O_RDONLY, 0i32); + // references like `os.oserror` and `os.flag` don't resolve at + // that step. RDONLY is 0; passing the literal keeps the call + // site standalone-compilable to byte-identical asm on both + // compilers. + let fd: i32 = os.open(path.ptr, 0, 0i32); if (fd < 0) { return 21; }; let rbuf: [128]u8; // Use raw os.read here (single syscall, plain i64) instead of diff --git a/test/wcc/700_e2e.c b/test/wcc/700_e2e.c index 89ede8ac..bec27bc2 100644 --- a/test/wcc/700_e2e.c +++ b/test/wcc/700_e2e.c @@ -1100,13 +1100,13 @@ static const struct row rows[] = { " let m: mode = mode.R | mode.W;\n" " return m as i32;\n" "};", 3 }, - /* enum: pkg-qualified access — `os.whence.CUR` resolves through + /* enum: pkg-qualified access — `pkg.dir.SOUTH` resolves through * SK_USE and folds to the member literal. */ - { "// MODULE: os\n" - "type whence = enum { SET, CUR, END };\n" + { "// MODULE: pkg\n" + "type dir = enum { NORTH, SOUTH, EAST, WEST };\n" "// MODULE: main\n" - "use os;\n" - "fn main() i32 = { return os.whence.CUR as i32; };", 1 }, + "use pkg;\n" + "fn main() i32 = { return pkg.dir.SOUTH as i32; };", 1 }, { NULL, 0 } };