commit d2bd3e64b09c393b8779475e329b8d7ca3fdeae5
parent 45235f53fe8121615aad186108880d91c8877d8e
Author: Drew DeVault <sir@cmpwn.com>
Date: Tue, 23 Feb 2021 15:00:59 -0500
all: use error propagation where appropriate
Diffstat:
11 files changed, 119 insertions(+), 233 deletions(-)
diff --git a/encoding/utf8/decode.ha b/encoding/utf8/decode.ha
@@ -19,7 +19,7 @@ export fn decode(src: (str | []u8)) decoder = match (src) {
export type more = void;
// An error indicating that an invalid UTF-8 sequence was found.
-export type invalid = void;
+export type invalid = void!;
// Returns the next rune from a decoder. If the slice ends with a complete UTF-8
// sequence, void is returned. If an incomplete sequence is encountered, more is
@@ -96,7 +96,7 @@ export fn prev(d: *decoder) (rune | void | more | invalid) = {
let decoder = decode(input);
for (let i = 0z; i < len(expected); i += 1) {
match (next(&decoder)) {
- (invalid | more | void ) => abort(),
+ (invalid | more | void) => abort(),
r: rune => assert(r == expected[i]),
};
};
@@ -104,7 +104,7 @@ export fn prev(d: *decoder) (rune | void | more | invalid) = {
assert(decoder.offs == len(decoder.src));
for (let i = 0z; i < len(expected); i += 1) {
match (prev(&decoder)) {
- (invalid | more | void ) => abort(),
+ (invalid | more | void) => abort(),
r: rune => assert(r == expected[len(expected) - i - 1]),
};
};
diff --git a/fmt/fmt.ha b/fmt/fmt.ha
@@ -82,6 +82,16 @@ export @noreturn fn fatal(fmt: str, args: formattable...) void = {
os::exit(1);
};
+// Formats text for printing and writes it to an [io::stream], followed by a
+// line feed.
+export fn fprintln(
+ s: *io::stream,
+ fmt: str,
+ args: formattable...
+) (io::error | size) = {
+ return fprintf(s, fmt, args...)? + io::write(s, ['\n': u32: u8])?;
+};
+
type negation = enum {
NONE,
SPACE,
@@ -130,13 +140,9 @@ export fn fprintf(
r: rune => r,
};
- const arg = if (r == '{') match (io::write(
- s, utf8::encode_rune('{'))) {
- err: io::error => return err,
- w: size => {
- n += w;
- continue;
- },
+ const arg = if (r == '{') {
+ n += io::write(s, utf8::encode_rune('{'))?;
+ continue;
} else if (ascii::isdigit(r)) {
strings::push(&iter, r);
args[scan_uint(&iter)];
@@ -164,37 +170,15 @@ export fn fprintf(
r: rune => assert(r == '}', "Invalid format string (hanging '}')"),
};
- match (io::write(s, utf8::encode_rune('}'))) {
- err: io::error => return err,
- w: size => n += w,
- };
- } else match (io::write(s, utf8::encode_rune(r))) {
- err: io::error => return err,
- w: size => n += w,
+ n += io::write(s, utf8::encode_rune('}'))?;
+ } else {
+ n += io::write(s, utf8::encode_rune(r))?;
};
};
return n;
};
-// Formats text for printing and writes it to an [io::stream], followed by a
-// line feed.
-export fn fprintln(
- s: *io::stream,
- fmt: str,
- args: formattable...
-) (io::error | size) = {
- let z = match(fprintf(s, fmt, args...)) {
- err: io::error => return err,
- z: size => z,
- };
- z += match (io::write(s, ['\n': u32: u8])) {
- err: io::error => return err,
- z: size => z,
- };
- return z;
-};
-
fn format(
out: *io::stream,
arg: formattable,
diff --git a/hare/lex/lex.ha b/hare/lex/lex.ha
@@ -16,10 +16,10 @@ export type lexer = struct {
};
// A syntax error
-export type syntax = (location, str);
+export type syntax = (location, str)!;
// All possible lexer errors
-export type error = (io::error | syntax);
+export type error = (io::error | syntax)!;
export fn errstr(err: error) const str = {
return match (err) {
@@ -48,8 +48,7 @@ export fn lex(lex: *lexer) ((token, location) | io::EOF | error) = {
};
let loc = location { ... };
- let r: rune = match (nextw(lex)) {
- e: io::error => return e,
+ let r: rune = match (nextw(lex)?) {
io::EOF => return io::EOF,
r: (rune, location) => {
loc = r.1;
@@ -104,10 +103,9 @@ fn lex_unicode(lex: *lexer, loc: location, n: size) (rune | error) = {
assert(n < 9);
let buf: [9]u8 = [0...];
for (let i = 0z; i < n; i += 1z) {
- let r = match (next(lex)) {
+ let r = match (next(lex)?) {
io::EOF => return syntaxerr(loc,
"unexpected EOF scanning for escape"),
- err: io::error => return err,
r: rune => r,
};
if (!ascii::isxdigit(r)) {
@@ -124,19 +122,17 @@ fn lex_unicode(lex: *lexer, loc: location, n: size) (rune | error) = {
};
fn lex_rune(lex: *lexer, loc: location) (rune | error) = {
- let r = match (next(lex)) {
+ let r = match (next(lex)?) {
io::EOF => return syntaxerr(loc,
"unexpected EOF scanning for rune"),
- err: io::error => return err,
r: rune => r,
};
if (r != '\\') {
return r;
};
- r = match (next(lex)) {
+ r = match (next(lex)?) {
io::EOF => return syntaxerr(loc,
"unexpected EOF scanning for escape"),
- err: io::error => return err,
r: rune => r,
};
return switch (r) {
@@ -162,17 +158,13 @@ fn lex_string(
loc: location,
) ((token, location) | io::EOF | error) = {
let chars: []u8 = [];
- for (true) match (next(lex)) {
- err: io::error => return err,
+ for (true) match (next(lex)?) {
io::EOF => return syntaxerr(loc, "unexpected EOF scanning string literal"),
r: rune =>
if (r == '"') break
else {
unget(lex, r);
- r = match (lex_rune(lex, loc)) {
- err: error => return err,
- r: rune => r,
- };
+ r = lex_rune(lex, loc)?;
append(chars, ...utf8::encode_rune(r));
},
};
@@ -197,16 +189,11 @@ fn lex_rn_str(
};
// Rune literal
- let ret = match (lex_rune(lex, loc)) {
- err: error => return err,
- r: rune => (literal {
- storage = literal_type::RUNE,
- _rune = r,
- }: token, loc),
- };
- match (next(lex)) {
- err: io::error =>
- return err,
+ let ret = (literal {
+ storage = literal_type::RUNE,
+ _rune = lex_rune(lex, loc)?,
+ }: token, loc);
+ match (next(lex)?) {
io::EOF =>
return syntaxerr(loc, "unexpected EOF"),
n: rune => if (n != '\'')
@@ -228,9 +215,8 @@ fn lex_name(
(io::EOF | io::error) => abort(),
};
- for (true) match (next(lex)) {
+ for (true) match (next(lex)?) {
io::EOF => break,
- err: io::error => return err,
r: rune => {
if (!is_name(r, true)) {
unget(lex, r);
@@ -258,8 +244,7 @@ fn lex2(
loc: location,
r: rune,
) ((token, location) | io::EOF | error) = {
- let n = match (next(lexr)) {
- err: io::error => return err,
+ let n = match (next(lexr)?) {
io::EOF => io::EOF,
r: rune => r,
};
@@ -284,8 +269,7 @@ fn lex2(
'=' => return (btoken::DIVEQ: token, loc),
'/' => {
// Comment
- for (true) match (next(lexr)) {
- err: io::error => return err,
+ for (true) match (next(lexr)?) {
io::EOF => break,
r: rune => if (r == '\n') {
break;
@@ -359,8 +343,7 @@ fn lex3(
loc: location,
r: rune,
) ((token, location) | io::EOF | error) = {
- let n = match (next(lex)) {
- err: io::error => return err,
+ let n = match (next(lex)?) {
io::EOF => return switch (r) {
'.' => (btoken::DOT: token, loc),
'<' => (btoken::LESS: token, loc),
@@ -383,8 +366,7 @@ fn lex3dot(
) ((token, location) | io::EOF | error) = {
let tok: token = switch (n) {
'.' => {
- let q = match (next(lex)) {
- err: io::error => return err,
+ let q = match (next(lex)?) {
io::EOF => io::EOF,
r: rune => r,
};
@@ -413,8 +395,7 @@ fn lex3lt(
) ((token, location) | io::EOF | error) = {
let tok: token = switch (n) {
'<' => {
- let q = match (next(lex)) {
- err: io::error => return err,
+ let q = match (next(lex)?) {
io::EOF => io::EOF,
r: rune => r,
};
@@ -444,8 +425,7 @@ fn lex3gt(
) ((token, location) | io::EOF | error) = {
let tok: token = switch (n) {
'>' => {
- let q = match (next(lex)) {
- err: io::error => return err,
+ let q = match (next(lex)?) {
io::EOF => io::EOF,
r: rune => r,
};
diff --git a/io/copy.ha b/io/copy.ha
@@ -15,16 +15,11 @@ export fn copy(dest: *stream, src: *stream) (error | size) = {
let w = 0z;
static let buf: [4096]u8 = [0...];
for (true) {
- match (read(src, buf[..])) {
- err: error => return err,
+ match (read(src, buf[..])?) {
n: size => for (let i = 0z; i < n) {
- match (write(dest, buf[i..n])) {
- err: error => return err,
- r: size => {
- w += r;
- i += r;
- },
- };
+ let r = write(dest, buf[i..n])?;
+ w += r;
+ i += r;
},
EOF => break,
};
diff --git a/io/types.ha b/io/types.ha
@@ -2,16 +2,16 @@
export type os_error = struct {
string: *fn(data: *void) str,
data: *void,
-};
+}!;
// An error indicating that the underlying stream has been closed.
-export type closed = void;
+export type closed = void!;
// An error indicating that the requested operation is not supported.
-export type unsupported = void;
+export type unsupported = void!;
// Any error which may be returned from an I/O function.
-export type error = (os_error | closed | unsupported);
+export type error = (os_error | closed | unsupported)!;
// Indicates an end-of-file condition.
export type EOF = void;
diff --git a/rt/+linux/errno.ha b/rt/+linux/errno.ha
@@ -1,5 +1,5 @@
// Represents an error returned from the Linux kernel.
-export type errno = int;
+export type errno = int!;
// Given an integer error number, wraps it in an error type.
export fn wrap_errno(err: int) errno = err: errno;
diff --git a/rt/+linux/stat.ha b/rt/+linux/stat.ha
@@ -10,11 +10,11 @@ fn fstatat_statx(
flags: int,
mask: uint,
statbuf: *stx,
-) (void | errno) = match (wrap_return(syscall5(
- SYS_statx, dirfd: u64, path: uintptr: u64, flags: u64,
- mask: u64, statbuf: uintptr: u64))) {
- err: errno => err,
- u64 => void,
+) (void | errno) = {
+ wrap_return(syscall5(SYS_statx,
+ dirfd: u64, path: uintptr: u64, flags: u64,
+ mask: u64, statbuf: uintptr: u64))?;
+ return;
};
export fn fstatat(
@@ -24,10 +24,7 @@ export fn fstatat(
flags: int,
) (errno | void) = {
let statxbuf = stx { ... };
- match (fstatat_statx(dirfd, path, flags, STATX_BASIC_STATS, &statxbuf)) {
- err: errno => return err,
- void => void,
- };
+ fstatat_statx(dirfd, path, flags, STATX_BASIC_STATS, &statxbuf)?;
statbuf.dev = mkdev(statxbuf.dev_major, statxbuf.dev_minor);
statbuf.ino = statxbuf.ino;
statbuf.mode = statxbuf.mode;
diff --git a/rt/+linux/syscalls.ha b/rt/+linux/syscalls.ha
@@ -7,34 +7,23 @@ fn syscall5(u64, u64, u64, u64, u64, u64) u64;
fn syscall6(u64, u64, u64, u64, u64, u64, u64) u64;
export fn read(fd: int, buf: *void, count: size) (size | errno) = {
- return match (wrap_return(syscall3(SYS_read,
- fd: u64, buf: uintptr: u64, count: u64))) {
- err: errno => err,
- n: u64 => n: size,
- };
+ return wrap_return(syscall3(SYS_read,
+ fd: u64, buf: uintptr: u64, count: u64))?: size;
};
export fn write(fd: int, buf: *const void, count: size) (size | errno) = {
- return match (wrap_return(syscall3(SYS_write,
- fd: u64, buf: uintptr: u64, count: u64))) {
- err: errno => err,
- n: u64 => n: size,
- };
+ return wrap_return(syscall3(SYS_write,
+ fd: u64, buf: uintptr: u64, count: u64))?: size;
};
export fn open(path: *const char, flags: int, mode: uint) (int | errno) = {
- return match (wrap_return(syscall4(SYS_openat, AT_FDCWD: u64,
- path: uintptr: u64, flags: u64, mode: u64))) {
- err: errno => err,
- n: u64 => n: int,
- };
+ return wrap_return(syscall4(SYS_openat, AT_FDCWD: u64,
+ path: uintptr: u64, flags: u64, mode: u64))?: int;
};
export fn close(fd: int) (void | errno) = {
- return match (wrap_return(syscall1(SYS_close, fd: u64))) {
- err: errno => err,
- u64 => void,
- };
+ wrap_return(syscall1(SYS_close, fd: u64))?;
+ return;
};
export fn execveat(dirfd: int, path: *const char, argv: *[*]nullable *const char,
@@ -58,27 +47,19 @@ export fn sendfile(
in: int,
offs: nullable *size,
count: size,
-) (size | errno) = match (wrap_return(syscall4(SYS_sendfile,
- out: u64, in: u64, offs: uintptr: u64, count: u64))) {
- n: u64 => n: size,
- err: errno => err,
-};
+) (size | errno) = wrap_return(syscall4(SYS_sendfile,
+ out: u64, in: u64, offs: uintptr: u64, count: u64))?: size;
export @noreturn fn exit(status: int) void = syscall1(SYS_exit, status: u64);
export fn kill(pid: int, signal: int) (void | errno) = {
- return match (wrap_return(syscall2(SYS_kill, pid: u64, signal: u64))) {
- err: errno => err,
- u64 => void,
- };
+ wrap_return(syscall2(SYS_kill, pid: u64, signal: u64))?;
+ return;
};
export fn pipe2(pipefd: *[2]int, flags: int) (void | errno) = {
- return match (wrap_return(syscall2(SYS_pipe2,
- pipefd: uintptr: u64, flags: u64))) {
- err: errno => err,
- u64 => void,
- };
+ wrap_return(syscall2(SYS_pipe2, pipefd: uintptr: u64, flags: u64))?;
+ return;
};
export fn mmap(
@@ -107,29 +88,22 @@ export fn mmap(
};
export fn munmap(addr: *void, length: size) (void | errno) = {
- return match (wrap_return(syscall2(SYS_munmap,
- addr: uintptr: u64, length: u64))) {
- err: errno => err,
- u64 => void,
- };
+ wrap_return(syscall2(SYS_munmap,
+ addr: uintptr: u64, length: u64))?;
+ return;
};
export fn mprotect(addr: *void, length: size, prot: uint) (void | errno) = {
- return match (wrap_return(syscall3(SYS_mprotect,
- addr: uintptr: u64, length: u64, prot: u64))) {
- err: errno => err,
- u64 => void,
- };
+ wrap_return(syscall3(SYS_mprotect,
+ addr: uintptr: u64, length: u64, prot: u64))?;
+ return;
};
export fn lseek(fd: int, off: i64, whence: uint) (i64 | errno) = {
- return match (wrap_return(syscall3(SYS_lseek,
- fd: u64, off: u64, whence: u64))) {
- err: errno => err,
- n: u64 => n: i64,
- };
+ return wrap_return(syscall3(SYS_lseek,
+ fd: u64, off: u64, whence: u64))?: i64;
};
export fn faccessat(
@@ -158,31 +132,23 @@ export type fcntl_arg = (void | int | *st_flock | *f_owner_ex | *u64);
export fn fcntl(fd: int, cmd: int, arg: fcntl_arg) (int | errno) = {
let _fd = fd: u64, _cmd = cmd: u64;
- return match (wrap_return(match (arg) {
+ return wrap_return(match (arg) {
void => syscall2(SYS_fcntl, _fd, _cmd),
i: int => syscall3(SYS_fcntl, _fd, _cmd, i: u64),
l: *st_flock => syscall3(SYS_fcntl, _fd, _cmd, l: uintptr: u64),
o: *f_owner_ex => syscall3(SYS_fcntl, _fd, _cmd, o: uintptr: u64),
u: *u64 => syscall3(SYS_fcntl, _fd, _cmd, u: uintptr: u64),
- })) {
- err: errno => err,
- n: u64 => n: int,
- };
+ })?: int;
};
export fn getrandom(buf: *void, bufln: size, flags: uint) (size | errno) = {
- return match (wrap_return(syscall3(SYS_getrandom,
- buf: uintptr: u64, bufln: u64, flags: u64))) {
- err: errno => err,
- n: u64 => n: size,
- };
+ return wrap_return(syscall3(SYS_getrandom,
+ buf: uintptr: u64, bufln: u64, flags: u64))?: size;
};
// TODO: Implement me with VDSO
export fn clock_gettime(clock_id: int, tp: *timespec) (void | errno) = {
- return match (wrap_return(syscall2(SYS_clock_gettime,
- clock_id: u64, tp: uintptr: u64))) {
- err: errno => err,
- u64 => void,
- };
+ wrap_return(syscall2(SYS_clock_gettime,
+ clock_id: u64, tp: uintptr: u64))?;
+ return;
};
diff --git a/strconv/stoi.ha b/strconv/stoi.ha
@@ -16,15 +16,11 @@ export fn stoi64(s: str) (i64 | invalid | overflow) = {
};
let u = if (sign < 0) stou64(strings::from_utf8_unsafe(b[1..]))
else stou64(s);
- match(u) {
- v: (invalid | overflow) => return v,
- n: u64 => {
- if (n > max) {
- return overflow;
- };
- return n: i64 * sign;
- },
+ let n = u?;
+ if (n > max) {
+ return overflow;
};
+ return n: i64 * sign;
};
// Converts a string to an i32 in base 10. If the string contains any
@@ -32,15 +28,11 @@ export fn stoi64(s: str) (i64 | invalid | overflow) = {
// [strconv::invalid] is returned. If the number is too large to be represented
// by an i32, [strconv::overflow] is returned.
export fn stoi32(s: str) (i32 | invalid | overflow) = {
- match (stoi64(s)) {
- v: (invalid | overflow) => return v,
- n: i64 => {
- if (n >= types::I32_MIN: i64 && n <= types::I32_MAX: i64) {
- return n: i32;
- };
- return overflow;
- },
+ let n = stoi64(s)?;
+ if (n >= types::I32_MIN: i64 && n <= types::I32_MAX: i64) {
+ return n: i32;
};
+ return overflow;
};
// Converts a string to an i16 in base 10. If the string contains any
@@ -48,15 +40,11 @@ export fn stoi32(s: str) (i32 | invalid | overflow) = {
// [strconv::invalid] is returned. If the number is too large to be represented
// by an i16, [strconv::overflow] is returned.
export fn stoi16(s: str) (i16 | invalid | overflow) = {
- match (stoi64(s)) {
- v: (invalid | overflow) => return v,
- n: i64 => {
- if (n >= types::I16_MIN: i64 && n <= types::I16_MAX: i64) {
- return n: i16;
- };
- return overflow;
- },
+ let n = stoi64(s)?;
+ if (n >= types::I16_MIN: i64 && n <= types::I16_MAX: i64) {
+ return n: i16;
};
+ return overflow;
};
// Converts a string to an i8 in base 10. If the string contains any
@@ -64,15 +52,11 @@ export fn stoi16(s: str) (i16 | invalid | overflow) = {
// [strconv::invalid] is returned. If the number is too large to be represented
// by an i8, [strconv::overflow] is returned.
export fn stoi8(s: str) (i8 | invalid | overflow) = {
- match (stoi64(s)) {
- v: (invalid | overflow) => return v,
- n: i64 => {
- if (n >= types::I8_MIN: i64 && n <= types::I8_MAX: i64) {
- return n: i8;
- };
- return overflow;
- },
+ let n= stoi64(s)?;
+ if (n >= types::I8_MIN: i64 && n <= types::I8_MAX: i64) {
+ return n: i8;
};
+ return overflow;
};
// Converts a string to an int in base 10. If the string contains any
@@ -81,11 +65,7 @@ export fn stoi8(s: str) (i8 | invalid | overflow) = {
// by an int, [strconv::overflow] is returned.
export fn stoi(s: str) (int | invalid | overflow) = {
static assert(size(int) == size(i32) || size(int) == size(i64));
- return if (size(int) == size(i32)) match (stoi32(s)) {
- v: (invalid | overflow) => v,
- n: i32 => n: int,
- } else match (stoi64(s)) {
- v: (invalid | overflow) => v,
- n: i64 => n: int,
- };
+ return
+ if (size(int) == size(i32)) stoi32(s)?: int
+ else stoi64(s)?: int;
};
diff --git a/strconv/stou.ha b/strconv/stou.ha
@@ -55,15 +55,11 @@ export fn stou64b(s: str, base: uint) (u64 | invalid | overflow) = {
// the number is too large to be represented by a u32, [strconv::overflow] is
// returned. Supported bases are 2, 8, 10 and 16.
export fn stou32b(s: str, base: uint) (u32 | invalid | overflow) = {
- match (stou64b(s, base)) {
- v: (invalid | overflow) => return v,
- n: u64 => {
- if (n <= types::U32_MAX: u64) {
- return n: u32;
- };
- return overflow;
- },
+ let n = stou64b(s, base)?;
+ if (n <= types::U32_MAX: u64) {
+ return n: u32;
};
+ return overflow;
};
// Converts a string to a u16 in the given base, If the string contains any
@@ -71,15 +67,11 @@ export fn stou32b(s: str, base: uint) (u32 | invalid | overflow) = {
// the number is too large to be represented by a u16, [strconv::overflow] is
// returned. Supported bases are 2, 8, 10 and 16.
export fn stou16b(s: str, base: uint) (u16 | invalid | overflow) = {
- match (stou64b(s, base)) {
- v: (invalid | overflow) => return v,
- n: u64 => {
- if (n <= types::U16_MAX: u64) {
- return n: u16;
- };
- return overflow;
- },
+ let n = stou64b(s, base)?;
+ if (n <= types::U16_MAX: u64) {
+ return n: u16;
};
+ return overflow;
};
// Converts a string to a u8 in the given base, If the string contains any
@@ -87,15 +79,11 @@ export fn stou16b(s: str, base: uint) (u16 | invalid | overflow) = {
// the number is too large to be represented by a u8, [strconv::overflow] is
// returned. Supported bases are 2, 8, 10 and 16.
export fn stou8b(s: str, base: uint) (u8 | invalid | overflow) = {
- match (stou64b(s, base)) {
- v: (invalid | overflow) => return v,
- n: u64 => {
- if (n <= types::U8_MAX: u64) {
- return n: u8;
- };
- return overflow;
- },
+ let n = stou64b(s, base)?;
+ if (n <= types::U8_MAX: u64) {
+ return n: u8;
};
+ return overflow;
};
// Converts a string to a uint in the given base, If the string contains any
@@ -104,13 +92,9 @@ export fn stou8b(s: str, base: uint) (u8 | invalid | overflow) = {
// returned. Supported bases are 2, 8, 10 and 16.
export fn stoub(s: str, base: uint) (uint | invalid | overflow) = {
static assert(size(uint) == size(u32) || size(uint) == size(u64));
- return if (size(uint) == size(u32)) match (stou32b(s, base)) {
- v: (invalid | overflow) => v,
- n: u32 => n: uint,
- } else match (stou64b(s, base)) {
- v: (invalid | overflow) => v,
- n: u64 => n: uint,
- };
+ return
+ if (size(uint) == size(u32)) stou32b(s, base)?: uint
+ else stou64b(s, base)?: uint;
};
// Converts a string to a size in the given base, If the string contains any
diff --git a/strconv/types.ha b/strconv/types.ha
@@ -1,9 +1,9 @@
// Indicates that the input string is not an integer
-export type invalid = void;
+export type invalid = void!;
// Indicates that the input number is too large to be represented by the
// requested data type
-export type overflow = void;
+export type overflow = void!;
// The valid numeric bases for numeric conversions.
export type base = enum uint {