hare

The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

commit 4fedf29d249ec7366f18f1ffda3b52293624fd2c
parent 70fdee743845096e7070f378c72ef5c66193174f
Author: Drew DeVault <sir@cmpwn.com>
Date:   Sat, 24 Apr 2021 08:28:39 -0400

all: fix error handling oversights

Following a change to harec and the specification to make error handling
mandatory, a lot of issues were found throughout the stdlib. This fixes
them.

Signed-off-by: Drew DeVault <sir@cmpwn.com>

Diffstat:
Mcmd/hare/plan.ha | 2+-
Mcmd/hare/schedule.ha | 7++++++-
Mcmd/hare/subcmds.ha | 16++++++++--------
Mcmd/harec/errors.ha | 8++++----
Mcmd/haredoc/docstr.ha | 10+++++-----
Mcmd/haredoc/html.ha | 72++++++++++++++++++++++++++++++++++++------------------------------------
Mcrypto/md5/md5.ha | 2+-
Mcrypto/sha1/sha1.ha | 4++--
Mcrypto/sha256/sha256.ha | 4++--
Mcrypto/sha512/sha512.ha | 6+++---
Mfmt/fmt.ha | 2+-
Mformat/xml/parser.ha | 14+++++++-------
Mfs/fs.ha | 6+++++-
Mfs/mem/stream.ha | 2+-
Mgetopt/getopts.ha | 8++++----
Mhare/lex/lex.ha | 6+++---
Mhare/module/manifest.ha | 8++++----
Mhare/parse/parse.ha | 5+++--
Mhare/parse/type.ha | 2+-
Mhare/unparse/expr.ha | 2+-
Mhare/unparse/ident.ha | 2+-
Mio/println+linux.ha | 12++++++------
Mio/stream.ha | 4++--
Mnet/+linux/socket.ha | 4++--
Mnet/+linux/util.ha | 2+-
Mos/+linux/dirfdfs.ha | 4++--
Mos/+linux/fdstream.ha | 4++--
Mos/exec/cmd.ha | 2+-
Mos/exec/exec+linux.ha | 12+++++-------
Mos/exec/process+linux.ha | 4++--
Mrt/+linux/abort.ha | 8++++----
Mrt/+linux/syscalls.ha | 8++++----
Mrt/abort.ha | 12++++++------
Mstrio/dynamic.ha | 16+++++++---------
34 files changed, 143 insertions(+), 137 deletions(-)

diff --git a/cmd/hare/plan.ha b/cmd/hare/plan.ha @@ -63,7 +63,7 @@ fn mkplan(ctx: *module::context) plan = { }; fn plan_finish(plan: *plan) void = { - os::rmdirall(plan.workdir); + os::rmdirall(plan.workdir)!; free(plan.workdir); for (let i = 0z; i < len(plan.complete); i += 1) { diff --git a/cmd/hare/schedule.ha b/cmd/hare/schedule.ha @@ -1,5 +1,6 @@ use encoding::hex; use fmt; +use fs; use hare::ast; use hare::module; use hare::unparse; @@ -185,7 +186,11 @@ fn sched_hare_object( for (let i = 0z; i < len(namespace); i += 1) { path = path::join(path, namespace[i]); }; - os::mkdirs(path); + match (os::mkdirs(path)) { + _: void => void, + err: fs::error => fmt::fatal("Error: mkdirs {}: {}", + path, fs::strerror(err)), + }; append(harec.cmd, "-t", path::join(path, td)); path::join(path, name); } else { diff --git a/cmd/hare/subcmds.ha b/cmd/hare/subcmds.ha @@ -331,20 +331,20 @@ fn test(args: []str) void = { }; fn version(args: []str) void = { - fmt::printfln("Hare version {}", VERSION); - fmt::errorln(); - fmt::printf("Build tags\t"); + fmt::printfln("Hare version {}", VERSION)!; + fmt::errorln()!; + fmt::printf("Build tags\t")!; const tags = default_tags(); for (let i = 0z; i < len(tags); i += 1) { const tag = tags[i]; const inclusive = (tag.mode & module::tag_mode::INCLUSIVE) == module::tag_mode::INCLUSIVE; - fmt::printf("{}{}", if (inclusive) '+' else '-', tag.name); + fmt::printf("{}{}", if (inclusive) '+' else '-', tag.name)!; }; - fmt::println(); + fmt::println()!; match (os::getenv("HAREPATH")) { - _: void => fmt::printfln("HAREPATH\t{}", HAREPATH), - s: str => fmt::printfln("HAREPATH\t{}\t(from environment)", s), + _: void => fmt::printfln("HAREPATH\t{}", HAREPATH)!, + s: str => fmt::printfln("HAREPATH\t{}\t(from environment)", s)!, }; if (len(args) > 1 && args[1] == "-v") { fmt::errorln(" @@ -381,6 +381,6 @@ fn version(args: []str) void = { ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⣀⣈⣀⣒⣓⡒⡒⠒⠒⢒⡀⠀⠀⠀⠀⠴⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠁⠀⣀⠀⠀⠤⠀⠤⠤⠀⠀⠒⠒⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠁⠉⠉⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠠⠄⠀⠀⠀⠐⠒⠒⠒⠀⠀⠀⠀⠀⠀⠈⠉⠉⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠁"); +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠁")!; }; }; diff --git a/cmd/harec/errors.ha b/cmd/harec/errors.ha @@ -31,10 +31,10 @@ fn printerr_syntax(err: lex::syntax) void = { defer free(line); let line = strings::fromutf8(line); fmt::errorfln("{}:{},{}: Syntax error: {}", - location.path, location.line, location.col, details); - fmt::errorln(line); + location.path, location.line, location.col, details)!; + fmt::errorln(line)!; for (let i = 0u; i < location.col - 2; i += 1) { - fmt::error(" "); + fmt::error(" ")!; }; - fmt::errorln("^--- here"); + fmt::errorln("^--- here")!; }; diff --git a/cmd/haredoc/docstr.ha b/cmd/haredoc/docstr.ha @@ -75,7 +75,7 @@ fn scantext(par: *parser) (token | void) = { break; }, '\n' => { - strio::appendrune(buf, rn); + strio::appendrune(buf, rn)!; const rn = match (bufio::scanrune(par.src)) { _: io::EOF => break, * => abort(), @@ -87,7 +87,7 @@ fn scantext(par: *parser) (token | void) = { }; bufio::unreadrune(par.src, rn); }, - * => strio::appendrune(buf, rn), + * => strio::appendrune(buf, rn)!, }; }; let result = strio::finish(buf); @@ -158,10 +158,10 @@ fn scansample(par: *parser) (token | void) = { }; switch (rn) { * => { - strio::appendrune(buf, rn); + strio::appendrune(buf, rn)!; continue; }, - '\n' => strio::appendrune(buf, rn), + '\n' => strio::appendrune(buf, rn)!, }; // Consume whitespace @@ -173,7 +173,7 @@ fn scansample(par: *parser) (token | void) = { ' ' => i += 1, '\t' => i += 8, '\n' => { - strio::appendrune(buf, rn); + strio::appendrune(buf, rn)!; i = 0; }, * => { diff --git a/cmd/haredoc/html.ha b/cmd/haredoc/html.ha @@ -21,16 +21,16 @@ fn emit_html(ctx: *context) (void | error) = { if (ctx.template) head(ctx.ident)?; if (len(ident) == 0) { - fmt::printf("<h2>The Hare standard library <span class='heading-extra'>", ident); + fmt::printf("<h2>The Hare standard library <span class='heading-extra'>", ident)?; } else { - fmt::printf("<h2>{} <span class='heading-extra'>", ident); + fmt::printf("<h2>{} <span class='heading-extra'>", ident)?; }; for (let i = 0z; i < len(ctx.tags); i += 1) { const mode = switch (ctx.tags[i].mode) { module::tag_mode::INCLUSIVE => '+', module::tag_mode::EXCLUSIVE => '-', }; - fmt::printf("{}{} ", mode, ctx.tags[i].name); + fmt::printf("{}{} ", mode, ctx.tags[i].name)?; }; fmt::println("</span></h2>")?; @@ -62,11 +62,11 @@ fn emit_html(ctx: *context) (void | error) = { let path = path::join("/", path, dir); defer free(path); - fmt::printf("<li><a href='"); - html::escape(os::stdout, path); - fmt::printf("'>"); - html::escape(os::stdout, dir); - fmt::printfln("</a></li>"); + fmt::printf("<li><a href='")?; + html::escape(os::stdout, path)?; + fmt::printf("'>")?; + html::escape(os::stdout, dir)?; + fmt::printfln("</a></li>")?; }; fmt::println("</ul>")?; }; @@ -150,12 +150,12 @@ fn tocentry(decl: ast::decl) (void | error) = { _: []ast::decl_type => "type", _: []ast::decl_const => "const", _: []ast::decl_global => "let", - }); - fmt::printf("<a href='#"); + })?; + fmt::printf("<a href='#")?; unparse::ident(os::stdout, decl_ident(decl))?; - fmt::printf("'>"); + fmt::printf("'>")?; unparse::ident(os::stdout, decl_ident(decl))?; - fmt::print("</a>"); + fmt::print("</a>")?; match (decl.decl) { g: []ast::decl_global => { @@ -173,12 +173,12 @@ fn tocentry(decl: ast::decl) (void | error) = { f.prototype._type as ast::func_type, true)?, }; - fmt::println(";"); + fmt::println(";")?; return; }; fn details(ctx: *context, decl: ast::decl) (void | error) = { - fmt::println("<section class='member'>"); + fmt::println("<section class='member'>")?; fmt::print("<h4 id='")?; unparse::ident(os::stdout, decl_ident(decl))?; fmt::print("'>")?; @@ -188,7 +188,7 @@ fn details(ctx: *context, decl: ast::decl) (void | error) = { _: []ast::decl_type => "type", _: []ast::decl_const => "def", _: []ast::decl_global => "let", - }); + })?; unparse::ident(os::stdout, decl_ident(decl))?; // TODO: Add source URL fmt::print("<span class='heading-extra'> @@ -199,8 +199,8 @@ fn details(ctx: *context, decl: ast::decl) (void | error) = { fmt::println("</h4>")?; if (len(decl.docs) == 0) { - fmt::println("<details>"); - fmt::println("<summary>Show undocumented member</summary>"); + fmt::println("<details>")?; + fmt::println("<summary>Show undocumented member</summary>")?; }; fmt::println("<pre class='decl'>")?; @@ -211,7 +211,7 @@ fn details(ctx: *context, decl: ast::decl) (void | error) = { const buf = strings::toutf8(decl.docs); markup_html(ctx, bufio::fixed(buf, io::mode::READ))?; } else { - fmt::println("</details>"); + fmt::println("</details>")?; }; fmt::println("</section>")?; @@ -222,7 +222,7 @@ fn htmlref(ctx: *context, ref: ast::ident) (void | io::error) = { const ik = match (resolve(ctx, ref)) { _: void => { const ident = unparse::identstr(ref); - fmt::errorfln("Warning: Unresolved reference: {}", ident); + fmt::errorfln("Warning: Unresolved reference: {}", ident)?; fmt::printf("<a href='#' " "class='ref invalid' " "title='This reference could not be found'>{}</a>", @@ -267,31 +267,31 @@ fn markup_html(ctx: *context, in: *io::stream) (void | io::error) = { }, tx: text => if (strings::has_prefix(tx, "https://")) { // Temporary hack - fmt::print("<a rel='nofollow noopener' href='"); - html::escape(os::stdout, tx); - fmt::print("'>"); - html::escape(os::stdout, tx); - fmt::print("</a>"); + fmt::print("<a rel='nofollow noopener' href='")?; + html::escape(os::stdout, tx)?; + fmt::print("'>")?; + html::escape(os::stdout, tx)?; + fmt::print("</a>")?; free(tx); } else { - html::escape(os::stdout, tx); + html::escape(os::stdout, tx)?; free(tx); }, re: reference => htmlref(ctx, re)?, sa: sample => { fmt::print("<pre class='sample'>")?; - html::escape(os::stdout, sa); + html::escape(os::stdout, sa)?; fmt::print("</pre>")?; free(sa); }, li: list => { - fmt::println("<ul>"); + fmt::println("<ul>")?; for (let i = 0z; i < len(li); i += 1) { - fmt::println("<li>"); - html::escape(os::stdout, li[i]); - fmt::println("</li>"); + fmt::println("<li>")?; + html::escape(os::stdout, li[i])?; + fmt::println("</li>")?; }; - fmt::println("</ul>"); + fmt::println("</ul>")?; }, }; }; @@ -618,13 +618,13 @@ fn breadcrumb(ident: ast::ident) str = { return ""; }; let buf = strio::dynamic(); - fmt::fprintf(buf, "<a href='/'>stdlib</a> » "); + fmt::fprintf(buf, "<a href='/'>stdlib</a> » ")!; for (let i = 0z; i < len(ident) - 1; i += 1) { let ipath = module::identpath(ident[..i+1]); defer free(ipath); - fmt::fprintf(buf, "<a href='{}'>{}</a>::", ipath, ident[i]); + fmt::fprintf(buf, "<a href='{}'>{}</a>::", ipath, ident[i])!; }; - fmt::fprint(buf, ident[len(ident) - 1]); + fmt::fprint(buf, ident[len(ident) - 1])!; return strio::finish(buf); }; @@ -782,8 +782,8 @@ details pre { <ul> <li> <a href='https://harelang.org'>Home</a> - </li>"); - fmt::printf("<li>{}</li>", breadcrumb); + </li>")?; + fmt::printf("<li>{}</li>", breadcrumb)?; fmt::print("</ul> </nav> <main>")?; diff --git a/crypto/md5/md5.ha b/crypto/md5/md5.ha @@ -97,7 +97,7 @@ fn sum(h: *hash::hash) []u8 = { let tmp: [1 + 63 + 8]u8 = [0x80, 0...]; const pad = (55 - ln) % 64; endian::leputu32(tmp[1+pad..], (ln << 3) : u32); - write(&h.hash.stream, tmp[..1+pad+8]); // append the length in bits + write(&h.hash.stream, tmp[..1+pad+8])!; // append the length in bits assert(h.nx == 0); diff --git a/crypto/sha1/sha1.ha b/crypto/sha1/sha1.ha @@ -102,12 +102,12 @@ fn sum(h: *hash::hash) []u8 = { let tmp: [64]u8 = [0x80, 0...]; const pad = if ((ln % 64z) < 56z) 56z - ln % 64z else 64 + 56z - ln % 64z; - write(&h.hash.stream, tmp[..pad]); + write(&h.hash.stream, tmp[..pad])!; // Length in bits. ln <<= 3; endian::beputu64(tmp, ln: u64); - write(&h.hash.stream, tmp[..8]); + write(&h.hash.stream, tmp[..8])!; assert(h.nx == 0); diff --git a/crypto/sha256/sha256.ha b/crypto/sha256/sha256.ha @@ -118,11 +118,11 @@ fn sum(h: *hash::hash) []u8 = { tmp[0] = 0x80; const n = if ((ln % 64z) < 56z) 56z - ln % 64z else 64z + 56z - ln % 64z; - write(&h.hash.stream, tmp[..n]); + write(&h.hash.stream, tmp[..n])!; ln <<= 3; endian::beputu64(tmp, ln: u64); - write(&h.hash.stream, tmp[..8]); + write(&h.hash.stream, tmp[..8])!; assert(h.nx == 0); diff --git a/crypto/sha512/sha512.ha b/crypto/sha512/sha512.ha @@ -143,17 +143,17 @@ fn sum(h: *hash::hash) []u8 = { let tmp: [chunk]u8 = [0x80, 0...]; if ((ln % 128) < 112) { const n = 112 - (ln % 128); - write(&d.hash.stream, tmp[..n]); + write(&d.hash.stream, tmp[..n])!; } else { const n = 128 + 112 - (ln % 128); - write(&d.hash.stream, tmp[..n]); + write(&d.hash.stream, tmp[..n])!; }; // Length in bits ln <<= 3; endian::beputu64(tmp, 0u64); // upper 64 bits are always zero endian::beputu64(tmp[8..], ln : u64); - write(&d.hash.stream, tmp[..16]); + write(&d.hash.stream, tmp[..16])!; assert(d.nx == 0); diff --git a/fmt/fmt.ha b/fmt/fmt.ha @@ -49,7 +49,7 @@ export fn bsprintf(buf: []u8, fmt: str, args: formattable...) str = { // Formats text for printing and writes it to [[os::stderr]], followed by a line // feed, then exits the program with an error status. export @noreturn fn fatal(fmt: str, args: formattable...) void = { - fprintfln(os::stderr, fmt, args...); + fprintfln(os::stderr, fmt, args...)!; os::exit(1); }; diff --git a/format/xml/parser.ha b/format/xml/parser.ha @@ -122,13 +122,13 @@ fn poptag(par: *parser, expect: str) (str | error) = { return syntaxerr; }; strio::reset(par.namebuf); - strio::concat(par.namebuf, pop); + strio::concat(par.namebuf, pop)!; return strio::string(par.namebuf); }; fn scan_attr(par: *parser) (token | error) = { let name = scan_name(par, par.namebuf)?; - want(par, OPTWS, '=', OPTWS); + want(par, OPTWS, '=', OPTWS)?; let quot = quote(par)?; strio::reset(par.textbuf); for (true) match (bufio::scanrune(par.in)?) { @@ -195,7 +195,7 @@ fn scan_cdata(par: *parser) (text | error) = { rn: rune => rn, }; if (rn != ']') { - strio::appendrune(par.textbuf, rn); + strio::appendrune(par.textbuf, rn)!; continue; }; let rn = match (bufio::scanrune(par.in)?) { @@ -203,7 +203,7 @@ fn scan_cdata(par: *parser) (text | error) = { rn: rune => rn, }; if (rn != ']') { - strio::appendrune(par.textbuf, rn); + strio::appendrune(par.textbuf, rn)!; continue; }; let rn = match (bufio::scanrune(par.in)?) { @@ -211,7 +211,7 @@ fn scan_cdata(par: *parser) (text | error) = { rn: rune => rn, }; if (rn == '>') break; - strio::appendrune(par.textbuf, rn); + strio::appendrune(par.textbuf, rn)!; }; return strio::string(par.textbuf): text; }; @@ -335,12 +335,12 @@ fn scan_name(par: *parser, buf: *io::stream) (str | error) = { if (!isnamestart(rn)) { return syntaxerr; }; - strio::appendrune(buf, rn); + strio::appendrune(buf, rn)!; for (true) match (bufio::scanrune(par.in)?) { _: io::EOF => return syntaxerr, rn: rune => if (isname(rn)) { - strio::appendrune(buf, rn); + strio::appendrune(buf, rn)!; } else { bufio::unreadrune(par.in, rn); break; diff --git a/fs/fs.ha b/fs/fs.ha @@ -92,7 +92,11 @@ export fn mkdirs(fs: *fs, path: str) (void | error) = { _: void => void, }; }; - return mkdir(fs, path); + return match (mkdir(fs, path)) { + _: errors::exists => void, + err: error => err, + _: void => void, + }; }; // Removes a directory. The target directory must be empty; see [[rmdirall]] to diff --git a/fs/mem/stream.ha b/fs/mem/stream.ha @@ -47,7 +47,7 @@ fn stream_open( bufio::truncate(s.source); }; }; - io::seek(s.source, 0, io::whence::SET); + io::seek(s.source, 0, io::whence::SET)?; return &s.stream; }; diff --git a/getopt/getopts.ha b/getopt/getopts.ha @@ -228,7 +228,7 @@ export fn printhelp(s: *io::stream, name: str, help: []help) void = { _: cmd_help => void, _: (flag_help | parameter_help) => { // Only print this if there are flags to show - fmt::fprint(s, "\n"); + fmt::fprint(s, "\n")!; break; }, }; @@ -236,10 +236,10 @@ export fn printhelp(s: *io::stream, name: str, help: []help) void = { for (let i = 0z; i < len(help); i += 1) match (help[i]) { _: cmd_help => void, f: flag_help => { - fmt::fprintfln(s, "-{}: {}", f.0: rune, f.1); + fmt::fprintfln(s, "-{}: {}", f.0: rune, f.1)!; }, p: parameter_help => { - fmt::fprintfln(s, "-{} <{}>: {}", p.0: rune, p.1, p.2); + fmt::fprintfln(s, "-{} <{}>: {}", p.0: rune, p.1, p.2)!; }, }; }; @@ -248,7 +248,7 @@ fn errmsg(name: str, err: str, opt: (rune | void), help: []help) void = { fmt::errorfln("{}: {}{}", name, err, match (opt) { r: rune => r, _: void => "", - }); + })!; printusage(os::stderr, name, help); }; diff --git a/hare/lex/lex.ha b/hare/lex/lex.ha @@ -195,7 +195,7 @@ fn lex_string(lex: *lexer, loc: location) (token | error) = { if (r == '"') { const tok = lex_string(lex, loc)?; const next = tok.1 as str; - strio::concat(buf, next); + strio::concat(buf, next)!; free(next); } else { unget(lex, r); @@ -232,7 +232,7 @@ fn lex_name(lex: *lexer, loc: location, keyword: bool) (token | error) = { match (next(lex)) { r: rune => { assert(is_name(r, false)); - strio::appendrune(buf, r); + strio::appendrune(buf, r)!; }, _: (io::EOF | io::error) => abort(), }; @@ -279,7 +279,7 @@ fn lex_comment(lexr: *lexer, loc: location) (token | error) = { for (true) match (next(lexr)?) { _: io::EOF => break, r: rune => { - strio::appendrune(buf, r); + strio::appendrune(buf, r)!; if (r == '\n') break; }, }; diff --git a/hare/module/manifest.ha b/hare/module/manifest.ha @@ -264,16 +264,16 @@ export fn manifest_write(ctx: *context, manifest: *manifest) (void | error) = { let hash = hex::encodestr(ver.hash); defer free(hash); - fmt::fprintf(fd, "module {}", hash); + fmt::fprintf(fd, "module {}", hash)?; for (let j = 0z; j < len(ver.inputs); j += 1) { let hash = hex::encodestr(ver.inputs[i].hash); defer free(hash); - fmt::fprintf(fd, " {}", hash); + fmt::fprintf(fd, " {}", hash)?; }; - fmt::fprintln(fd); + fmt::fprintln(fd)?; }; }; @@ -296,7 +296,7 @@ fn lock(fs: *fs::fs, cachedir: str) (*io::stream | error) = { err: fs::error => return err, }; if (!logged) { - fmt::errorfln("Waiting for lock on {}...", lockpath); + fmt::errorfln("Waiting for lock on {}...", lockpath): void; logged = true; }; time::sleep(1 * time::SECOND); diff --git a/hare/parse/parse.ha b/hare/parse/parse.ha @@ -41,9 +41,10 @@ fn want(lexer: *lex::lexer, want: lex::ltok...) (lex::token | error) = { let buf = strio::dynamic(); defer io::close(buf); for (let i = 0z; i < len(want); i += 1) { - fmt::fprintf(buf, "'{}'", lex::tokstr((want[i], void, mkloc(lexer)))); + const tstr = lex::tokstr((want[i], void, mkloc(lexer))); + fmt::fprintf(buf, "'{}'", tstr)!; if (i + 1 < len(want)) { - fmt::fprint(buf, ", "); + fmt::fprint(buf, ", ")!; }; }; return syntaxerr(mkloc(lexer), "Unexpected '{}', was expecting {}", diff --git a/hare/parse/type.ha b/hare/parse/type.ha @@ -24,7 +24,7 @@ fn prototype(lexer: *lex::lexer) (ast::func_type | error) = { _: void => want(lexer, ltok::NAME)?.1 as str, _: lex::token => "", }; - want(lexer, ltok::COLON); + want(lexer, ltok::COLON)?; append(params, ast::func_param { loc = loc, name = name, diff --git a/hare/unparse/expr.ha b/hare/unparse/expr.ha @@ -381,7 +381,7 @@ fn struct_constant( }; indent -= 1; newline(out, indent)?; - fmt::fprint(out, "}"); + fmt::fprint(out, "}")?; return z; }; diff --git a/hare/unparse/ident.ha b/hare/unparse/ident.ha @@ -17,7 +17,7 @@ export fn ident(out: *io::stream, id: ast::ident) (size | io::error) = { // Unparses an identifier into a string. The caller must free the return value. export fn identstr(id: ast::ident) str = { let buf = strio::dynamic(); - ident(buf, id); + ident(buf, id)!; return strio::finish(buf); }; diff --git a/io/println+linux.ha b/io/println+linux.ha @@ -7,14 +7,14 @@ use rt; export fn println(msgs: str...) void = { for (let i = 0z; i < len(msgs); i += 1) { let msg = msgs[i]; - rt::write(1, *(&msg: **void): *const char, len(msg)); + rt::write(1, *(&msg: **void): *const char, len(msg)): void; if (i + 1 < len(msgs)) { const sp = " "; - rt::write(1, *(&sp: **void): *const char, 1); + rt::write(1, *(&sp: **void): *const char, 1): void; }; }; const linefeed = "\n"; - rt::write(1, *(&linefeed: **void): *const char, 1); + rt::write(1, *(&linefeed: **void): *const char, 1): void; }; // Prints strings to stderr, separated by spaces, and followed by a newline. @@ -24,12 +24,12 @@ export fn println(msgs: str...) void = { export fn errorln(msgs: str...) void = { for (let i = 0z; i < len(msgs); i += 1) { let msg = msgs[i]; - rt::write(2, *(&msg: **void): *const char, len(msg)); + rt::write(2, *(&msg: **void): *const char, len(msg)): void; if (i + 1 < len(msgs)) { const sp = " "; - rt::write(2, *(&sp: **void): *const char, 1); + rt::write(2, *(&sp: **void): *const char, 1): void; }; }; const linefeed = "\n"; - rt::write(2, *(&linefeed: **void): *const char, 1); + rt::write(2, *(&linefeed: **void): *const char, 1): void; }; diff --git a/io/stream.ha b/io/stream.ha @@ -50,9 +50,9 @@ export fn write(s: *stream, buf: const []u8) (size | error) = { }; // Closes the stream. -export fn close(s: *stream) (error | void) = { +export fn close(s: *stream) void = { return match (s.closer) { - null => errors::unsupported, + null => void, c: *closer => c(s), }; }; diff --git a/net/+linux/socket.ha b/net/+linux/socket.ha @@ -70,7 +70,7 @@ fn listen_fd( p: portassignment => portout = p, }; }; - setfcntl(sockfd, rt::O_CLOEXEC); + setfcntl(sockfd, rt::O_CLOEXEC)!; wrap(rt::bind(sockfd, &addr, sockasz(addr)))?; wrap(rt::listen(sockfd, bk))?; @@ -124,7 +124,7 @@ fn stream_accept(l: *listener) (*io::stream | io::error) = { fn stream_shutdown(l: *listener) void = { assert(l.shutdown == &stream_shutdown); let l = l: *stream_listener; - rt::close(l.fd); + rt::close(l.fd)!; free(l); }; diff --git a/net/+linux/util.ha b/net/+linux/util.ha @@ -14,7 +14,7 @@ fn setsockopt(sockfd: int, option: int, value: bool) (void | rt::errno) = { fn setfcntl(sockfd: int, flag: int) (void | rt::errno) = { let flags = rt::fcntl(sockfd, rt::F_GETFL, 0)?; - rt::fcntl(sockfd, rt::F_SETFL, flags | flag); // ? always detects io::error + rt::fcntl(sockfd, rt::F_SETFL, flags | flag)!; return; }; diff --git a/os/+linux/dirfdfs.ha b/os/+linux/dirfdfs.ha @@ -329,7 +329,7 @@ fn fs_resolve(fs: *fs::fs, path: str) str = { fn fs_close(fs: *fs::fs) void = { let fs = fs: *os_filesystem; - rt::close(fs.dirfd); + rt::close(fs.dirfd)!; }; def BUFSIZ: size = 2048; @@ -370,7 +370,7 @@ fn iter_next(iter: *fs::iterator) (fs::dirent | void) = { if (iter.buf_pos >= iter.buf_end) { let n = rt::getdents64(iter.fd, &iter.buf, BUFSIZ) as size; if (n == 0) { - rt::close(iter.fd); + rt::close(iter.fd)!; free(iter); return; }; diff --git a/os/+linux/fdstream.ha b/os/+linux/fdstream.ha @@ -88,14 +88,14 @@ fn fd_write(s: *io::stream, buf: const []u8) (size | io::error) = { fn fd_close(s: *io::stream) void = { let stream = s: *fd_stream; - rt::close(stream.fd); + rt::close(stream.fd)!; free(s.name); free(stream); }; fn fd_close_static(s: *io::stream) void = { let stream = s: *fd_stream; - rt::close(stream.fd); + rt::close(stream.fd)!; free(stream); }; diff --git a/os/exec/cmd.ha b/os/exec/cmd.ha @@ -54,7 +54,7 @@ export fn finish(cmd: *command) void = { // running process with the new command. export @noreturn fn exec(cmd: *command) void = { defer finish(cmd); // Note: doesn't happen if exec succeeds - platform_exec(cmd); + platform_exec(cmd): void; abort("os::exec::exec failed"); }; diff --git a/os/exec/exec+linux.ha b/os/exec/exec+linux.ha @@ -14,10 +14,8 @@ export fn fork() (int | void | error) = match (rt::fork()) { fn open(path: str) (platform_cmd | errors::opaque) = { match (rt::access(path, rt::X_OK)) { - err: rt::errno => errors::errno(err), - b: bool => if (!b) { - return errors::errno(rt::EACCES); - }, + err: rt::errno => return errors::errno(err), + b: bool => if (!b) return errors::errno(rt::EACCES), }; // O_PATH is used because it allows us to use an executable for which we // have execute permissions, but not read permissions. @@ -63,7 +61,7 @@ fn platform_start(cmd: *command) (errors::opaque | process) = { match (rt::clone(null, 0, null, null, 0)) { err: rt::errno => return errors::errno(err), pid: int => { - rt::close(pipe[1]); + rt::close(pipe[1])!; let errno: int = 0; return match (rt::read(pipe[0], &errno, size(int))) { err: rt::errno => errors::errno(err), @@ -75,10 +73,10 @@ fn platform_start(cmd: *command) (errors::opaque | process) = { }; }, _: void => { - rt::close(pipe[0]); + rt::close(pipe[0])!; let err = platform_exec(cmd); let err = &err.data: *rt::errno; - rt::write(pipe[1], &err, size(int)); + rt::write(pipe[1], &err, size(int))!; rt::exit(1); }, }; diff --git a/os/exec/process+linux.ha b/os/exec/process+linux.ha @@ -38,7 +38,7 @@ export fn wait(proc: *process) (status | error) = { let ru: rt::rusage = rt::rusage { ... }; let st: status = status { ... }; match (rt::wait4(*proc, &st.status, 0, &ru)) { - err: rt::errno => errors::errno(err), + err: rt::errno => return errors::errno(err), pid: int => assert(pid == *proc), }; rusage(&st, &ru); @@ -51,7 +51,7 @@ export fn peek(proc: *process) (status | void | error) = { let ru: rt::rusage = rt::rusage { ... }; let st: status = status { ... }; match (rt::wait4(*proc, &st.status, 0, &ru)) { - err: rt::errno => errors::errno(err), + err: rt::errno => return errors::errno(err), pid: int => switch (pid) { 0 => return void, * => assert(pid == *proc), diff --git a/rt/+linux/abort.ha b/rt/+linux/abort.ha @@ -1,8 +1,8 @@ fn platform_abort(msg: str) void = { const prefix = "Abort: "; const linefeed = "\n"; - write(2, *(&prefix: **void): *const char, len(prefix)); - write(2, *(&msg: **void): *const char, len(msg)); - write(2, *(&linefeed: **void): *const char, 1); - kill(getpid(), SIGABRT); + write(2, *(&prefix: **void): *const char, len(prefix))!; + write(2, *(&msg: **void): *const char, len(msg))!; + write(2, *(&linefeed: **void): *const char, 1)!; + kill(getpid(), SIGABRT)!; }; diff --git a/rt/+linux/syscalls.ha b/rt/+linux/syscalls.ha @@ -70,21 +70,21 @@ export fn openat2( export fn unlink(path: path) (void | errno) = { let path = kpath(path)?; wrap_return(syscall3(SYS_unlinkat, - AT_FDCWD: u64, path: uintptr: u64, 0u64)); + AT_FDCWD: u64, path: uintptr: u64, 0u64))?; return; }; export fn unlinkat(dirfd: int, path: path, flags: int) (void | errno) = { let path = kpath(path)?; wrap_return(syscall3(SYS_unlinkat, - dirfd: u64, path: uintptr: u64, flags: u64)); + dirfd: u64, path: uintptr: u64, flags: u64))?; return; }; export fn chmod(path: path, mode: uint) (void | errno) = { let path = kpath(path)?; wrap_return(syscall3(SYS_fchmodat, - AT_FDCWD: u64, path: uintptr: u64, mode: u64)); + AT_FDCWD: u64, path: uintptr: u64, mode: u64))?; return; }; @@ -98,7 +98,7 @@ export fn fchmodat(dirfd: int, path: path, mode: uint) (void | errno) = { export fn chown(path: path, uid: uint, gid: uint) (void | errno) = { let path = kpath(path)?; wrap_return(syscall4(SYS_fchownat, - AT_FDCWD: u64, path: uintptr: u64, uid: u32, gid: u32)); + AT_FDCWD: u64, path: uintptr: u64, uid: u32, gid: u32))?; return; }; diff --git a/rt/abort.ha b/rt/abort.ha @@ -14,10 +14,10 @@ export @noreturn fn abort_fixed(loc: str, i: int) void = { const prefix = "Abort: "; const sep = ": "; const linefeed = "\n"; - write(2, *(&prefix: **void): *const char, len(prefix)); - write(2, *(&loc: **void): *const char, len(loc)); - write(2, *(&sep: **void): *const char, len(sep)); - write(2, *(&reasons[i]: **void): *const char, len(reasons[i])); - write(2, *(&linefeed: **void): *const char, 1); - kill(getpid(), SIGABRT); + write(2, *(&prefix: **void): *const char, len(prefix))!; + write(2, *(&loc: **void): *const char, len(loc))!; + write(2, *(&sep: **void): *const char, len(sep))!; + write(2, *(&reasons[i]: **void): *const char, len(reasons[i]))!; + write(2, *(&linefeed: **void): *const char, 1)!; + kill(getpid(), SIGABRT)!; }; diff --git a/strio/dynamic.ha b/strio/dynamic.ha @@ -30,7 +30,7 @@ export fn dynamic() *io::stream = { // of it to the caller. export fn finish(s: *io::stream) str = { assert(s.writer == &dynamic_write, - "strio::finish called on non-strio stream"); + "strio::finish called on non-strio::dynamic stream"); let s = s: *dynamic_stream; let buf = s.buf; free(s); @@ -39,20 +39,18 @@ export fn finish(s: *io::stream) str = { // Resets the buffer's length to zero, but keeps the allocated memory around for // future writes. -export fn reset(s: *io::stream) (void | errors::unsupported) = { - if (s.writer != &dynamic_write || s.closer != &dynamic_close) { - return errors::unsupported; - }; +export fn reset(s: *io::stream) void = { + assert(s.writer == &dynamic_write, + "strio::reset called on non-strio::dynamic stream"); const s = s: *dynamic_stream; s.buf = s.buf[..0]; }; // Truncates the buffer, freeing memory associated with it and setting its // length to zero. -export fn truncate(s: *io::stream) (void | errors::unsupported) = { - if (s.writer != &dynamic_write || s.closer != &dynamic_close) { - return errors::unsupported; - }; +export fn truncate(s: *io::stream) void = { + assert(s.writer == &dynamic_write, + "strio::truncate called on non-strio::dynamic stream"); let s = s: *dynamic_stream; delete(s.buf[..]); };