From 3400b0428b9147012553c6f2280147d8dc99bbf1 Mon Sep 17 00:00:00 2001 From: Ori Bernstein Date: Tue, 6 Oct 2015 13:32:25 -0700 Subject: Fix up error handling for syswrap+posixy.myr --- bench/runbench.myr | 17 +++------- doc/lang.txt | 2 ++ doc/mc.1 | 5 +++ lib/bio/bio.myr | 80 ++++++++++++++++++++++----------------------- lib/std/blat.myr | 28 ++++++++-------- lib/std/execvp.myr | 4 +-- lib/std/fmt.myr | 14 +++++--- lib/std/result.myr | 2 -- lib/std/slurp.myr | 33 ++++++++++--------- lib/std/spork.myr | 35 ++++++++++++-------- lib/std/syswrap+posixy.myr | 81 ++++++++++++++++++++++++++-------------------- mbld/build.myr | 8 ++--- 12 files changed, 164 insertions(+), 145 deletions(-) diff --git a/bench/runbench.myr b/bench/runbench.myr index f30691e..ece5aa2 100644 --- a/bench/runbench.myr +++ b/bench/runbench.myr @@ -13,15 +13,6 @@ const main = {args : byte[:][:] std.put("total:\t{}s\n", tot); } - -generic perror = {a : @a::(numeric,integral), msg : byte[:] -> @a - if a < 0 - std.fatal("{}", msg) - else - -> a - ;; -} - const timeit = {prog -> flt64 var avg, m, d, x, n : flt64 @@ -49,10 +40,10 @@ const run = {prog -> flt64 if pid < 0 std.fatal("Could not fork\n"); elif pid == 0 - infd = perror(std.open("/dev/zero", std.Ordonly), "could not open /dev/zero") - outfd = perror(std.open("/dev/null", std.Owronly), "could not open /dev/null") - perror(std.dup2(infd, 0), "could not redirect stdin") - perror(std.dup2(outfd, 1), "could not redirect stdout") + infd = std.try(std.open("/dev/zero", std.Ordonly)) + outfd = std.try(std.open("/dev/null", std.Owronly)) + std.try(std.dup2(infd, 0)) + std.try(std.dup2(outfd, 1)) std.execv(prog, [prog][:]) std.fatal("Failed to exec\n") else diff --git a/doc/lang.txt b/doc/lang.txt index 26763f6..18543ce 100644 --- a/doc/lang.txt +++ b/doc/lang.txt @@ -818,6 +818,8 @@ TABLE OF CONTENTS: 7. STANDARD LIBRARY: + This is documented separately. + 8. GRAMMAR: 9. FUTURE DIRECTIONS: diff --git a/doc/mc.1 b/doc/mc.1 index 6261ad8..7ef544c 100644 --- a/doc/mc.1 +++ b/doc/mc.1 @@ -15,6 +15,11 @@ file is named .I filename.myr then the the object file that is generated will be named .I filename.o. +.PP +Any text between the first '+' in the file name and the suffix are +stripped. This functionality is used to specify system tags for +tools like 'mbld'. +.PP If the filename does not end with the suffix .I .myr then the suffix diff --git a/lib/bio/bio.myr b/lib/bio/bio.myr index f9517ca..bb1592a 100644 --- a/lib/bio/bio.myr +++ b/lib/bio/bio.myr @@ -49,7 +49,7 @@ pkg bio = const flush : (f : file# -> bool) /* seeking */ - const seek : (f : file#, std.off -> std.off) + const seek : (f : file#, std.off -> std.result(std.off, ioerr)) /* single unit operations */ const putb : (f : file#, b : byte -> status(std.size)) @@ -133,13 +133,9 @@ const sysmode = {mode /* open the file, and return it */ const sysopen = {path, mode, openmode, perm - var fd - - fd = std.openmode(path, openmode, perm castto(int64)) - if fd < 0 - -> `std.Fail "could not open fd" - else - -> `std.Ok mkfile(fd, mode) + match std.openmode(path, openmode, perm castto(int64)) + | `std.Ok fd: -> `std.Ok mkfile(fd, mode) + | `std.Fail e: -> `std.Fail "could not open fd" ;; } @@ -189,8 +185,8 @@ reads as much into 'dst' as possible, up to the size of 'dst', returning the number of bytes read. */ const read = {f, dst - var n, d - var count + var count : std.size + var d : byte[:] /* Clear the error state so we can retry */ if f.lasterr != 0 @@ -218,21 +214,22 @@ const read = {f, dst /* Read the rest directly from the fd */ d = dst[count:] while dst.len > 0 - n = std.read(f.fd, d) - if n == 0 + match std.read(f.fd, d) + | `std.Ok 0: break - elif n < 0 - if count > 0 - f.lasterr = n castto(std.errno) + | `std.Ok n: + count += n + d = d[n:] + | `std.Fail err: + if count == 0 + -> `Err errtype(err) + else + f.lasterr = err ;; break ;; - count += n - d = d[n:] ;; - if n < 0 && count == 0 - -> `Err errtype(n) - elif count == 0 + if count == 0 -> `Eof else -> `Ok dst[:count] @@ -256,7 +253,10 @@ const flush = {f const seek = {f, off flush(f) - -> std.seek(f.fd, off, std.Seekset) + match std.seek(f.fd, off, std.Seekset) + | `std.Ok ret: -> `std.Ok ret + | `std.Fail e: -> `std.Fail errtype(e) + ;; } /* writes a single byte to the output stream */ @@ -581,19 +581,19 @@ const ensureread = {f, n /* blats a buffer to an fd */ const writebuf = {fd, src - var n var count count = 0 while src.len != 0 - n = std.write(fd, src) - if n == 0 + match std.write(fd, src) + | `std.Ok 0: -> `Eof - elif n < 0 - -> `Err errtype(n) + | `std.Ok n: + count += n + src = src[n:] + | `std.Fail e: + -> `Err errtype(e) ;; - count += n - src = src[n:] ;; :writedone -> `Ok count @@ -606,7 +606,6 @@ Reads as many bytes as possible from the file into the read buffer. */ const fill = {f, min - var n var count count = 0 @@ -615,27 +614,28 @@ const fill = {f, min -> `Err geterr(f) ;; while count < min - n = std.read(f.fd, f.rbuf[f.rend:]) /* If we've already read data, we don't want to throw it away, so we report a successful short read, and then error on the next read. */ - if n == 0 + match std.read(f.fd, f.rbuf[f.rend:]) + | `std.Ok 0: break - elif n < 0 + | `std.Ok n: + count += n + f.rend += n + | `std.Fail e: if count > 0 - f.lasterr = n castto(std.errno) + f.lasterr = e + else + -> `Err errtype(e) ;; break ;; - count += n - f.rend += n ;; - if n < 0 && count == 0 - -> `Err errtype(n) - elif count == 0 + if count == 0 -> `Eof else -> `Ok count @@ -647,10 +647,10 @@ const geterr = {f e = f.lasterr f.lasterr = 0 - -> errtype(e castto(std.size)) + -> errtype(e) } -const errtype : (e : std.size -> ioerr )= {e : std.size -> ioerr +const errtype : (e : std.errno -> ioerr )= {e : std.errno -> ioerr var errno errno = e castto(std.errno) diff --git a/lib/std/blat.myr b/lib/std/blat.myr index 90c0f94..ed27f97 100644 --- a/lib/std/blat.myr +++ b/lib/std/blat.myr @@ -1,4 +1,5 @@ use "syswrap.use" +use "result.use" pkg std = const blat : (path : byte[:], buf : byte[:], perm : int64 -> bool) @@ -6,27 +7,26 @@ pkg std = ;; const blat = {path, buf, perm - var fd - - fd = openmode(path, Ocreat|Owronly, perm) - if fd < 0 - -> false + match openmode(path, Ocreat|Owronly, perm) + | `Ok fd: -> fblat(fd, buf) + | `Fail e: -> false ;; - -> fblat(fd, buf) } const fblat = {fd, buf - var written, n + var count - n = 0 + count = 0 while true - written = write(fd, buf[n:]) - if written <= 0 - goto done + match write(fd, buf[count:]) + | `Fail e: -> false + | `Ok n: + if n == 0 + break + ;; + count += n ;; - n += written ;; -:done - -> written == 0 && n == buf.len + -> count == buf.len } diff --git a/lib/std/execvp.myr b/lib/std/execvp.myr index 58c8c60..d8a5119 100644 --- a/lib/std/execvp.myr +++ b/lib/std/execvp.myr @@ -8,8 +8,8 @@ use "strsplit.use" use "syswrap.use" pkg std = - const execvp : (cmd : byte[:], args : byte[:][:] -> int64) - const execvpe : (cmd : byte[:], args : byte[:][:], env : byte[:][:] -> int64) + const execvp : (cmd : byte[:], args : byte[:][:] -> errno) + const execvpe : (cmd : byte[:], args : byte[:][:], env : byte[:][:] -> errno) ;; const execvp = {cmd, args diff --git a/lib/std/fmt.myr b/lib/std/fmt.myr index 0b66bb5..816b157 100644 --- a/lib/std/fmt.myr +++ b/lib/std/fmt.myr @@ -9,6 +9,7 @@ use "htab.use" use "introspect.use" use "intparse.use" use "option.use" +use "result.use" use "sleq.use" use "slpush.use" use "strbuf.use" @@ -529,15 +530,18 @@ generic intfmt = {sb, opts, signed, bits : @a::(integral,numeric) } const writeall = {fd, buf - var n, len + var len len = 0 while true - n = write(fd, buf) - if n <= 0 || n >= len - break + match write(fd, buf[len:]) + | `Fail err: break + | `Ok n: + len += n + if n == 0 || len == buf.len + break + ;; ;; - len += n ;; -> len } diff --git a/lib/std/result.myr b/lib/std/result.myr index 58ef45b..e98078a 100644 --- a/lib/std/result.myr +++ b/lib/std/result.myr @@ -1,5 +1,3 @@ -use "die.use" - pkg std = type result(@a, @b) = union `Ok @a diff --git a/lib/std/slurp.myr b/lib/std/slurp.myr index 8636f40..ac90b23 100644 --- a/lib/std/slurp.myr +++ b/lib/std/slurp.myr @@ -3,41 +3,42 @@ use "die.use" use "result.use" use "extremum.use" use "syswrap.use" +use "errno.use" use "types.use" pkg std = - const slurp : (path : byte[:] -> result(byte[:], byte[:])) - const fslurp : (path : fd -> result(byte[:], byte[:])) + const slurp : (path : byte[:] -> result(byte[:], errno)) + const fslurp : (path : fd -> result(byte[:], errno)) ;; const Bufstart = 4096 const slurp = {path - var fd - fd = open(path, Ordonly) - if fd < 0 - -> `Fail "Could not open file" + match open(path, Ordonly) + | `Ok fd: -> fslurp(fd) + | `Fail e: -> `Fail e ;; - -> fslurp(fd) } const fslurp = {fd var len, bufsz var buf - var n len = 0 bufsz = Bufstart buf = slalloc(bufsz) while true - n = read(fd, buf[len:]) - if n <= 0 - goto done + match read(fd, buf[len:]) + | `Ok n: + if n == 0 + -> `Ok buf[:len] + ;; + len += n + bufsz *= 2 + buf = slgrow(buf, bufsz) + | `Fail e: + -> `Fail e ;; - len += n - bufsz *= 2 - buf = slgrow(buf, bufsz) ;; -:done - -> `Ok buf[:len] + die("unreachable") } diff --git a/lib/std/spork.myr b/lib/std/spork.myr index 64e8fce..8143064 100644 --- a/lib/std/spork.myr +++ b/lib/std/spork.myr @@ -3,10 +3,11 @@ use "execvp.use" use "fmt.use" use "result.use" use "syswrap.use" +use "errno.use" pkg std = - const spork : (cmd : byte[:][:] -> result((pid, fd, fd), int)) - const sporkfd : (cmd : byte[:][:], infd : fd, outfd : fd -> result(pid, int)) + const spork : (cmd : byte[:][:] -> result((pid, fd, fd), errno)) + const sporkfd : (cmd : byte[:][:], infd : fd, outfd : fd -> result(pid, errno)) ;; const spork = {cmd @@ -14,13 +15,13 @@ const spork = {cmd var err /* open up pipes */ - err = pipe(&infds) - if err != 0 - -> `Fail (-err castto(int)) + err = pipe(&infds) + if err != Enone + -> `Fail err ;; err = pipe(&outfds) - if err != 0 - -> `Fail (-err castto(int)) + if err != Enone + -> `Fail err ;; match sporkfd(cmd, infds[0] castto(fd), outfds[1] castto(fd)) @@ -35,7 +36,7 @@ const spork = {cmd } const sporkfd = {cmd, infd, outfd - var pid + var pid, err pid = fork() /* error */ @@ -44,16 +45,22 @@ const sporkfd = {cmd, infd, outfd /* child */ elif pid == 0 /* stdin/stdout for our communication. */ - if dup2(infd castto(fd), 0) != 0 - fatal("unable to set stdin\n") + match dup2(infd castto(fd), 0) + | `Ok _: /* nothing */ + | `Fail e: -> `Fail e ;; - if dup2(outfd castto(fd), 1) != 1 - fatal("unable to set stdout\n") + match dup2(outfd castto(fd), 1) + | `Ok _: /* nothing */ + | `Fail e: -> `Fail e ;; close(infd) close(outfd) - execvp(cmd[0], cmd) < 0 - fatal("failed to exec {}\n", cmd[0]) + err = execvp(cmd[0], cmd) + if err != Enone + -> `Fail err + ;; + /* if fork succeeds, we never return */ + die("unreachable") /* parent */ else -> `Ok pid diff --git a/lib/std/syswrap+posixy.myr b/lib/std/syswrap+posixy.myr index 31d98b5..393a55f 100644 --- a/lib/std/syswrap+posixy.myr +++ b/lib/std/syswrap+posixy.myr @@ -1,8 +1,9 @@ use sys use "cstrconv.use" +use "errno.use" use "option.use" +use "result.use" use "types.use" -use "errno.use" pkg std = type fd = sys.fd @@ -29,23 +30,22 @@ pkg std = const Ordwr : fdopt = sys.Ordwr castto(fdopt) const Ocreat : fdopt = sys.Ocreat castto(fdopt) const Otrunc : fdopt = sys.Otrunc castto(fdopt) - const Oappend : fdopt = sys.Oappend castto(fdopt) const Odir : fdopt = sys.Odir castto(fdopt) /* fd stuff */ - const open : (path : byte[:], opts : fdopt -> fd) - const openmode : (path : byte[:], opts : fdopt, mode : int64 -> fd) - const close : (fd : fd -> int64) - const creat : (path : byte[:], mode : int64 -> fd) - const read : (fd : fd, buf : byte[:] -> size) - const write : (fd : fd, buf : byte[:] -> size) - const pipe : (fds : fd[2]# -> int64) - const seek : (fd : fd, delta : off, whence : whence -> off) - const dup2 : (ofd : fd, nfd : fd -> fd) + const open : (path : byte[:], opts : fdopt -> result(fd, errno)) + const openmode : (path : byte[:], opts : fdopt, mode : int64 -> result(fd, errno)) + const close : (fd : fd -> errno) + const creat : (path : byte[:], mode : int64 -> result(fd, errno)) + const read : (fd : fd, buf : byte[:] -> result(size, errno)) + const write : (fd : fd, buf : byte[:] -> result(size, errno)) + const pipe : (fds : fd[2]# -> errno) + const seek : (fd : fd, delta : off, whence : whence -> result(off, errno)) + const dup2 : (ofd : fd, nfd : fd -> result(fd, errno)) /* useful/portable bits of stat */ - const fmtime : (f : byte[:] -> option(time)) - const fsize : (f : byte[:] -> option(off)) + const fmtime : (f : byte[:] -> result(time, errno)) + const fsize : (f : byte[:] -> result(off, errno)) const fexists : (f : byte[:] -> bool) /* useful/portable bits of uname */ @@ -60,26 +60,27 @@ pkg std = const getpid : ( -> pid) const suicide : ( -> void) const fork : (-> pid) - const execv : (cmd : byte[:], args : byte[:][:] -> int64) - const execve : (cmd : byte[:], args : byte[:][:], env : byte[:][:] -> int64) - const waitpid : (pid:pid, loc:int32#, opt : int64 -> int64) + const execv : (cmd : byte[:], args : byte[:][:] -> errno) + const execve : (cmd : byte[:], args : byte[:][:], env : byte[:][:] -> errno) pkglocal const Canunmap : bool = true pkglocal const getmem : (sz : size -> byte#) pkglocal const freemem : (p : byte#, sz : size -> void) pkglocal const curtime : (-> time) + pkglocal const waitpid : (pid:pid, loc:int32#, opt : int64 -> int64) ;; /* fd stuff */ -const open = {path, opts; -> sys.open(path, opts castto(sys.fdopt)) castto(fd)} -const openmode = {path, opts, mode; -> sys.openmode(path, opts castto(sys.fdopt), mode) castto(fd)} -const close = {fd; -> sys.close(fd castto(sys.fd))} -const creat = {path, mode; -> sys.creat(path, mode) castto(fd)} -const read = {fd, buf; -> sys.read(fd castto(sys.fd), buf) castto(size)} -const write = {fd, buf; -> sys.write(fd castto(sys.fd), buf) castto(size)} -const pipe = {fds; -> sys.pipe(fds castto(sys.fd[2]#))} -const seek = {fd, delta, whence; -> sys.lseek(fd castto(sys.fd), delta castto(sys.off), whence castto(sys.whence)) castto(off)} -const dup2 = {ofd, nfd; -> sys.dup2(ofd castto(sys.fd), nfd castto(sys.fd)) castto(fd)} +const open = {path, opts; -> check(sys.open(path, opts castto(sys.fdopt)))} +const openmode = {path, opts, mode; -> check(sys.openmode(path, opts castto(sys.fdopt), mode))} +const close = {fd; -> sys.close(fd castto(sys.fd)) castto(errno)} + +const creat = {path, mode; -> check(sys.creat(path, mode))} +const read = {fd, buf; -> check(sys.read(fd castto(sys.fd), buf))} +const write = {fd, buf; -> check(sys.write(fd castto(sys.fd), buf))} +const pipe = {fds; -> sys.pipe(fds castto(sys.fd[2]#)) castto(errno)} +const seek = {fd, delta, whence; -> check(sys.lseek(fd castto(sys.fd), delta castto(sys.off), whence castto(sys.whence)))} +const dup2 = {ofd, nfd; -> check(sys.dup2(ofd castto(sys.fd), nfd castto(sys.fd)) castto(fd))} /* path manipulation */ const mkdir = {path, mode; -> sys.mkdir(path, mode)} @@ -99,8 +100,8 @@ const getsysinfo = {si const getpid = {; -> sys.getpid() castto(pid)} const suicide = {; sys.kill(sys.getpid(), 6)} /* kill self with sigabort */ const fork = {; -> sys.fork() castto(pid)} -const execv = {cmd, args; -> sys.execv(cmd, args)} -const execve = {cmd, args, env; -> sys.execve(cmd, args, env)} +const execv = {cmd, args; -> sys.execv(cmd, args) castto(errno)} +const execve = {cmd, args, env; -> sys.execve(cmd, args, env) castto(errno)} const sleep = {time; sys.sleep(time)} /* memory stuff */ @@ -125,24 +126,34 @@ const fexists = {path } const fmtime = {path - var sb + var sb, r var sec, nsec - if sys.stat(path, &sb) == 0 + r = sys.stat(path, &sb) + if r >= 0 sec = sb.mtime.sec castto(time) nsec = sb.mtime.nsec castto(time) - -> `Some sec*1000 + nsec/1_000_000 + -> `Ok sec*1000 + nsec/1_000_000 else - -> `None + -> check(r) ;; } const fsize = {path - var sb + var sb, r + + r = sys.stat(path, &sb) + if r >= 0 + -> `Ok (sb.size castto(off)) + else + -> check(r) + ;; +} - if sys.stat(path, &sb) == 0 - -> `Some (sb.size castto(off)) +generic check = {e : @a::(integral, numeric) -> result(@b, errno) + if e < 0 + -> `Fail e castto(errno) else - -> `None + -> `Ok e castto(@b) ;; } diff --git a/mbld/build.myr b/mbld/build.myr index 055f8b7..7d2b804 100644 --- a/mbld/build.myr +++ b/mbld/build.myr @@ -479,12 +479,12 @@ const isfresh = {src, dst up to date. */ match std.fmtime(src) - | `std.Some mt: srcmt = mt - | `std.None: std.fatal("could not stat {}\n", src) + | `std.Ok mt: srcmt = mt + | `std.Fail e: std.fatal("could not stat {}: {}\n", src, e) ;; match std.fmtime(dst) - | `std.Some mt: dstmt = mt - | `std.None: -> false + | `std.Ok mt: dstmt = mt + | `std.Fail e: -> false ;; -> srcmt <= dstmt } -- cgit v1.1