commit 7f03a98873f32601cfe280206280f719486f8625 parent 10e1b3c6b846612a1a5543a5721920c78144a97c Author: Lorenz (xha) <me@xha.li> Date: Mon, 6 Jan 2025 16:55:58 +0100 updates for the allocation failure RFC for now, handle all allocation failures using an error assertion, effectively preserving the old behavior for now. this means that the only breaking change is that errors::nomem was removed and instead replaced by the builtin "nomem". Signed-off-by: Lorenz (xha) <me@xha.li> Diffstat:
132 files changed, 712 insertions(+), 674 deletions(-)
diff --git a/ascii/string.ha b/ascii/string.ha @@ -9,7 +9,7 @@ use strings; // representation, returning a new string. The return value must be freed by the // caller. export fn strlower(s: str) str = { - let new: []u8 = alloc([], len(s)); + let new: []u8 = alloc([], len(s))!; return strlower_buf(s, new); }; @@ -22,7 +22,7 @@ export fn strlower_buf(s: str, buf: []u8) str = { let buf = buf[..0]; let it = strings::iter(s); for (let r => strings::next(&it)) { - static append(buf, utf8::encoderune(tolower(r))...); + static append(buf, utf8::encoderune(tolower(r))...)!; }; return strings::fromutf8(buf)!; }; @@ -31,7 +31,7 @@ export fn strlower_buf(s: str, buf: []u8) str = { // representation, returning a new string. The return value must be freed by the // caller. export fn strupper(s: str) str = { - let new: []u8 = alloc([], len(s)); + let new: []u8 = alloc([], len(s))!; return strupper_buf(s, new); }; @@ -44,7 +44,7 @@ export fn strupper_buf(s: str, buf: []u8) str = { let buf = buf[..0]; let it = strings::iter(s); for (let r => strings::next(&it)) { - static append(buf, utf8::encoderune(toupper(r))...); + static append(buf, utf8::encoderune(toupper(r))...)!; }; return strings::fromutf8(buf)!; }; diff --git a/bufio/scanner.ha b/bufio/scanner.ha @@ -76,7 +76,7 @@ export fn newscanner( return scanner { stream = &scanner_vtable, src = src, - buffer = alloc([0...], BUFSZ), + buffer = alloc([0...], BUFSZ)!, maxread = maxread, start = 0, pending = [], @@ -151,7 +151,7 @@ fn scan_readahead(scan: *scanner) (size | io::EOF | io::error) = { if (pending >= readahead) { return errors::overflow; }; - append(scan.buffer, [0...], readahead); + append(scan.buffer, [0...], readahead)!; }; }; @@ -332,7 +332,7 @@ export fn read_tok(h: io::handle, delim: u8...) ([]u8 | io::EOF | io::error) = { if (bytes::contains(delim, res)) { break; }; - append(buf, res); + append(buf, res)!; case io::EOF => if (len(buf) == 0) { return io::EOF; diff --git a/cmd/genbootstrap/main.ha b/cmd/genbootstrap/main.ha @@ -46,7 +46,7 @@ export fn main() void = { defer io::close(&objs)!; for (let i = 0z; i < len(mods); i += 1) { append(ids, (strings::join("_", mods[i].ns...), - unparse::identstr(mods[i].ns))); + unparse::identstr(mods[i].ns)))!; fmt::fprintf(&tds, ` HARE_TD_{}=$(HARECACHE)/{}.td`, ids[i].1, ids[i].0)!; fmt::fprintf(&objs, ` $(HARECACHE)/{}.o`, ids[i].0)!; diff --git a/cmd/genoiddb/main.ha b/cmd/genoiddb/main.ha @@ -71,7 +71,7 @@ fn parse_oids() []entry = { name = strings::dup(name), val = strings::dup(val), ... - }); + })!; }; return oids; @@ -97,7 +97,7 @@ fn write_db(h: io::handle, oids: []entry) (void | io::error) = { let der = oidtoder(e.val); assert(len(der) <= 0xff); - insert(der[0], len(der): u8); + insert(der[0], len(der): u8)!; defer free(der); for (let byte .. der) { @@ -121,7 +121,7 @@ fn oidtoder(oid: str) []u8 = { let nums = oidtou64s(oid); defer free(nums); - let der: []u8 = alloc([0...], 1); + let der: []u8 = alloc([0...], 1)!; assert(nums[0] <= 6); assert(nums[1] < 40); der[0] = nums[0]: u8 * 40 + nums[1]: u8; @@ -130,7 +130,7 @@ fn oidtoder(oid: str) []u8 = { for (let i = 2z; i < len(nums); i += 1) { let n = nums[i]; if (n == 0) { - insert(der[end], 0u8); + insert(der[end], 0u8)!; end = len(der); continue; }; @@ -144,7 +144,7 @@ fn oidtoder(oid: str) []u8 = { } else { p |= 0x80; }; - insert(der[end], p); + insert(der[end], p)!; }; end = len(der); @@ -158,7 +158,7 @@ fn oidtou64s(oid: str) []u64 = { let intnums: []u64 = []; for (let s => strings::next_token(&nums)) { - append(intnums, strconv::stou64(s)!); + append(intnums, strconv::stou64(s)!)!; }; return intnums; diff --git a/cmd/hare/arch.ha b/cmd/hare/arch.ha @@ -43,7 +43,7 @@ const arches: [_]build::arch = [ fn set_arch_tags(tags: *[]str, a: *build::arch) void = { merge_tags(tags, "-aarch64-riscv64-x86_64")!; - append(tags, a.name); + append(tags, a.name)!; }; fn get_arch(name: str) (*build::arch | unknown_arch) = { diff --git a/cmd/hare/build.ha b/cmd/hare/build.ha @@ -63,7 +63,7 @@ fn build(name: str, cmd: *getopt::command) (void | error) = { let sc = bufio::newscanner(&buf, len(opt.1)); defer bufio::finish(&sc); let lexer = lex::init(&sc, "<-D argument>"); - append(ctx.defines, parse::define(&lexer)?); + append(ctx.defines, parse::define(&lexer)?)!; case 'F' => ctx.freestanding = true; case 'j' => @@ -83,9 +83,9 @@ fn build(name: str, cmd: *getopt::command) (void | error) = { fmt::fatal("Number of jobs must be non-zero"); }; case 'L' => - append(ctx.libdirs, opt.1); + append(ctx.libdirs, opt.1)!; case 'l' => - append(ctx.libs, opt.1); + append(ctx.libs, opt.1)!; case 'N' => ast::ident_free(ctx.ns); ctx.ns = []; @@ -175,7 +175,7 @@ fn build(name: str, cmd: *getopt::command) (void | error) = { const input = if (len(cmd.args) == 0) os::getcwd() else cmd.args[0]; ctx.mods = build::gather(&ctx, os::realpath(input)?)?; - append(ctx.hashes, [[void...]...], len(ctx.mods)); + append(ctx.hashes, [[void...]...], len(ctx.mods))!; let built = build::execute(&ctx)?; defer free(built); diff --git a/cmd/hare/build/gather.ha b/cmd/hare/build/gather.ha @@ -37,7 +37,7 @@ export fn gather(ctx: *context, input: str) ([]module::module | error) = { append(mods, module::module { path = strings::dup(input), ... - }); + })!; yield len(mods) - 1; }; return mods; diff --git a/cmd/hare/build/queue.ha b/cmd/hare/build/queue.ha @@ -42,7 +42,7 @@ export fn execute(ctx: *context) (str | error) = { sort::sort(q, size(*task), &task_cmp); ctx.total = len(q); - let jobs: []job = alloc([], ctx.jobs); + let jobs: []job = alloc([], ctx.jobs)!; defer free(jobs); if (len(os::tryenv("NO_COLOR", "")) == 0 @@ -85,24 +85,24 @@ fn queue(ctx: *context, q: *[]*task, kind: stage, idx: size) *task = { kind = kind, idx = idx, ... - }); + })!; switch (kind) { case stage::BIN => t.ndeps = len(ctx.mods); for (let i = 0z; i < len(ctx.mods); i += 1) { - append(queue(ctx, q, stage::O, i).rdeps, t); + append(queue(ctx, q, stage::O, i).rdeps, t)!; }; case stage::O, stage::S => t.ndeps = 1; - append(queue(ctx, q, kind - 1, idx).rdeps, t); + append(queue(ctx, q, kind - 1, idx).rdeps, t)!; case stage::SSA => t.ndeps = len(ctx.mods[idx].deps); for (let (dep_idx, _) .. ctx.mods[idx].deps) { - append(queue(ctx, q, stage::SSA, dep_idx).rdeps, t); + append(queue(ctx, q, stage::SSA, dep_idx).rdeps, t)!; }; case stage::TD => abort(); }; - append(q, t); + append(q, t)!; return t; }; @@ -192,7 +192,7 @@ fn run_task(ctx: *context, jobs: *[]job, t: *task) (bool | error) = { pid = exec::start(&cmd)?, task = t, lock = lock, - }); + })!; return true; }; diff --git a/cmd/hare/build/util.ha b/cmd/hare/build/util.ha @@ -26,25 +26,25 @@ fn get_deps(ctx: *context, t: *task) []str = { case stage::SSA => let deps = strings::dupall(mod.srcs.ha); for (let (dep_idx, _) .. mod.deps) { - append(deps, get_cache(ctx, dep_idx, stage::TD)!); + append(deps, get_cache(ctx, dep_idx, stage::TD)!)!; }; return deps; case stage::S => - return alloc([get_cache(ctx, t.idx, stage::SSA)!]...); + return alloc([get_cache(ctx, t.idx, stage::SSA)!]...)!; case stage::O => let deps = strings::dupall(mod.srcs.s); - append(deps, get_cache(ctx, t.idx, stage::S)!); + append(deps, get_cache(ctx, t.idx, stage::S)!)!; return deps; case stage::BIN => let deps: []str = []; for (let i = 0z; i < len(ctx.mods); i += 1) { let srcs = &ctx.mods[i].srcs; for (let j = 0z; j < len(srcs.sc); j += 1) { - append(deps, strings::dup(srcs.sc[j])); + append(deps, strings::dup(srcs.sc[j]))!; }; - append(deps, get_cache(ctx, i, stage::O)!); + append(deps, get_cache(ctx, i, stage::O)!)!; for (let o .. srcs.o) { - append(deps, strings::dup(o)); + append(deps, strings::dup(o))!; }; }; return deps; @@ -70,7 +70,7 @@ fn get_flags(ctx: *context, t: *task) ([]str | error) = { }; match (shlex::split(os::tryenv(flags_env, ""))) { case let s: []str => - append(flags, s...); + append(flags, s...)!; case shlex::syntaxerr => fmt::errorfln("warning: invalid shell syntax in ${}; ignoring", flags_env)?; @@ -80,55 +80,55 @@ fn get_flags(ctx: *context, t: *task) ([]str | error) = { case stage::TD => abort(); case stage::SSA => void; // below case stage::S => - append(flags, strings::dup("-t")); - append(flags, strings::dup(ctx.arch.qbe_name)); + append(flags, strings::dup("-t"))!; + append(flags, strings::dup(ctx.arch.qbe_name))!; return flags; case stage::O => return flags; case stage::BIN => for (let libdir .. ctx.libdirs) { - append(flags, strings::dup("-L")); - append(flags, strings::dup(libdir)); + append(flags, strings::dup("-L"))!; + append(flags, strings::dup(libdir))!; }; if (ctx.libc) { - append(flags, strings::dup("-Wl,--gc-sections")); + append(flags, strings::dup("-Wl,--gc-sections"))!; } else { - append(flags, strings::dup("--gc-sections")); - append(flags, strings::dup("-z")); - append(flags, strings::dup("noexecstack")); + append(flags, strings::dup("--gc-sections"))!; + append(flags, strings::dup("-z"))!; + append(flags, strings::dup("noexecstack"))!; }; return flags; }; - append(flags, strings::dup("-a")); - append(flags, strings::dup(ctx.arch.name)); + append(flags, strings::dup("-a"))!; + append(flags, strings::dup(ctx.arch.name))!; let mod = ctx.mods[t.idx]; if (len(ctx.ns) != 0 && t.idx == ctx.top) { - append(flags, strings::dup("-N")); - append(flags, unparse::identstr(ctx.ns)); + append(flags, strings::dup("-N"))!; + append(flags, unparse::identstr(ctx.ns))!; } else if (len(mod.ns) != 0 || ctx.libc) { - append(flags, strings::dup("-N")); - append(flags, unparse::identstr(mod.ns)); + append(flags, strings::dup("-N"))!; + append(flags, unparse::identstr(mod.ns))!; }; if (ctx.freestanding) { - append(flags, strings::dup("-m")); - append(flags, ""); + append(flags, strings::dup("-m"))!; + append(flags, "")!; } else if (ctx.libc) { - append(flags, strings::dup("-m.main")); + append(flags, strings::dup("-m.main"))!; }; - append(flags, strings::dup("-M")); + append(flags, strings::dup("-M"))!; path::set(&buf, mod.path)?; for (let i = 0z; i < len(mod.ns); i += 1) { path::pop(&buf); }; - append(flags, strings::concat(path::string(&buf), "/")); + append(flags, strings::concat(path::string(&buf), "/"))!; path::set(&buf, mod.path)?; let test = ctx.test && t.idx == ctx.top; test ||= path::trimprefix(&buf, os::getcwd()) is str && ctx.submods; if (test) { - append(flags, strings::dup("-T")); + append(flags, strings::dup("-T"))!; }; for (let define .. ctx.defines) { @@ -147,7 +147,7 @@ fn get_flags(ctx: *context, t: *task) ([]str | error) = { }; memio::concat(&buf, "=")!; unparse::expr(&buf, &unparse::syn_nowrap, define.init)!; - append(flags, memio::string(&buf)!); + append(flags, memio::string(&buf)!)!; }; return flags; @@ -208,8 +208,8 @@ fn get_hash( // the hash. see [[get_flags]] for the arguments that don't depend on the hash fn get_args(ctx: *context, tmp: str, flags: []str, t: *task) []str = { let args = strings::dupall(flags); - append(args, strings::dup("-o")); - append(args, strings::dup(tmp)); + append(args, strings::dup("-o"))!; + append(args, strings::dup(tmp))!; // TODO: https://todo.sr.ht/~sircmpwn/hare/837 let srcs: []str = switch (t.kind) { @@ -217,25 +217,25 @@ fn get_args(ctx: *context, tmp: str, flags: []str, t: *task) []str = { case stage::SSA => let td = get_cache(ctx, t.idx, stage::SSA)!; defer free(td); - append(args, strings::dup("-t")); - append(args, strings::concat(td, ".td.tmp")); + append(args, strings::dup("-t"))!; + append(args, strings::concat(td, ".td.tmp"))!; yield ctx.mods[t.idx].srcs.ha; case stage::S => - append(args, get_cache(ctx, t.idx, stage::SSA)!); + append(args, get_cache(ctx, t.idx, stage::SSA)!)!; yield []; case stage::O => - append(args, get_cache(ctx, t.idx, stage::S)!); + append(args, get_cache(ctx, t.idx, stage::S)!)!; yield ctx.mods[t.idx].srcs.s; case stage::BIN => for (let i = 0z; i < len(ctx.mods); i += 1) { let srcs = ctx.mods[i].srcs; for (let sc .. srcs.sc) { - append(args, strings::dup("-T")); - append(args, strings::dup(sc)); + append(args, strings::dup("-T"))!; + append(args, strings::dup(sc))!; }; - append(args, get_cache(ctx, i, stage::O)!); + append(args, get_cache(ctx, i, stage::O)!)!; for (let o .. srcs.o) { - append(args, strings::dup(o)); + append(args, strings::dup(o))!; }; }; // XXX: when dynamically linking on Linux, we have to disable @@ -243,16 +243,16 @@ fn get_args(ctx: *context, tmp: str, flags: []str, t: *task) []str = { // like leaving this enabled gets us SIGILL in libc (musl). this // is not broken on other platforms such as OpenBSD if (ctx.libc) { - append(args, strings::dup("-Wl,--no-gc-sections")); + append(args, strings::dup("-Wl,--no-gc-sections"))!; }; for (let lib .. ctx.libs) { - append(args, strings::dup("-l")); - append(args, strings::dup(lib)); + append(args, strings::dup("-l"))!; + append(args, strings::dup(lib))!; }; yield []; }; for (let src .. srcs) { - append(args, strings::dup(src)); + append(args, strings::dup(src))!; }; return args; }; diff --git a/cmd/hare/deps.ha b/cmd/hare/deps.ha @@ -122,7 +122,7 @@ fn deps_graph(mods: *[]module::module) void = { let links: []link = []; defer free(links); - let depth: []uint = alloc([0...], len(mods)); + let depth: []uint = alloc([0...], len(mods))!; // traverse in reverse because reverse-topo-sort for (let i = len(mods) - 1; i < len(mods); i -= 1) { // reverse-sort deps so that we know the last in the list is the @@ -190,7 +190,7 @@ fn deps_graph(mods: *[]module::module) void = { depth = depth[i], child = mods[i].deps[j].0, final = len(mods[i].deps) == j + 1, - }); + })!; }; }; }; diff --git a/cmd/hare/util.ha b/cmd/hare/util.ha @@ -25,7 +25,7 @@ fn merge_tags(current: *[]str, new: str) (void | module::error) = { }; }; if (newtag.include) { - append(current, newtag.name); + append(current, newtag.name)!; }; }; }; @@ -46,6 +46,6 @@ fn default_tags() []str = { let arch = os::arch_name(os::architecture()); static let platform: [7]u8 = [0...]; let platform = ascii::strlower_buf(os::sysname(), platform[..0]); - let tags: []str = alloc([arch, platform]); + let tags: []str = alloc([arch, platform])!; return tags; }; diff --git a/cmd/hare/version.ha b/cmd/hare/version.ha @@ -58,7 +58,7 @@ fn version(name: str, cmd: *getopt::command) (void | error) = { defer free(toolchains); for (let arch .. arches) { - append(toolchains, arch.name); + append(toolchains, arch.name)!; }; const toolchains = strings::join(" ", toolchains...); diff --git a/cmd/haredoc/doc/resolve.ha b/cmd/haredoc/doc/resolve.ha @@ -148,7 +148,7 @@ fn lookup_remote_enum(ctx: *context, what: ast::ident) (ast::ident | void | erro for (let in .. srcs.ha) { let d = scan(in)?; defer free(d); - append(decls, d...); + append(decls, d...)!; }; for (let decl .. decls) { diff --git a/cmd/haredoc/doc/sort.ha b/cmd/haredoc/doc/sort.ha @@ -36,7 +36,7 @@ export fn sort_decls(decls: []ast::decl) summary = { attrs = f.attrs, }, docs = decl.docs, - }); + })!; case let types: []ast::decl_type => for (let t .. types) { let bucket = &sorted.types; @@ -47,9 +47,9 @@ export fn sort_decls(decls: []ast::decl) summary = { exported = false, start = decl.start, end = decl.end, - decl = alloc([t]), + decl = alloc([t])!, docs = decl.docs, - }); + })!; }; case let consts: []ast::decl_const => for (let c .. consts) { @@ -57,9 +57,9 @@ export fn sort_decls(decls: []ast::decl) summary = { exported = false, start = decl.start, end = decl.end, - decl = alloc([c]), + decl = alloc([c])!, docs = decl.docs, - }); + })!; }; case let globals: []ast::decl_global => for (let g .. globals) { @@ -74,9 +74,9 @@ export fn sort_decls(decls: []ast::decl) summary = { ident = g.ident, _type = g._type, init = null, - }]), + }])!, docs = decl.docs, - }); + })!; }; case ast::assert_expr => void; }; diff --git a/cmd/haredoc/doc/util.ha b/cmd/haredoc/doc/util.ha @@ -29,7 +29,7 @@ export fn submodules(path: str, show_undocumented: bool) ([]str | error) = { for (let d => module::next(it)?) { path::set(&pathbuf, path, d.name, "README")!; if (show_undocumented || os::exists(path::string(&pathbuf))) { - append(submodules, strings::dup(d.name)); + append(submodules, strings::dup(d.name))!; }; }; sort::sort(submodules, size(str), &cmp::strs); diff --git a/cmd/haredoc/main.ha b/cmd/haredoc/main.ha @@ -172,14 +172,14 @@ fn doc(name: str, cmd: *getopt::command) (void | error) = { match (err) { case let err: lex::syntax => const msg = strings::dup(err.1); - append(parse_errs, (err.0, msg)); + append(parse_errs, (err.0, msg))!; continue; case => return err; }; }; defer free(d); - append(decls, d...); + append(decls, d...)!; }; let matching: []ast::decl = []; @@ -187,9 +187,9 @@ fn doc(name: str, cmd: *getopt::command) (void | error) = { for (let decl .. decls) { if (has_decl(decl, id[len(id) - 1])) { - append(matching, decl); + append(matching, decl)!; } else { - append(notmatching, decl); + append(notmatching, decl)!; }; }; get_init_funcs(&matching, ¬matching); @@ -232,14 +232,14 @@ fn doc(name: str, cmd: *getopt::command) (void | error) = { match (err) { case let err: lex::syntax => const msg = strings::dup(err.1); - append(parse_errs, (err.0, msg)); + append(parse_errs, (err.0, msg))!; continue; case => return err; }; }; defer free(d); - append(decls, d...); + append(decls, d...)!; }; const rpath = match (path::init(modpath, "README")) { @@ -328,7 +328,7 @@ fn parseident(in: str) ((ast::ident, bool) | void) = { lex::unlex(&lexer, tok); return; }; - append(ident, name); + append(ident, name)!; z += len(name); const tok = lex::lex(&lexer)!; switch (tok.0) { @@ -494,7 +494,7 @@ fn get_init_funcs(matching: *[]ast::decl, notmatching: *[]ast::decl) void = { }; if (is_init_type(ident, _type)) { - append(matching, notmatching[i]); + append(matching, notmatching[i])!; delete(notmatching[i]); i -= 1; }; diff --git a/cmd/haredoc/util.ha b/cmd/haredoc/util.ha @@ -27,7 +27,7 @@ fn merge_tags(current: *[]str, new: str) (void | module::error) = { }; }; if (newtag.include) { - append(current, newtag.name); + append(current, newtag.name)!; }; }; }; @@ -48,6 +48,6 @@ fn default_tags() []str = { let arch = os::arch_name(os::architecture()); static let platform: [7]u8 = [0...]; let platform = ascii::strlower_buf(os::sysname(), platform[..0]); - let tags: []str = alloc([arch, platform]); + let tags: []str = alloc([arch, platform])!; return tags; }; diff --git a/crypto/+test/authenc_test.ha b/crypto/+test/authenc_test.ha @@ -190,7 +190,7 @@ const polyaligned: sample = sample { }; @test fn rfc() void = { - let result: []u8 = alloc(rfcsample.msg...); + let result: []u8 = alloc(rfcsample.msg...)!; defer free(result); let b = encrypt(&rfcsample.key, &rfcsample.nonce, result[..], @@ -207,7 +207,7 @@ const polyaligned: sample = sample { }; @test fn rfcmultiadditonals() void = { - let result: []u8 = alloc(rfcsample.msg...); + let result: []u8 = alloc(rfcsample.msg...)!; defer free(result); let b = encrypt(&rfcsample.key, &rfcsample.nonce, result[..], @@ -224,7 +224,7 @@ const polyaligned: sample = sample { }; @test fn noadditional() void = { - let result: []u8 = alloc(noadsample.msg...); + let result: []u8 = alloc(noadsample.msg...)!; defer free(result); let b = encrypt(&noadsample.key, &noadsample.nonce, result[..]); @@ -272,7 +272,7 @@ const polyaligned: sample = sample { }; @test fn polyaligned() void = { - let result: []u8 = alloc(polyaligned.msg...); + let result: []u8 = alloc(polyaligned.msg...)!; defer free(result); let b = encrypt(&polyaligned.key, &polyaligned.nonce, result[..], @@ -295,7 +295,7 @@ const polyaligned: sample = sample { let key = rfcsample.key; key[0] = 0x00; - let cipher: []u8 = alloc(rfcsample.cipher...); + let cipher: []u8 = alloc(rfcsample.cipher...)!; defer free(cipher); let b: box = (rfcsample.mac, rfcsample.nonce, cipher[..]); @@ -309,7 +309,7 @@ const polyaligned: sample = sample { @test fn invalidcipher() void = { const zero: [114]u8 = [0...]; - let cipher: []u8 = alloc(rfcsample.cipher...); + let cipher: []u8 = alloc(rfcsample.cipher...)!; defer free(cipher); cipher[0] = 0x00; @@ -323,9 +323,9 @@ const polyaligned: sample = sample { @test fn invalidcipher2() void = { - let cipher: []u8 = alloc(rfcsample.cipher...); + let cipher: []u8 = alloc(rfcsample.cipher...)!; defer free(cipher); - append(cipher, 0xff); + append(cipher, 0xff)!; let b: box = (rfcsample.mac, rfcsample.nonce, cipher[..]); @@ -338,7 +338,7 @@ const polyaligned: sample = sample { }; @test fn invalidcipher3() void = { - let cipher: []u8 = alloc(rfcsample.cipher...); + let cipher: []u8 = alloc(rfcsample.cipher...)!; defer free(cipher); delete(cipher[len(cipher) - 1]); @@ -355,10 +355,10 @@ const polyaligned: sample = sample { @test fn invalidaddition() void = { const zero: [114]u8 = [0...]; - let cipher: []u8 = alloc(rfcsample.cipher...); + let cipher: []u8 = alloc(rfcsample.cipher...)!; defer free(cipher); - let ad: []u8 = alloc(rfcsample.additional...); + let ad: []u8 = alloc(rfcsample.additional...)!; defer free(ad); ad[0] = 0x00; @@ -373,12 +373,12 @@ const polyaligned: sample = sample { @test fn invalidaddition2() void = { const zero: [114]u8 = [0...]; - let cipher: []u8 = alloc(rfcsample.cipher...); + let cipher: []u8 = alloc(rfcsample.cipher...)!; defer free(cipher); - let ad: []u8 = alloc(rfcsample.additional...); + let ad: []u8 = alloc(rfcsample.additional...)!; defer free(ad); - append(ad, 0xff); + append(ad, 0xff)!; let b: box = (rfcsample.mac, rfcsample.nonce, cipher[..]); @@ -391,10 +391,10 @@ const polyaligned: sample = sample { @test fn invalidaddition3() void = { const zero: [114]u8 = [0...]; - let cipher: []u8 = alloc(rfcsample.cipher...); + let cipher: []u8 = alloc(rfcsample.cipher...)!; defer free(cipher); - let ad: []u8 = alloc(rfcsample.additional...); + let ad: []u8 = alloc(rfcsample.additional...)!; defer free(ad); delete(ad[len(ad) - 1]); @@ -409,7 +409,7 @@ const polyaligned: sample = sample { @test fn invalidaddition4() void = { const zero: [114]u8 = [0...]; - let cipher: []u8 = alloc(rfcsample.cipher...); + let cipher: []u8 = alloc(rfcsample.cipher...)!; defer free(cipher); let b: box = (rfcsample.mac, rfcsample.nonce, cipher[..]); @@ -423,7 +423,7 @@ const polyaligned: sample = sample { @test fn invalidaddition5() void = { const zero: [114]u8 = [0...]; - let cipher: []u8 = alloc(rfcsample.cipher...); + let cipher: []u8 = alloc(rfcsample.cipher...)!; defer free(cipher); let b: box = (rfcsample.mac, rfcsample.nonce, cipher[..]); @@ -435,7 +435,7 @@ const polyaligned: sample = sample { }; @test fn cipheradditionswap() void = { - let additional: []u8 = alloc(rfcsample.additional...); + let additional: []u8 = alloc(rfcsample.additional...)!; defer free(additional); let b: box = (rfcsample.mac, rfcsample.nonce, additional); @@ -451,7 +451,7 @@ const polyaligned: sample = sample { @test fn invalidmac() void = { const zero: [114]u8 = [0...]; - let cipher: []u8 = alloc(rfcsample.cipher...); + let cipher: []u8 = alloc(rfcsample.cipher...)!; defer free(cipher); let mac: mac = rfcsample.mac; diff --git a/crypto/aes/+test/gcm.ha b/crypto/aes/+test/gcm.ha @@ -606,7 +606,7 @@ const gcmtestcases: []gcmtestcase = [ let result: []u8 = if (len(t.cipher) == 0) { yield []; } else { - yield alloc([0...], len(t.cipher)); + yield alloc([0...], len(t.cipher))!; }; defer free(result); let resultbuf = memio::fixed(result); @@ -634,7 +634,7 @@ const gcmtestcases: []gcmtestcase = [ let result: []u8 = if (len(t.cipher) == 0) { yield []; } else { - yield alloc([0...], len(t.cipher)); + yield alloc([0...], len(t.cipher))!; }; defer free(result); let cipherbuf = memio::fixed(t.cipher); @@ -668,7 +668,7 @@ const gcmtestcases: []gcmtestcase = [ let result: []u8 = if (len(t.plain) == 0) { yield []; } else { - let r: []u8 = alloc([0...], len(t.plain)); + let r: []u8 = alloc([0...], len(t.plain))!; r[..] = t.plain[..]; yield r; }; diff --git a/crypto/argon2/+test.ha b/crypto/argon2/+test.ha @@ -42,7 +42,7 @@ use test; let data: [12]u8 = [4...]; let result: [32]u8 = [0...]; - let mem: []u64 = alloc([0...], 32z * BLOCKSZ); + let mem: []u64 = alloc([0...], 32z * BLOCKSZ)!; defer free(mem); let expected: [_]u8 = [ @@ -75,7 +75,7 @@ use test; let data: [12]u8 = [4...]; let result: [32]u8 = [0...]; - let mem: []u64 = alloc([0...], 32z * BLOCKSZ); + let mem: []u64 = alloc([0...], 32z * BLOCKSZ)!; defer free(mem); let expected: [_]u8 = [ @@ -107,7 +107,7 @@ use test; let data: [12]u8 = [4...]; let result: [32]u8 = [0...]; - let mem: []u64 = alloc([0...], 32z * BLOCKSZ); + let mem: []u64 = alloc([0...], 32z * BLOCKSZ)!; defer free(mem); let expected: [_]u8 = [ @@ -226,7 +226,7 @@ type tcase = struct { const t = tests[i]; const expected = hex::decodestr(t.h)!; defer free(expected); - let dest: []u8 = alloc([0...], len(expected)); + let dest: []u8 = alloc([0...], len(expected))!; defer free(dest); argon2(dest, pass, salt, &t.c, t.m)!; @@ -257,7 +257,7 @@ type tcase = struct { const t = tests[i]; const expected = hex::decodestr(t.h)!; defer free(expected); - let dest: []u8 = alloc([0...], len(expected)); + let dest: []u8 = alloc([0...], len(expected))!; defer free(dest); argon2(dest, pass, salt, &t.c, t.m)!; diff --git a/crypto/argon2/argon2.ha b/crypto/argon2/argon2.ha @@ -5,7 +5,6 @@ use bytes; use crypto::blake2b; use crypto::math; use endian; -use errors::{nomem}; use hash; use io; use memio; @@ -180,7 +179,7 @@ fn argon2( initmemsize = memsize; const memsize = memsize - memsize % (4 * cfg.parallel); - yield alloc([0...], memsize * BLOCKSZ): []u64; + yield alloc([0...], memsize * BLOCKSZ)!: []u64; }; let h0: [64]u8 = [0...]; diff --git a/crypto/bigint/+test/encoding_test.ha b/crypto/bigint/+test/encoding_test.ha @@ -24,7 +24,7 @@ use bytes; ]; let result: [25]u8 = [0...]; - let buf: []word = alloc([0...], encodelen(decoded)); + let buf: []word = alloc([0...], encodelen(decoded))!; defer free(buf); encode(buf, decoded); @@ -52,7 +52,7 @@ use bytes; let mod = fromhex("00190000"); defer free(mod); - let resultbuf: []word = alloc([0...], encodelen(input)); + let resultbuf: []word = alloc([0...], encodelen(input))!; defer free(resultbuf); let result: [4]u8 = [0...]; @@ -79,7 +79,7 @@ use bytes; let mod = fromhex("190000"); defer free(mod); - let resultbuf: []word = alloc([0...], encodelen(input)); + let resultbuf: []word = alloc([0...], encodelen(input))!; defer free(resultbuf); let result: [4]u8 = [0...]; @@ -88,14 +88,14 @@ use bytes; assert(bytes::equal(result, input)); const input: [4]u8 = [0, 0x19, 0, 0]; - let resultbuf: []word = alloc([0...], encodelen(input)); + let resultbuf: []word = alloc([0...], encodelen(input))!; defer free(resultbuf); encodereduce(resultbuf, input, mod); decode(result, resultbuf); assert(iszero(resultbuf) == 1); const input: [4]u8 = [0x24, 0x17, 0x01, 0x05]; - let resultbuf: []word = alloc([0...], encodelen(input)); + let resultbuf: []word = alloc([0...], encodelen(input))!; defer free(resultbuf); encodereduce(resultbuf, input, mod); decode(result, resultbuf); diff --git a/crypto/bigint/+test/utils.ha b/crypto/bigint/+test/utils.ha @@ -8,7 +8,7 @@ export fn fromhex(h: str) []word = { let n: []u8 = hex::decodestr(h)!; defer free(n); - let i: []word = alloc([0...], encodelen(n)); + let i: []word = alloc([0...], encodelen(n))!; encode(i, n); return i; }; @@ -22,7 +22,7 @@ export fn fromhexmod(h: str, m: []word) []word = { // The caller must free the result. export fn tohex(x: []word) str = { - let buf: []u8 = alloc([0...], (len(x) - 1) * size(word)); + let buf: []u8 = alloc([0...], (len(x) - 1) * size(word))!; defer free(buf); decode(buf, x); diff --git a/crypto/blake2b/+test.ha b/crypto/blake2b/+test.ha @@ -20,10 +20,10 @@ use strings; let blake = blake2b(key, len(out)); defer hash::close(&blake); hash::write(&blake, in); - let sum: []u8 = alloc([], len(out)); + let sum: []u8 = alloc([], len(out))!; defer free(sum); for (let i = 0z; i < len(out); i += 1) { - append(sum, 0); + append(sum, 0)!; }; hash::sum(&blake, sum); let out = memio::dynamic(); diff --git a/crypto/ec/curves+test.ha b/crypto/ec/curves+test.ha @@ -31,7 +31,7 @@ fn tmuladd(c: *curve, tcs: []multc) void = { let m1: [P256_SCALARSZ]u8 = [0...]; m1[len(m1) - 1] = 1; - let g = alloc(P256_G); + let g = alloc(P256_G)!; defer free(g); assert(c.mul(g, m1) == 1); assert(bytes::equal(g, P256_G)); @@ -40,7 +40,7 @@ fn tmuladd(c: *curve, tcs: []multc) void = { assert(bytes::equal(g, P256_G)); // multiply by order - 1 - let o = alloc(P256_N); + let o = alloc(P256_N)!; defer free(o); o[len(o) - 1] -= 1; @@ -57,7 +57,7 @@ fn tmuladd(c: *curve, tcs: []multc) void = { assert(c.mul(g, o) == 1); assert(bytes::equal(g, expected)); - let g = alloc(P256_G); + let g = alloc(P256_G)!; defer free(g); assert(c.mulgen(g, o) == 65); assert(bytes::equal(g, expected)); @@ -77,7 +77,7 @@ fn tmuladd(c: *curve, tcs: []multc) void = { 0x43, 0x37, 0x13, 0xdf, 0xc9, ]; - let g = alloc(P256_G); + let g = alloc(P256_G)!; defer free(g); assert(c.mul(g, priv) == 1); assert(bytes::equal(g, expected)); @@ -306,7 +306,7 @@ fn tmuladd(c: *curve, tcs: []multc) void = { let m1: [P384_SCALARSZ]u8 = [0...]; m1[len(m1) - 1] = 1; - let g = alloc(P384_G); + let g = alloc(P384_G)!; defer free(g); assert(c.mul(g, m1) == 1); assert(bytes::equal(g, P384_G)); @@ -315,7 +315,7 @@ fn tmuladd(c: *curve, tcs: []multc) void = { assert(bytes::equal(g, P384_G)); // multiply by order - 1 - let o = alloc(P384_N); + let o = alloc(P384_N)!; defer free(o); o[len(o) - 1] -= 1; @@ -335,7 +335,7 @@ fn tmuladd(c: *curve, tcs: []multc) void = { assert(c.mul(g, o) == 1); assert(bytes::equal(g, expected)); - let g = alloc(P384_G); + let g = alloc(P384_G)!; defer free(g); assert(c.mulgen(g, o) == 97); assert(bytes::equal(g, expected)); @@ -361,7 +361,7 @@ fn tmuladd(c: *curve, tcs: []multc) void = { 0xcf, 0x6b, 0x62, 0xfd, 0xe5, 0x4b, 0xcc, ]; - let g = alloc(P384_G); + let g = alloc(P384_G)!; defer free(g); assert(c.mul(g, priv) == 1); assert(bytes::equal(g, expected)); @@ -652,7 +652,7 @@ fn tmuladd(c: *curve, tcs: []multc) void = { let m1: [P521_SCALARSZ]u8 = [0...]; m1[len(m1) - 1] = 1; - let g = alloc(P521_G); + let g = alloc(P521_G)!; defer free(g); assert(c.mul(g, m1) == 1); assert(bytes::equal(g, P521_G)); @@ -661,7 +661,7 @@ fn tmuladd(c: *curve, tcs: []multc) void = { assert(bytes::equal(g, P521_G)); // multiply by order - 1 - let o = alloc(P521_N); + let o = alloc(P521_N)!; defer free(o); o[len(o) - 1] -= 1; @@ -685,7 +685,7 @@ fn tmuladd(c: *curve, tcs: []multc) void = { assert(c.mul(g, o) == 1); assert(bytes::equal(g, expected)); - let g = alloc(P521_G); + let g = alloc(P521_G)!; defer free(g); assert(c.mulgen(g, o) == 133); assert(bytes::equal(g, expected)); @@ -717,7 +717,7 @@ fn tmuladd(c: *curve, tcs: []multc) void = { 0xb2, 0xb1, 0x62, ]; - let g = alloc(P521_G); + let g = alloc(P521_G)!; defer free(g); assert(c.mul(g, priv) == 1); assert(bytes::equal(g, expected)); diff --git a/crypto/ecdsa/rfc6979+test.ha b/crypto/ecdsa/rfc6979+test.ha @@ -327,7 +327,7 @@ fn rfc6979_cases() []testcase = alloc([ k = "016200813020ec986863bedfc1b121f605c1215645018aea1a7b215a564de9eb1b38a67aa1128b80ce391c4fb71187654aaa3431027bfc7f395766ca988c964dc56d", sig = "013e99020abf5cee7525d16b69b229652ab6bdf2affcaef38773b4b7d08725f10cdb93482fdcc54edcee91eca4166b2a7c6265ef0ce2bd7051b7cef945babd47ee6d01fbd0013c674aa79cb39849527916ce301c66ea7ce8b80682786ad60f98f7e78a19ca69eff5c57400e3b3a0ad66ce0978214d13baf4e9ac60752f7b155e2de4dce3", }, -]); +])!; @test fn ecdsa_rfc6979() void = { test::require("slow"); diff --git a/crypto/keyderiv.ha b/crypto/keyderiv.ha @@ -41,7 +41,7 @@ export fn derivekey( password: []u8, mem: (u32 | []u64), passes: u32, -) (void | errors::nomem) = { +) (void | nomem) = { const config = argon2::conf { mem = mem, parallel = 1, diff --git a/crypto/keystore/impl.ha b/crypto/keystore/impl.ha @@ -10,7 +10,7 @@ export type key = []u8; // Creates a new secure key. The caller should clear the secret buffer with // [[bytes::zero]] after initialization. export fn newkey(buf: []u8, name: str) (key | errors::error) = { - return alloc(buf...): []u8: key; + return alloc(buf...)!: []u8: key; }; // Destroys a secure key. diff --git a/crypto/rsa/+test/core_test.ha b/crypto/rsa/+test/core_test.ha @@ -150,7 +150,7 @@ let pkcs1_signbuf: [PKCS1_SIGNBUFSZ]u8 = [0...]; 0x65, 0x5f, 0x28, 0x85, ]; - let xc = alloc(x); + let xc = alloc(x)!; defer free(xc); pubexp(&sign3072.pub, xc, pubbuf)!; diff --git a/crypto/rsa/+test/pkcs1_test.ha b/crypto/rsa/+test/pkcs1_test.ha @@ -252,7 +252,7 @@ fn assertpkcs1( sig: []u8, algo: pkcs1_hashalgo ) void = { - let nsig: []u8 = alloc([0...], len(sig)); + let nsig: []u8 = alloc([0...], len(sig))!; defer free(nsig); let msghash = pkcs1_hash(msg, algo); @@ -290,7 +290,7 @@ fn pkcs1_hash(msg: []u8, algo: pkcs1_hashalgo) []u8 = { abort("unreachable"); }; defer hash::close(h); - let out: []u8 = alloc([0...], hash::sz(h)); + let out: []u8 = alloc([0...], hash::sz(h))!; io::writeall(h, msg)!; hash::sum(h, out); diff --git a/debug/backtrace.ha b/debug/backtrace.ha @@ -132,7 +132,7 @@ fn printframe( return; }; }; - static append(seen, pc); + static append(seen, pc)!; fmt::errorln(): void; if (imgstat.mask & fs::stat_mask::MTIME != 0) { diff --git a/debug/dwarf/abbrev.ha b/debug/dwarf/abbrev.ha @@ -50,7 +50,7 @@ export fn load_abbrevs( case io::EOF => break; case io::error => return errors::invalid; case let ab: abbrev => - append(abbrevs, ab); + append(abbrevs, ab)!; }; }; @@ -80,7 +80,7 @@ fn read_abbrev( append(fields, afield { attr = name: u32, form = form: u32, - }); + })!; }; return abbrev { diff --git a/debug/dwarf/info.ha b/debug/dwarf/info.ha @@ -32,12 +32,12 @@ export fn read_debug_info( return; }; - const memrd = alloc(image::section_reader(image, sec)); + const memrd = alloc(image::section_reader(image, sec))!; io::seek(memrd, offs: io::off, io::whence::SET)?; const rd = match (new_table_reader(memrd, true)?) { case let rd: table_reader => - yield alloc(rd); + yield alloc(rd)!; case io::EOF => return; }; @@ -195,7 +195,7 @@ fn read_die( case => return errors::unsupported; }; - append(fields, field); + append(fields, field)!; }; return entry { diff --git a/debug/dwarf/line.ha b/debug/dwarf/line.ha @@ -77,9 +77,9 @@ export fn exec_line_program( case null => return; }; - const memrd = alloc(image::section_reader(image, sec)); + const memrd = alloc(image::section_reader(image, sec))!; io::seek(memrd, offs: io::off, io::whence::SET)?; - const rd = alloc(new_table_reader(memrd, true)? as table_reader); + const rd = alloc(new_table_reader(memrd, true)? as table_reader)!; // Read program header const ver = read_uhalf(rd)!; @@ -98,7 +98,7 @@ export fn exec_line_program( // Opcode lengths for (let i = 0u8; i < head.opcode_base - 1; i += 1) { const op = read_ubyte(rd)?; - append(head.opcode_lengths, op); + append(head.opcode_lengths, op)!; }; // Directories @@ -107,7 +107,7 @@ export fn exec_line_program( if (len(dir) == 0) { break; }; - append(head.dirs, dir); + append(head.dirs, dir)!; }; // Files @@ -124,7 +124,7 @@ export fn exec_line_program( dir = dir, mtime = mtime, length = length, - }); + })!; }; let prog = line_program { @@ -208,7 +208,7 @@ export fn line_step( dir = dir, mtime = mtime, length = length, - }); + })!; state.file = len(prog.head.files): uint; case DW_LNE_set_discriminator => state.discriminator = read_uleb128(prog.rd)?: uint; diff --git a/debug/ident.ha b/debug/ident.ha @@ -13,10 +13,10 @@ export fn symname_to_ident(name: str) const str = { const iter = strings::iter(name); for (const rn => strings::next(&iter)) { if (rn == '.') { - static append(slice, ':'); - static append(slice, ':'); + static append(slice, ':')!; + static append(slice, ':')!; } else { - static append(slice, utf8::encoderune(rn)...); + static append(slice, utf8::encoderune(rn)...)!; }; }; diff --git a/debug/traces.ha b/debug/traces.ha @@ -36,7 +36,7 @@ export fn trace_store(frame: stackframe) u64 = { const hash = fnv::fnv64a(); for (true) { hash::write(&hash, &frame_pc(frame): *[size(uintptr)]u8); - append(pc, frame_pc(frame)); + append(pc, frame_pc(frame))!; match (next(frame)) { case let next: stackframe => @@ -53,7 +53,7 @@ export fn trace_store(frame: stackframe) u64 = { }; }; - let frames: []stackframe = alloc([stackframe { ... }...], len(pc) + 1); + let frames: []stackframe = alloc([stackframe { ... }...], len(pc) + 1)!; for (let i = 0z; i < len(pc); i += 1) { frames[i] = mkframe(&frames[i + 1], pc[i]); }; @@ -61,7 +61,7 @@ export fn trace_store(frame: stackframe) u64 = { append(bucket, trace { id = id, frames = &frames[0], - }); + })!; return id; }; diff --git a/encoding/asn1/+test/decoder_test.ha b/encoding/asn1/+test/decoder_test.ha @@ -18,7 +18,7 @@ fn d(i: []u8) decoder = { let buf = memio::fixed(i); let h = match (mem) { case null => - let h = alloc(buf); + let h = alloc(buf)!; mem = h; yield h; case let m: *memio::stream => diff --git a/encoding/asn1/strings.ha b/encoding/asn1/strings.ha @@ -249,7 +249,7 @@ fn t61_decoder(s: *utf8stream, buf: []u8) (size | io::EOF | io::error) = { match (dataread(s.d, chr)?) { case let sz: size => assert(sz == 1); - static append(in, chr[0]); + static append(in, chr[0])!; case io::EOF => if (len(in) > 0) return wrap_err(invalid); if (n > 0) return n; diff --git a/encoding/base64/base64.ha b/encoding/base64/base64.ha @@ -403,7 +403,7 @@ export fn decodeslice( }; let ins = memio::fixed(in); let decoder = newdecoder(enc, &ins); - let out = alloc([0u8...], decodedsize(len(in))); + let out = alloc([0u8...], decodedsize(len(in)))!; let outs = memio::fixed(out); match (io::copy(&outs, &decoder)) { case io::error => @@ -474,7 +474,7 @@ export fn decode( for (true) match (io::read(&decoder, buf)!) { case let z: size => if (z > 0) { - append(decb, buf[..z]...); + append(decb, buf[..z]...)!; }; case io::EOF => break; diff --git a/errors/common.ha b/errors/common.ha @@ -31,9 +31,6 @@ export type cancelled = !void; // A connection attempt was refused. export type refused = !void; -// Unable to allocate sufficient memory for the requested operation. -export type nomem = !void; - // An operation was interrupted. export type interrupted = !void; @@ -55,7 +52,6 @@ export type error = !( timeout | cancelled | refused | - nomem | interrupted | again | netunreachable | diff --git a/errors/string.ha b/errors/string.ha @@ -32,8 +32,6 @@ case cancelled => yield "The requested operation was cancelled"; case refused => yield "A connection attempt was refused"; -case nomem => - yield "Unable to allocate sufficient memory for the requested operation"; case interrupted => yield "Operation interrupted"; case again => diff --git a/fs/util.ha b/fs/util.ha @@ -89,7 +89,7 @@ export fn readdir(fs: *fs, path: str) ([]dirent | error) = { let ents: []dirent = []; for (let d => next(i)?) { - append(ents, dirent_dup(&d)); + append(ents, dirent_dup(&d))!; }; return ents; }; diff --git a/getopt/getopts.ha b/getopt/getopts.ha @@ -120,7 +120,7 @@ export fn tryparse(args: []str, help: help...) (command | error) = { for (let j = 0z; j < len(help); j += 1) match (help[j]) { case let f: flag_help => if (r == f.0) { - append(opts, (r, "")); + append(opts, (r, ""))!; found = true; break; }; @@ -133,9 +133,9 @@ export fn tryparse(args: []str, help: help...) (command | error) = { return (args[0], help, r: requires_arg): error; }; i += 1; - append(opts, (r, args[i])); + append(opts, (r, args[i]))!; } else { - append(opts, (r, value)); + append(opts, (r, value))!; }; continue :arg; }; @@ -159,7 +159,7 @@ export fn tryparse(args: []str, help: help...) (command | error) = { expects_subcmd = true; if (s.0 == args[i]) match (tryparse(args[i..], s.1...)) { case let c: command => - subcmd = (s.0, alloc(c)); + subcmd = (s.0, alloc(c)!); case let e: error => free(opts); return e; diff --git a/glob/glob.ha b/glob/glob.ha @@ -303,7 +303,7 @@ fn strstack_size(ss: *strstack) size = ss.bufc; fn strstack_push(ss: *strstack) *memio::stream = { if (ss.bufc == len(ss.bufv)) { - append(ss.bufv, memio::dynamic()); + append(ss.bufv, memio::dynamic())!; }; let b = &ss.bufv[ss.bufc]; memio::reset(b); diff --git a/hare/ast/expr.ha b/hare/ast/expr.ha @@ -241,7 +241,7 @@ export type tuple_literal = []*expr; export type _null = void; // A scalar value. -export type value = (bool | done | _null | str | rune | void); +export type value = (bool | done | nomem |_null | str | rune | void); // An integer or float literal. export type number_literal = struct { diff --git a/hare/ast/type.ha b/hare/ast/type.ha @@ -12,8 +12,8 @@ export type alias_type = struct { // A built-in primitive type (int, bool, str, etc). export type builtin_type = enum { BOOL, DONE, F32, F64, FCONST, I16, I32, I64, I8, ICONST, INT, NEVER, - NULL, OPAQUE, RCONST, RUNE, SIZE, STR, U16, U32, U64, U8, UINT, UINTPTR, - VALIST, VOID, + NOMEM, NULL, OPAQUE, RCONST, RUNE, SIZE, STR, U16, U32, U64, U8, UINT, + UINTPTR, VALIST, VOID }; // An enumeration field (and optional value). diff --git a/hare/lex/+test.ha b/hare/lex/+test.ha @@ -457,9 +457,9 @@ type op = enum { for (let i = 0z; i < len(ops); i += 1) { switch (ops[i]) { case op::LEX => - append(t, lex(&lexer)!); + append(t, lex(&lexer)!)!; case op::NEXT => - append(r, next(&lexer) as (rune, location)); + append(r, next(&lexer) as (rune, location))!; case op::UNGET => unget(&lexer, r[len(r) - 1].0); delete(r[len(r) - 1]); diff --git a/hare/lex/lex.ha b/hare/lex/lex.ha @@ -390,7 +390,7 @@ fn lex_comment(lexr: *lexer) (void | error) = { }; }; let bytes = strings::toutf8(lexr.comment); - append(bytes, strings::toutf8(memio::string(&buf)!)...); + append(bytes, strings::toutf8(memio::string(&buf)!)...)!; lexr.comment = strings::fromutf8(bytes)!; }; @@ -407,7 +407,7 @@ fn lex_literal(lex: *lexer) (token | error) = { let started = false; let base = strconv::base::DEC; if (r.0 == '0') { - append(chars, utf8::encoderune(r.0)...); + append(chars, utf8::encoderune(r.0)...)!; r = match (next(lex)?) { case io::EOF => return (ltok::LIT_ICONST, 0u64, loc); @@ -487,7 +487,7 @@ fn lex_literal(lex: *lexer) (token | error) = { }; unget(lex, r.0); float = true; - append(chars, utf8::encoderune('.')...); + append(chars, utf8::encoderune('.')...)!; }; case 'e', 'E', 'p', 'P' => if (!started) { @@ -504,7 +504,7 @@ fn lex_literal(lex: *lexer) (token | error) = { break; } else { if (end == 0) end = len(chars); - append(chars, utf8::encoderune(r.0)...); + append(chars, utf8::encoderune(r.0)...)!; exp = len(chars); r = match (next(lex)?) { case io::EOF => @@ -514,7 +514,7 @@ fn lex_literal(lex: *lexer) (token | error) = { }; switch (r.0) { case '+', '-' => - append(chars, utf8::encoderune(r.0)...); + append(chars, utf8::encoderune(r.0)...)!; case => unget(lex, r.0); }; @@ -533,7 +533,7 @@ fn lex_literal(lex: *lexer) (token | error) = { } else { suff = len(chars); if (end == 0) end = len(chars); - append(chars, utf8::encoderune(r.0)...); + append(chars, utf8::encoderune(r.0)...)!; basechrs = "0123456789"; }; case '_' => @@ -556,7 +556,7 @@ fn lex_literal(lex: *lexer) (token | error) = { }; } else { last_rune_was_separator = false; - append(chars, utf8::encoderune(r.0)...); + append(chars, utf8::encoderune(r.0)...)!; }; started = true; }; diff --git a/hare/lex/token.ha b/hare/lex/token.ha @@ -50,6 +50,7 @@ export type ltok = enum uint { LET, MATCH, NEVER, + NOMEM, NULL, NULLABLE, OFFSET, @@ -202,6 +203,7 @@ const bmap: [_]str = [ "let", "match", "never", + "nomem", "null", "nullable", "offset", diff --git a/hare/module/deps.ha b/hare/module/deps.ha @@ -50,7 +50,7 @@ export fn parse_deps(files: str...) ([]ast::ident | error) = { let id = import.ident; let idx = sort::rbisect(deps, size(ast::ident), &id, &idcmp); if (idx == 0 || idcmp(&deps[idx - 1], &id) != 0) { - insert(deps[idx], ast::ident_dup(id)); + insert(deps[idx], ast::ident_dup(id))!; }; }; }; @@ -102,7 +102,7 @@ fn get_deps(cachedir: str, srcs: *srcset) ([]ast::ident | error) = { } else { let in = bufio::newscanner_static(depsfile, buf.buf); for (let s => bufio::scan_line(&in)?) { - append(deps, parse::identstr(s)?); + append(deps, parse::identstr(s)?)!; }; }; return deps; @@ -148,7 +148,7 @@ export fn gather_submodules( case let b: *path::buffer => yield b; case let m: ast::ident => - append(id, m...); + append(id, m...)!; static let b = path::buffer { ... }; let res = find(ctx, id)?; defer finish_srcset(&res.1); @@ -190,7 +190,7 @@ export fn _gather_submodules( defer free(stack); path::push(buf, dir.name)?; defer path::pop(buf); - append(mod, dir.name); + append(mod, dir.name)!; defer delete(mod[len(mod) - 1]); match (_gather(ctx, out, &stack, *mod, false, recursive)) { case size => @@ -227,7 +227,7 @@ fn _gather( for (let j = 0z; j < len(stack); j += 1) { if (modpath == stack[j]) { - append(stack, modpath); + append(stack, modpath)!; return strings::dupall(stack[j..]): dep_cycle; }; }; @@ -237,18 +237,18 @@ fn _gather( return j; }; }; - append(stack, modpath); + append(stack, modpath)!; defer delete(stack[len(stack) - 1]); let cache = get_cache(ctx.harecache, modpath)?; let depids = get_deps(cache, &srcs)?; defer free(depids); - let deps: [](size, ast::ident) = alloc([], len(depids)); + let deps: [](size, ast::ident) = alloc([], len(depids))!; if (!is_dep || recursive) { for (let depid .. depids) { static append(deps, (_gather(ctx, out, stack, depid, - true, recursive)?, depid)); + true, recursive)?, depid))!; }; }; @@ -269,7 +269,7 @@ fn _gather( srcs = srcs, deps = deps, is_dep = is_dep, - }); + })!; return len(out) - 1; }; diff --git a/hare/module/srcs.ha b/hare/module/srcs.ha @@ -109,7 +109,7 @@ fn path_find(ctx: *context, buf: *path::buffer) (srcset | error) = { _findsrcs(buf, ctx.tags, &srcs, &res, 0)?; for (let i = 0z; i < len(srcs); i += 1) { if (len(srcs[i].3) != 1) { - return alloc(srcs[i].3...): file_conflict; + return alloc(srcs[i].3...)!: file_conflict; }; let out = switch (srcs[i].1) { case "ha" => @@ -122,7 +122,7 @@ fn path_find(ctx: *context, buf: *path::buffer) (srcset | error) = { yield &res.sc; case => abort(); }; - append(out, srcs[i].3[0]); + append(out, srcs[i].3[0])!; }; // module needs either a hare source file or a README in order to be @@ -249,7 +249,7 @@ fn _findsrcs( strings::freeall(srcs[i].3); srcs[i].3 = []; }; - append(srcs[i].3, strings::dup(bufstr)); + append(srcs[i].3, strings::dup(bufstr))!; return; }; }; @@ -258,14 +258,14 @@ fn _findsrcs( strings::dup(base), strings::dup(ext), ntags, - alloc([strings::dup(bufstr)]), - )); + alloc([strings::dup(bufstr)])!, + ))!; return; }; if (!fs::isdir(stat.mode)) return; // ignore special files - append(res.dirs, strings::dup(pathstr)); + append(res.dirs, strings::dup(pathstr))!; if (time::compare(res.mtime, stat.mtime) < 0) { res.mtime = stat.mtime; }; @@ -328,7 +328,7 @@ export fn parse_tags(s: str) ([]tag | error) = { append(tags, tag { name = strings::fromutf8_unsafe(bs[start+1..end]), include = bs[start] == '+', - }); + })!; start = end; }; return tags; diff --git a/hare/module/types.ha b/hare/module/types.ha @@ -70,7 +70,7 @@ export fn locstr(loc: location) str = { // XXX: this shouldn't be necessary, the language should have some built-in way // to carry context with errors -fn attach(ctx: str, e: error) errcontext = (ctx, alloc(e)): errcontext; +fn attach(ctx: str, e: error) errcontext = (ctx, alloc(e)!): errcontext; // Returns the original [[error]] that might be hidden behind more context. export fn unwrap_error(err: error) error = { diff --git a/hare/module/util.ha b/hare/module/util.ha @@ -16,7 +16,7 @@ fn insert_uniq(into: *[]str, s: str) void = { i += 1; }; if (i == len(into) || into[i] != s) { - insert(into[i], strings::dup(s)); + insert(into[i], strings::dup(s))!; }; }; diff --git a/hare/parse/+test/expr_test.ha b/hare/parse/+test/expr_test.ha @@ -50,13 +50,15 @@ @test fn builtin() void = { roundtrip(`export fn main() void = { align(u32); - alloc(1234); - alloc(1234...); - alloc(4321, 1234); - append(x, 10); - append(x, [10]...); - append(x, [10...], 20); - static append(x, 10); + alloc(1234)!; + let x: (*int | nomem) = alloc(1234...); + alloc(4321, 1234)!; + append(x, 10)!; + append(x, [10]...)!; + append(x, [10...], 20)!; + static append(x, 10)!; + let y: (void | nomem) = append(x, 10); + let y: (void | nomem) = static append(x, 10); abort(); abort("surprize"); static abort(); @@ -71,10 +73,11 @@ delete(x.y.z[..]); static delete(x[10]); free(x); - insert(x[0], foo); - insert(x[0], foo...); - insert(x[0], foo, bar); - static insert(x[0], foo); + let x: (void | nomem) = insert(x[0], foo); + let x: (void | nomem) = static insert(x[0], foo); + insert(x[0], foo...)!; + insert(x[0], foo, bar)!; + static insert(x[0], foo)!; len([1, 2, 3, 4]); offset(foo.bar); size(u32); @@ -346,7 +349,7 @@ export fn main() void = { "export fn main() void = -((2 + 2) * 2);\n\n" "export fn main() void = &(1: uint);\n\n" "export fn main() void = **x;\n\n" - "export fn main() void = *alloc(2);\n\n" + "export fn main() void = *alloc(2)!;\n\n" "export fn main() void = &(&x);\n\n" "export fn main() void = &*&*&x;\n\n" "export fn main() void = x: int: uint: u8;\n\n" diff --git a/hare/parse/+test/ident_test.ha b/hare/parse/+test/ident_test.ha @@ -44,12 +44,12 @@ fn ident_test(in: str, expected: ast::ident, extra: ltok...) void = { // identifier exceeds maximum length let buf: [ast::IDENT_MAX / 2 + ast::IDENT_MAX + 3]u8 = [0...]; let buf = buf[..0]; - static append(buf, 'a'); + static append(buf, 'a')!; for (let i = 0z; i < ast::IDENT_MAX / 2; i += 1) { - static append(buf, [':', ':', 'a']...); + static append(buf, [':', ':', 'a']...)!; }; ident_test(strings::fromutf8(buf)!, ["a"...]: [ast::IDENT_MAX / 2 + 1]str); - static append(buf, [':', ':', 'a']...); + static append(buf, [':', ':', 'a']...)!; ident_test(strings::fromutf8(buf)!, []); }; diff --git a/hare/parse/+test/loc.ha b/hare/parse/+test/loc.ha @@ -33,8 +33,8 @@ fn expr_testloc(srcs: str...) void = for (let i = 0z; i < len(srcs); i += 1) { @test fn expr_loc() void = { expr_testloc("foo", "foo[bar]", "foo.bar", "foo.1"); - expr_testloc("alloc(foo)"); - expr_testloc("append(foo, bar)", "append(foo, bar, baz)"); + expr_testloc("alloc(foo)!"); + expr_testloc("append(foo, bar)!", "append(foo, bar, baz)!"); expr_testloc("assert(foo)", `assert(foo, "bar")`, "abort()", `abort("foo")`); expr_testloc("foo is bar", "foo as bar"); @@ -55,7 +55,7 @@ fn expr_testloc(srcs: str...) void = for (let i = 0z; i < len(srcs); i += 1) { "for (let bar = 0; baz; quux) quuux"); expr_testloc("free(foo)"); expr_testloc("if (foo) bar", "if (foo) bar else baz"); - expr_testloc("insert(foo[0], bar)", "insert(foo[0], bar, baz)"); + expr_testloc("insert(foo[0], bar)!", "insert(foo[0], bar, baz)!"); expr_testloc("len(foo)"); expr_testloc("{ foo; bar; }", "{ defer foo; }", "{ let foo: bar = baz; }", "{ let foo: bar = baz, quux = quuux; }", diff --git a/hare/parse/+test/roundtrip.ha b/hare/parse/+test/roundtrip.ha @@ -37,6 +37,7 @@ fn _roundtrip(src: str) str = { case let decls: []ast::decl => yield decls; case let err: error => + fmt::errorln(src)!; fmt::errorln(strerror(err))!; abort(); }, diff --git a/hare/parse/decl.ha b/hare/parse/decl.ha @@ -30,11 +30,11 @@ fn attr_symbol(lexer: *lex::lexer) (str | error) = { export fn define(lexer: *lex::lexer) (ast::decl_const | error) = { const ident = ident(lexer)?; const _type: nullable *ast::_type = match (try(lexer, ltok::COLON)?) { - case lex::token => yield alloc(_type(lexer)?); + case lex::token => yield alloc(_type(lexer)?)!; case void => yield null; }; want(lexer, ltok::EQUAL)?; - const init: *ast::expr = alloc(expr(lexer)?); + const init: *ast::expr = alloc(expr(lexer)?)!; return ast::decl_const { ident = ident, _type = _type, @@ -48,7 +48,7 @@ fn decl_const( ) ([]ast::decl_const | error) = { let decl: []ast::decl_const = []; for (true) { - append(decl, define(lexer)?); + append(decl, define(lexer)?)!; if (try(lexer, ltok::COMMA)? is void) { break; @@ -79,14 +79,14 @@ fn decl_global( const _type: nullable *ast::_type = match (try(lexer, ltok::COLON)?) { case lex::token => - yield alloc(_type(lexer)?); + yield alloc(_type(lexer)?)!; case void => yield null; }; const init: nullable *ast::expr = match (try(lexer, ltok::EQUAL)?) { case lex::token => - yield alloc(expr(lexer)?); + yield alloc(expr(lexer)?)!; case void => yield null; }; @@ -98,7 +98,7 @@ fn decl_global( ident = ident, _type = _type, init = init, - }); + })!; if (btok is void) { break; }; @@ -115,8 +115,8 @@ fn decl_type(lexer: *lex::lexer) ([]ast::decl_type | error) = { let btok = try(lexer, ltok::COMMA)?; append(decl, ast::decl_type { ident = ident, - _type = alloc(_type), - }); + _type = alloc(_type)!, + })!; if (btok is void) { break; }; @@ -165,7 +165,7 @@ fn decl_func(lexer: *lex::lexer) (ast::decl_func | error) = { len(param.name) > 0, "Expected parameter name in function declaration")?; }; - yield alloc(expr(lexer)?); + yield alloc(expr(lexer)?)!; case ltok::SEMICOLON => lex::unlex(lexer, tok); yield null; @@ -180,7 +180,7 @@ fn decl_func(lexer: *lex::lexer) (ast::decl_func | error) = { end = proto_end, flags = 0, repr = prototype, - }), + })!, body = body, attrs = attr, }; @@ -243,7 +243,7 @@ export fn decls(lexer: *lex::lexer) ([]ast::decl | error) = { let decls: []ast::decl = []; for (true) { if (peek(lexer, ltok::EOF)? is lex::token) break; - append(decls, decl(lexer)?); + append(decls, decl(lexer)?)!; }; return decls; }; diff --git a/hare/parse/doc/doc.ha b/hare/parse/doc/doc.ha @@ -78,16 +78,16 @@ fn _parse( switch (r) { case '\t' => loc.col = 8; - append(doc, scan_code_sample(sc, loc)?); + append(doc, scan_code_sample(sc, loc)?)!; case '\n' => loc.line += 1; loc.col = 0; case '-' => loc.col += 1; - append(doc, scan_list(sc, loc)?); + append(doc, scan_list(sc, loc)?)!; case => bufio::unreadrune(sc, r); - append(doc, scan_paragraph(sc, loc)?); + append(doc, scan_paragraph(sc, loc)?)!; }; }; @@ -152,7 +152,7 @@ fn scan_list( for (true) { match (bufio::scan_rune(sc)?) { case io::EOF => - append(li, []); + append(li, [])!; break; case let r: rune => if (r != ' ') { @@ -160,7 +160,7 @@ fn scan_list( }; }; - append(li, scan_paragraph(sc, loc)?); + append(li, scan_paragraph(sc, loc)?)!; match (bufio::scan_rune(sc)?) { case io::EOF => @@ -255,7 +255,7 @@ fn scan_paragraph( loc.col += 1; const part = memio::string(&s)!; if (part != "") { - append(p, strings::dup(part)); + append(p, strings::dup(part))!; memio::reset(&s); }; @@ -282,7 +282,7 @@ fn scan_paragraph( }; loc.line += lexer.loc.0 - 1; - append(p, if (mod) ident: mod_ref else ident: decl_ref); + append(p, if (mod) ident: mod_ref else ident: decl_ref)!; if (lexer.un.0 == lex::ltok::RBRACKET) { match (bufio::scan_rune(sc)?) { @@ -299,7 +299,7 @@ fn scan_paragraph( const part = memio::string(&s)!; if (part != "") { - append(p, strings::dup(part)); + append(p, strings::dup(part))!; }; return p; }; diff --git a/hare/parse/expr.ha b/hare/parse/expr.ha @@ -87,8 +87,8 @@ export fn expr(lexer: *lex::lexer) (ast::expr | error) = { yield ast::binarithm_op::TIMES; case => abort(); // unreachable }, - object = alloc(ex), - value = alloc(expr(lexer)?), + object = alloc(ex)!, + value = alloc(expr(lexer)?)!, }; return ast::expr { @@ -109,7 +109,7 @@ fn assert_expr(lexer: *lex::lexer, is_static: bool) (ast::expr | error) = { case lex::token => yield null; case => - yield alloc(expr(lexer)?); + yield alloc(expr(lexer)?)!; }; want(lexer, ltok::RPAREN)?; @@ -121,11 +121,11 @@ fn assert_expr(lexer: *lex::lexer, is_static: bool) (ast::expr | error) = { case ltok::ASSERT => want(lexer, ltok::LPAREN)?; const cond: nullable *ast::expr = - alloc(expr(lexer)?); + alloc(expr(lexer)?)!; const msg: nullable *ast::expr = match (try(lexer, ltok::COMMA)?) { case lex::token => - yield alloc(expr(lexer)?); + yield alloc(expr(lexer)?)!; case => yield null; }; @@ -150,11 +150,11 @@ fn alloc_expr(lexer: *lex::lexer) (ast::expr | error) = { const start = want(lexer, ltok::ALLOC)?; want(lexer, ltok::LPAREN)?; - const init = alloc(expr(lexer)?); + const init = alloc(expr(lexer)?)!; const expr = switch (want(lexer, ltok::COMMA, ltok::ELLIPSIS, ltok::RPAREN)?.0) { case ltok::COMMA => - const capacity = alloc(expr(lexer)?); + const capacity = alloc(expr(lexer)?)!; want(lexer, ltok::RPAREN)?; yield ast::alloc_expr { init = init, @@ -202,7 +202,7 @@ fn append_insert_expr( case let tok: lex::token => switch (tok.0) { case ltok::COMMA => - length = alloc(expr(lexer)?); + length = alloc(expr(lexer)?)!; case ltok::ELLIPSIS => variadic = true; case => abort(); @@ -212,8 +212,8 @@ fn append_insert_expr( want(lexer, ltok::RPAREN)?; let expr = ast::append_expr { - object = alloc(object), - value = alloc(value), + object = alloc(object)!, + value = alloc(value)!, length = length, variadic = variadic, is_static = is_static, @@ -234,13 +234,13 @@ fn measurement(lexer: *lex::lexer) (ast::expr | error) = { want(lexer, ltok::LPAREN)?; const expr = switch (tok.0) { case ltok::LEN => - yield alloc(expr(lexer)?): ast::len_expr; + yield alloc(expr(lexer)?)!: ast::len_expr; case ltok::ALIGN => - yield alloc(_type(lexer)?): ast::align_expr; + yield alloc(_type(lexer)?)!: ast::align_expr; case ltok::SIZE => - yield alloc(_type(lexer)?): ast::size_expr; + yield alloc(_type(lexer)?)!: ast::size_expr; case ltok::OFFSET => - yield alloc(expr(lexer)?): ast::offset_expr; + yield alloc(expr(lexer)?)!: ast::offset_expr; case => abort(); // unreachable }; want(lexer, ltok::RPAREN)?; @@ -284,8 +284,8 @@ fn binarithm( end = lex::prevloc(lexer), expr = ast::binarithm_expr { op = op, - lvalue = alloc(lvalue), - rvalue = alloc(rvalue), + lvalue = alloc(lvalue)!, + rvalue = alloc(rvalue)!, }, }; lvalue = expr; @@ -301,9 +301,9 @@ fn binding_unpack(lexer: *lex::lexer) (ast::binding_unpack | error) = { const (tok, value, _) = want(lexer, ltok::NAME, ltok::UNDERSCORE)?; if (tok == ltok::UNDERSCORE) { - append(fields, void); + append(fields, void)!; } else { - append(fields, value as str); + append(fields, value as str)!; }; if (len(fields) == 1) { want(lexer, ltok::COMMA)?; @@ -348,15 +348,15 @@ fn binding(lexer: *lex::lexer, is_static: bool) (ast::expr | error) = { }; const btype: nullable *ast::_type = if (try(lexer, ltok::COLON)? is lex::token) { - yield alloc(_type(lexer)?); + yield alloc(_type(lexer)?)!; } else null; want(lexer, ltok::EQUAL)?; - const init = alloc(expr(lexer)?); + const init = alloc(expr(lexer)?)!; append(bindings, ast::binding { name = name, _type = btype, init = init, - }); + })!; match (try(lexer, ltok::COMMA)?) { case void => break; case lex::token => void; @@ -382,7 +382,7 @@ fn builtin(lexer: *lex::lexer) (ast::expr | error) = { case let tok: lex::token => yield tok; case void => - return postfix(lexer, void); + return plain_expression(lexer); }; switch (tok.0) { case ltok::ALLOC => @@ -412,9 +412,9 @@ fn builtin(lexer: *lex::lexer) (ast::expr | error) = { case ltok::VAARG => want(lexer, ltok::VAARG)?; want(lexer, ltok::LPAREN)?; - const ap = alloc(objsel(lexer)?); + const ap = alloc(objsel(lexer)?)!; want(lexer, ltok::COMMA)?; - const _type = alloc(_type(lexer)?); + const _type = alloc(_type(lexer)?)!; want(lexer, ltok::RPAREN)?; return ast::expr { start = tok.2, @@ -427,7 +427,7 @@ fn builtin(lexer: *lex::lexer) (ast::expr | error) = { case ltok::VAEND => want(lexer, ltok::VAEND)?; want(lexer, ltok::LPAREN)?; - const expr = alloc(objsel(lexer)?); + const expr = alloc(objsel(lexer)?)!; want(lexer, ltok::RPAREN)?; return ast::expr { start = tok.2, @@ -448,7 +448,7 @@ fn call(lexer: *lex::lexer, lvalue: ast::expr) (ast::expr | error) = { case void => void; }; - append(args, alloc(expr(lexer)?)); + append(args, alloc(expr(lexer)?)!)!; match (try(lexer, ltok::ELLIPSIS)?) { case lex::token => @@ -468,7 +468,7 @@ fn call(lexer: *lex::lexer, lvalue: ast::expr) (ast::expr | error) = { start = lvalue.start, end = lex::prevloc(lexer), expr = ast::call_expr { - lvalue = alloc(lvalue), + lvalue = alloc(lvalue)!, variadic = variadic, args = args, }, @@ -504,16 +504,16 @@ fn cast(lexer: *lex::lexer, lvalue: (ast::expr | void)) (ast::expr | error) = { end = lex::prevloc(lexer), flags = 0, repr = ast::builtin_type::NULL, - }); + })!; case void => - yield alloc(_type(lexer)?); + yield alloc(_type(lexer)?)!; }; return cast(lexer, ast::expr { start = lvalue.start, end = lex::prevloc(lexer), expr = ast::cast_expr { kind = kind, - value = alloc(lvalue), + value = alloc(lvalue)!, _type = typ, }, })?; @@ -554,6 +554,8 @@ fn literal(lexer: *lex::lexer) (ast::expr | error) = { }; case ltok::VOID => yield void; + case ltok::NOMEM => + yield nomem; case ltok::DONE => yield done; case ltok::TRUE => @@ -592,7 +594,7 @@ fn control(lexer: *lex::lexer) (ast::expr | error) = { ltok::RBRACKET, ltok::RPAREN, ltok::SEMICOLON, ltok::EOF)?) { case void => - yield alloc(expr(lexer)?): ast::return_expr; + yield alloc(expr(lexer)?)!: ast::return_expr; case lex::token => yield null: ast::return_expr; }; @@ -608,7 +610,7 @@ fn control(lexer: *lex::lexer) (ast::expr | error) = { fn delete_expr(lexer: *lex::lexer, is_static: bool) (ast::expr | error) = { const start = want(lexer, ltok::DELETE)?; want(lexer, ltok::LPAREN)?; - const expr = alloc(postfix(lexer, void)?); + const expr = alloc(postfix(lexer, void)?)!; // TODO: Assert that this was an indexing expression want(lexer, ltok::RPAREN)?; return ast::expr { @@ -635,7 +637,7 @@ fn compound_expr(lexer: *lex::lexer) (ast::expr | error) = { }; for (true) { - append(items, alloc(stmt(lexer)?)); + append(items, alloc(stmt(lexer)?)!)!; if (try(lexer, ltok::RBRACE)? is lex::token) { break; }; @@ -657,7 +659,7 @@ fn stmt(lexer: *lex::lexer) (ast::expr | error) = { case let tok: lex::token => yield switch (tok.0) { case ltok::DEFER => - let expr = alloc(expr(lexer)?); + let expr = alloc(expr(lexer)?)!; yield ast::expr { start = tok.2, end = lex::prevloc(lexer), @@ -718,7 +720,7 @@ fn for_expr(lexer: *lex::lexer) (ast::expr | error) = { }; const btype: nullable *ast::_type = if (try(lexer, ltok::COLON)? is lex::token) { - yield alloc(_type(lexer)?); + yield alloc(_type(lexer)?)!; } else null; const (tok, _, _) = want(lexer, ltok::EQUAL, @@ -744,13 +746,13 @@ fn for_expr(lexer: *lex::lexer) (ast::expr | error) = { "Cannot create multiple bindings in non-c-style loop"); }; - const init_expr = alloc(expr(lexer)?); + const init_expr = alloc(expr(lexer)?)!; append(bindings, ast::binding { name = binding_name, _type = btype, init = init_expr, - }); + })!; match (try(lexer, ltok::COMMA)?) { case lex::token => @@ -772,7 +774,7 @@ fn for_expr(lexer: *lex::lexer) (ast::expr | error) = { kind = binding_kind, bindings = bindings, }, - }); + })!; case void => kind = ast::for_kind::ACCUMULATOR; yield null; @@ -782,17 +784,17 @@ fn for_expr(lexer: *lex::lexer) (ast::expr | error) = { const afterthought: nullable *ast::expr = null; if (kind as ast::for_kind == ast::for_kind::ACCUMULATOR) { - cond = alloc(expr(lexer)?); + cond = alloc(expr(lexer)?)!; match (try(lexer, ltok::SEMICOLON)) { case lex::token => - afterthought = alloc(expr(lexer)?); + afterthought = alloc(expr(lexer)?)!; case void => void; }; }; want(lexer, ltok::RPAREN)?; - const body = alloc(expr(lexer)?); + const body = alloc(expr(lexer)?)!; return ast::expr { start = tok.2, end = lex::prevloc(lexer), @@ -810,7 +812,7 @@ fn for_expr(lexer: *lex::lexer) (ast::expr | error) = { fn free_expr(lexer: *lex::lexer) (ast::expr | error) = { const start = want(lexer, ltok::FREE)?; want(lexer, ltok::LPAREN)?; - const expr = alloc(expr(lexer)?); + const expr = alloc(expr(lexer)?)!; want(lexer, ltok::RPAREN)?; return ast::expr { start = start.2, @@ -822,14 +824,14 @@ fn free_expr(lexer: *lex::lexer) (ast::expr | error) = { fn if_expr(lexer: *lex::lexer) (ast::expr | error) = { const start = want(lexer, ltok::IF)?; want(lexer, ltok::LPAREN)?; - const cond = alloc(expr(lexer)?); + const cond = alloc(expr(lexer)?)!; want(lexer, ltok::RPAREN)?; - const tbranch = alloc(expr(lexer)?); + const tbranch = alloc(expr(lexer)?)!; const fbranch: nullable *ast::expr = match (try(lexer, ltok::ELSE)?) { case void => yield null; case lex::token => - yield alloc(expr(lexer)?); + yield alloc(expr(lexer)?)!; }; return ast::expr { start = start.2, @@ -849,13 +851,13 @@ fn indexing(lexer: *lex::lexer, lvalue: ast::expr) (ast::expr | error) = { if (try(lexer, ltok::DOUBLE_DOT)? is lex::token) { is_slice = true; } else { - start = alloc(expr(lexer)?); + start = alloc(expr(lexer)?)!; }; if (!is_slice && try(lexer, ltok::DOUBLE_DOT)? is lex::token) { is_slice = true; }; if (is_slice && peek(lexer, ltok::RBRACKET)? is void) { - end = alloc(expr(lexer)?); + end = alloc(expr(lexer)?)!; }; want(lexer, ltok::RBRACKET)?; @@ -863,11 +865,11 @@ fn indexing(lexer: *lex::lexer, lvalue: ast::expr) (ast::expr | error) = { start = lvalue.start, end = lex::prevloc(lexer), expr = if (is_slice) ast::slice_expr { - object = alloc(lvalue), + object = alloc(lvalue)!, start = start, end = end, } else ast::access_index { - object = alloc(lvalue), + object = alloc(lvalue)!, index = { assert(end == null); yield start as *ast::expr; @@ -953,7 +955,7 @@ fn plain_array(lexer: *lex::lexer) (ast::expr | error) = { case void => void; }; - append(values, alloc(expr(lexer)?)); + append(values, alloc(expr(lexer)?)!)!; match (try(lexer, ltok::COMMA, ltok::ELLIPSIS)?) { case void => @@ -1003,7 +1005,7 @@ fn plain_struct( break; case ltok::NAME, ltok::STRUCT => lex::unlex(lexer, tok); - append(fields, struct_field(lexer)?); + append(fields, struct_field(lexer)?)!; case => abort(); // unreachable }; @@ -1036,36 +1038,36 @@ fn struct_field( case let tok: lex::token => yield tok; case void => - let id: ast::ident = alloc([name]); - return alloc(plain_struct(lexer, id)?); + let id: ast::ident = alloc([name])!; + return alloc(plain_struct(lexer, id)?)!; }; switch (tok.0) { case ltok::COLON => - const _type = alloc(_type(lexer)?); + const _type = alloc(_type(lexer)?)!; want(lexer, ltok::EQUAL)?; - const init = alloc(expr(lexer)?); + const init = alloc(expr(lexer)?)!; return ast::struct_value { name = name, _type = _type, init = init, }; case ltok::DOUBLE_COLON => - let id: ast::ident = alloc([name]); + let id: ast::ident = alloc([name])!; let rest = ident(lexer)?; - append(id, rest...); - return alloc(plain_struct(lexer, id)?); + append(id, rest...)!; + return alloc(plain_struct(lexer, id)?)!; case ltok::EQUAL => return ast::struct_value { name = name, _type = null, - init = alloc(expr(lexer)?), + init = alloc(expr(lexer)?)!, }; case => abort(); // Invariant }; case ltok::STRUCT => lex::unlex(lexer, tok); - return alloc(plain_struct(lexer, [])?); + return alloc(plain_struct(lexer, [])?)!; case => abort(); // Invariant }; }; @@ -1076,10 +1078,10 @@ fn plain_tuple( start: lex::location ) (ast::expr | error) = { let values: []*ast::expr = []; - append(values, alloc(ex)); + append(values, alloc(ex)!)!; for (true) { - append(values, alloc(expr(lexer)?)); + append(values, alloc(expr(lexer)?)!)!; match (try(lexer, ltok::COMMA)?) { case lex::token => @@ -1103,7 +1105,7 @@ fn plain_tuple( fn postfix(lexer: *lex::lexer, lvalue: (ast::expr | void)) (ast::expr | error) = { let lvalue = match (lvalue) { case void => - yield plain_expression(lexer)?; + yield builtin(lexer)?; case let ex: ast::expr => yield ex; }; @@ -1127,13 +1129,13 @@ fn postfix(lexer: *lex::lexer, lvalue: (ast::expr | void)) (ast::expr | error) = yield ast::expr { start = lvalue.start, end = lex::prevloc(lexer), - expr = alloc(lvalue): ast::propagate_expr, + expr = alloc(lvalue)!: ast::propagate_expr, }; case ltok::LNOT => yield ast::expr { start = lvalue.start, end = lex::prevloc(lexer), - expr = alloc(lvalue): ast::error_assert_expr, + expr = alloc(lvalue)!: ast::error_assert_expr, }; case => abort(); }; @@ -1151,7 +1153,7 @@ fn postfix_dot( start = lvalue.start, end = lex::prevloc(lexer), expr = ast::access_field { - object = alloc(lvalue), + object = alloc(lvalue)!, field = tok.1 as str, }, }; @@ -1165,8 +1167,8 @@ fn postfix_dot( start = lvalue.start, end = lex::prevloc(lexer), expr = ast::access_tuple { - object = alloc(lvalue), - value = alloc(lit), + object = alloc(lvalue)!, + value = alloc(lit)!, }, }; }; @@ -1181,7 +1183,8 @@ fn static_expr(lexer: *lex::lexer) (ast::expr | error) = { case ltok::ABORT, ltok::ASSERT => return assert_expr(lexer, true); case ltok::APPEND, ltok::INSERT => - return append_insert_expr(lexer, true); + let expr = append_insert_expr(lexer, true)?; + return postfix(lexer, expr); case ltok::DELETE => return delete_expr(lexer, true); case => abort(); // unreachable @@ -1208,7 +1211,7 @@ fn switch_expr(lexer: *lex::lexer) (ast::expr | error) = { let opts: []*ast::expr = []; if (try(lexer, ltok::ARROW)? is void) for (true) { - append(opts, alloc(expr(lexer)?)); + append(opts, alloc(expr(lexer)?)!)!; switch (want(lexer, ltok::ARROW, ltok::COMMA)?.0) { case ltok::ARROW => break; @@ -1222,7 +1225,7 @@ fn switch_expr(lexer: *lex::lexer) (ast::expr | error) = { let exprs: []*ast::expr = []; for (true) { - append(exprs, alloc(stmt(lexer)?)); + append(exprs, alloc(stmt(lexer)?)!)!; match (peek(lexer, ltok::CASE, ltok::RBRACE)?) { case lex::token => break; @@ -1233,7 +1236,7 @@ fn switch_expr(lexer: *lex::lexer) (ast::expr | error) = { append(cases, ast::switch_case { options = opts, exprs = exprs, - }); + })!; if (try(lexer, ltok::RBRACE)? is lex::token) { break; @@ -1244,7 +1247,7 @@ fn switch_expr(lexer: *lex::lexer) (ast::expr | error) = { start = start.2, end = lex::prevloc(lexer), expr = ast::switch_expr { - value = alloc(value), + value = alloc(value)!, cases = cases, label = label, }, @@ -1263,21 +1266,21 @@ fn match_case(lexer: *lex::lexer) (ast::match_case | error) = { end = lex::prevloc(lexer), flags = 0, repr = ast::builtin_type::NULL, - }); + })!; case ltok::LET => name = want(lexer, ltok::NAME)?.1 as str; want(lexer, ltok::COLON)?; - typ = alloc(_type(lexer)?); + typ = alloc(_type(lexer)?)!; case ltok::ARROW => lex::unlex(lexer, tok); case => lex::unlex(lexer, tok); - typ = alloc(_type(lexer)?); + typ = alloc(_type(lexer)?)!; }; want(lexer, ltok::ARROW)?; let exprs: []*ast::expr = []; for (true) { - append(exprs, alloc(stmt(lexer)?)); + append(exprs, alloc(stmt(lexer)?)!)!; if (peek(lexer, ltok::CASE, ltok::RBRACE)? is lex::token) { break; }; @@ -1303,7 +1306,7 @@ fn match_expr(lexer: *lex::lexer) (ast::expr | error) = { let cases: []ast::match_case = []; for (true) { - append(cases, match_case(lexer)?); + append(cases, match_case(lexer)?)!; if (try(lexer, ltok::RBRACE)? is lex::token) { break; }; @@ -1313,7 +1316,7 @@ fn match_expr(lexer: *lex::lexer) (ast::expr | error) = { start = start.2, end = lex::prevloc(lexer), expr = ast::match_expr { - value = alloc(value), + value = alloc(value)!, cases = cases, label = label, }, @@ -1325,7 +1328,7 @@ fn unarithm(lexer: *lex::lexer) (ast::expr | error) = { ltok::MINUS, ltok::BNOT, ltok::LNOT, ltok::TIMES, ltok::BAND, ltok::SWITCH, ltok::MATCH, ltok::COLON, ltok::LBRACE)?) { case void => - return builtin(lexer); + return postfix(lexer, void); case let tok: lex::token => yield switch (tok.0) { case ltok::SWITCH => @@ -1386,7 +1389,7 @@ fn unarithm(lexer: *lex::lexer) (ast::expr | error) = { yield ast::unarithm_expr { op = op, - operand = alloc(operand), + operand = alloc(operand)!, }; }; return ast::expr { @@ -1403,14 +1406,14 @@ fn yield_expr(lexer: *lex::lexer) (ast::expr | error) = { match (try(lexer, ltok::COLON, ltok::COMMA, ltok::ELSE, ltok::RBRACE, ltok::RBRACKET, ltok::RPAREN, ltok::SEMICOLON, ltok::EOF)?) { case void => - value = alloc(expr(lexer)?); + value = alloc(expr(lexer)?)!; case let t: lex::token => if (t.0 == ltok::COLON) { label = want(lexer, ltok::NAME)?.1 as str; match (try(lexer, ltok::COMMA)?) { case void => void; case lex::token => - value = alloc(expr(lexer)?); + value = alloc(expr(lexer)?)!; }; } else { lex::unlex(lexer, t); diff --git a/hare/parse/ident.ha b/hare/parse/ident.ha @@ -14,7 +14,7 @@ export fn ident_trailing(lexer: *lex::lexer) ((ast::ident, bool) | error) = { let ident: []str = []; let trailing = false; const tok = want(lexer, ltok::NAME)?; - append(ident, tok.1 as str); + append(ident, tok.1 as str)!; const loc = tok.2; let z = len(ident[0]); for (true) { @@ -30,7 +30,7 @@ export fn ident_trailing(lexer: *lex::lexer) ((ast::ident, bool) | error) = { trailing = true; break; }; - append(ident, name); + append(ident, name)!; z += len(name); }; if (z > ast::IDENT_MAX) { diff --git a/hare/parse/import.ha b/hare/parse/import.ha @@ -8,7 +8,7 @@ use hare::lex::{ltok}; fn name_list(lexer: *lex::lexer) (ast::import_members | error) = { let names: []str = []; for (true) { - append(names, want(lexer, ltok::NAME)?.1 as str); + append(names, want(lexer, ltok::NAME)?.1 as str)!; switch (want(lexer, ltok::COMMA, ltok::RBRACE)?.0) { case ltok::COMMA => match (try(lexer, ltok::RBRACE)?) { @@ -35,7 +35,7 @@ export fn imports(lexer: *lex::lexer) ([]ast::import | error) = { append(imports, ast::import { bindings = void, ... - }); + })!; let import = &imports[len(imports) - 1]; import.start = lex::mkloc(lexer); let (name, trailing) = ident_trailing(lexer)?; diff --git a/hare/parse/type.ha b/hare/parse/type.ha @@ -27,9 +27,9 @@ fn prototype(lexer: *lex::lexer) (ast::func_type | error) = { append(params, ast::func_param { loc = loc, name = "", - _type = alloc(name_or_type), + _type = alloc(name_or_type)!, default_value = void, - }); + })!; case lex::token => // Bit of a hack because we can't unlex twice. synassert(loc, name_or_type.repr is ast::alias_type, @@ -39,9 +39,9 @@ fn prototype(lexer: *lex::lexer) (ast::func_type | error) = { append(params, ast::func_param { loc = loc, name = ns[0], - _type = alloc(_type(lexer)?), + _type = alloc(_type(lexer)?)!, default_value = void, - }); + })!; }; match (try(lexer, ltok::EQUAL)?) { case void => @@ -65,7 +65,7 @@ fn prototype(lexer: *lex::lexer) (ast::func_type | error) = { }; let t = _type(lexer)?; return ast::func_type { - result = alloc(t), + result = alloc(t)!, variadism = variadism, params = params, }; @@ -132,6 +132,8 @@ fn primitive_type(lexer: *lex::lexer) (ast::_type | error) = { yield builtin_type::OPAQUE; case ltok::NEVER => yield builtin_type::NEVER; + case ltok::NOMEM => + yield builtin_type::NOMEM; case => return syntaxerr(lex::mkloc(lexer), "Unexpected {}, was expecting primitive type", @@ -175,7 +177,7 @@ fn pointer_type(lexer: *lex::lexer) (ast::_type | error) = { end = lex::prevloc(lexer), flags = ast::type_flag::NONE, repr = ast::pointer_type { - referent = alloc(_type), + referent = alloc(_type)!, flags = flags, }, }; @@ -187,9 +189,9 @@ fn tagged_type( start: lex::location ) (ast::_type | error) = { let tagged: ast::tagged_type = []; - append(tagged, alloc(first)); + append(tagged, alloc(first)!)!; for (true) { - append(tagged, alloc(_type(lexer)?)); + append(tagged, alloc(_type(lexer)?)!)!; match (try(lexer, ltok::BOR)?) { case lex::token => @@ -216,9 +218,9 @@ fn tuple_type( start: lex::location ) (ast::_type | error) = { let tuple: ast::tuple_type = []; - append(tuple, alloc(first)); + append(tuple, alloc(first)!)!; for (true) { - append(tuple, alloc(_type(lexer)?)); + append(tuple, alloc(_type(lexer)?)!)!; match (try(lexer, ltok::COMMA)?) { case lex::token => match (try(lexer, ltok::RPAREN)) { @@ -278,7 +280,7 @@ fn struct_union_type(lexer: *lex::lexer) (ast::_type | error) = { want(lexer, ltok::LPAREN)?; let ex = expr(lexer)?; want(lexer, ltok::RPAREN)?; - yield alloc(ex); + yield alloc(ex)!; }; let tok = want(lexer, ltok::NAME, ltok::STRUCT, ltok::UNION)?; @@ -289,15 +291,15 @@ fn struct_union_type(lexer: *lex::lexer) (ast::_type | error) = { case ltok::NAME => lex::unlex(lexer, tok); let memb = struct_embed_or_field(lexer, offs, comment)?; - append(membs, memb); + append(membs, memb)!; case ltok::STRUCT, ltok::UNION => lex::unlex(lexer, tok); let subtype = struct_union_type(lexer)?; append(membs, ast::struct_member { _offset = offs, - member = alloc(subtype), + member = alloc(subtype)!, docs = comment, - }); + })!; case => abort(); }; @@ -347,13 +349,13 @@ fn struct_embed_or_field( let id: ast::ident = match (try(lexer, ltok::COLON, ltok::DOUBLE_COLON)?) { case void => - yield alloc([name.1 as str]); + yield alloc([name.1 as str])!; case let tok: lex::token => yield switch (tok.0) { case ltok::COLON => let field = ast::struct_field { name = name.1 as str, - _type = alloc(_type(lexer)?), + _type = alloc(_type(lexer)?)!, }; return ast::struct_member { _offset = offs, @@ -362,7 +364,7 @@ fn struct_embed_or_field( }; case ltok::DOUBLE_COLON => let id = ident(lexer)?; - insert(id[0], name.1 as str); + insert(id[0], name.1 as str)!; yield id; case => abort(); }; @@ -381,7 +383,7 @@ fn array_slice_type(lexer: *lex::lexer) (ast::_type | error) = { let length = match (try(lexer, ltok::UNDERSCORE, ltok::TIMES, ltok::RBRACKET)?) { case void => - yield alloc(expr(lexer)?); + yield alloc(expr(lexer)?)!; case let tok: lex::token => yield switch (tok.0) { case ltok::UNDERSCORE => @@ -405,7 +407,7 @@ fn array_slice_type(lexer: *lex::lexer) (ast::_type | error) = { flags = ast::type_flag::NONE, repr = ast::list_type { length = length, - members = alloc(_type), + members = alloc(_type)!, }, }; }; @@ -442,7 +444,7 @@ fn enum_type(lexer: *lex::lexer) (ast::_type | error) = { let comment = strings::dup(lex::comment(lexer)); let value: nullable *ast::expr = if (try(lexer, ltok::EQUAL)? is lex::token) - alloc(expr(lexer)?) + alloc(expr(lexer)?)! else null; defer append(membs, ast::enum_field { @@ -450,7 +452,7 @@ fn enum_type(lexer: *lex::lexer) (ast::_type | error) = { value = value, loc = loc, docs = comment, - }); + })!; switch (want(lexer, ltok::COMMA, ltok::RBRACE)?.0) { case ltok::COMMA => @@ -494,7 +496,7 @@ export fn _type(lexer: *lex::lexer) (ast::_type | error) = { ltok::I32, ltok::I64, ltok::U8, ltok::U16, ltok::U32, ltok::U64, ltok::INT, ltok::UINT, ltok::UINTPTR, ltok::SIZE, ltok::F32, ltok::F64, ltok::VALIST, - ltok::VOID, ltok::OPAQUE, ltok::NEVER => + ltok::VOID, ltok::OPAQUE, ltok::NEVER, ltok::NOMEM => yield primitive_type(lexer)?; case ltok::ENUM => yield enum_type(lexer)?; diff --git a/hare/types/+test.ha b/hare/types/+test.ha @@ -318,8 +318,8 @@ fn resolve( assert(htype._align == st.arch._int); let t = htype.repr as tagged; assert(len(t) == 2); - assert(t[0].repr as builtin == builtin::INT); - assert(t[1].repr as builtin == builtin::VOID); + assert(t[0].repr as builtin == builtin::VOID); + assert(t[1].repr as builtin == builtin::INT); let atype = parse_type("(int | (int | str | void))"); defer ast::type_finish(&atype); @@ -328,8 +328,8 @@ fn resolve( assert(htype._align == 8); let t = htype.repr as tagged; assert(len(t) == 3); - assert(t[0].repr as builtin == builtin::INT); - assert(t[1].repr as builtin == builtin::VOID); + assert(t[0].repr as builtin == builtin::VOID); + assert(t[1].repr as builtin == builtin::INT); assert(t[2].repr as builtin == builtin::STR); }; @@ -377,6 +377,7 @@ fn resolve( (&builtin_i16, "i16"), (&builtin_i32, "i32"), (&builtin_i64, "i64"), + (&builtin_nomem, "nomem"), (&builtin_opaque, "opaque"), (&builtin_rune, "rune"), (&builtin_u8, "u8"), diff --git a/hare/types/builtins.ha b/hare/types/builtins.ha @@ -72,7 +72,7 @@ export const builtin_i64: _type = _type { export const builtin_opaque: _type = _type { repr = builtin::OPAQUE, sz = SIZE_UNDEFINED, _align = SIZE_UNDEFINED, - id = 1737287038, + id = 2843771249, ... }; @@ -84,11 +84,20 @@ export const builtin_never: _type = _type { ... }; +// [[_type]] representation of never. +export const builtin_nomem: _type = _type { + repr = builtin::NOMEM, + flags = flag::ERROR, + sz = 0, _align = 0, + id = 2408538893, + ... +}; + // [[_type]] representation of rune. export const builtin_rune: _type = _type { repr = builtin::RUNE, sz = 4, _align = 4, - id = 2843771249, + id = 2206074632, ... }; @@ -96,7 +105,7 @@ export const builtin_rune: _type = _type { export const builtin_u8: _type = _type { repr = builtin::U8, sz = 1, _align = 1, - id = 3181589295, + id = 2543892678, ... }; @@ -104,7 +113,7 @@ export const builtin_u8: _type = _type { export const builtin_u16: _type = _type { repr = builtin::U16, sz = 2, _align = 2, - id = 3481467866, + id = 1906196061, ... }; @@ -112,7 +121,7 @@ export const builtin_u16: _type = _type { export const builtin_u32: _type = _type { repr = builtin::U32, sz = 4, _align = 4, - id = 1906196061, + id = 1268499444, ... }; @@ -120,7 +129,7 @@ export const builtin_u32: _type = _type { export const builtin_u64: _type = _type { repr = builtin::U64, sz = 8, _align = 8, - id = 1268499444, + id = 3181589295, ... }; @@ -128,6 +137,6 @@ export const builtin_u64: _type = _type { export const builtin_void: _type = _type { repr = builtin::VOID, sz = 0, _align = 0, - id = 3012680272, + id = 630802827, ... }; diff --git a/hare/types/hash.ha b/hare/types/hash.ha @@ -8,8 +8,8 @@ use strings; // Keep ordered with respect to bootstrap harec:include/types.h type storage = enum u8 { - BOOL, DONE, F32, F64, I16, I32, I64, I8, INT, NEVER, NULL, OPAQUE, RUNE, - SIZE, STRING, U16, U32, U64, U8, UINT, UINTPTR, VOID, ALIAS, ARRAY, + BOOL, DONE, F32, F64, I16, I32, I64, I8, INT, NEVER, NOMEM, NULL, OPAQUE, + RUNE, SIZE, STRING, U16, U32, U64, U8, UINT, UINTPTR, VOID, ALIAS, ARRAY, ENUM, FUNCTION, POINTER, SLICE, STRUCT, TAGGED, TUPLE, UNION, VALIST, }; @@ -35,6 +35,8 @@ fn builtin_storage(b: builtin) u8 = { return storage::INT; case builtin::NEVER => return storage::NEVER; + case builtin::NOMEM => + return storage::NOMEM; case builtin::NULL => return storage::NULL; case builtin::OPAQUE => diff --git a/hare/types/store.ha b/hare/types/store.ha @@ -40,7 +40,7 @@ export fn store( resolve = resolver, rstate = rstate, ... -}); +})!; // Frees state associated with a [[typestore]]. export fn store_free(store: *typestore) void = { @@ -90,7 +90,7 @@ export fn newalias( // Or create a new alias let bucket = &store.map[id % BUCKETS]; - append(bucket, atype); + append(bucket, atype)!; return &bucket[len(bucket) - 1]; }; @@ -151,6 +151,8 @@ export fn lookup( return &builtin_void; case builtin::DONE => return &builtin_done; + case builtin::NOMEM => + return &builtin_nomem; case => void; }; case => void; @@ -165,7 +167,7 @@ export fn lookup( }; }; ty.id = id; - append(bucket, ty); + append(bucket, ty)!; return &bucket[len(bucket) - 1]; }; @@ -265,6 +267,9 @@ fn fromast(store: *typestore, atype: *ast::_type) (_type | deferred | error) = { sz = SIZE_UNDEFINED; _align = SIZE_UNDEFINED; yield builtin::NEVER; + case ast::builtin_type::NOMEM => + sz = 0; _align = 0; + yield builtin::NOMEM; case ast::builtin_type::VALIST => sz = store.arch.valist_size; _align = store.arch.valist_align; @@ -368,10 +373,10 @@ fn func_from_ast( case ast::variadism::HARE => yield variadism::HARE; }, - params = alloc([], len(ft.params)), + params = alloc([], len(ft.params))!, }; for (let i = 0z; i < len(ft.params); i += 1) { - append(f.params, lookup(store, ft.params[i]._type)?); + append(f.params, lookup(store, ft.params[i]._type)?)!; }; return f; }; @@ -477,7 +482,7 @@ fn _struct_from_ast( name = memb.name, offs = *offs, _type = _type, - }); + })!; if (!is_union) { *offs += _type.sz; @@ -519,7 +524,7 @@ fn tagged_collect( case let ta: ast::tagged_type => tagged_collect(store, ta, types)?; case => - append(types, lookup(store, atype[i])?); + append(types, lookup(store, atype[i])?)!; }; }; @@ -564,7 +569,7 @@ fn tuple_from_ast( append(values, tuple_value { _type = vtype, offs = offs, - }); + })!; offs += vtype.sz; }; diff --git a/hare/types/types.ha b/hare/types/types.ha @@ -22,8 +22,8 @@ export type builtin = enum u8 { // Keep me consistent with ast::builtin BOOL, DONE, F32, F64, FCONST, I16, I32, I64, I8, ICONST, INT, NEVER, - NULL, OPAQUE, RCONST, RUNE, SIZE, STR, U16, U32, U64, U8, UINT, UINTPTR, - VALIST, VOID + NOMEM, NULL, OPAQUE, RCONST, RUNE, SIZE, STR, U16, U32, U64, U8, UINT, + UINTPTR, VALIST, VOID }; // An enum type, e.g. enum { FOO = 0 } diff --git a/hare/unit/+test.ha b/hare/unit/+test.ha @@ -14,12 +14,12 @@ fn parse_expr(src: str) *ast::expr = { let sc = bufio::newscanner(&stream); defer bufio::finish(&sc); let lexer = lex::init(&sc, "<test>"); - return alloc(parse::expr(&lexer)!); + return alloc(parse::expr(&lexer)!)!; }; fn mktestctx() context = context { store = types::store(types::x86_64, null, null), - scope = alloc(scope { ... }), + scope = alloc(scope { ... })!, ... }; diff --git a/hare/unit/check.ha b/hare/unit/check.ha @@ -14,7 +14,7 @@ export fn check( ) (unit | error) = { let ctx = context { store = store, - scope = alloc(scope { class = scope_class::UNIT, ... }), + scope = alloc(scope { class = scope_class::UNIT, ... })!, ... }; scan(&ctx, subunits)?; diff --git a/hare/unit/process.ha b/hare/unit/process.ha @@ -21,7 +21,7 @@ fn process(ctx: *context, subunits: const []ast::subunit) (unit | error) = { case error => abort(); // TODO }; - append(unit.decls, decl); + append(unit.decls, decl)!; }; }; @@ -171,7 +171,7 @@ fn process_access(ctx: *context, aexpr: *ast::expr) (*expr | error) = { result = result, expr = ex, terminates = false, - }); + })!; }; fn process_binding(ctx: *context, aexpr: *ast::expr) (*expr | error) = { @@ -199,7 +199,7 @@ fn process_binding(ctx: *context, aexpr: *ast::expr) (*expr | error) = { append(bindings, binding { object = object, init = init, - }); + })!; }; return alloc(expr { start = aexpr.start, @@ -207,17 +207,17 @@ fn process_binding(ctx: *context, aexpr: *ast::expr) (*expr | error) = { result = &types::builtin_void, expr = bindings, ... - }); + })!; }; fn process_compound(ctx: *context, aexpr: *ast::expr) (*expr | error) = { const compound_expr = aexpr.expr as ast::compound_expr; const scope = scope_push(ctx, scope_class::COMPOUND); - let exprs: compound = alloc([], len(compound_expr.exprs)); + let exprs: compound = alloc([], len(compound_expr.exprs))!; let i = 0z; for (i < len(compound_expr.exprs); i += 1) { - append(exprs, process_expr(ctx, compound_expr.exprs[i])?); + append(exprs, process_expr(ctx, compound_expr.exprs[i])?)!; }; scope_pop(ctx); @@ -228,7 +228,7 @@ fn process_compound(ctx: *context, aexpr: *ast::expr) (*expr | error) = { expr = exprs, terminates = exprs[i - 1].terminates, ... - }); + })!; }; fn process_constant(ctx: *context, aexpr: *ast::expr) (*expr | error) = { @@ -297,7 +297,7 @@ fn process_constant(ctx: *context, aexpr: *ast::expr) (*expr | error) = { result = result, expr = ex, ... - }); + })!; }; fn process_return(ctx: *context, aexpr: *ast::expr) (*expr | error) = { @@ -315,5 +315,5 @@ fn process_return(ctx: *context, aexpr: *ast::expr) (*expr | error) = { terminates = true, result = &types::builtin_void, expr = rval: _return, - }); + })!; }; diff --git a/hare/unit/scope.ha b/hare/unit/scope.ha @@ -57,7 +57,7 @@ fn scope_push(ctx: *context, class: scope_class) *scope = { class = class, parent = ctx.scope, ... - }); + })!; ctx.scope = new; return new; }; @@ -80,11 +80,11 @@ fn ident_hash(ident: ast::ident) u64 = { fn scope_insert(ctx: *context, obj: object) *object = { const scope = ctx.scope; - append(scope.objects, obj); + append(scope.objects, obj)!; let obj = &scope.objects[len(scope.objects) - 1]; const hash = ident_hash(obj.ident); obj.hash = hash; - append(scope.hashmap[hash: size % SCOPE_BUCKETS], obj); + append(scope.hashmap[hash: size % SCOPE_BUCKETS], obj)!; return obj; }; diff --git a/hare/unparse/expr.ha b/hare/unparse/expr.ha @@ -556,6 +556,8 @@ fn literal( return syn(ctx, "null", synkind::KEYWORD)?; case done => return syn(ctx, "done", synkind::KEYWORD)?; + case nomem => + return syn(ctx, "nomem", synkind::KEYWORD)?; case let b: bool => return syn(ctx, if (b) "true" else "false", synkind::KEYWORD)?; @@ -953,7 +955,7 @@ fn is_plain(e: *ast::expr) bool = { }; fn is_postfix(e: *ast::expr) bool = { - if (is_plain(e)) { + if (is_builtin(e)) { return true; }; @@ -974,7 +976,7 @@ fn is_postfix(e: *ast::expr) bool = { }; fn is_builtin(e: *ast::expr) bool = { - if (is_postfix(e)) { + if (is_plain(e)) { return true; }; @@ -1005,7 +1007,7 @@ fn is_builtin(e: *ast::expr) bool = { }; fn is_unary(e: *ast::expr) bool = { - if (is_builtin(e)) { + if (is_postfix(e)) { return true; }; diff --git a/hare/unparse/syn.ha b/hare/unparse/syn.ha @@ -113,7 +113,7 @@ export fn syn_wrap(ctx: *context, s: str, kind: synkind) (size | io::error) = { let z = _type(io::empty, &syn_nowrap, t)!; if (ctx.linelen + z < 80) yield; - st.extra = alloc(syn_wrap_extra::MULTILINE_FN_PARAM); + st.extra = alloc(syn_wrap_extra::MULTILINE_FN_PARAM)!; z = fmt::fprintln(ctx.out, s)?; ctx.linelen = 0; ctx.indent += 1; @@ -141,7 +141,7 @@ export fn syn_wrap(ctx: *context, s: str, kind: synkind) (size | io::error) = { yield :extra, &syn_wrap_extra::NONE; }; - st.extra = alloc(syn_wrap_extra::MULTILINE_TAGGED_OR_TUPLE); + st.extra = alloc(syn_wrap_extra::MULTILINE_TAGGED_OR_TUPLE)!; let z = fmt::fprintln(ctx.out, s)?; ctx.indent += 1; ctx.linelen = ctx.indent * 8; diff --git a/hare/unparse/type.ha b/hare/unparse/type.ha @@ -34,6 +34,8 @@ case ast::builtin_type::INT => yield "int"; case ast::builtin_type::NEVER => yield "never"; +case ast::builtin_type::NOMEM => + yield "nomem"; case ast::builtin_type::NULL => yield "null"; case ast::builtin_type::OPAQUE => diff --git a/io/drain.ha b/io/drain.ha @@ -8,7 +8,7 @@ export fn drain(in: handle) ([]u8 | error) = { static let buf: [4096]u8 = [0...]; for (let n => read(in, buf[..])?) { - append(sink, buf[..n]...); + append(sink, buf[..n]...)!; }; return sink; }; diff --git a/linux/vdso/+linux/vdso.ha b/linux/vdso/+linux/vdso.ha @@ -116,7 +116,7 @@ fn get_vdso_ctx() nullable *vdso_ctx = { hashhdr = hashhdr: *elf::hashhdr, verdef = verdef, versym = versym, - }); + })!; ctx = vctx; return ctx; diff --git a/memio/stream.ha b/memio/stream.ha @@ -158,7 +158,7 @@ fn dynamic_write(s: *io::stream, buf: const []u8) (size | io::error) = { s.buf[s.pos..s.pos+bufend] = buf[..bufend]; s.pos += bufend; if (bufend < len(buf)) { - append(s.buf, buf[bufend..]...); + append(s.buf, buf[bufend..]...)!; s.pos += len(buf[bufend..]); }; return len(buf); @@ -229,7 +229,7 @@ fn dynamic_close(s: *io::stream) (void | io::error) = { assert(len(buffer(&s)) == 0); assert(io::writeall(&s, [1, 2, 3]) as size == 3); - let sl: []u8 = alloc([1, 2, 3]); + let sl: []u8 = alloc([1, 2, 3])!; let s = dynamic_from(sl); defer io::close(&s)!; assert(io::writeall(&s, [0, 0]) as size == 2); @@ -238,7 +238,7 @@ fn dynamic_close(s: *io::stream) (void | io::error) = { assert(bytes::equal(buffer(&s), [0, 0, 3, 4, 5, 6])); assert(io::read(&s, buf[..]) is io::EOF); - sl = alloc([1, 2]); + sl = alloc([1, 2])!; let s = dynamic_from(sl); defer io::close(&s)!; assert(io::read(&s, buf[..1]) as size == 1 && buf[0] == 1); diff --git a/mime/database.ha b/mime/database.ha @@ -30,7 +30,7 @@ let exttable: [MIME_BUCKETS][]*mimetype = [[]...]; // implement new Media Types. export fn register(mime: *mimetype...) void = { let i = len(static_db); - append(static_db, mime...); + append(static_db, mime...)!; for (i < len(static_db); i += 1) { hashtable_insert(static_db[i]); }; @@ -39,12 +39,12 @@ export fn register(mime: *mimetype...) void = { fn hashtable_insert(item: *mimetype) void = { const hash = fnv::string(item.mime); let bucket = &mimetable[hash % len(mimetable)]; - append(bucket, item); + append(bucket, item)!; for (let ext .. item.exts) { const hash = fnv::string(ext); let bucket = &exttable[hash % len(exttable)]; - append(bucket, item); + append(bucket, item)!; }; }; diff --git a/mime/system.ha b/mime/system.ha @@ -37,9 +37,9 @@ fn load_systemdb() (void | fs::error | io::error | utf8::invalid) = { let entry = alloc(mimetype { mime = strings::dup(mime), exts = [], - }); + })!; for (let ext => strings::next_token(&tok)) { - append(entry.exts, strings::dup(ext)); + append(entry.exts, strings::dup(ext))!; }; register_heap(entry); }; @@ -47,7 +47,7 @@ fn load_systemdb() (void | fs::error | io::error | utf8::invalid) = { fn register_heap(mime: *mimetype) void = { let i = len(heap_db); - append(heap_db, mime); + append(heap_db, mime)!; for (i < len(heap_db); i += 1) { hashtable_insert(heap_db[i]); }; diff --git a/net/dial/registry.ha b/net/dial/registry.ha @@ -82,7 +82,7 @@ export fn registerproto(name: str, dial: *dialer) void = { append(protocols, protocol { name = name, dial = dial, - }); + })!; }; // Registers a new application-level service (e.g. SSH) with the dialer. Note @@ -100,7 +100,7 @@ export fn registersvc( name = name, alias = alias, port = port, - }); + })!; }; fn lookup_service(proto: str, service: str) (u16 | void) = { diff --git a/net/dial/resolve.ha b/net/dial/resolve.ha @@ -94,7 +94,7 @@ export fn resolve( fn resolve_addr(addr: str) ([]ip::addr | error) = { match (ip::parse(addr)) { case let addr: ip::addr => - return alloc([addr]); + return alloc([addr])!; case ip::invalid => void; }; @@ -167,9 +167,9 @@ fn collect_answers(addrs: *[]ip::addr, answers: *[]dns::rrecord) void = { for (let i = 0z; i < len(answers); i += 1) { match (answers[i].rdata) { case let addr: dns::aaaa => - append(addrs, addr: ip::addr); + append(addrs, addr: ip::addr)!; case let addr: dns::a => - append(addrs, addr: ip::addr); + append(addrs, addr: ip::addr)!; case => void; }; }; diff --git a/net/dns/decode.ha b/net/dns/decode.ha @@ -16,12 +16,12 @@ type decoder = struct { // return value. export fn decode(buf: []u8) (*message | format) = { let success = false; - let msg = alloc(message { ... }); + let msg = alloc(message { ... })!; defer if (!success) message_free(msg); let dec = decoder_init(buf); decode_header(&dec, &msg.header)?; for (let i = 0z; i < msg.header.qdcount; i += 1) { - append(msg.questions, decode_question(&dec)?); + append(msg.questions, decode_question(&dec)?)!; }; decode_rrecords(&dec, msg.header.ancount, &msg.answers)?; decode_rrecords(&dec, msg.header.nscount, &msg.authority)?; @@ -36,7 +36,7 @@ fn decode_rrecords( out: *[]rrecord, ) (void | format) = { for (let i = 0z; i < count; i += 1) { - append(out, decode_rrecord(dec)?); + append(out, decode_rrecord(dec)?)!; }; }; @@ -151,7 +151,7 @@ fn decode_name(dec: *decoder) ([]str | format) = { return format; }; - append(names, strings::dup(name)); + append(names, strings::dup(name))!; }; return format; }; @@ -296,7 +296,7 @@ fn decode_dnskey(dec: *decoder) (rdata | format) = { algorithm = decode_u8(dec)?, key = [], }; - append(r.key, dec.cur[..]...); + append(r.key, dec.cur[..]...)!; return r; }; @@ -333,9 +333,9 @@ fn decode_opt(dec: *decoder) (rdata | format) = { if (len(dec.cur) < sz) { return format; }; - append(o.data, dec.cur[..sz]...); + append(o.data, dec.cur[..sz]...)!; dec.cur = dec.cur[sz..]; - append(r.options, o); + append(r.options, o)!; }; success = true; return r; @@ -346,7 +346,7 @@ fn decode_nsec(dec: *decoder) (rdata | format) = { next_domain = decode_name(dec)?, type_bitmaps = [], }; - append(r.type_bitmaps, dec.cur[..]...); + append(r.type_bitmaps, dec.cur[..]...)!; return r; }; @@ -368,7 +368,7 @@ fn decode_rrsig(dec: *decoder) (rdata | format) = { signer_name = decode_name(dec)?, signature = [], }; - append(r.signature, dec.cur[..]...); + append(r.signature, dec.cur[..]...)!; return r; }; @@ -398,7 +398,7 @@ fn decode_sshfp(dec: *decoder) (rdata | format) = { fp_type = decode_u8(dec)?, fingerprint = [], }; - append(r.fingerprint, dec.cur[..]...); + append(r.fingerprint, dec.cur[..]...)!; return r; }; @@ -417,7 +417,7 @@ fn decode_tsig(dec: *decoder) (rdata | format) = { if (len(dec.cur) < r.mac_len) { return format; }; - append(r.mac, dec.cur[..r.mac_len]...); + append(r.mac, dec.cur[..r.mac_len]...)!; defer if (!success) free(r.mac); dec.cur = dec.cur[r.mac_len..]; @@ -429,7 +429,7 @@ fn decode_tsig(dec: *decoder) (rdata | format) = { return format; }; if (r.other_len > 0) { - append(r.other_data, dec.cur[..]...); + append(r.other_data, dec.cur[..]...)!; }; success = true; @@ -446,9 +446,9 @@ fn decode_txt(dec: *decoder) (rdata | format) = { return format; }; let item: []u8 = []; - append(item, dec.cur[..ln]...); + append(item, dec.cur[..ln]...)!; dec.cur = dec.cur[ln..]; - append(items, item); + append(items, item)!; }; success = true; return items; diff --git a/net/dns/query.ha b/net/dns/query.ha @@ -119,7 +119,7 @@ export fn query(query: *message, servers: ip::addr...) (*message | error) = { case => return format; }; - let tcpbuf: []u8 = alloc([0...], rz); + let tcpbuf: []u8 = alloc([0...], rz)!; defer free(tcpbuf); match (io::readall(socket, tcpbuf)?) { diff --git a/net/msg.ha b/net/msg.ha @@ -44,7 +44,7 @@ export fn addvector(msg: *msghdr, vec: []u8) void = { append(msg.vectors, rt::iovec { iov_base = vec: *[*]u8, iov_len = len(vec), - }); + })!; }; // Sets flags for this message. @@ -79,7 +79,7 @@ export fn addcontrol( ) []u8 = { const prev = len(msg.control); const space = cmsg_space(length); - append(msg.control, [0...], space); + append(msg.control, [0...], space)!; let newbuf = msg.control[prev..prev + space]: *[*]rt::cmsghdr; newbuf[0].cmsg_len = cmsg_len(length): uint; newbuf[0].cmsg_level = level; diff --git a/net/uri/parse.ha b/net/uri/parse.ha @@ -347,7 +347,7 @@ fn percent_decode_static(out: io::handle, s: str) (void | invalid) = { match (strconv::stou8(memio::string(&tmp)!, strconv::base::HEX)) { case let ord: u8 => - append(percent_data, ord); + append(percent_data, ord)!; case => return invalid; }; diff --git a/os/+freebsd/dirfdfs.ha b/os/+freebsd/dirfdfs.ha @@ -19,7 +19,7 @@ type os_filesystem = struct { // Opens a file descriptor as an [[fs::fs]]. This file descriptor must be a // directory file. The file will be closed when the fs is closed. export fn dirfdopen(fd: io::file) *fs::fs = { - let ofs = alloc(os_filesystem { ... }); + let ofs = alloc(os_filesystem { ... })!; let fs = static_dirfdopen(fd, ofs); fs.close = &fs_close; return fs; @@ -439,11 +439,12 @@ fn fs_iter(fs: *fs::fs, path: str) (*fs::iterator | fs::error) = { yield fd; }; + // TODO: handle allocation failure let buf = match (rt::malloc(fs.getdents_bufsz)) { case let v: *opaque => yield v: *[*]u8; case null => - return errors::nomem; + abort("out of memory"); }; let iter = alloc(os_iterator { iter = fs::iterator { @@ -453,7 +454,7 @@ fn fs_iter(fs: *fs::fs, path: str) (*fs::iterator | fs::error) = { fd = fd, buf = buf[..fs.getdents_bufsz], ... - }); + })!; return &iter.iter; }; diff --git a/os/+freebsd/platform_environ.ha b/os/+freebsd/platform_environ.ha @@ -21,9 +21,9 @@ let args_static: [32]str = [""...]; args[i] = c::tostr(rt::argv[i]: *const c::char)!; }; } else { - args = alloc([], rt::argc); + args = alloc([], rt::argc)!; for (let i = 0z; i < rt::argc; i += 1) { - append(args, c::tostr(rt::argv[i]: *const c::char)!); + append(args, c::tostr(rt::argv[i]: *const c::char)!)!; }; }; @@ -42,7 +42,7 @@ export fn getenvs() []str = { }; for (let i = 0z; rt::envp[i] != null; i += 1) { let s = c::tostr(rt::envp[i]: *const c::char)!; - append(envp, strings::dup(s)); + append(envp, strings::dup(s))!; }; return envp; }; diff --git a/os/+linux/dirfdfs.ha b/os/+linux/dirfdfs.ha @@ -52,7 +52,7 @@ export fn dirfdopen( fd: io::file, resolve_flags: resolve_flag = resolve_flag::NORMAL, ) *fs::fs = { - let ofs = alloc(os_filesystem { resolve = resolve_flags, ... }); + let ofs = alloc(os_filesystem { resolve = resolve_flags, ... })!; let fs = static_dirfdopen(fd, ofs); fs.close = &fs_close; return fs; @@ -99,7 +99,7 @@ export fn dirfs_clone( ) *fs::fs = { assert(fs.open == &fs_open); let fs = fs: *os_filesystem; - let new = alloc(*fs); + let new = alloc(*fs)!; fs.resolve |= resolve_flags; new.dirfd = rt::fcntl(new.dirfd, rt::F_DUPFD_CLOEXEC, 0) as int; return &new.fs; @@ -449,11 +449,12 @@ fn fs_iter(fs: *fs::fs, path: str) (*fs::iterator | fs::error) = { yield fd; }; + // TODO: handle allocation failure let buf = match (rt::malloc(fs.getdents_bufsz)) { case let v: *opaque => yield v: *[*]u8; case null => - return errors::nomem; + abort("out of memory"); }; let iter = alloc(os_iterator { iter = fs::iterator { @@ -463,7 +464,7 @@ fn fs_iter(fs: *fs::fs, path: str) (*fs::iterator | fs::error) = { fd = fd, buf = buf[..fs.getdents_bufsz], ... - }); + })!; return &iter.iter; }; diff --git a/os/+linux/fs.ha b/os/+linux/fs.ha @@ -160,7 +160,7 @@ export fn getxattr(path: str, name: str) ([]u8 | fs::error) = { yield s; }; - let buf: []u8 = alloc([0...], attr_size); + let buf: []u8 = alloc([0...], attr_size)!; match (rt::getxattr(path, name, buf)) { case let err: rt::errno => return errno_to_fs(err); diff --git a/os/+linux/platform_environ.ha b/os/+linux/platform_environ.ha @@ -22,9 +22,9 @@ let args_static: [32]str = [""...]; args[i] = c::tostr(rt::argv[i]: *const c::char)!; }; } else { - args = alloc([], rt::argc); + args = alloc([], rt::argc)!; for (let i = 0z; i < rt::argc; i += 1) { - append(args, c::tostr(rt::argv[i]: *const c::char)!); + append(args, c::tostr(rt::argv[i]: *const c::char)!)!; }; }; @@ -43,7 +43,7 @@ export fn getenvs() []str = { }; for (let i = 0z; rt::envp[i] != null; i += 1) { let s = c::tostr(rt::envp[i]: *const c::char)!; - append(envp, strings::dup(s)); + append(envp, strings::dup(s))!; }; return envp; }; diff --git a/os/+netbsd/dirfdfs.ha b/os/+netbsd/dirfdfs.ha @@ -19,7 +19,7 @@ type os_filesystem = struct { // Opens a file descriptor as an [[fs::fs]]. This file descriptor must be a // directory file. The file will be closed when the fs is closed. export fn dirfdopen(fd: io::file) *fs::fs = { - let ofs = alloc(os_filesystem { ... }); + let ofs = alloc(os_filesystem { ... })!; let fs = static_dirfdopen(fd, ofs); fs.close = &fs_close; return fs; @@ -449,11 +449,12 @@ fn fs_iter(fs: *fs::fs, path: str) (*fs::iterator | fs::error) = { yield fd; }; + // TODO: handle allocation failure let buf = match (rt::malloc(fs.getdents_bufsz)) { case let v: *opaque => yield v: *[*]u8; case null => - return errors::nomem; + abort("out of memory"); }; let iter = alloc(os_iterator { iter = fs::iterator { @@ -463,7 +464,7 @@ fn fs_iter(fs: *fs::fs, path: str) (*fs::iterator | fs::error) = { fd = fd, buf = buf[..fs.getdents_bufsz], ... - }); + })!; return &iter.iter; }; diff --git a/os/+netbsd/platform_environ.ha b/os/+netbsd/platform_environ.ha @@ -21,9 +21,9 @@ let args_static: [32]str = [""...]; args[i] = c::tostr(rt::argv[i]: *const c::char)!; }; } else { - args = alloc([], rt::argc); + args = alloc([], rt::argc)!; for (let i = 0z; i < rt::argc; i += 1) { - append(args, c::tostr(rt::argv[i]: *const c::char)!); + append(args, c::tostr(rt::argv[i]: *const c::char)!)!; }; }; @@ -42,7 +42,7 @@ export fn getenvs() []str = { }; for (let i = 0z; rt::envp[i] != null; i += 1) { let s = c::tostr(rt::envp[i]: *const c::char)!; - append(envp, strings::dup(s)); + append(envp, strings::dup(s))!; }; return envp; }; diff --git a/os/+openbsd/dirfdfs.ha b/os/+openbsd/dirfdfs.ha @@ -272,12 +272,14 @@ fn fs_iter(fs: *fs::fs, path: str) (*fs::iterator | fs::error) = { yield fd; }; + // TODO: handle allocation failure let buf = match (rt::malloc(fs.getdents_bufsz)) { case let v: *opaque => yield v: *[*]u8; case null => - return errors::nomem; + abort("out of memory"); }; + let iter = alloc(os_iterator { iter = fs::iterator { next = &iter_next, @@ -286,7 +288,7 @@ fn fs_iter(fs: *fs::fs, path: str) (*fs::iterator | fs::error) = { fd = fd, buf = buf[..fs.getdents_bufsz], ... - }); + })!; return &iter.iter; }; @@ -469,7 +471,7 @@ fn fs_close(fs: *fs::fs) void = { // Opens a file descriptor as an [[fs::fs]]. This file descriptor must be a // directory file. The file will be closed when the fs is closed. export fn dirfdopen(fd: io::file) *fs::fs = { - let ofs = alloc(os_filesystem { ... }); + let ofs = alloc(os_filesystem { ... })!; let fs = static_dirfdopen(fd, ofs); fs.close = &fs_close; return fs; diff --git a/os/+openbsd/platform_environ.ha b/os/+openbsd/platform_environ.ha @@ -21,9 +21,9 @@ let args_static: [32]str = [""...]; args[i] = c::tostr(rt::argv[i]: *const c::char)!; }; } else { - args = alloc([], rt::argc); + args = alloc([], rt::argc)!; for (let i = 0z; i < rt::argc; i += 1) { - append(args, c::tostr(rt::argv[i]: *const c::char)!); + append(args, c::tostr(rt::argv[i]: *const c::char)!)!; }; }; }; @@ -41,7 +41,7 @@ export fn getenvs() []str = { }; for (let i = 0z; rt::envp[i] != null; i += 1) { let s = c::tostr(rt::envp[i]: *const c::char)!; - append(envp, strings::dup(s)); + append(envp, strings::dup(s))!; }; return envp; }; diff --git a/os/environ.ha b/os/environ.ha @@ -49,7 +49,7 @@ case void => return default; export fn setenv(name: const str, value: const str) (void | errors::invalid) = { if (strings::contains(value, '\0')) return errors::invalid; unsetenv(name)?; - append(envp, strings::join("=", name, value)); + append(envp, strings::join("=", name, value))!; }; // Unsets an environment variable. Does nothing if the variable isn't set. The diff --git a/os/exec/+freebsd/exec.ha b/os/exec/+freebsd/exec.ha @@ -96,19 +96,19 @@ fn platform_finish(cmd: *command) void = rt::close(cmd.platform)!; fn platform_exec(cmd: *command) error = { // We don't worry about freeing the return values from c::fromstr // because once we exec(2) our heap is fried anyway - let argv: []nullable *const c::char = alloc([], len(cmd.argv) + 1z); + let argv: []nullable *const c::char = alloc([], len(cmd.argv) + 1z)!; for (let arg .. cmd.argv) { - append(argv, c::fromstr(arg)); + append(argv, c::fromstr(arg))!; }; - append(argv, null); + append(argv, null)!; let envp: nullable *[*]nullable *const c::char = null; if (len(cmd.env) != 0) { - let env: []nullable *const c::char = alloc([], len(cmd.env) + 1); + let env: []nullable *const c::char = alloc([], len(cmd.env) + 1)!; for (let e .. cmd.env) { - append(env, c::fromstr(e)); + append(env, c::fromstr(e))!; }; - append(env, null); + append(env, null)!; envp = env: *[*]nullable *const c::char; }; diff --git a/os/exec/+freebsd/platform_cmd.ha b/os/exec/+freebsd/platform_cmd.ha @@ -12,12 +12,12 @@ export type platform_cmd = io::file; export fn cmdfile(file: io::file, name: str, args: str...) command = { let cmd = command { platform = file, - argv = alloc([], len(args) + 1), + argv = alloc([], len(args) + 1)!, env = strings::dupall(os::getenvs()), files = [], dir = "", }; - append(cmd.argv, name); - append(cmd.argv, args...); + append(cmd.argv, name)!; + append(cmd.argv, args...)!; return cmd; }; diff --git a/os/exec/+linux/exec.ha b/os/exec/+linux/exec.ha @@ -101,19 +101,19 @@ fn platform_finish(cmd: *command) void = rt::close(cmd.platform)!; fn platform_exec(cmd: *command) error = { // We don't worry about freeing the return values from c::fromstr // because once we exec(2) our heap is fried anyway - let argv: []nullable *const c::char = alloc([], len(cmd.argv) + 1z); + let argv: []nullable *const c::char = alloc([], len(cmd.argv) + 1z)!; for (let arg .. cmd.argv) { - append(argv, c::fromstr(arg)); + append(argv, c::fromstr(arg))!; }; - append(argv, null); + append(argv, null)!; let envp: nullable *[*]nullable *const c::char = null; if (len(cmd.env) != 0) { - let env: []nullable *const c::char = alloc([], len(cmd.env) + 1); + let env: []nullable *const c::char = alloc([], len(cmd.env) + 1)!; for (let e .. cmd.env) { - append(env, c::fromstr(e)); + append(env, c::fromstr(e))!; }; - append(env, null); + append(env, null)!; envp = env: *[*]nullable *const c::char; }; diff --git a/os/exec/+linux/platform_cmd.ha b/os/exec/+linux/platform_cmd.ha @@ -12,12 +12,12 @@ export type platform_cmd = io::file; export fn cmdfile(file: io::file, name: str, args: str...) command = { let cmd = command { platform = file, - argv = alloc([], len(args) + 1), + argv = alloc([], len(args) + 1)!, env = strings::dupall(os::getenvs()), files = [], dir = "", }; - append(cmd.argv, name); - append(cmd.argv, args...); + append(cmd.argv, name)!; + append(cmd.argv, args...)!; return cmd; }; diff --git a/os/exec/+netbsd/exec.ha b/os/exec/+netbsd/exec.ha @@ -96,19 +96,19 @@ fn platform_finish(cmd: *command) void = rt::close(cmd.platform)!; fn platform_exec(cmd: *command) error = { // We don't worry about freeing the return values from c::fromstr // because once we exec(2) our heap is fried anyway - let argv: []nullable *const c::char = alloc([], len(cmd.argv) + 1z); + let argv: []nullable *const c::char = alloc([], len(cmd.argv) + 1z)!; for (let arg .. cmd.argv) { - append(argv, c::fromstr(arg)); + append(argv, c::fromstr(arg))!; }; - append(argv, null); + append(argv, null)!; let envp: nullable *[*]nullable *const c::char = null; if (len(cmd.env) != 0) { - let env: []nullable *const c::char = alloc([], len(cmd.env) + 1); + let env: []nullable *const c::char = alloc([], len(cmd.env) + 1)!; for (let e .. cmd.env) { - append(env, c::fromstr(e)); + append(env, c::fromstr(e))!; }; - append(env, null); + append(env, null)!; envp = env: *[*]nullable *const c::char; }; diff --git a/os/exec/+netbsd/platform_cmd.ha b/os/exec/+netbsd/platform_cmd.ha @@ -12,12 +12,12 @@ export type platform_cmd = io::file; export fn cmdfile(file: io::file, name: str, args: str...) command = { let cmd = command { platform = file, - argv = alloc([], len(args) + 1), + argv = alloc([], len(args) + 1)!, env = strings::dupall(os::getenvs()), files = [], dir = "", }; - append(cmd.argv, name); - append(cmd.argv, args...); + append(cmd.argv, name)!; + append(cmd.argv, args...)!; return cmd; }; diff --git a/os/exec/+openbsd/exec.ha b/os/exec/+openbsd/exec.ha @@ -71,19 +71,19 @@ fn platform_finish(cmd: *command) void = void; fn platform_exec(cmd: *command) error = { // We don't worry about freeing the return values from c::fromstr // because once we exec(2) our heap is fried anyway - let argv: []nullable *const c::char = alloc([], len(cmd.argv) + 1z); + let argv: []nullable *const c::char = alloc([], len(cmd.argv) + 1z)!; for (let arg .. cmd.argv) { - append(argv, c::fromstr(arg)); + append(argv, c::fromstr(arg))!; }; - append(argv, null); + append(argv, null)!; let envp: nullable *[*]nullable *const c::char = null; if (len(cmd.env) != 0) { - let env: []nullable *const c::char = alloc([], len(cmd.env) + 1); + let env: []nullable *const c::char = alloc([], len(cmd.env) + 1)!; for (let e .. cmd.env) { - append(env, c::fromstr(e)); + append(env, c::fromstr(e))!; }; - append(env, null); + append(env, null)!; envp = env: *[*]nullable *const c::char; }; diff --git a/os/exec/cmd.ha b/os/exec/cmd.ha @@ -40,13 +40,13 @@ export fn cmd(name: str, args: str...) (command | error) = { }; let cmd = command { platform = platcmd, - argv = alloc([], len(args) + 1), + argv = alloc([], len(args) + 1)!, env = strings::dupall(os::getenvs()), files = [], dir = "", }; - append(cmd.argv, name); - append(cmd.argv, args...); + append(cmd.argv, name)!; + append(cmd.argv, args...)!; return cmd; }; @@ -111,7 +111,7 @@ export fn unsetenv(cmd: *command, key: str) (void | errors::invalid) = { export fn setenv(cmd: *command, key: str, value: str) (void | errors::invalid) = { if (strings::contains(value, '\0')) return errors::invalid; unsetenv(cmd, key)?; - append(cmd.env, strings::join("=", key, value)); + append(cmd.env, strings::join("=", key, value))!; }; // Configures a file in the child process's file table, such that the file @@ -138,7 +138,7 @@ export fn addfile( child: io::file, source: (io::file | nullfd | closefd), ) void = { - append(cmd.files, (source, child)); + append(cmd.files, (source, child))!; }; // Closes all standard files (stdin, stdout, and stderr) in the child process. diff --git a/path/buffer.ha b/path/buffer.ha @@ -55,9 +55,9 @@ fn _local(path: str, buf: *[MAX]u8) str = { for (let byte .. bytes) { if (byte == '/') { - static append(buf, SEP); + static append(buf, SEP)!; } else { - static append(buf, byte); + static append(buf, byte)!; }; }; return strings::fromutf8(buf)!; diff --git a/regex/regex.ha b/regex/regex.ha @@ -157,7 +157,7 @@ fn handle_bracket( }; if (*bracket_idx == -1) { - append(charsets, []); + append(charsets, [])!; }; *bracket_idx += 1; @@ -181,7 +181,7 @@ fn handle_bracket( return `Trailing backslash '\'`: error; } else { append(charsets[len(charsets) - 1], - peek1: charset_lit_item); + peek1: charset_lit_item)!; strings::next(iter); *r_idx += 1; }; @@ -190,7 +190,7 @@ fn handle_bracket( idx = len(charsets) - 1, is_positive = *is_charset_positive, }; - append(insts, newinst); + append(insts, newinst)!; *in_bracket = false; *bracket_idx = -1; *is_charset_positive = true; @@ -203,7 +203,7 @@ fn handle_bracket( for (let cc_idx = 0z; cc_idx < n_cc; cc_idx += 1) { if (strings::hasprefix(rest, charclass_map[cc_idx].0)) { append(charsets[len(charsets) - 1], - charclass_map[cc_idx]); + charclass_map[cc_idx])!; *skip_charclass_rest = true; break; }; @@ -220,13 +220,13 @@ fn handle_bracket( }; append(charsets[len(charsets) - 1], - (start_b, end_b): charset_range_item); + (start_b, end_b): charset_range_item)!; strings::next(iter); strings::next(iter); *r_idx += 2; } else { append(charsets[len(charsets) - 1], - r: charset_lit_item); + r: charset_lit_item)!; }; *r_idx += 1; @@ -239,7 +239,7 @@ export fn compile(expr: str) (regex | error) = { let iter = strings::iter(expr); let r_idx = 0z; let jump_idxs: [][]size = []; - append(jump_idxs, []); + append(jump_idxs, [])!; defer free(jump_idxs); let in_bracket = false; let skip_charclass_rest = false; @@ -254,7 +254,7 @@ export fn compile(expr: str) (regex | error) = { const next = strings::next(&iter); if (r_idx == 0 && next is rune && next: rune != '^') { - append(insts, inst_skip); + append(insts, inst_skip)!; }; if (in_bracket) { @@ -283,7 +283,7 @@ export fn compile(expr: str) (regex | error) = { if (peek1 is done) { return `Trailing backslash '\'`: error; } else { - append(insts, (peek1 as rune): inst_lit); + append(insts, (peek1 as rune): inst_lit)!; r_idx += 1; }; case '^' => @@ -304,23 +304,23 @@ export fn compile(expr: str) (regex | error) = { }; strings::prev(&iter); }; - append(insts, true: inst_match); + append(insts, true: inst_match)!; case '[' => in_bracket = true; case ']' => - append(insts, r: inst_lit); + append(insts, r: inst_lit)!; case '(' => - append(insts, capture_idx: inst_groupstart); + append(insts, capture_idx: inst_groupstart)!; group_level += 1; capture_idx += 1; for (len(jump_idxs) < group_level + 1) { - append(jump_idxs, []); + append(jump_idxs, [])!; }; case ')' => if (group_level == 0) { return `Unmatched ')'`: error; }; - append(insts, inst_groupend); + append(insts, inst_groupend)!; for (let jump_idx .. jump_idxs[group_level]) { assert(insts[jump_idx] is inst_jump); insts[jump_idx] = (len(insts) - 1): inst_jump; @@ -328,7 +328,7 @@ export fn compile(expr: str) (regex | error) = { delete(jump_idxs[group_level][..]); group_level -= 1; case '|' => - append(insts, types::SIZE_MAX: inst_jump); + append(insts, types::SIZE_MAX: inst_jump)!; const origin = match (find_last_groupstart(insts)) { case error => yield 0z; @@ -339,7 +339,7 @@ export fn compile(expr: str) (regex | error) = { // add split after last jump (if any) or at origin const split_idx = if (len(jump_idxs[group_level]) > 0) jump_idxs[group_level][len(jump_idxs[group_level]) - 1] + 1 else origin; - insert(insts[split_idx], newinst); + insert(insts[split_idx], newinst)!; shift(insts[split_idx + 1..]); // our insertion of our split_idx should never interfere // with an existing jump_idx @@ -349,13 +349,13 @@ export fn compile(expr: str) (regex | error) = { // incremented assert(jump_idx < split_idx, `Found jump_idx interference. Please report this as a bug`); }; - append(jump_idxs[group_level], len(insts) - 1); + append(jump_idxs[group_level], len(insts) - 1)!; // add skip if it's a whole-expression alternation if (origin == 0) { const peek1 = strings::next(&iter); if (peek1 is rune) { if (peek1 as rune != '^') { - append(insts, inst_skip); + append(insts, inst_skip)!; }; strings::prev(&iter); }; @@ -379,7 +379,7 @@ export fn compile(expr: str) (regex | error) = { // advance to len(insts) + 1 to make space for the `inst_split` // advance to len(insts) + 2 to make space for the `inst_repeat` insert(insts[origin], - len(insts) + 2: inst_split); + len(insts) + 2: inst_split)!; shift(insts[origin + 1..]); origin += 1; }; @@ -393,7 +393,7 @@ export fn compile(expr: str) (regex | error) = { strings::next(&iter); r_idx += 1; }; - append(insts, newinst); + append(insts, newinst)!; n_reps += 1; case '?' => if (r_idx == 0 || len(insts) == 0) { @@ -411,7 +411,7 @@ export fn compile(expr: str) (regex | error) = { return `Misused '?'`: error; }; const after_idx = len(insts) + 1; - insert(insts[term_start_idx], after_idx: inst_split); + insert(insts[term_start_idx], after_idx: inst_split)!; shift(insts[term_start_idx + 1..]); case '*' => if (r_idx == 0 || len(insts) == 0) { @@ -433,9 +433,9 @@ export fn compile(expr: str) (regex | error) = { }; const split_idx = term_start_idx; term_start_idx += new_inst_offset; - insert(insts[split_idx], after_idx: inst_split); + insert(insts[split_idx], after_idx: inst_split)!; shift(insts[split_idx + 1..]); - append(insts, split_idx: inst_jump); + append(insts, split_idx: inst_jump)!; case '+' => if (r_idx == 0 || len(insts) == 0) { return `Unused '+'`: error; @@ -451,11 +451,11 @@ export fn compile(expr: str) (regex | error) = { case => return `Misused '+'`: error; }; - append(insts, term_start_idx: inst_split); + append(insts, term_start_idx: inst_split)!; case '.' => - append(insts, inst_any); + append(insts, inst_any)!; case => - append(insts, r: inst_lit); + append(insts, r: inst_lit)!; }; was_prev_rune_pipe = (r == '|'); r_idx += 1; @@ -468,7 +468,7 @@ export fn compile(expr: str) (regex | error) = { }; if (len(insts) == 0 || !(insts[len(insts) - 1] is inst_match)) { - append(insts, false: inst_match); + append(insts, false: inst_match)!; }; return regex { @@ -566,10 +566,10 @@ fn add_thread(threads: *[]thread, parent_idx: size, new_pc: size) void = { start_bytesize = threads[parent_idx].start_bytesize, matched = threads[parent_idx].matched, failed = threads[parent_idx].failed, - captures = alloc(threads[parent_idx].captures...), - rep_counters = alloc(threads[parent_idx].rep_counters...), + captures = alloc(threads[parent_idx].captures...)!, + rep_counters = alloc(threads[parent_idx].rep_counters...)!, ... - }); + })!; }; fn run_thread( @@ -623,7 +623,7 @@ fn run_thread( if (idx >= len(threads[i].captures)) { append(threads[i].captures, [capture { ... }...], - idx - len(threads[i].captures) + 1); + idx - len(threads[i].captures) + 1)!; }; assert(threads[i].captures[idx].end != types::SIZE_MAX); threads[i].captures[idx] = capture { @@ -737,9 +737,9 @@ fn search( ) (void | []capture) = { let threads: []thread = alloc([ thread { captures = [], ... } - ]); + ])!; if (re.n_reps > 0) { - threads[0].rep_counters = alloc([0...], re.n_reps); + threads[0].rep_counters = alloc([0...], re.n_reps)!; }; defer { for (let i = 0z; i < len(threads); i += 1) { @@ -800,12 +800,12 @@ fn search( case => void; }; }; - let res: result = alloc([], length); - static append(res, threads[best_idx].root_capture); - static append(res, threads[best_idx].captures...); + let res: result = alloc([], length)!; + static append(res, threads[best_idx].root_capture)!; + static append(res, threads[best_idx].captures...)!; if (length != len(res)) { static append(res, [capture { ... }...], - length - len(res)); + length - len(res))!; }; return res; }; @@ -908,7 +908,7 @@ export fn findall(re: *regex, string: str) []result = { str_bytes[str_bytesize..]); match (search(re, substring, &strm, true)) { case let m: []capture => - append(res, m); + append(res, m)!; m[0].start += str_idx; m[0].end += str_idx; m[0].start_bytesize += str_bytesize; @@ -972,24 +972,24 @@ export fn replacen( defer result_freeall(matches); const bytes = strings::toutf8(string); - let buf = alloc(bytes[..matches[0][0].start_bytesize]...); + let buf = alloc(bytes[..matches[0][0].start_bytesize]...)!; const n = if (len(matches) > n) n else len(matches); for (let i = 0z; i < n; i += 1) { for (let j = 0z; j < len(target); j += 1) { match (target[j]) { case let b: []u8 => - append(buf, b...); + append(buf, b...)!; case let z: size => if (z >= len(matches[i])) yield; const b = strings::toutf8(matches[i][z].content); - append(buf, b...); + append(buf, b...)!; }; }; const start = matches[i][0].end_bytesize; const end = if (i == n - 1) len(bytes) else matches[i + 1][0].start_bytesize; - append(buf, bytes[start..end]...); + append(buf, bytes[start..end]...)!; }; return strings::fromutf8(buf)!; @@ -997,19 +997,19 @@ export fn replacen( fn parse_replace_target(targetstr: str) ([]([]u8 | size) | error) = { const bytes = strings::toutf8(targetstr); - let target: []([]u8 | size) = alloc([], 1); + let target: []([]u8 | size) = alloc([], 1)!; let iter = strings::iter(targetstr); let start = 0z, end = 0z; for (true) match (strings::next(&iter)) { case done => if (start != end) { - append(target, bytes[start..]); + append(target, bytes[start..])!; }; break; case let r: rune => if (r == '\\') { if (start != end) { - append(target, bytes[start..end]); + append(target, bytes[start..end])!; }; const r = match (strings::next(&iter)) { @@ -1021,9 +1021,9 @@ fn parse_replace_target(targetstr: str) ([]([]u8 | size) | error) = { }; if (r == '\\') { - append(target, '\\'); + append(target, '\\')!; } else if (ascii::isdigit(r)) { - append(target, r: u32: size - 0x30); + append(target, r: u32: size - 0x30)!; } else { free(target); return "Backslash must be followed by positive decimal number or a backslash": error; @@ -1064,16 +1064,16 @@ export fn rawreplacen(re: *regex, string: str, targetstr: str, n: size) str = { const bytes = strings::toutf8(string); let buf: []u8 = []; - append(buf, bytes[..matches[0][0].start_bytesize]...); + append(buf, bytes[..matches[0][0].start_bytesize]...)!; const n = if (len(matches) > n) n else len(matches); for (let i = 1z; i < n; i += 1) { - append(buf, target...); + append(buf, target...)!; const start = matches[i - 1][0].end_bytesize; const end = matches[i][0].start_bytesize; - append(buf, bytes[start..end]...); + append(buf, bytes[start..end]...)!; }; - append(buf, target...); - append(buf, bytes[matches[n - 1][0].end_bytesize..]...); + append(buf, target...)!; + append(buf, bytes[matches[n - 1][0].end_bytesize..]...)!; return strings::fromutf8(buf)!; }; diff --git a/rt/abort.ha b/rt/abort.ha @@ -31,12 +31,10 @@ export @symbol("rt.abort") fn _abort( const reasons: [_]str = [ "slice or array access out of bounds", // 0 "type assertion failed", // 1 - "out of memory", // 2 - "static insert/append exceeds slice capacity", // 3 - "execution reached unreachable code (compiler bug)", // 4 - "slice allocation capacity smaller than initializer", // 5 - "assertion failed", // 6 - "error occurred", // 7 + "execution reached unreachable code (compiler bug)", // 2 + "slice allocation capacity smaller than initializer", // 3 + "assertion failed", // 4 + "error occurred", // 5 ]; export fn abort_fixed(path: *str, line: u64, col: u64, i: u64) void = { diff --git a/rt/ensure.ha b/rt/ensure.ha @@ -7,33 +7,43 @@ export type slice = struct { capacity: size, }; -export fn ensure(s: *slice, membsz: size) void = { - let capacity = s.capacity; - if (capacity >= s.length) { - return; +export fn ensure(s: *slice, membsz: size) bool = { + let cap = s.capacity; + if (cap >= s.length) { + return true; }; - for (capacity < s.length) { - assert(capacity >= s.capacity, "slice out of memory (overflow)"); - if (capacity == 0) { - capacity = s.length; + for (cap < s.length) { + assert(cap >= s.capacity, "slice out of memory (overflow)"); + if (cap == 0) { + cap = s.length; } else { - capacity *= 2; + cap *= 2; + }; + }; + s.capacity = cap; + let data = realloc(s.data, s.capacity * membsz); + if (data == null) { + if (s.capacity * membsz == 0) { + s.data = null; + return true; + } else { + return false; }; }; - s.capacity = capacity; - const data = realloc(s.data, s.capacity * membsz); - assert(data != null || s.capacity * membsz == 0); s.data = data; + return true; }; export fn unensure(s: *slice, membsz: size) void = { - let capacity = s.capacity; - for (capacity > s.length) { - capacity /= 2; + let cap = s.capacity; + for (cap > s.length) { + cap /= 2; + }; + cap *= 2; + s.capacity = cap; + let data = realloc(s.data, s.capacity * membsz); + + if (data != null || s.capacity * membsz == 0) { + s.data = data; }; - capacity *= 2; - s.capacity = capacity; - const data = realloc(s.data, s.capacity * membsz); - assert(data != null || s.capacity * membsz == 0); - s.data = data; }; diff --git a/rt/u64tos.ha b/rt/u64tos.ha @@ -6,10 +6,10 @@ def U64_BUFSZ = 20; fn u64tos(buf: []u8, u: u64) str = { let sl = buf[..0]; if (u == 0) { - static append(sl, '0'); + static append(sl, '0')!; }; for (u > 0) { - static append(sl, (u % 10): u8 + '0'); + static append(sl, (u % 10): u8 + '0')!; u /= 10; }; for (let s = 0z, e = len(sl) - 1; s < e) { diff --git a/rt/unknown_errno.ha b/rt/unknown_errno.ha @@ -7,17 +7,17 @@ fn unknown_errno(err: errno) str = { let sl = buf[..0]; const s = *(&"[unknown errno ": *[]u8); - static append(sl, s...); + static append(sl, s...)!; if (err < 0) { - static append(sl, '-'); + static append(sl, '-')!; const s = u64tos(ubuf, -err: u64); - static append(sl, *(&s: *[]u8)...); - static append(sl, ']'); + static append(sl, *(&s: *[]u8)...)!; + static append(sl, ']')!; } else { const s = u64tos(ubuf, err: u64); - static append(sl, *(&s: *[]u8)...); - static append(sl, ']'); + static append(sl, *(&s: *[]u8)...)!; + static append(sl, ']')!; }; return *(&sl: *str); diff --git a/shlex/split.ha b/shlex/split.ha @@ -35,7 +35,7 @@ export fn split(in: const str) ([]str | syntaxerr) = { }; if (!first) { const item = memio::string(&s)!; - append(slice, strings::dup(item)); + append(slice, strings::dup(item))!; memio::reset(&s); }; dirty = false; @@ -56,7 +56,7 @@ export fn split(in: const str) ([]str | syntaxerr) = { if (dirty) { const item = memio::string(&s)!; - append(slice, strings::dup(item)); + append(slice, strings::dup(item))!; }; return slice; diff --git a/sort/+test.ha b/sort/+test.ha @@ -65,7 +65,7 @@ use types; }; @test fn big_equal() void = { - let nums = alloc([42...], 1000000); + let nums = alloc([42...], 1000000)!; defer free(nums); sort(nums, size(int), &cmp::ints); for (let i = 0z; i < len(nums); i += 1) { @@ -74,7 +74,7 @@ use types; }; @test fn big_random() void = { - let nums = alloc([0...], 100000); + let nums = alloc([0...], 100000)!; defer free(nums); let rand = random::init(0x424242); diff --git a/sort/sort.ha b/sort/sort.ha @@ -89,11 +89,11 @@ type run = struct { fn powersort(items: []opaque, itemsz: size, cmp: *cmpfunc) void = { // npowers = floor(log2(n)) + 1 const npowers = math::bit_size(len(items)) + 1; - const runs: []run = alloc([run { start = EMPTY, ... }...], npowers + 1); + const runs: []run = alloc([run { start = EMPTY, ... }...], npowers + 1)!; defer free(runs); let top = 0u8; - const aux: []u8 = alloc([0...], len(items) * itemsz); + const aux: []u8 = alloc([0...], len(items) * itemsz)!; defer free(aux); let a = run { diff --git a/strings/concat.ha b/strings/concat.ha @@ -8,9 +8,9 @@ export fn concat(strs: str...) str = { z += len(s); }; - let new: []u8 = alloc([], z); + let new: []u8 = alloc([], z)!; for (let s .. strs) { - static append(new, toutf8(s)...); + static append(new, toutf8(s)...)!; }; return fromutf8_unsafe(new); }; @@ -51,11 +51,11 @@ export fn join(delim: str, strs: str...) str = { z += len(delim); }; }; - let new: []u8 = alloc([], z); + let new: []u8 = alloc([], z)!; for (let i = 0z; i < len(strs); i += 1) { - static append(new, toutf8(strs[i])...); + static append(new, toutf8(strs[i])...)!; if (i + 1 < len(strs)) { - static append(new, toutf8(delim)...); + static append(new, toutf8(delim)...)!; }; }; return fromutf8_unsafe(new); diff --git a/strings/dup.ha b/strings/dup.ha @@ -12,7 +12,7 @@ export fn dup(s: const str) str = { case let b: *[*]u8 => yield b; }; - let buf: []u8 = alloc(id[..in.length], in.length); + let buf: []u8 = alloc(id[..in.length], in.length)!; let out = types::string { data = buf: *[*]u8, length = in.length, @@ -24,9 +24,9 @@ export fn dup(s: const str) str = { // Creates a copy of a []str slice with all the strings duplicated. The result // must be freed using [[freeall]]. export fn dupall(strs: []str) []str = { - let newsl: []str = alloc([], len(strs)); + let newsl: []str = alloc([], len(strs))!; for (let s .. strs) { - static append(newsl, dup(s)); + static append(newsl, dup(s))!; }; return newsl; }; diff --git a/strings/pad.ha b/strings/pad.ha @@ -9,11 +9,11 @@ export fn lpad(s: str, p: rune, maxlen: size) str = { if (len(s) >= maxlen) { return dup(s); }; - let res: []u8 = alloc([], maxlen); + let res: []u8 = alloc([], maxlen)!; for (let i = 0z; i < maxlen - len(s); i += 1) { - append(res, utf8::encoderune(p)...); + append(res, utf8::encoderune(p)...)!; }; - append(res, toutf8(s)...); + append(res, toutf8(s)...)!; return fromutf8_unsafe(res[..maxlen]); }; @@ -37,10 +37,10 @@ export fn rpad(s: str, p: rune, maxlen: size) str = { if (len(s) >= maxlen) { return dup(s); }; - let res: []u8 = alloc([], maxlen); - append(res, toutf8(s)...); + let res: []u8 = alloc([], maxlen)!; + append(res, toutf8(s)...)!; for (let i = 0z; i < maxlen - len(s); i += 1) { - append(res, utf8::encoderune(p)...); + append(res, utf8::encoderune(p)...)!; }; return fromutf8_unsafe(res[..maxlen]); }; diff --git a/strings/replace.ha b/strings/replace.ha @@ -27,8 +27,8 @@ export fn multireplace(s: str, repls: (str, str)...) str = { for (let (replace, with) .. repls) { const replb = (toutf8(replace), toutf8(with)); if (bytes::hasprefix(b[i..], replb.0)) { - append(res, b[prev..i]...); - append(res, replb.1...); + append(res, b[prev..i]...)!; + append(res, replb.1...)!; i += len(replb.0); prev = i; continue :step; @@ -36,7 +36,7 @@ export fn multireplace(s: str, repls: (str, str)...) str = { }; i += 1; }; - append(res, b[prev..i]...); + append(res, b[prev..i]...)!; return fromutf8_unsafe(res); }; diff --git a/strings/runes.ha b/strings/runes.ha @@ -9,7 +9,7 @@ export fn torunes(s: str) []rune = { let sl: []rune = []; let iter = iter(s); for (let r => next(&iter)) { - append(sl, r); + append(sl, r)!; }; return sl; }; @@ -19,7 +19,7 @@ export fn fromrunes(runes: []rune) str = { let bytes: []u8 = []; for (let r .. runes) { const bs = utf8::encoderune(r); - append(bytes, bs...); + append(bytes, bs...)!; }; return fromutf8_unsafe(bytes); }; diff --git a/strings/template/template.ha b/strings/template/template.ha @@ -39,7 +39,7 @@ export fn compile(input: str) (template | invalid) = { } else { strings::prev(&iter); const lit = memio::string(&buf)!; - append(instrs, strings::dup(lit): literal); + append(instrs, strings::dup(lit): literal)!; memio::reset(&buf); parse_variable(&instrs, &iter, &buf)?; @@ -54,7 +54,7 @@ export fn compile(input: str) (template | invalid) = { if (len(memio::string(&buf)!) != 0) { const lit = memio::string(&buf)!; - append(instrs, strings::dup(lit): literal); + append(instrs, strings::dup(lit): literal)!; }; return instrs; @@ -149,7 +149,7 @@ fn parse_variable( }; const var = memio::string(buf)!; - append(instrs, strings::dup(var): variable); + append(instrs, strings::dup(var): variable)!; memio::reset(buf); }; diff --git a/strings/tokenize.ha b/strings/tokenize.ha @@ -170,7 +170,7 @@ export fn splitn(in: str, delim: str, n: size) []str = { for (let i = 0z; i < n - 1z; i += 1) { match (next_token(&tok)) { case let s: str => - append(toks, s); + append(toks, s)!; case done => return toks; }; @@ -178,7 +178,7 @@ export fn splitn(in: str, delim: str, n: size) []str = { match(peek_token(&tok)) { case done => void; case let s: str => - append(toks, remaining_tokens(&tok)); + append(toks, remaining_tokens(&tok))!; }; return toks; }; @@ -194,7 +194,7 @@ export fn rsplitn(in: str, delim: str, n: size) []str = { for (let i = 0z; i < n - 1z; i += 1) { match (next_token(&tok)) { case let s: str => - append(toks, s); + append(toks, s)!; case done => return toks; }; @@ -202,7 +202,7 @@ export fn rsplitn(in: str, delim: str, n: size) []str = { match(peek_token(&tok)) { case done => void; case let s: str => - append(toks, remaining_tokens(&tok)); + append(toks, remaining_tokens(&tok))!; }; for (let i = 0z; i < len(toks) / 2; i += 1) { diff --git a/test/+test.ha b/test/+test.ha @@ -99,11 +99,11 @@ export @symbol("__test_main") fn main() size = { let enabled_tests: []test = []; defer free(enabled_tests); if (len(os::args) == 1) { - append(enabled_tests, tests...); + append(enabled_tests, tests...)!; } else for (let i = 0z; i < ntest; i += 1) { for (let arg .. os::args) { if (fnmatch::fnmatch(arg, tests[i].name)) { - append(enabled_tests, tests[i]); + append(enabled_tests, tests[i])!; break; }; }; @@ -263,7 +263,7 @@ fn do_test(ctx: *context, test: test) void = { test = test.name, stdout = stdout, stderr = stderr, - }); + })!; } else { free(stdout); free(stderr); @@ -339,7 +339,7 @@ fn interpret_status(ctx: *context, test: str, status: status) bool = { ... }, trace = 0, - }); + })!; return true; } else { styled_print(92, "PASS"); @@ -355,7 +355,7 @@ fn interpret_status(ctx: *context, test: str, status: status) bool = { test = test, reason = reason, trace = trace, - }); + })!; return true; }; case status::SKIP => @@ -363,7 +363,7 @@ fn interpret_status(ctx: *context, test: str, status: status) bool = { append(ctx.skipped, skipped { test = test, reason = reason.msg, - }); + })!; return false; case status::SEGV => styled_print(91, "FAIL"); @@ -374,7 +374,7 @@ fn interpret_status(ctx: *context, test: str, status: status) bool = { ... }, trace = trace, - }); + })!; return true; }; }; diff --git a/time/chrono/leapsec.ha b/time/chrono/leapsec.ha @@ -73,7 +73,7 @@ fn parse_utc_leapsecs(h: io::handle) (void | utf8::invalid | io::error) = { let secs = secs as i64 - SECS_1900_1970; let diff = diff as i64; - append(utc_leapsecs, (secs, diff)); + append(utc_leapsecs, (secs, diff))!; }; }; diff --git a/time/chrono/timescale.ha b/time/chrono/timescale.ha @@ -43,7 +43,7 @@ export fn convert(i: time::instant, tscs: *timescale...) (time::instant | analyt // try .convto match (a.convto(b, t)) { case let convs: []time::instant => - append(tmps, convs...); + append(tmps, convs...)!; continue; case void => void; }; @@ -51,7 +51,7 @@ export fn convert(i: time::instant, tscs: *timescale...) (time::instant | analyt // try .convfrom match (b.convfrom(a, t)) { case let convs: []time::instant => - append(tmps, convs...); + append(tmps, convs...)!; continue; case void => void; }; @@ -62,7 +62,7 @@ export fn convert(i: time::instant, tscs: *timescale...) (time::instant | analyt for (let conv .. convs) { append(tmps, ( b.convfrom(&tai, conv) as []time::instant - )...); + )...)!; }; }; @@ -88,7 +88,7 @@ export const tai: timescale = timescale { fn tai_conv(ts: *timescale, i: time::instant) ([]time::instant | void) = { if (ts == &tai) { - return alloc([i]...); + return alloc([i]...)!; }; }; @@ -112,7 +112,7 @@ export const utc: timescale = timescale { fn utc_convto(ts: *timescale, i: time::instant) ([]time::instant | void) = { if (ts == &utc) { - return alloc([i]...); + return alloc([i]...)!; } else if (ts == &tai) { let ret: []time::instant = []; if (!utc_isinitialized) { @@ -129,7 +129,7 @@ fn utc_convto(ts: *timescale, i: time::instant) ([]time::instant | void) = { append(ret, time::instant { sec = i.sec + firstleap.1, nsec = i.nsec, - }); + })!; return ret; }; @@ -150,7 +150,7 @@ fn utc_convto(ts: *timescale, i: time::instant) ([]time::instant | void) = { append(ret, time::instant { sec = i.sec + leapoffset, nsec = i.nsec, - }); + })!; return ret; }; @@ -164,7 +164,7 @@ fn utc_convto(ts: *timescale, i: time::instant) ([]time::instant | void) = { sec = i.sec + leapoffset, nsec = i.nsec, }, - ]...); + ]...)!; return ret; }; @@ -177,7 +177,7 @@ fn utc_convto(ts: *timescale, i: time::instant) ([]time::instant | void) = { append(ret, time::instant { sec = i.sec + leapoffset, nsec = i.nsec, - }); + })!; return ret; }; @@ -193,7 +193,7 @@ fn utc_convto(ts: *timescale, i: time::instant) ([]time::instant | void) = { fn utc_convfrom(ts: *timescale, i: time::instant) ([]time::instant | void) = { if (ts == &utc) { - return alloc([i]...); + return alloc([i]...)!; } else if (ts == &tai) { let ret: []time::instant = []; if (!utc_isinitialized) { @@ -210,7 +210,7 @@ fn utc_convfrom(ts: *timescale, i: time::instant) ([]time::instant | void) = { append(ret, time::instant { sec = i.sec - firstleap.1, nsec = i.nsec, - }); + })!; return ret; }; @@ -231,7 +231,7 @@ fn utc_convfrom(ts: *timescale, i: time::instant) ([]time::instant | void) = { append(ret, time::instant { sec = i.sec - leapoffset, nsec = i.nsec, - }); + })!; return ret; }; @@ -244,7 +244,7 @@ fn utc_convfrom(ts: *timescale, i: time::instant) ([]time::instant | void) = { append(ret, time::instant { sec = i.sec - leapoffset, nsec = i.nsec, - }); + })!; return ret; }; @@ -273,17 +273,17 @@ def GPS_OFFSET: time::duration = -19 * time::SECOND; fn gps_convto(ts: *timescale, i: time::instant) ([]time::instant | void) = { if (ts == &gps) { - return alloc([i]...); + return alloc([i]...)!; } else if (ts == &tai) { - return alloc([time::add(i, -GPS_OFFSET)]...); + return alloc([time::add(i, -GPS_OFFSET)]...)!; }; }; fn gps_convfrom(ts: *timescale, i: time::instant) ([]time::instant | void) = { if (ts == &gps) { - return alloc([i]...); + return alloc([i]...)!; } else if (ts == &tai) { - return alloc([time::add(i, GPS_OFFSET)]...); + return alloc([time::add(i, GPS_OFFSET)]...)!; }; }; @@ -306,18 +306,18 @@ def TT_OFFSET: time::duration = 32184 * time::MILLISECOND; // 32.184 seconds fn tt_convto(ts: *timescale, i: time::instant) ([]time::instant | void) = { if (ts == &tt) { - return alloc([i]...); + return alloc([i]...)!; } else if (ts == &tai) { - return alloc([time::add(i, -TT_OFFSET)]...); + return alloc([time::add(i, -TT_OFFSET)]...)!; }; }; fn tt_convfrom(ts: *timescale, i: time::instant) ([]time::instant | void) = { if (ts == &tt) { - return alloc([i]...); + return alloc([i]...)!; } else if (ts == &tai) { - return alloc([time::add(i, TT_OFFSET)]...); + return alloc([time::add(i, TT_OFFSET)]...)!; }; }; @@ -358,7 +358,7 @@ def DELTA_JANSIX_ADJUSTMENT: time::duration = 82944 * time::MILLISECOND; fn mtc_convto(ts: *timescale, i: time::instant) ([]time::instant | void) = { let ret: []time::instant = []; if (ts == &mtc) { - return alloc([i]...); + return alloc([i]...)!; } else if (ts == &tai) { // Change epoch from that of the Mars Sol Date // to the Earth-Mars convergence date 2000 Jan 6th. @@ -376,13 +376,13 @@ fn mtc_convto(ts: *timescale, i: time::instant) ([]time::instant | void) = { // Get the TAI time. // assertion since TT and TAI are continuous. - return alloc([(tt.convto(&tai, i) as []time::instant)[0]]...); + return alloc([(tt.convto(&tai, i) as []time::instant)[0]]...)!; }; }; fn mtc_convfrom(ts: *timescale, i: time::instant) ([]time::instant | void) = { if (ts == &mtc) { - return alloc([i]...); + return alloc([i]...)!; } else if (ts == &tai) { // Get the "Terrestrial Time". // assertion since TT and TAI are continuous. @@ -400,7 +400,7 @@ fn mtc_convfrom(ts: *timescale, i: time::instant) ([]time::instant | void) = { i = time::add(i, -DELTA_JANSIX_ADJUSTMENT); // Change epoch to that of the Mars Sol Date. - return alloc([time::add(i, DELTA_MARSEPOCH_JANSIX)]...); + return alloc([time::add(i, DELTA_MARSEPOCH_JANSIX)]...)!; }; }; diff --git a/time/chrono/timezone.ha b/time/chrono/timezone.ha @@ -166,7 +166,7 @@ export fn fixedzone(ts: *timescale, daylen: time::duration, z: zone) timezone = name = z.name, timescale = ts, daylength = daylen, - zones = alloc([z]), + zones = alloc([z])!, transitions = [], posix_extend = "", }; diff --git a/time/chrono/tzdb.ha b/time/chrono/tzdb.ha @@ -52,7 +52,7 @@ export fn tz(name: str) (locality | tzdberror) = { timescale = &utc, daylength = EARTH_DAY, ... - }); + })!; match (load_tzif(&bufstrm, loc)) { case void => io::close(&bufstrm)?; @@ -193,7 +193,7 @@ fn load_tzif(h: io::handle, tz: *timezone) (void | invalidtzif | io::error) = { if (buf1[0] == 0x0) { // cannot contain NUL return invalidtzif; }; - append(footerdata, buf1...); + append(footerdata, buf1...)!; }; const posix_extend = strings::dup(match (strings::fromutf8(footerdata)) { case let s: str => @@ -250,7 +250,7 @@ fn load_tzif(h: io::handle, tz: *timezone) (void | invalidtzif | io::error) = { }; zone.abbr = strings::dup(abbr); - append(zones, zone); + append(zones, zone)!; }; // assemble transitions @@ -272,7 +272,7 @@ fn load_tzif(h: io::handle, tz: *timezone) (void | invalidtzif | io::error) = { // stdwalldata and normlocaldata have been omitted, // until they show their utility. - append(transitions, tx); + append(transitions, tx)!; }; // commit and return data @@ -301,7 +301,7 @@ fn readbytes( for (let i = 0z; i < n; i += 1) { mustread(h, buf)?; const it = buf[0]; - append(items, it); + append(items, it)!; }; }; @@ -314,7 +314,7 @@ fn readitems8( for (let i = 0z; i < n; i += 1) { mustread(h, buf)?; const it = endian::begetu64(buf): i64; - append(items, it); + append(items, it)!; }; }; @@ -327,6 +327,6 @@ fn readitems4( for (let i = 0z; i < n; i += 1) { mustread(h, buf)?; const it = endian::begetu32(buf): i64; - append(items, it); + append(items, it)!; }; }; diff --git a/time/date/virtual.ha b/time/date/virtual.ha @@ -498,7 +498,7 @@ fn realize_validzoffs( case size => void; case void => - append(dates, d); + append(dates, d)!; sort::sort(dates, size(date), &cmpdates); }; case invalid => @@ -521,7 +521,7 @@ fn realize_validzoffs( case size => void; case void => - append(dates, d); + append(dates, d)!; sort::sort(dates, size(date), &cmpdates); }; case invalid => diff --git a/types/c/strings.ha b/types/c/strings.ha @@ -60,7 +60,7 @@ export fn tostrn(cstr: *const char, length: size) (const str | utf8::invalid) = // Converts a Hare string to a C string. The result is allocated; the caller // must free it when they're done. export fn fromstr(s: const str) *char = { - let slice: []char = alloc([0...], len(s) + 1); + let slice: []char = alloc([0...], len(s) + 1)!; return fromstr_buf(s, slice); }; diff --git a/unix/hosts/hosts.ha b/unix/hosts/hosts.ha @@ -55,7 +55,7 @@ export fn next(rd: *reader) (host | done | error) = { if (len(tok) == 0) { continue; }; - append(rd.names, tok); + append(rd.names, tok)!; }; if (len(rd.names) == 0) { @@ -87,7 +87,7 @@ fn _lookup(rd: *reader, name: const str) ([]ip::addr | error) = { for (const host => next(rd)?) { for (const cand .. host.names) { if (cand == name) { - append(addrs, host.addr); + append(addrs, host.addr)!; }; }; }; diff --git a/unix/passwd/group.ha b/unix/passwd/group.ha @@ -176,7 +176,7 @@ export fn getgroups(name: str) []grent = { for (const tok => strings::next_token(&tok)) { if (tok == name) { grent_dup(&ent); - append(groups, ent); + append(groups, ent)!; }; }; }; diff --git a/unix/resolvconf/load.ha b/unix/resolvconf/load.ha @@ -59,13 +59,13 @@ fn parse(conf: *config, in: io::handle) (void | error) = { for (const param => next(&rd)!) { switch (param.name) { case "nameserver" => - append(conf.nameservers, param.value as ip::addr); + append(conf.nameservers, param.value as ip::addr)!; case "search" => strings::freeall(conf.search); conf.search = strings::dupall(param.value as []str); case "sortlist" => free(conf.sortlist); - conf.sortlist = alloc((param.value as []ip::subnet)...); + conf.sortlist = alloc((param.value as []ip::subnet)...)!; case "options" => conf.options = *(param.value as *options); case => void; diff --git a/unix/resolvconf/reader.ha b/unix/resolvconf/reader.ha @@ -99,7 +99,7 @@ fn parse_subnet_list(rd: *reader, tok: *strings::tokenizer) (value | error) = { }; const subnet = ip::parsecidr(tok)?; - append(rd.subnet_list, subnet); + append(rd.subnet_list, subnet)!; }; return rd.subnet_list; @@ -112,7 +112,7 @@ fn parse_str_list(rd: *reader, tok: *strings::tokenizer) (value | error) = { if (len(tok) == 0) { continue; }; - append(rd.str_list, tok); + append(rd.str_list, tok)!; }; return rd.str_list; diff --git a/wordexp/wordexp.ha b/wordexp/wordexp.ha @@ -55,7 +55,7 @@ export fn wordexp(s: str, flags: flag = flag::NONE) ([]str | error) = { match (bufio::scan_string(&scan, "\0")?) { case io::EOF => break; case let word: const str => - append(words, strings::dup(word)); + append(words, strings::dup(word))!; }; };