os: graduate O_*, SEEK_* defs to flag and whence enums
Mirrors Hare's `fs::flag` and `io::whence`:
export type flag = enum i32 {
RDONLY = 0,
WRONLY = 1,
RDWR = 2,
CREATE = 64, // 0o100
TRUNC = 512, // 0o1000
};
export type whence = enum i32 { SET = 0, CUR = 1, END = 2 };
open/tryopen/lseek signatures take the enum types (`flags: flag`,
`w: whence`) so callers get type-checked: `os.open(p, os.flag.RDONLY,
0)` is the correct shape, and `os.flag.WRONLY | os.flag.CREATE |
os.flag.TRUNC` typechecks as a `flag` via the same-named-type rule.
Callers in selfhost/cmd/{ww,w6c,w6a,w6l,wwdump} updated from
`os.O_RDONLY` etc. to `os.flag.RDONLY`. SYS_* syscall numbers kept
as `def` for now (internal-only, ABI surface, no Hare analogue in
this scope).
selfhost/test/smoke.ww keeps its standalone-compile property by
using a numeric literal (`0`, RDONLY's value) for the open flags
arg — probe 6 in 990_selfhost compiles smoke.ww with no `use`
expansion, so cross-module type refs like `os.flag.RDONLY` can't
resolve there. Untyped 0 → flag via type_isnum.
This commit is contained in:
@@ -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 <fcntl.h>.
|
||||
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 <fcntl.h>. 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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user