commit 07c4c8efb39a29d5accfdd79a0581930e697104e
parent 8164df021f0deedbbc245f3e484ee9d3e478745c
Author: Lorenz (xha) <me@xha.li>
Date: Sat, 30 Mar 2024 07:45:31 +0100
for-each changes
implement for-each for the parser, ast and add the done type to
hare::types::
also change a lot of modules to make use of for-each.
breaking changes:
* "done" cannot be used as a name anymore
* io::EOF is now a done type alias, which means that most stuff
using it can be converted to for-each a iterator loop.
* strings::next() and strings::prev() return done instead of void
* glob::next() returns done instead of void
* path::nextiter() returns done instead of void
* fs::next() returns done instead of void
Signed-off-by: Lorenz (xha) <me@xha.li>
Diffstat:
111 files changed, 1072 insertions(+), 1231 deletions(-)
diff --git a/ascii/string.ha b/ascii/string.ha
@@ -19,9 +19,7 @@ export fn strlower(s: str) str = {
// to fit the entire string.
export fn strlower_buf(s: str, buf: []u8) str = {
let it = strings::iter(s);
- for (true) match (strings::next(&it)) {
- case void => break;
- case let r: rune =>
+ for (let r => strings::next(&it)) {
static append(buf, utf8::encoderune(tolower(r))...);
};
return strings::fromutf8(buf)!;
@@ -41,9 +39,7 @@ export fn strupper(s: str) str = {
// to fit the entire string.
export fn strupper_buf(s: str, buf: []u8) str = {
let it = strings::iter(s);
- for (true) match (strings::next(&it)) {
- case void => break;
- case let r: rune =>
+ for (let r => strings::next(&it)) {
static append(buf, utf8::encoderune(toupper(r))...);
};
return strings::fromutf8(buf)!;
diff --git a/ascii/valid.ha b/ascii/valid.ha
@@ -8,9 +8,9 @@ export fn valid(c: rune) bool = c: u32 <= 0o177;
// Returns true if all runes in a string are valid ASCII characters.
export fn validstr(s: str) bool = {
- const s = strings::toutf8(s);
- for (let i = 0z; i < len(s); i += 1) {
- if (s[i] >= 0o200) {
+ const bytes = strings::toutf8(s);
+ for (let byte .. bytes) {
+ if (byte >= 0o200) {
return false;
};
};
diff --git a/cmd/genoiddb/main.ha b/cmd/genoiddb/main.ha
@@ -33,8 +33,8 @@ export fn main() void = {
write_db(os::stdout, oids)!;
fmt::println("\tnames = [")!;
- for (let i = 0z; i < len(oids); i += 1) {
- fmt::printfln("\t\t\"{}\",", oids[i].name)!;
+ for (let oid .. oids) {
+ fmt::printfln("\t\t\"{}\",", oid.name)!;
};
fmt::println("\t],")!;
fmt::println("};\n")!;
@@ -53,20 +53,12 @@ fn parse_oids() []entry = {
defer bufio::finish(&s);
let oids: []entry = [];
- for (true) {
- const l = match (bufio::scan_line(&s)!) {
- case io::EOF =>
- break;
- case let s: const str =>
- yield s;
- };
-
- if (l == "" || strings::hasprefix(l, '#')) {
+ for (let line => bufio::scan_line(&s)!) {
+ if (line == "" || strings::hasprefix(line, '#')) {
continue;
};
-
- const p = strings::split(l, " ");
+ const p = strings::split(line, " ");
defer free(p);
const name = p[0];
const val = p[len(p)-1];
@@ -82,9 +74,9 @@ fn parse_oids() []entry = {
};
fn free_oids(oids: []entry) void = {
- for (let i = 0z; i < len(oids); i += 1) {
- free(oids[i].name);
- free(oids[i].val);
+ for (let oid .. oids) {
+ free(oid.name);
+ free(oid.val);
};
free(oids);
@@ -96,8 +88,7 @@ fn write_db(h: io::handle, oids: []entry) (void | io::error) = {
const maxcols = 12z;
let idx = 0z;
- for (let i = 0z; i < len(oids); i += 1) {
- let e = &oids[i];
+ for (let e .. oids) {
e.idx = idx;
let der = oidtoder(e.val);
@@ -105,9 +96,9 @@ fn write_db(h: io::handle, oids: []entry) (void | io::error) = {
insert(der[0], len(der): u8);
defer free(der);
- for (let j = 0z; j < len(der); j += 1) {
+ for (let byte .. der) {
fmt::print(if (idx % maxcols == 0) "\n\t\t" else " ")?;
- fmt::printf("0x{:.2x},", der[j])?;
+ fmt::printf("0x{:.2x},", byte)?;
idx += 1;
};
};
@@ -132,8 +123,7 @@ fn oidtoder(oid: str) []u8 = {
der[0] = nums[0]: u8 * 40 + nums[1]: u8;
let end = 1z;
- for (let i = 2z; i < len(nums); i += 1) {
- let n = nums[i];
+ for (let n .. nums) {
if (n == 0) {
insert(der[end], 0u8);
end = len(der);
@@ -162,13 +152,8 @@ fn oidtou64s(oid: str) []u64 = {
let nums = strings::tokenize(oid, ".");
let intnums: []u64 = [];
- for (true) {
- match (strings::next_token(&nums)) {
- case let s: str =>
- append(intnums, strconv::stou64(s)!);
- case void =>
- break;
- };
+ for (let s => strings::next_token(&nums)) {
+ append(intnums, strconv::stou64(s)!);
};
return intnums;
@@ -178,31 +163,26 @@ fn write_varname(h: io::handle, name: str) (void | io::error) = {
// assume that names are in ascii
let i = strings::iter(name);
let prevlow = false;
- for (true) {
- match (strings::next(&i)) {
- case void =>
- break;
- case let r: rune =>
- let r = if (r == '-') {
+ for (let r => strings::next(&i)) {
+ let r = if (r == '-') {
+ prevlow = false;
+ yield '_';
+ } else if (ascii::isdigit(r)) {
+ prevlow = true;
+ yield r;
+ } else if (ascii::isupper(r)) {
+ if (prevlow) {
+ fmt::fprint(h, "_")?;
prevlow = false;
- yield '_';
- } else if (ascii::isdigit(r)) {
- prevlow = true;
- yield r;
- } else if (ascii::isupper(r)) {
- if (prevlow) {
- fmt::fprint(h, "_")?;
- prevlow = false;
- };
- yield r;
- } else if (ascii::islower(r)) {
- prevlow = true;
- yield ascii::toupper(r);
- } else {
- fmt::fatalf("Unexpected character in oid name: {}", r);
};
-
- fmt::fprint(h, r)?;
+ yield r;
+ } else if (ascii::islower(r)) {
+ prevlow = true;
+ yield ascii::toupper(r);
+ } else {
+ fmt::fatalf("Unexpected character in oid name: {}", r);
};
+
+ fmt::fprint(h, r)?;
};
};
diff --git a/cmd/hare/arch.ha b/cmd/hare/arch.ha
@@ -47,9 +47,9 @@ fn set_arch_tags(tags: *[]str, a: *build::arch) void = {
};
fn get_arch(name: str) (*build::arch | unknown_arch) = {
- for (let i = 0z; i < len(arches); i += 1) {
- if (arches[i].name == name) {
- return &arches[i];
+ for (let arch &.. arches) {
+ if (arch.name == name) {
+ return arch;
};
};
return name: unknown_arch;
diff --git a/cmd/hare/build.ha b/cmd/hare/build.ha
@@ -53,8 +53,7 @@ fn build(name: str, cmd: *getopt::command) (void | error) = {
ctx.mode = build::output::SILENT;
};
- for (let i = 0z; i < len(cmd.opts); i += 1) {
- let opt = cmd.opts[i];
+ for (let opt .. cmd.opts) {
switch (opt.0) {
case 'a' =>
arch = get_arch(opt.1)?;
diff --git a/cmd/hare/build/gather.ha b/cmd/hare/build/gather.ha
@@ -54,10 +54,8 @@ fn gather_submodules(
let n = 0z;
let it = os::iter(path::string(buf))?;
defer fs::finish(it);
- for (true) match (module::next(it)?) {
- case void =>
- break;
- case let dir: fs::dirent =>
+
+ for (let dir => module::next(it)?) {
path::push(buf, dir.name)?;
defer path::pop(buf);
append(mod, dir.name);
diff --git a/cmd/hare/build/platform.ha b/cmd/hare/build/platform.ha
@@ -37,9 +37,9 @@ const platforms: [_]platform = [
];
export fn get_platform(name: str) (*platform | unknown_platform) = {
- for (let i = 0z; i < len(platforms); i += 1) {
- if (platforms[i].name == name) {
- return &platforms[i];
+ for (let platform &.. platforms) {
+ if (platform.name == name) {
+ return platform;
};
};
return name: unknown_platform;
diff --git a/cmd/hare/build/queue.ha b/cmd/hare/build/queue.ha
@@ -31,8 +31,8 @@ type job = struct {
export fn execute(ctx: *context) (str | error) = {
let q: []*task = [];
defer free(q);
- defer for (let i = 0z; i < len(q); i += 1) {
- free_task(q[i]);
+ defer for (let t .. q) {
+ free_task(t);
};
// stage::TD (typedef files) are generated by the SSA stage (harec)
@@ -77,9 +77,9 @@ fn task_cmp(a: const *opaque, b: const *opaque) int = {
fn queue(ctx: *context, q: *[]*task, kind: stage, idx: size) *task = {
// return already existing task to avoid creating duplicates
- for (let i = 0z; i < len(q); i += 1) {
- if (q[i].kind == kind && q[i].idx == idx) {
- return q[i];
+ for (let t .. *q) {
+ if (t.kind == kind && t.idx == idx) {
+ return t;
};
};
let t = alloc(task {
@@ -98,8 +98,7 @@ fn queue(ctx: *context, q: *[]*task, kind: stage, idx: size) *task = {
append(queue(ctx, q, kind - 1, idx).rdeps, t);
case stage::SSA =>
t.ndeps = len(ctx.mods[idx].deps);
- for (let i = 0z; i < t.ndeps; i += 1) {
- let dep_idx = ctx.mods[idx].deps[i].0;
+ for (let (dep_idx, _) .. ctx.mods[idx].deps) {
append(queue(ctx, q, stage::SSA, dep_idx).rdeps, t);
};
case stage::TD => abort();
@@ -173,9 +172,9 @@ fn run_task(ctx: *context, jobs: *[]job, t: *task) (bool | error) = {
};
case output::VVERBOSE =>
fmt::error(ctx.cmds[t.kind])?;
- for (let i = 0z; i < len(args); i += 1) {
+ for (let arg .. args) {
fmt::error(" ")?;
- shlex::quote(os::stderr, args[i])?;
+ shlex::quote(os::stderr, arg)?;
};
fmt::errorln()?;
};
diff --git a/cmd/hare/build/types.ha b/cmd/hare/build/types.ha
@@ -37,8 +37,8 @@ export type task = struct {
};
export fn free_task(t: *task) void = {
- for (let i = 0z; i < len(t.rdeps); i += 1) {
- t.rdeps[i].ndeps -= 1;
+ for (let rdep &.. t.rdeps) {
+ rdep.ndeps -= 1;
};
free(t.rdeps);
free(t);
@@ -96,12 +96,12 @@ export type context = struct {
export fn ctx_finish(ctx: *context) void = {
free(ctx.ctx.tags);
- for (let i = 0z; i < len(ctx.defines); i += 1) {
- ast::ident_free(ctx.defines[i].ident);
- ast::type_finish(ctx.defines[i]._type);
- free(ctx.defines[i]._type);
- ast::expr_finish(ctx.defines[i].init);
- free(ctx.defines[i].init);
+ for (let define .. ctx.defines) {
+ ast::ident_free(define.ident);
+ ast::type_finish(define._type);
+ free(define._type);
+ ast::expr_finish(define.init);
+ free(define.init);
};
free(ctx.defines);
free(ctx.libdirs);
diff --git a/cmd/hare/build/util.ha b/cmd/hare/build/util.ha
@@ -48,8 +48,8 @@ fn get_deps(ctx: *context, t: *task) []str = {
case stage::TD => abort();
case stage::SSA =>
let deps = strings::dupall(mod.srcs.ha);
- for (let i = 0z; i < len(mod.deps); i += 1) {
- append(deps, get_cache(ctx, mod.deps[i].0, stage::TD)!);
+ for (let (dep_idx, _) .. mod.deps) {
+ append(deps, get_cache(ctx, dep_idx, stage::TD)!);
};
return deps;
case stage::S =>
@@ -66,8 +66,8 @@ fn get_deps(ctx: *context, t: *task) []str = {
append(deps, strings::dup(srcs.sc[j]));
};
append(deps, get_cache(ctx, i, stage::O)!);
- for (let j = 0z; j < len(srcs.o); j += 1) {
- append(deps, strings::dup(srcs.o[j]));
+ for (let o .. srcs.o) {
+ append(deps, strings::dup(o));
};
};
return deps;
@@ -109,9 +109,9 @@ fn get_flags(ctx: *context, t: *task) ([]str | error) = {
case stage::O =>
return flags;
case stage::BIN =>
- for (let i = 0z; i < len(ctx.libdirs); i += 1) {
+ for (let libdir .. ctx.libdirs) {
append(flags, strings::dup("-L"));
- append(flags, strings::dup(ctx.libdirs[i]));
+ append(flags, strings::dup(libdir));
};
if (ctx.libc) {
append(flags, strings::dup("-Wl,--gc-sections"));
@@ -154,23 +154,22 @@ fn get_flags(ctx: *context, t: *task) ([]str | error) = {
append(flags, strings::dup("-T"));
};
- for (let i = 0z; i < len(ctx.defines); i += 1) {
- let ident = ctx.defines[i].ident;
+ for (let define .. ctx.defines) {
+ let ident = define.ident;
let ns = ident[..len(ident) - 1];
if (!ast::ident_eq(ns, mod.ns)) {
continue;
};
let buf = memio::dynamic();
memio::concat(&buf, "-D", ident[len(ident) - 1])!;
- match (ctx.defines[i]._type) {
+ match (define._type) {
case null => void;
case let t: *ast::_type =>
memio::concat(&buf, ":")!;
unparse::_type(&buf, &unparse::syn_nowrap, t)!;
};
memio::concat(&buf, "=")!;
- unparse::expr(&buf, &unparse::syn_nowrap,
- ctx.defines[i].init)!;
+ unparse::expr(&buf, &unparse::syn_nowrap, define.init)!;
append(flags, memio::string(&buf)!);
};
@@ -186,8 +185,8 @@ fn get_hash(
let h = sha256::sha256();
hash::write(&h, strings::toutf8(ctx.cmds[t.kind]));
- for (let i = 0z; i < len(flags); i += 1) {
- hash::write(&h, strings::toutf8(flags[i]));
+ for (let flag .. flags) {
+ hash::write(&h, strings::toutf8(flag));
};
switch (t.kind) {
@@ -197,8 +196,8 @@ fn get_hash(
hash::write(&h, [0]);
hash::write(&h, ctx.version);
hash::write(&h, [0]);
- for (let i = 0z; i < len(ctx.mods[t.idx].deps); i += 1) {
- let ns = unparse::identstr(ctx.mods[t.idx].deps[i].1);
+ for (let dep .. ctx.mods[t.idx].deps) {
+ let ns = unparse::identstr(dep.1);
defer free(ns);
let var = strings::concat("HARE_TD_", ns);
defer free(var);
@@ -218,14 +217,14 @@ fn get_hash(
hash::write(&h, [0]);
case stage::O => void;
case stage::BIN =>
- for (let i = 0z; i < len(ctx.libs); i += 1) {
- hash::write(&h, strings::toutf8(ctx.libs[i]));
+ for (let lib .. ctx.libs) {
+ hash::write(&h, strings::toutf8(lib));
hash::write(&h, [0]);
};
};
- for (let i = 0z; i < len(deps); i += 1) {
- hash::write(&h, strings::toutf8(deps[i]));
+ for (let dep .. deps) {
+ hash::write(&h, strings::toutf8(dep));
hash::write(&h, [0]);
};
@@ -259,13 +258,13 @@ fn get_args(ctx: *context, tmp: str, flags: []str, t: *task) []str = {
case stage::BIN =>
for (let i = 0z; i < len(ctx.mods); i += 1) {
let srcs = ctx.mods[i].srcs;
- for (let i = 0z; i < len(srcs.sc); i += 1) {
+ for (let sc .. srcs.sc) {
append(args, strings::dup("-T"));
- append(args, strings::dup(srcs.sc[i]));
+ append(args, strings::dup(sc));
};
append(args, get_cache(ctx, i, stage::O)!);
- for (let i = 0z; i < len(srcs.o); i += 1) {
- append(args, strings::dup(srcs.o[i]));
+ for (let o .. srcs.o) {
+ append(args, strings::dup(o));
};
};
// XXX: when dynamically linking on Linux, we have to disable
@@ -275,14 +274,14 @@ fn get_args(ctx: *context, tmp: str, flags: []str, t: *task) []str = {
if (ctx.libc) {
append(args, strings::dup("-Wl,--no-gc-sections"));
};
- for (let i = 0z; i < len(ctx.libs); i += 1) {
+ for (let lib .. ctx.libs) {
append(args, strings::dup("-l"));
- append(args, strings::dup(ctx.libs[i]));
+ append(args, strings::dup(lib));
};
yield [];
};
- for (let i = 0z; i < len(srcs); i += 1) {
- append(args, strings::dup(srcs[i]));
+ for (let src .. srcs) {
+ append(args, strings::dup(src));
};
return args;
};
@@ -291,8 +290,8 @@ fn write_args(ctx: *context, out: str, args: []str, t: *task) (void | error) = {
let txt = os::create(out, 0o644)?;
defer io::close(txt)!;
if (t.kind == stage::SSA) {
- for (let i = 0z; i < len(ctx.mods[t.idx].deps); i += 1) {
- let ns = unparse::identstr(ctx.mods[t.idx].deps[i].1);
+ for (let (_, ident) .. ctx.mods[t.idx].deps) {
+ let ns = unparse::identstr(ident);
defer free(ns);
let var = strings::concat("HARE_TD_", ns);
defer free(var);
@@ -300,9 +299,9 @@ fn write_args(ctx: *context, out: str, args: []str, t: *task) (void | error) = {
};
};
fmt::fprint(txt, ctx.cmds[t.kind])?;
- for (let i = 0z; i < len(args); i += 1) {
+ for (let arg .. args) {
fmt::fprint(txt, " ")?;
- shlex::quote(txt, args[i])?;
+ shlex::quote(txt, arg)?;
};
fmt::fprintln(txt)?;
};
diff --git a/cmd/hare/cache.ha b/cmd/hare/cache.ha
@@ -16,8 +16,7 @@ use path;
fn cache(name: str, cmd: *getopt::command) (void | error) = {
let clear = false;
- for (let i = 0z; i < len(cmd.opts); i += 1) {
- let opt = cmd.opts[i];
+ for (let opt .. cmd.opts) {
switch (opt.0) {
case 'c' =>
clear = true;
@@ -51,10 +50,8 @@ fn dirsize(buf: *path::buffer) (size | error) = {
let s = 0z;
let it = os::iter(path::string(buf))?;
defer fs::finish(it);
- for (true) match (fs::next(it)?) {
- case void =>
- break;
- case let d: fs::dirent =>
+
+ for (let d => fs::next(it)?) {
path::push(buf, d.name)?;
let stat = os::stat(path::string(buf))?;
s += stat.sz;
diff --git a/cmd/hare/deps.ha b/cmd/hare/deps.ha
@@ -28,8 +28,8 @@ fn deps(name: str, cmd: *getopt::command) (void | error) = {
let build_dir: str = "";
let goal = deps_fmt::TERM;
- for (let i = 0z; i < len(cmd.opts); i += 1) {
- let opt = cmd.opts[i];
+
+ for (let opt .. cmd.opts) {
switch (opt.0) {
case 'd' =>
goal = deps_fmt::DOT;
@@ -70,11 +70,11 @@ fn deps(name: str, cmd: *getopt::command) (void | error) = {
deps_graph(&mods);
case deps_fmt::DOT =>
fmt::println("strict digraph deps {")!;
- for (let i = 0z; i < len(mods); i += 1) {
- for (let j = 0z; j < len(mods[i].deps); j += 1) {
- const child = mods[mods[i].deps[j].0];
+ for (let mod .. mods) {
+ for (let dep .. mod.deps) {
+ const child = mods[dep.0];
fmt::printfln("\t\"{}\" -> \"{}\";",
- mods[i].name, child.name)!;
+ mod.name, child.name)!;
};
};
fmt::println("}")!;
diff --git a/cmd/hare/util.ha b/cmd/hare/util.ha
@@ -15,17 +15,17 @@ fn merge_tags(current: *[]str, new: str) (void | module::error) = {
};
let newtags = module::parse_tags(trimmed)?;
defer free(newtags);
- for :new (let i = 0z; i < len(newtags); i += 1) {
+ for :new (let newtag .. newtags) {
for (let j = 0z; j < len(current); j += 1) {
- if (newtags[i].name == current[j]) {
- if (!newtags[i].include) {
+ if (newtag.name == current[j]) {
+ if (!newtag.include) {
static delete(current[j]);
};
continue :new;
};
};
- if (newtags[i].include) {
- append(current, newtags[i].name);
+ if (newtag.include) {
+ append(current, newtag.name);
};
};
};
diff --git a/cmd/hare/version.ha b/cmd/hare/version.ha
@@ -10,8 +10,7 @@ use strings;
fn version(name: str, cmd: *getopt::command) (void | error) = {
let verbose = false;
- for (let i = 0z; i < len(cmd.opts); i += 1) {
- const opt = cmd.opts[i];
+ for (let opt .. cmd.opts) {
switch (opt.0) {
case 'v' =>
verbose = true;
@@ -33,18 +32,15 @@ fn version(name: str, cmd: *getopt::command) (void | error) = {
if (os::getenv("HAREPATH") is str) " (from environment)" else "")?;
let tok = strings::tokenize(harepath(), ":");
- for (true) match (strings::next_token(&tok)) {
- case void =>
- break;
- case let s: str =>
+ for (let s => strings::next_token(&tok)) {
fmt::printfln("\t{}", s)?;
};
fmt::println("toolchains:")?;
- for (let i = 0z; i < len(arches); i += 1) {
- fmt::printfln(" {}:", arches[i].name)?;
- fmt::printfln("\tAS={}", arches[i].as_cmd)?;
- fmt::printfln("\tCC={}", arches[i].cc_cmd)?;
- fmt::printfln("\tLD={}", arches[i].ld_cmd)?;
+ for (let arch .. arches) {
+ fmt::printfln(" {}:", arch.name)?;
+ fmt::printfln("\tAS={}", arch.as_cmd)?;
+ fmt::printfln("\tCC={}", arch.cc_cmd)?;
+ fmt::printfln("\tLD={}", arch.ld_cmd)?;
};
};
diff --git a/cmd/haredoc/doc/color.ha b/cmd/haredoc/doc/color.ha
@@ -41,8 +41,8 @@ fn init_colors() (void | error) = {
const matches = regex::findall(&expr, env_colors);
defer regex::result_freeall(matches);
- for (let i = 0z; i < len(matches); i += 1) :colors {
- let (k, v) = (matches[i][1].content, matches[i][2].content);
+ for (let m .. matches) {
+ let (k, v) = (m[1].content, m[2].content);
let idx = 0z;
let out: *str = switch (k) {
diff --git a/cmd/haredoc/doc/html.ha b/cmd/haredoc/doc/html.ha
@@ -20,26 +20,21 @@ use strings;
fn html_escape(out: io::handle, in: str) (size | io::error) = {
let z = 0z;
let iter = strings::iter(in);
- for (true) {
- match (strings::next(&iter)) {
- case void =>
- break;
- case let rn: rune =>
- z += fmt::fprint(out, switch (rn) {
- case '&' =>
- yield "&";
- case '<' =>
- yield "<";
- case '>' =>
- yield ">";
- case '"' =>
- yield """;
- case '\'' =>
- yield "'";
- case =>
- yield strings::fromutf8(utf8::encoderune(rn))!;
- })?;
- };
+ for (let rn => strings::next(&iter)) {
+ z += fmt::fprint(out, switch (rn) {
+ case '&' =>
+ yield "&";
+ case '<' =>
+ yield "<";
+ case '>' =>
+ yield ">";
+ case '"' =>
+ yield """;
+ case '\'' =>
+ yield "'";
+ case =>
+ yield strings::fromutf8(utf8::encoderune(rn))!;
+ })?;
};
return z;
};
@@ -76,8 +71,8 @@ export fn emit_html(ctx: *context) (void | error) = {
} else {
fmt::fprintf(ctx.out, "<h2><span class='heading-body'>{}</span><span class='heading-extra'>", ident)?;
};
- for (let i = 0z; i < len(ctx.tags); i += 1) {
- fmt::fprintf(ctx.out, "+{} ", ctx.tags[i])?;
+ for (let tag .. ctx.tags) {
+ fmt::fprintf(ctx.out, "+{} ", tag)?;
};
fmt::fprintln(ctx.out, "</span></h2>")?;
@@ -103,8 +98,7 @@ export fn emit_html(ctx: *context) (void | error) = {
fmt::fprintln(ctx.out, "<h3>Submodules</h3>")?;
};
fmt::fprintln(ctx.out, "<ul class='submodules'>")?;
- for (let i = 0z; i < len(ctx.submods); i += 1) {
- let submodule = ctx.submods[i];
+ for (let submodule .. ctx.submods) {
let path = path::init("/", identpath, submodule)!;
fmt::fprintf(ctx.out, "<li><a href='")?;
@@ -133,36 +127,36 @@ export fn emit_html(ctx: *context) (void | error) = {
if (len(decls.types) != 0) {
fmt::fprintln(ctx.out, "<h3>Types</h3>")?;
- for (let i = 0z; i < len(decls.types); i += 1) {
- details(ctx, &decls.types[i])?;
+ for (let t &.. decls.types) {
+ details(ctx, t)?;
};
};
if (len(decls.errors) != 0) {
fmt::fprintln(ctx.out, "<h3>Errors</h3>")?;
- for (let i = 0z; i < len(decls.errors); i += 1) {
- details(ctx, &decls.errors[i])?;
+ for (let e &.. decls.errors) {
+ details(ctx, e)?;
};
};
if (len(decls.constants) != 0) {
fmt::fprintln(ctx.out, "<h3>Constants</h3>")?;
- for (let i = 0z; i < len(decls.constants); i += 1) {
- details(ctx, &decls.constants[i])?;
+ for (let c &.. decls.constants) {
+ details(ctx, c)?;
};
};
if (len(decls.globals) != 0) {
fmt::fprintln(ctx.out, "<h3>Globals</h3>")?;
- for (let i = 0z; i < len(decls.globals); i += 1) {
- details(ctx, &decls.globals[i])?;
+ for (let g &.. decls.globals) {
+ details(ctx, g)?;
};
};
if (len(decls.funcs) != 0) {
fmt::fprintln(ctx.out, "<h3>Functions</h3>")?;
- for (let i = 0z; i < len(decls.funcs); i += 1) {
- details(ctx, &decls.funcs[i])?;
+ for (let f &.. decls.funcs) {
+ details(ctx, f)?;
};
};
};
@@ -286,8 +280,8 @@ fn htmlref(ctx: *context, ref: ast::ident) (void | error) = {
};
fn html_paragraph(ctx: *context, p: doc::paragraph) (void | error) = {
- for (let i = 0z; i < len(p); i += 1) {
- match (p[i]) {
+ for (let elem .. p) {
+ match (elem) {
case let s: str =>
match (uri::parse(s)) {
case let uri: uri::uri =>
@@ -330,17 +324,17 @@ fn markup_html(
};
defer doc::freeall(doc);
- for (let i = 0z; i < len(doc); i += 1) {
- match (doc[i]) {
+ for (let elem .. doc) {
+ match (elem) {
case let p: doc::paragraph =>
fmt::fprint(ctx.out, "<p>")?;
html_paragraph(ctx, p)?;
fmt::fprintln(ctx.out)?;
case let l: doc::list =>
fmt::fprintln(ctx.out, "<ul>")?;
- for (let i = 0z; i < len(l); i += 1) {
+ for (let entry .. l) {
fmt::fprint(ctx.out, "<li>")?;
- html_paragraph(ctx, l[i])?;
+ html_paragraph(ctx, entry)?;
fmt::fprintln(ctx.out)?;
};
fmt::fprintln(ctx.out, "</ul>")?;
diff --git a/cmd/haredoc/doc/resolve.ha b/cmd/haredoc/doc/resolve.ha
@@ -71,32 +71,32 @@ fn is_local(ctx: *context, what: ast::ident) bool = {
};
const summary = ctx.summary;
- for (let i = 0z; i < len(summary.constants); i += 1) {
- const name = decl_ident(&summary.constants[i])[0];
+ for (let c &.. summary.constants) {
+ const name = decl_ident(c)[0];
if (name == what[0]) {
return true;
};
};
- for (let i = 0z; i < len(summary.errors); i += 1) {
- const name = decl_ident(&summary.errors[i])[0];
+ for (let e &.. summary.errors) {
+ const name = decl_ident(e)[0];
if (name == what[0]) {
return true;
};
};
- for (let i = 0z; i < len(summary.types); i += 1) {
- const name = decl_ident(&summary.types[i])[0];
+ for (let t &.. summary.types) {
+ const name = decl_ident(t)[0];
if (name == what[0]) {
return true;
};
};
- for (let i = 0z; i < len(summary.globals); i += 1) {
- const name = decl_ident(&summary.globals[i])[0];
+ for (let g &.. summary.globals) {
+ const name = decl_ident(g)[0];
if (name == what[0]) {
return true;
};
};
- for (let i = 0z; i < len(summary.funcs); i += 1) {
- const name = decl_ident(&summary.funcs[i])[0];
+ for (let f &.. summary.funcs) {
+ const name = decl_ident(f)[0];
if (name == what[0]) {
return true;
};
@@ -106,8 +106,7 @@ fn is_local(ctx: *context, what: ast::ident) bool = {
};
fn lookup_local_enum(ctx: *context, what: ast::ident) (ast::ident | void) = {
- for (let i = 0z; i < len(ctx.summary.types); i += 1) {
- const decl = &ctx.summary.types[i];
+ for (let decl &.. ctx.summary.types) {
const name = decl_ident(decl)[0];
if (name == what[0]) {
const t = (decl.decl as []ast::decl_type)[0];
@@ -117,8 +116,8 @@ fn lookup_local_enum(ctx: *context, what: ast::ident) (ast::ident | void) = {
case =>
return;
};
- for (let i = 0z; i < len(e.values); i += 1) {
- if (e.values[i].name == what[1]) {
+ for (let value .. e.values) {
+ if (value.name == what[1]) {
return what;
};
};
@@ -143,34 +142,34 @@ fn lookup_remote_enum(ctx: *context, what: ast::ident) (ast::ident | void | erro
// This would take a lot of memory to load
let decls: []ast::decl = [];
defer {
- for (let i = 0z; i < len(decls); i += 1) {
- ast::decl_finish(decls[i]);
+ for (let decl .. decls) {
+ ast::decl_finish(decl);
};
free(decls);
};
- for (let i = 0z; i < len(srcs.ha); i += 1) {
- const in = srcs.ha[i];
+ for (let in .. srcs.ha) {
let u = scan(in)?;
append(decls, u.decls...);
};
- for (let i = 0z; i < len(decls); i += 1) {
- const decl = match (decls[i].decl) {
+ for (let decl .. decls) {
+ const decls = match (decl.decl) {
case let t: []ast::decl_type =>
yield t;
case =>
continue;
};
- for (let i = 0z; i < len(decl); i += 1) {
- if (decl[i].ident[0] == decl_name) {
- const e = match (decl[i]._type.repr) {
+
+ for (let d .. decls) {
+ if (d.ident[0] == decl_name) {
+ const e = match (d._type.repr) {
case let e: ast::enum_type =>
yield e;
case =>
abort();
};
- for (let i = 0z; i < len(e.values); i += 1) {
- if (e.values[i].name == member) {
+ for (let value .. e.values) {
+ if (value.name == member) {
return what;
};
};
diff --git a/cmd/haredoc/doc/sort.ha b/cmd/haredoc/doc/sort.ha
@@ -17,8 +17,7 @@ use strings;
export fn sort_decls(decls: []ast::decl) summary = {
let sorted = summary { ... };
- for (let i = 0z; i < len(decls); i += 1) {
- let decl = decls[i];
+ for (let decl .. decls) {
if (!decl.exported) {
continue;
};
@@ -38,42 +37,42 @@ export fn sort_decls(decls: []ast::decl) summary = {
},
docs = decl.docs,
});
- case let t: []ast::decl_type =>
- for (let j = 0z; j < len(t); j += 1) {
+ case let types: []ast::decl_type =>
+ for (let t .. types) {
let bucket = &sorted.types;
- if (t[j]._type.flags & ast::type_flag::ERROR == ast::type_flag::ERROR) {
+ if (t._type.flags & ast::type_flag::ERROR == ast::type_flag::ERROR) {
bucket = &sorted.errors;
};
append(bucket, ast::decl {
exported = false,
start = decl.start,
end = decl.end,
- decl = alloc([t[j]]),
+ decl = alloc([t]),
docs = decl.docs,
});
};
- case let c: []ast::decl_const =>
- for (let j = 0z; j < len(c); j += 1) {
+ case let consts: []ast::decl_const =>
+ for (let c .. consts) {
append(sorted.constants, ast::decl {
exported = false,
start = decl.start,
end = decl.end,
- decl = alloc([c[j]]),
+ decl = alloc([c]),
docs = decl.docs,
});
};
- case let g: []ast::decl_global =>
- for (let j = 0z; j < len(g); j += 1) {
+ case let globals: []ast::decl_global =>
+ for (let g .. globals) {
append(sorted.globals, ast::decl {
exported = false,
start = decl.start,
end = decl.end,
decl = alloc([ast::decl_global {
- is_const = g[j].is_const,
- is_threadlocal = g[j].is_threadlocal,
- symbol = g[j].symbol,
- ident = g[j].ident,
- _type = g[j]._type,
+ is_const = g.is_const,
+ is_threadlocal = g.is_threadlocal,
+ symbol = g.symbol,
+ ident = g.ident,
+ _type = g._type,
init = null,
}]),
docs = decl.docs,
diff --git a/cmd/haredoc/doc/tty.ha b/cmd/haredoc/doc/tty.ha
@@ -45,13 +45,11 @@ export fn emit_tty(ctx: *context) (void | error) = {
let readme = bufio::init(readme, rbuf, []);
let sc = bufio::newscanner(&readme, types::SIZE_MAX);
defer bufio::finish(&sc);
- for (true) match (bufio::scan_line(&sc)?) {
- case io::EOF => break;
- case let s: const str =>
+ for (let line => bufio::scan_line(&sc)?) {
firstline = false;
if (!no_color) fmt::fprintf(ctx.out, "\x1b[{}m",
color(unparse::synkind::COMMENT))?;
- fmt::fprint(ctx.out, "//", s)?;
+ fmt::fprint(ctx.out, "//", line)?;
if (!no_color) fmt::fprint(ctx.out, "\x1b[m")?;
fmt::fprintln(ctx.out)?;
};
@@ -62,28 +60,28 @@ export fn emit_tty(ctx: *context) (void | error) = {
// XXX: Should we emit the dependencies, too?
let printed = false;
- for (let i = 0z; i < len(summary.types); i += 1) {
- if (details_tty(ctx, &summary.types[i])?) {
+ for (let t &.. summary.types) {
+ if (details_tty(ctx, t)?) {
printed = true;
};
};
- for (let i = 0z; i < len(summary.constants); i += 1) {
- if (details_tty(ctx, &summary.constants[i])?) {
+ for (let c &.. summary.constants) {
+ if (details_tty(ctx, c)?) {
printed = true;
};
};
- for (let i = 0z; i < len(summary.errors); i += 1) {
- if (details_tty(ctx, &summary.errors[i])?) {
+ for (let e &.. summary.errors) {
+ if (details_tty(ctx, e)?) {
printed = true;
};
};
- for (let i = 0z; i < len(summary.globals); i += 1) {
- if (details_tty(ctx, &summary.globals[i])?) {
+ for (let g &.. summary.globals) {
+ if (details_tty(ctx, g)?) {
printed = true;
};
};
- for (let i = 0z; i < len(summary.funcs); i += 1) {
- if (details_tty(ctx, &summary.funcs[i])?) {
+ for (let f &.. summary.funcs) {
+ if (details_tty(ctx, f)?) {
printed = true;
};
};
@@ -113,13 +111,13 @@ fn emit_submodules_tty(ctx: *context) (void | error) = {
} else {
fmt::fprintln(ctx.out, "// Submodules")?;
};
- for (let i = 0z; i < len(ctx.submods); i += 1) {
+ for (let submodule .. ctx.submods) {
let submodule = if (len(ctx.ident) != 0) {
const s = unparse::identstr(ctx.ident);
defer free(s);
- yield strings::concat(s, "::", ctx.submods[i]);
+ yield strings::concat(s, "::", submodule);
} else {
- yield strings::dup(ctx.submods[i]);
+ yield strings::dup(submodule);
};
defer free(submodule);
diff --git a/cmd/haredoc/doc/types.ha b/cmd/haredoc/doc/types.ha
@@ -70,23 +70,23 @@ export type summary = struct {
};
export fn finish_summary(s: summary) void = {
- for (let i = 0z; i < len(s.constants); i += 1) {
- free(s.constants[i].decl as []ast::decl_const);
+ for (let c .. s.constants) {
+ free(c.decl as []ast::decl_const);
};
free(s.constants);
- for (let i = 0z; i < len(s.errors); i += 1) {
- free(s.errors[i].decl as []ast::decl_type);
+ for (let e .. s.errors) {
+ free(e.decl as []ast::decl_type);
};
free(s.errors);
- for (let i = 0z; i < len(s.types); i += 1) {
- free(s.types[i].decl as []ast::decl_type);
+ for (let t .. s.types) {
+ free(t.decl as []ast::decl_type);
};
free(s.types);
- for (let i = 0z; i < len(s.globals); i += 1) {
- free(s.globals[i].decl as []ast::decl_global);
+ for (let g .. s.globals) {
+ free(g.decl as []ast::decl_global);
};
free(s.globals);
diff --git a/cmd/haredoc/doc/util.ha b/cmd/haredoc/doc/util.ha
@@ -17,13 +17,7 @@ let firstline: bool = true;
fn trim_comment(s: str) str = {
let trimmed = memio::dynamic();
let tok = strings::tokenize(s, "\n");
- for (true) {
- const line = match (strings::next_token(&tok)) {
- case void =>
- break;
- case let line: str =>
- yield line;
- };
+ for (let line => strings::next_token(&tok)) {
memio::concat(&trimmed, strings::trimprefix(line, " "), "\n")!;
};
return strings::dup(memio::string(&trimmed)!);
@@ -34,14 +28,11 @@ export fn submodules(path: str, show_undocumented: bool) ([]str | error) = {
let it = os::iter(path)?;
defer fs::finish(it);
let pathbuf = path::init(path)!;
- for (true) match (module::next(it)?) {
- case let d: fs::dirent =>
+ 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));
};
- case void =>
- break;
};
sort::sort(submodules, size(str), &cmp::strs);
return submodules;
diff --git a/cmd/haredoc/main.ha b/cmd/haredoc/main.ha
@@ -60,20 +60,19 @@ fn doc(name: str, cmd: *getopt::command) (void | error) = {
let tags: []str = default_tags();
defer free(tags);
- for (let i = 0z; i < len(cmd.opts); i += 1) {
- let opt = cmd.opts[i];
- switch (opt.0) {
+ for (let (k, v) .. cmd.opts) {
+ switch (k) {
case 'F' =>
- switch (opt.1) {
+ switch (v) {
case "tty" =>
html = false;
case "html" =>
html = true;
case =>
- fmt::fatal("Invalid format", opt.1);
+ fmt::fatal("Invalid format", v);
};
case 'T' =>
- merge_tags(&tags, opt.1)?;
+ merge_tags(&tags, v)?;
case 't' =>
template = false;
case 'a' =>
@@ -148,32 +147,33 @@ fn doc(name: str, cmd: *getopt::command) (void | error) = {
let decls: []ast::decl = [];
defer {
- for (let i = 0z; i < len(decls); i += 1) {
- ast::decl_finish(decls[i]);
+ for (let decl .. decls) {
+ ast::decl_finish(decl);
};
free(decls);
};
if (declpath != "") {
- for (let i = 0z; i < len(declsrcs.ha); i += 1) {
- let u = doc::scan(declsrcs.ha[i])?;
+ for (let ha .. declsrcs.ha) {
+ let u = doc::scan(ha)?;
ast::imports_finish(u.imports);
append(decls, u.decls...);
};
let matching: []ast::decl = [];
let notmatching: []ast::decl = [];
- for (let i = 0z; i < len(decls); i += 1) {
- if (has_decl(decls[i], id[len(id) - 1])) {
- append(matching, decls[i]);
+
+ for (let decl .. decls) {
+ if (has_decl(decl, id[len(id) - 1])) {
+ append(matching, decl);
} else {
- append(notmatching, decls[i]);
+ append(notmatching, decl);
};
};
get_init_funcs(&matching, ¬matching);
- for (let i = 0z; i < len(notmatching); i += 1) {
- ast::decl_finish(notmatching[i]);
+ for (let decl .. notmatching) {
+ ast::decl_finish(decl);
};
free(notmatching);
free(decls);
@@ -199,8 +199,8 @@ fn doc(name: str, cmd: *getopt::command) (void | error) = {
const ambiguous = modpath != "" && len(decls) > 0;
if (len(decls) == 0) {
- for (let i = 0z; i < len(modsrcs.ha); i += 1) {
- let u = doc::scan(modsrcs.ha[i])?;
+ for (let ha .. modsrcs.ha) {
+ let u = doc::scan(ha)?;
ast::imports_finish(u.imports);
append(decls, u.decls...);
};
@@ -343,9 +343,9 @@ fn has_decl(decl: ast::decl, name: str) bool = {
};
match (decl.decl) {
- case let d: []ast::decl_const =>
- for (let i = 0z; i < len(d); i += 1) {
- if (len(d[i].ident) == 1 && d[i].ident[0] == name) {
+ case let consts: []ast::decl_const =>
+ for (let d .. consts) {
+ if (len(d.ident) == 1 && d.ident[0] == name) {
return true;
};
};
@@ -355,25 +355,25 @@ fn has_decl(decl: ast::decl, name: str) bool = {
};
let tok = strings::rtokenize(d.symbol, ".");
match (strings::next_token(&tok)) {
- case void => void;
+ case done => void;
case let s: str =>
return s == name;
};
- case let d: []ast::decl_global =>
- for (let i = 0z; i < len(d); i += 1) {
- if (len(d[i].ident) == 1 && d[i].ident[0] == name) {
+ case let globals: []ast::decl_global =>
+ for (let d .. globals) {
+ if (len(d.ident) == 1 && d.ident[0] == name) {
return true;
};
- let tok = strings::rtokenize(d[i].symbol, ".");
+ let tok = strings::rtokenize(d.symbol, ".");
match (strings::next_token(&tok)) {
- case void => void;
+ case done => void;
case let s: str =>
return s == name;
};
};
- case let d: []ast::decl_type =>
- for (let i = 0z; i < len(d); i += 1) {
- if (len(d[i].ident) == 1 && d[i].ident[0] == name) {
+ case let types: []ast::decl_type =>
+ for (let d .. types) {
+ if (len(d.ident) == 1 && d.ident[0] == name) {
return true;
};
};
@@ -479,8 +479,8 @@ fn is_init_type(ident: ast::ident, _type: *ast::_type) bool = {
return false;
};
case let repr: ast::tagged_type =>
- for (let i = 0z; i < len(repr); i += 1) {
- if (is_init_type(ident, repr[i])) {
+ for (let t .. repr) {
+ if (is_init_type(ident, t)) {
return true;
};
};
diff --git a/cmd/haredoc/util.ha b/cmd/haredoc/util.ha
@@ -17,17 +17,17 @@ fn merge_tags(current: *[]str, new: str) (void | module::error) = {
};
let newtags = module::parse_tags(trimmed)?;
defer free(newtags);
- for :new (let i = 0z; i < len(newtags); i += 1) {
- for (let j = 0z; j < len(current); j += 1) {
- if (newtags[i].name == current[j]) {
- if (!newtags[i].include) {
- static delete(current[j]);
+ for :new (let newtag .. newtags) {
+ for (let i = 0z; i < len(current); i += 1) {
+ if (newtag.name == current[i]) {
+ if (!newtag.include) {
+ static delete(current[i]);
};
continue :new;
};
};
- if (newtags[i].include) {
- append(current, newtags[i].name);
+ if (newtag.include) {
+ append(current, newtag.name);
};
};
};
diff --git a/cmd/parsechk/main.ha b/cmd/parsechk/main.ha
@@ -22,10 +22,7 @@ export fn main() void = {
fn iter(buf: *path::buffer, status: *int) void = {
let it = os::iter(path::string(buf))!;
defer fs::finish(it);
- for (true) match (fs::next(it)!) {
- case void =>
- break;
- case let ent: fs::dirent =>
+ for (let ent => fs::next(it)!) {
path::push(buf, ent.name)!;
defer path::pop(buf);
const st = os::stat(path::string(buf))!;
diff --git a/encoding/base64/base64.ha b/encoding/base64/base64.ha
@@ -150,8 +150,8 @@ fn writeavail(s: *encoder) (void | io::error) = {
// Flushes pending writes to the underlying stream.
fn encode_closer(s: *io::stream) (void | io::error) = {
let s = s: *encoder;
- let done = false;
- defer if (done) clear(s);
+ let finished = false;
+ defer if (finished) clear(s);
match (s.err) {
case let e: io::error =>
@@ -164,12 +164,12 @@ fn encode_closer(s: *io::stream) (void | io::error) = {
for (s.oavail > 0) {
writeavail(s)?;
};
- done = true;
+ finished = true;
return;
};
if (s.iavail == 0) {
- done = true;
+ finished = true;
return;
};
@@ -191,7 +191,7 @@ fn encode_closer(s: *io::stream) (void | io::error) = {
for (s.oavail > 0) {
writeavail(s)?;
};
- done = true;
+ finished = true;
};
fn clear(e: *encoder) void = {
diff --git a/fmt/iter.ha b/fmt/iter.ha
@@ -55,10 +55,10 @@ fn iter(fmt: str, args: []field) iterator = iterator {
checkunused = true,
};
-fn next(it: *iterator) (str | (formattable, mods) | void) = {
+fn next(it: *iterator) (str | (formattable, mods) | done) = {
let r = match (strings::next(&it.iter)) {
- case void =>
- return void;
+ case done =>
+ return done;
case let r: rune =>
yield r;
};
@@ -66,7 +66,7 @@ fn next(it: *iterator) (str | (formattable, mods) | void) = {
case '{' => void; // handled below
case '}' =>
match (strings::next(&it.iter)) {
- case void =>
+ case done =>
abort("Invalid format string (hanging '}')");
case let r: rune =>
assert(r == '}', "Invalid format string (hanging '}')");
@@ -75,9 +75,7 @@ fn next(it: *iterator) (str | (formattable, mods) | void) = {
case =>
strings::prev(&it.iter);
let start = it.iter;
- for (true) match (strings::next(&it.iter)) {
- case void => break;
- case let r: rune =>
+ for (let r => strings::next(&it.iter)) {
if (r == '{' || r == '}') {
strings::prev(&it.iter);
break;
@@ -189,7 +187,7 @@ fn scan_sz(it: *iterator) size = {
};
fn getrune(it: *iterator) rune = match (strings::next(&it.iter)) {
-case void =>
+case done =>
abort("Invalid format string (unterminated '{')");
case let r: rune =>
return r;
diff --git a/fmt/print.ha b/fmt/print.ha
@@ -31,7 +31,7 @@ export fn fprintf(
let n = 0z, i = 0z;
let it = iter(fmt, args);
for (true) match (next(&it)) {
- case void => break;
+ case done => break;
case let s: str =>
n += format(h, s, &mods { ... })?;
case let f: (formattable, mods) =>
diff --git a/fnmatch/+test.ha b/fnmatch/+test.ha
@@ -185,8 +185,7 @@ const testcases: [_]testcase = [
];
@test fn fnmatch() void = {
- for (let i = 0z; i < len(testcases); i += 1) {
- let tc = testcases[i];
+ for (let tc .. testcases) {
assert(fnmatch(tc.0, tc.1, tc.3...) == tc.2);
};
diff --git a/fnmatch/fnmatch.ha b/fnmatch/fnmatch.ha
@@ -45,8 +45,8 @@ type token = (rune | bracket | star | question | end);
// [[fnmatch]]. For an explanation of their meaning, see [[flag]].
export fn fnmatch(pattern: str, string: str, flags: flag...) bool = {
let fl: flag = 0;
- for (let i = 0z; i < len(flags); i += 1) {
- fl |= flags[i];
+ for (let flag .. flags) {
+ fl |= flag;
};
let b = if (fl & flag::PATHNAME != 0) {
yield fnmatch_pathname(pattern, string, fl);
@@ -78,7 +78,7 @@ fn fnmatch_pathname(
case (question | star) => void;
};
let s = match (strings::next_token(&tok)) {
- case void =>
+ case done =>
return false;
case let s: str =>
yield s;
@@ -91,13 +91,13 @@ fn fnmatch_pathname(
};
};
let s = match(strings::next_token(&tok)) {
- case void =>
+ case done =>
return false;
case let s: str =>
yield s;
};
let p = strings::iterstr(&start);
- return fnmatch_internal(p, s, fl)? && strings::next_token(&tok) is void;
+ return fnmatch_internal(p, s, fl)? && strings::next_token(&tok) is done;
};
// Core fnmatch function, implementing the "Sea of stars" algorithm that is also
@@ -128,7 +128,7 @@ fn fnmatch_internal(
case star =>
break;
case end =>
- return rn is void;
+ return rn is done;
case question =>
yield rn is rune;
case bracket =>
@@ -170,7 +170,7 @@ fn fnmatch_internal(
let rn = strings::prev(&s);
let matches = match (pat_next(&p, fl)?) {
case end =>
- if (rn is void) {
+ if (rn is done) {
break;
} else {
return false;
@@ -221,7 +221,7 @@ fn fnmatch_internal(
s = copy;
};
match (strings::next(&s_copy)) {
- case void =>
+ case done =>
return false;
case rune => void;
};
@@ -326,7 +326,7 @@ fn match_ctype(it: *strings::iterator, c: rune) (bool | errors::invalid) = {
fn pat_next(pat: *strings::iterator, fl: flag) (token | errors::invalid) = {
let r = match (strings::next(pat)) {
- case void =>
+ case done =>
return end;
case let r: rune =>
yield r;
@@ -351,7 +351,7 @@ fn advance_or_err(it: *strings::iterator) (rune | errors::invalid) = {
match (strings::next(it)) {
case let r: rune =>
return r;
- case void =>
+ case done =>
return errors::invalid;
};
};
diff --git a/fs/fs.ha b/fs/fs.ha
@@ -315,4 +315,4 @@ export fn symlink(fs: *fs, target: str, path: str) (void | error) = {
// not guaranteed to be complete when an error has been returned. The file stat
// returned may only have the type bits set on the file mode; callers should
// call [[stat]] to obtain the detailed file mode.
-export fn next(iter: *iterator) (dirent | void | error) = iter.next(iter);
+export fn next(iter: *iterator) (dirent | done | error) = iter.next(iter);
diff --git a/fs/types.ha b/fs/types.ha
@@ -312,7 +312,7 @@ export type fs = struct {
};
// A function which returns the next directory from an [[iterator]].
-export type nextfunc = fn(iter: *iterator) (dirent | void | error);
+export type nextfunc = fn(iter: *iterator) (dirent | done | error);
// A function which frees state associated with an [[iterator]].
export type finishfunc = fn(iter: *iterator) void;
diff --git a/fs/util.ha b/fs/util.ha
@@ -87,23 +87,19 @@ export fn readdir(fs: *fs, path: str) ([]dirent | error) = {
let i = iter(fs, path)?;
defer finish(i);
let ents: []dirent = [];
- for (true) {
- match (next(i)) {
- case let d: dirent =>
- append(ents, dirent_dup(&d));
- case void =>
- break;
- };
+
+ for (let d => next(i)?) {
+ append(ents, dirent_dup(&d));
};
return ents;
};
// Frees a slice of [[dirent]]s.
-export fn dirents_free(d: []dirent) void = {
- for (let i = 0z; i < len(d); i += 1) {
- dirent_finish(&d[i]);
+export fn dirents_free(dirents: []dirent) void = {
+ for (let d &.. dirents) {
+ dirent_finish(d);
};
- free(d);
+ free(dirents);
};
// Removes a directory, and anything in it.
@@ -115,21 +111,16 @@ export fn rmdirall(fs: *fs, path: str) (void | error) = {
fn rmdirall_path(fs: *fs, buf: *path::buffer) (void | error) = {
let it = iter(fs, path::string(buf))?;
defer finish(it);
- for (true) {
- match (next(it)) {
- case let ent: dirent =>
- path::push(buf, ent.name)!;
-
- switch (ent.ftype & mode::DIR) {
- case mode::DIR =>
- rmdirall_path(fs, buf)?;
- case =>
- remove(fs, path::string(buf))?;
- };
- path::pop(buf);
- case void =>
- break;
+ for (let ent => next(it)?) {
+ path::push(buf, ent.name)!;
+
+ switch (ent.ftype & mode::DIR) {
+ case mode::DIR =>
+ rmdirall_path(fs, buf)?;
+ case =>
+ remove(fs, path::string(buf))?;
};
+ path::pop(buf);
};
return rmdir(fs, path::string(buf));
};
@@ -143,15 +134,10 @@ export fn realpath(fs: *fs, path: str) (str | error) = {
static let pathbuf = path::buffer { ... };
path::set(&pathbuf, resolve(fs, path))!;
const iter = path::iter(&pathbuf);
- for (true) {
- const item = match (path::nextiter(&iter)) {
- case let item: str =>
- yield item;
- case void =>
- break;
- };
+ for (let item => path::nextiter(&iter)) {
const item = path::push(&res, item)!;
+
const link = match (readlink(fs, item)) {
case let link: str =>
yield link;
diff --git a/getopt/getopts.ha b/getopt/getopts.ha
@@ -115,9 +115,7 @@ export fn tryparse(args: []str, help: help...) (command | error) = {
let iter = strings::iter(arg);
assert(strings::next(&iter) as rune == '-');
- for (true) match (strings::next(&iter)) {
- case void => break;
- case let r: rune =>
+ for (let r => strings::next(&iter)) {
let found = false;
for (let j = 0z; j < len(help); j += 1) match (help[j]) {
case let f: flag_help =>
@@ -217,26 +215,32 @@ fn _printusage(
z += fmt::fprint(out, " [-h")?;
started_flags = true;
};
- for (let i = 0z; i < len(help); i += 1) match (help [i]) {
- case let h: flag_help =>
- if (!started_flags) {
- z += fmt::fprint(out, " [-")?;
- started_flags = true;
+ for (let h .. help) {
+ match (h) {
+ case let h: flag_help =>
+ if (!started_flags) {
+ z += fmt::fprint(out, " [-")?;
+ started_flags = true;
+ };
+ z += fmt::fprint(out, h.0)?;
+ case => void;
};
- z += fmt::fprint(out, h.0)?;
- case => void;
};
if (started_flags) {
z += fmt::fprint(out, "]")?;
};
- for (let i = 0z; i < len(help); i += 1) if (help[i] is parameter_help) {
- const help = help[i] as parameter_help;
- if (indent) {
- z += fmt::fprintf(out, "\n\t")?;
+ for (let h .. help) {
+ match (h) {
+ case let h: parameter_help =>
+ if (indent) {
+ z += fmt::fprintf(out, "\n\t")?;
+ };
+ z += fmt::fprintf(out, " [-{} <{}>]", h.0, h.1)?;
+ case => void;
};
- z += fmt::fprintf(out, " [-{} <{}>]", help.0, help.1)?;
};
+
let first_arg = true;
for (let i = 1z; i < len(help); i += 1) if (help[i] is cmd_help) {
if (first_arg) {
@@ -252,8 +256,8 @@ fn _printusage(
};
fn contains_h(help: []help) bool = {
- for (let i = 0z; i < len(help); i += 1) {
- const r = match (help[i]) {
+ for (let h .. help) {
+ const r = match (h) {
case let h: flag_help => yield h.0;
case let h: parameter_help => yield h.0;
case => continue;
@@ -287,12 +291,14 @@ export fn printhelp(
if (!contains_h) {
fmt::fprintln(out, "-h: print this help text")?;
};
- for (let i = 0z; i < len(help); i += 1) match (help[i]) {
- case let f: flag_help =>
- fmt::fprintfln(out, "-{}: {}", f.0, f.1)?;
- case let p: parameter_help =>
- fmt::fprintfln(out, "-{} <{}>: {}", p.0, p.1, p.2)?;
- case => void;
+ for (let h .. help) {
+ match (h) {
+ case let f: flag_help =>
+ fmt::fprintfln(out, "-{}: {}", f.0, f.1)?;
+ case let p: parameter_help =>
+ fmt::fprintfln(out, "-{} <{}>: {}", p.0, p.1, p.2)?;
+ case => void;
+ };
};
printsubcmds(out, help)?;
@@ -300,19 +306,22 @@ export fn printhelp(
fn printsubcmds(out: io::handle, help: []help) (void | io::error) = {
let first = true;
- for (let i = 0z; i < len(help); i += 1) match (help[i]) {
- case let s: subcmd_help =>
- // Only print this if there are subcommands to show
- if (first) {
- fmt::fprintln(out, "\nSubcommands:")?;
- first = false;
- };
- if (len(s.1) == 0 || !(s.1[0] is cmd_help)) {
- fmt::fprintfln(out, " {}", s.0)?;
- } else {
- fmt::fprintfln(out, " {}: {}", s.0, s.1[0] as cmd_help: str)?;
+ for (let h .. help) {
+ match (h) {
+ case let s: subcmd_help =>
+ // Only print this if there are subcommands to show
+ if (first) {
+ fmt::fprintln(out, "\nSubcommands:")?;
+ first = false;
+ };
+ if (len(s.1) == 0 || !(s.1[0] is cmd_help)) {
+ fmt::fprintfln(out, " {}", s.0)?;
+ } else {
+ fmt::fprintfln(out, " {}: {}", s.0,
+ s.1[0] as cmd_help: str)?;
+ };
+ case => void;
};
- case => void;
};
};
diff --git a/glob/+test.ha b/glob/+test.ha
@@ -23,23 +23,23 @@ use strings;
("..", flag::NONE),
("\\*", flag::NONE),
];
- for (let i = 0z; i < len(cases); i += 1) {
- let gen = glob(cases[i].0, cases[i].1);
+ for (let c .. cases) {
+ let gen = glob(c.0, c.1);
defer finish(&gen);
for (true) match (next(&gen)) {
- case void =>
+ case done =>
break;
case failure =>
continue;
case let s: str =>
let bs = fnmatch::flag::PATHNAME;
- if (cases[i].1 & flag::NOESCAPE != 0) {
+ if (c.1 & flag::NOESCAPE != 0) {
bs |= fnmatch::flag::NOESCAPE;
};
- assert(fnmatch::fnmatch(cases[i].0, s, bs)
- || cases[i].1 & flag::MARK != 0
+ assert(fnmatch::fnmatch(c.0, s, bs)
+ || c.1 & flag::MARK != 0
&& fnmatch::fnmatch(
- cases[i].0,
+ c.0,
strings::rtrim(s, '/'),
bs
)
@@ -82,13 +82,13 @@ use strings;
];
let p = pattern_init();
defer pattern_free(&p);
- for (let i = 0z; i < len(cases); i += 1) {
- pattern_parse(&p, cases[i].0, cases[i].1);
+ for (let c .. cases) {
+ pattern_parse(&p, c.0, c.1);
const dir = pattern_dir(&p);
const pat = pattern_pat(&p);
const rem = pattern_rem(&p);
- assert(dir == cases[i].2);
- assert(pat == cases[i].3);
- assert(rem == cases[i].4);
+ assert(dir == c.2);
+ assert(pat == c.3);
+ assert(rem == c.4);
};
};
diff --git a/glob/glob.ha b/glob/glob.ha
@@ -68,8 +68,8 @@ export fn glob(pattern: str, flags: flag...) generator = {
let ss = strstack_init();
memio::concat(strstack_push(&ss), pattern)!;
let bs = flag::NONE;
- for (let i = 0z; i < len(flags); i += 1) {
- bs |= flags[i];
+ for (let flag .. flags) {
+ bs |= flag;
};
return generator {
pats = ss,
@@ -89,7 +89,7 @@ export fn finish(gen: *generator) void = {
// is called again. If, during the search, a directory is encountered that
// cannot be opened or read, a [[failure]] object is returned instead.
// [[next]] can be repeatedly called until void is returned.
-export fn next(gen: *generator) (str | void | failure) = {
+export fn next(gen: *generator) (str | done | failure) = {
const init = strstack_size(&gen.pats) == 1
&& len(memio::string(&gen.tmpp.dir)!) == 0
&& len(memio::string(&gen.tmpp.pat)!) == 0
@@ -102,6 +102,7 @@ export fn next(gen: *generator) (str | void | failure) = {
if (init && gen.flgs & flag::NOCHECK != 0) {
return memio::string(&gen.pats.bufv[0])!;
};
+ return done;
};
fn next_match(gen: *generator) (str | void | failure) = {
@@ -145,7 +146,7 @@ fn next_match(gen: *generator) (str | void | failure) = {
defer fs::finish(it);
for (true) match (fs::next(it)) {
- case void =>
+ case done =>
break;
case let de: fs::dirent =>
if (patm && !fs::isdir(de.ftype) && !fs::islink(de.ftype)) {
@@ -233,7 +234,7 @@ fn pattern_parse(p: *pattern, pstr: str, noesc: bool) void = {
// characters.
for (let brk = false, esc = false; true) {
const r = match (strings::next(&itdir)) {
- case void =>
+ case done =>
memio::concat(&p.dir, memio::string(&p.pat)!)!;
memio::reset(&p.pat);
return;
@@ -270,14 +271,9 @@ fn pattern_parse(p: *pattern, pstr: str, noesc: bool) void = {
// p.pat is the first path component which contains special
// characters.
memio::reset(&p.pat);
- for (let esc = false; true) {
- const r = match (strings::next(&itpat)) {
- case void =>
- return;
- case let r: rune =>
- yield r;
- };
+ let esc = false;
+ for (let r => strings::next(&itpat)) {
if (!esc && r == '\\' && !noesc) {
esc = true;
continue;
@@ -302,8 +298,8 @@ fn strstack_init() strstack = strstack {
};
fn strstack_free(ss: *strstack) void = {
- for (let i = 0z; i < len(ss.bufv); i += 1) {
- io::close(&ss.bufv[i])!;
+ for (let stream &.. ss.bufv) {
+ io::close(stream)!;
};
free(ss.bufv);
};
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 | _null | str | rune | void);
+export type value = (bool | done | _null | str | rune | void);
// An integer or float literal.
export type number_literal = struct {
@@ -273,12 +273,24 @@ export type delete_expr = struct {
is_static: bool,
};
+// The kind of for expression being used.
+export type for_kind = enum {
+ ACCUMULATOR,
+ EACH_VALUE,
+ EACH_POINTER,
+ ITERATOR,
+};
+
// A for loop.
//
// for (let foo = 0; foo < bar; baz) quux
+// for (let line => next_line()) quux
+// for (let number .. [1, 2, 3]) quux
+// for (let ptr &.. [1, 2, 3]) quux
export type for_expr = struct {
+ kind: for_kind,
bindings: nullable *expr,
- cond: *expr,
+ cond: nullable *expr,
afterthought: nullable *expr,
body: *expr,
label: label,
diff --git a/hare/ast/type.ha b/hare/ast/type.ha
@@ -11,8 +11,8 @@ export type alias_type = struct {
// A built-in primitive type (int, bool, str, etc).
export type builtin_type = enum {
- BOOL, F32, F64, FCONST, I16, I32, I64, I8, ICONST, INT, NEVER, NULL,
- OPAQUE, RCONST, RUNE, SIZE, STR, U16, U32, U64, U8, UINT, UINTPTR,
+ 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,
};
diff --git a/hare/lex/+test.ha b/hare/lex/+test.ha
@@ -136,7 +136,7 @@ fn loc(line: uint, col: uint) location = location {
const in = ". .. ... < << <= <<= > >> >= >>= >>";
const expected: [_]token = [
(ltok::DOT, void, loc(1, 1)),
- (ltok::SLICE, void, loc(1, 3)),
+ (ltok::DOUBLE_DOT, void, loc(1, 3)),
(ltok::ELLIPSIS, void, loc(1, 6)),
(ltok::LESS, void, loc(1, 10)),
(ltok::LSHIFT, void, loc(1, 12)),
diff --git a/hare/lex/lex.ha b/hare/lex/lex.ha
@@ -689,7 +689,7 @@ fn lex3(lex: *lexer) (token | error) = {
lex.require_int = true;
yield ltok::DOT;
} else if (try(lex, '.')? is void) {
- yield ltok::SLICE;
+ yield ltok::DOUBLE_DOT;
} else ltok::ELLIPSIS;
line_comment(lex)?;
return (tok, void, r.1);
diff --git a/hare/lex/token.ha b/hare/lex/token.ha
@@ -31,6 +31,7 @@ export type ltok = enum uint {
DEF,
DEFER,
DELETE,
+ DONE,
ELSE,
ENUM,
EXPORT,
@@ -97,6 +98,7 @@ export type ltok = enum uint {
DIVEQ,
DOT,
DOUBLE_COLON,
+ DOUBLE_DOT,
ELLIPSIS,
EQUAL,
GT,
@@ -130,7 +132,6 @@ export type ltok = enum uint {
RSHIFT,
RSHIFTEQ,
SEMICOLON,
- SLICE,
TIMES,
TIMESEQ,
LAST_BTOK = TIMESEQ,
@@ -182,6 +183,7 @@ const bmap: [_]str = [
"def",
"defer",
"delete",
+ "done",
"else",
"enum",
"export",
@@ -244,6 +246,7 @@ const bmap: [_]str = [
"/=",
".",
"::",
+ "..",
"...",
"=",
">",
@@ -277,7 +280,6 @@ const bmap: [_]str = [
">>",
">>=",
";",
- "..",
"*",
"*=",
];
diff --git a/hare/module/deps.ha b/hare/module/deps.ha
@@ -30,24 +30,24 @@ export type module = struct {
// The list will be sorted alphabetically and deduplicated.
export fn parse_deps(files: str...) ([]ast::ident | error) = {
let deps: []ast::ident = [];
- for (let i = 0z; i < len(files); i += 1) {
- let handle = match (os::open(files[i])) {
+ for (let file .. files) {
+ let handle = match (os::open(file)) {
case let f: io::file =>
yield f;
case let e: fs::error =>
- return attach(strings::dup(files[i]), e);
+ return attach(strings::dup(file), e);
};
defer io::close(handle)!;
let sc = bufio::newscanner(handle, types::SIZE_MAX);
defer bufio::finish(&sc);
- let lexer = lex::init(&sc, files[i]);
+ let lexer = lex::init(&sc, file);
let imports = parse::imports(&lexer)?;
defer ast::imports_finish(imports);
// dedupe + insertion sort
- for (let i = 0z; i < len(imports); i += 1) {
- let id = imports[i].ident;
+ for (let import &.. imports) {
+ 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));
@@ -95,16 +95,13 @@ fn get_deps(cachedir: str, srcs: *srcset) ([]ast::ident | error) = {
deps = parse_deps(srcs.ha...)?;
io::trunc(depsfile, 0)?;
let out = bufio::init(depsfile, [], buf.buf);
- for (let i = 0z; i < len(deps); i += 1) {
- unparse::ident(&out, deps[i])?;
+ for (let dep .. deps) {
+ unparse::ident(&out, dep)?;
fmt::fprintln(&out)?;
};
} else {
let in = bufio::newscanner_static(depsfile, buf.buf);
- for (true) match (bufio::scan_line(&in)?) {
- case io::EOF =>
- break;
- case let s: const str =>
+ for (let s => bufio::scan_line(&in)?) {
append(deps, parse::identstr(s)?);
};
};
@@ -193,16 +190,16 @@ export fn finish(mod: *module) void = {
ast::ident_free(mod.ns);
free(mod.path);
finish_srcset(&mod.srcs);
- for (let i = 0z; i < len(mod.deps); i += 1) {
- ast::ident_free(mod.deps[i].1);
+ for (let (_, ident) .. mod.deps) {
+ ast::ident_free(ident);
};
free(mod.deps);
};
// Free all the [[module]]s in a slice of modules, and then the slice itself.
export fn free_slice(mods: []module) void = {
- for (let i = 0z; i < len(mods); i += 1) {
- finish(&mods[i]);
+ for (let mod &.. mods) {
+ finish(mod);
};
free(mods);
};
diff --git a/hare/module/format.ha b/hare/module/format.ha
@@ -15,15 +15,15 @@ export fn format_tags(
let n = 0z;
match (tags) {
case let tags: []str =>
- for (let i = 0z; i < len(tags); i += 1) {
- n += fmt::fprintf(out, "+{}", tags[i])?;
+ for (let tag .. tags) {
+ n += fmt::fprintf(out, "+{}", tag)?;
};
case let tags: []tag =>
- for (let i = 0z; i < len(tags); i += 1) {
+ for (let tag .. tags) {
n += fmt::fprintf(
out,
- if (tags[i].include) "+{}" else "-{}",
- tags[i].name)?;
+ if (tag.include) "+{}" else "-{}",
+ tag.name)?;
};
};
return n;
@@ -37,18 +37,22 @@ export fn format_srcset(out: io::handle, srcs: *srcset) (size | io::error) = {
n += fmt::fprintln(out)?;
const dt = date::from_instant(chrono::LOCAL, srcs.mtime);
n += date::format(out, "last change to source list: %F %T\n", &dt)?;
+
n += fmt::fprintln(out, "hare sources:")?;
- for (let i = 0z; i < len(srcs.ha); i += 1) {
- n += fmt::fprintln(out, " ", srcs.ha[i])?;
+ for (let ha .. srcs.ha) {
+ n += fmt::fprintln(out, " ", ha)?;
};
+
n += fmt::fprintln(out, "assembly sources:")?;
- for (let i = 0z; i < len(srcs.s); i += 1) {
- n += fmt::fprintln(out, " ", srcs.s[i])?;
+ for (let s .. srcs.s) {
+ n += fmt::fprintln(out, " ", s)?;
};
+
n += fmt::fprintln(out, "object sources:")?;
- for (let i = 0z; i < len(srcs.o); i += 1) {
- n += fmt::fprintln(out, " ", srcs.o[i])?;
+ for (let o .. srcs.o) {
+ n += fmt::fprintln(out, " ", o)?;
};
+
return n;
};
@@ -59,9 +63,9 @@ export fn format(out: io::handle, mod: *module) (size | io::error) = {
n += fmt::fprintln(out, "path:", mod.path)?;
n += format_srcset(out, &mod.srcs)?;
n += fmt::fprintln(out, "dependencies:")?;
- for (let i = 0z; i < len(mod.deps); i += 1) {
+ for (let (_, ident) .. mod.deps) {
n += fmt::fprint(out, " ")?;
- n += unparse::ident(out, mod.deps[i].1)?;
+ n += unparse::ident(out, ident)?;
n += fmt::fprintln(out)?;
};
return n;
diff --git a/hare/module/srcs.ha b/hare/module/srcs.ha
@@ -63,9 +63,9 @@ export fn find(ctx: *context, loc: location) ((str, srcset) | error) = {
case let e: error =>
return e;
};
- case let mod: ast::ident =>
+ case let ident: ast::ident =>
let tok = strings::tokenize(ctx.harepath, ":");
- let next: (str | void) = ".";
+ let next: (str | done) = ".";
for (next is str; next = strings::next_token(&tok)) {
if (!os::exists(next as str)) {
continue;
@@ -73,8 +73,8 @@ export fn find(ctx: *context, loc: location) ((str, srcset) | error) = {
static let buf = path::buffer { ... };
path::set(&buf, os::realpath(next as str)?)?;
- for (let i = 0z; i < len(mod); i += 1) {
- path::push(&buf, mod[i])?;
+ for (let part .. ident) {
+ path::push(&buf, part)?;
};
match (path_find(ctx, &buf)) {
@@ -85,7 +85,7 @@ export fn find(ctx: *context, loc: location) ((str, srcset) | error) = {
return attach(strings::dup(path::string(&buf)), e);
};
};
- return attach(locstr(mod), not_found);
+ return attach(locstr(ident), not_found);
};
};
@@ -277,10 +277,8 @@ fn _findsrcs(
return attach(strings::dup(pathstr), e);
};
defer fs::finish(iter);
- for (true) match (fs::next(iter)?) {
- case void =>
- break;
- case let d: fs::dirent =>
+
+ for (let d => fs::next(iter)?) {
path::push(buf, d.name)?;
defer path::pop(buf);
@@ -338,13 +336,16 @@ export fn parse_tags(s: str) ([]tag | error) = {
// Checks if a set of tags are compatible with a tag requirement.
export fn tags_compat(have: []str, want: []tag) bool = {
- for (let i = 0z; i < len(want); i += 1) {
- let t = want[i];
+ for (let t .. want) {
let found = false;
- for (let j = 0z; j < len(have); j += 1) if (have[j] == t.name) {
- found = true;
- break;
+
+ for (let ht .. have) {
+ if (ht == t.name) {
+ found = true;
+ break;
+ };
};
+
if (t.include ^^ found) {
return false;
};
@@ -355,14 +356,17 @@ export fn tags_compat(have: []str, want: []tag) bool = {
// same as tags_compat, but also adds any relevant tags to a seentags list
// for use in _findsrcs.
fn seentags_compat(have: []str, want: []tag, seen: *[]str) bool = {
- for (let i = 0z; i < len(want); i += 1) {
- let t = want[i];
+ for (let t .. want) {
let found = false;
- for (let j = 0z; j < len(have); j += 1) if (have[j] == t.name) {
- insert_uniq(seen, t.name);
- found = true;
- break;
+
+ for (let ht .. have) {
+ if (ht == t.name) {
+ insert_uniq(seen, t.name);
+ found = true;
+ break;
+ };
};
+
if (t.include ^^ found) {
return false;
};
diff --git a/hare/module/util.ha b/hare/module/util.ha
@@ -33,23 +33,22 @@ export fn outdated(target: str, deps: []str, mtime: time::instant) bool = {
if (time::compare(current, mtime) < 0) {
return true;
};
- for (let i = 0z; i < len(deps); i += 1) match (os::stat(deps[i])) {
- case fs::error =>
- continue;
- case let stat: fs::filestat =>
- if (time::compare(current, stat.mtime) < 0) {
- return true;
+ for (let dep .. deps) {
+ match (os::stat(dep)) {
+ case fs::error =>
+ continue;
+ case let stat: fs::filestat =>
+ if (time::compare(current, stat.mtime) < 0) {
+ return true;
+ };
};
};
return false;
};
// Wrapper for [[fs::next]] that only returns valid submodule directories.
-export fn next(it: *fs::iterator) (fs::dirent | void | fs::error) = {
- for (true) match (fs::next(it)?) {
- case void =>
- return void;
- case let d: fs::dirent =>
+export fn next(it: *fs::iterator) (fs::dirent | done | fs::error) = {
+ for (let d => fs::next(it)?) {
if (!fs::isdir(d.ftype)) {
continue;
};
@@ -57,18 +56,20 @@ export fn next(it: *fs::iterator) (fs::dirent | void | fs::error) = {
return d;
};
};
+ return done;
};
fn is_submodule(path: str) bool = {
let it = strings::iter(path);
- for (let first = true; true; first = false) match (strings::next(&it)) {
- case void =>
- break;
- case let r: rune =>
+
+ let first = true;
+ for (let r => strings::next(&it)) {
if (!ascii::isalpha(r) && r != '_'
&& (first || !ascii::isdigit(r))) {
return false;
};
+
+ first = false;
};
return true;
};
diff --git a/hare/parse/+test/expr_test.ha b/hare/parse/+test/expr_test.ha
@@ -199,7 +199,9 @@
};
@test fn for_expr() void = {
- roundtrip("export fn main() void = {
+ roundtrip("fn next() (int | done) = 4;
+
+export fn main() void = {
for (true) {
x;
};
@@ -215,7 +217,13 @@
for (let x = 10; x < 10; x) {
x;
};
- for (static let x = 0; x < 10) {
+ for (let x => next()) {
+ x;
+ };
+ for (let x .. [1, 2, 3]) {
+ x;
+ };
+ for (let x &.. [1, 2, 3]) {
x;
};
};
diff --git a/hare/parse/decl.ha b/hare/parse/decl.ha
@@ -13,15 +13,12 @@ fn attr_symbol(lexer: *lex::lexer) (str | error) = {
let s = t.1 as str;
let d = strings::iter(s);
match (strings::next(&d)) {
- case void => void;
+ case done => void;
case let r: rune =>
synassert(t.2, ascii::isalpha(r) || r == '.'
|| r == '_', "Invalid symbol")?;
};
- for (true) match (strings::next(&d)) {
- case void =>
- break;
- case let r: rune =>
+ for (let r => strings::next(&d)) {
synassert(t.2, ascii::isalnum(r) || r == '$'
|| r == '.' || r == '_', "Invalid symbol")?;
};
@@ -163,10 +160,9 @@ fn decl_func(lexer: *lex::lexer) (ast::decl_func | error) = {
let tok = want(lexer, ltok::EQUAL, ltok::SEMICOLON)?;
let body = switch (tok.0) {
case ltok::EQUAL =>
- const params = prototype.params;
- for (let i = 0z; i < len(params); i += 1) {
- synassert(params[i].loc,
- len(params[i].name) > 0,
+ for (let param &.. prototype.params) {
+ synassert(param.loc,
+ len(param.name) > 0,
"Expected parameter name in function declaration")?;
};
yield alloc(expr(lexer)?);
diff --git a/hare/parse/doc/doc.ha b/hare/parse/doc/doc.ha
@@ -63,10 +63,7 @@ fn _parse(sc: *bufio::scanner) (doc | ...error | utf8::invalid) = {
let loc = lex::location { ... };
let doc: doc = [];
- for (true) match (bufio::scan_rune(sc)?) {
- case io::EOF =>
- break;
- case let r: rune =>
+ for (let r => bufio::scan_rune(sc)?) {
if (r == ' ') {
r = match (bufio::scan_rune(sc)?) {
case io::EOF =>
@@ -101,10 +98,7 @@ fn scan_code_sample(
loc: *lex::location,
) (code_sample | ...error | utf8::invalid) = {
let s = memio::dynamic();
- for (true) match (bufio::scan_rune(sc)?) {
- case io::EOF =>
- break;
- case let r: rune =>
+ for (let r => bufio::scan_rune(sc)?) {
switch (r) {
case '\t' =>
loc.col += 8 - loc.col % 8;
@@ -197,10 +191,7 @@ fn scan_paragraph(
defer io::close(&s)!;
let state = state::NORMAL;
- for (true) match (bufio::scan_rune(sc)?) {
- case io::EOF =>
- break;
- case let r: rune =>
+ for (let r => bufio::scan_rune(sc)?) {
switch (r) {
case '\t' =>
if (state == state::NEWLINE && loc.col <= 1) {
@@ -314,13 +305,13 @@ fn scan_paragraph(
// Frees resources associated with a [[doc]].
export fn freeall(doc: doc) void = {
- for (let i = 0z; i < len(doc); i += 1) {
- match (doc[i]) {
+ for (let d .. doc) {
+ match (d) {
case let p: paragraph =>
free_paragraph(p);
case let l: list =>
- for (let i = 0z; i < len(l); i += 1) {
- free_paragraph(l[i]);
+ for (let p .. l) {
+ free_paragraph(p);
};
free(l);
case let c: code_sample =>
@@ -331,8 +322,8 @@ export fn freeall(doc: doc) void = {
};
fn free_paragraph(p: paragraph) void = {
- for (let i = 0z; i < len(p); i += 1) {
- match (p[i]) {
+ for (let entry .. p) {
+ match (entry) {
case let s: str =>
free(s);
case let d: decl_ref =>
diff --git a/hare/parse/expr.ha b/hare/parse/expr.ha
@@ -549,6 +549,8 @@ fn literal(lexer: *lex::lexer) (ast::expr | error) = {
};
case ltok::VOID =>
yield void;
+ case ltok::DONE =>
+ yield done;
case ltok::TRUE =>
yield true;
case ltok::FALSE =>
@@ -684,35 +686,104 @@ fn for_expr(lexer: *lex::lexer) (ast::expr | error) = {
} else "";
want(lexer, ltok::LPAREN)?;
- const bindings: nullable *ast::expr =
- match (peek(lexer, ltok::DEF, ltok::LET, ltok::CONST,
- ltok::STATIC)?) {
- case void =>
- yield null;
- case let tok: lex::token =>
- let is_static = if (tok.0 == ltok::STATIC) {
- want(lexer, ltok::STATIC)?;
- match (peek(lexer, ltok::LET, ltok::CONST)?) {
- case lex::token => void;
- case void =>
- want(lexer, ltok::LET, ltok::CONST)?;
- abort(); // unreachable
+ let kind = void: (ast::for_kind | void);
+ let predicate_loc = lex::mkloc(lexer);
+
+ const bindings = match (try(lexer, ltok::LET, ltok::CONST)?) {
+ case let tok: lex::token =>
+ const binding_kind = switch (tok.0) {
+ case ltok::LET =>
+ yield ast::binding_kind::LET;
+ case ltok::CONST =>
+ yield ast::binding_kind::CONST;
+ case => abort(); // unreachable
+ };
+
+ let bindings: []ast::binding = [];
+
+ for (true) {
+ const (tok, value, _) = want(lexer,
+ ltok::NAME, ltok::LPAREN)?;
+ const binding_name = switch (tok) {
+ case ltok::NAME =>
+ yield value as str;
+ case ltok::LPAREN =>
+ yield binding_unpack(lexer)?;
+ case => abort(); // unreachable
+ };
+ const btype: nullable *ast::_type =
+ if (try(lexer, ltok::COLON)? is lex::token) {
+ yield alloc(_type(lexer)?);
+ } else null;
+
+ const (tok, _, _) = want(lexer, ltok::EQUAL,
+ ltok::DOUBLE_DOT, ltok::BAND, ltok::ARROW)?;
+
+ if (kind is void) {
+ switch (tok) {
+ case ltok::EQUAL =>
+ kind = ast::for_kind::ACCUMULATOR;
+ case ltok::DOUBLE_DOT =>
+ kind = ast::for_kind::EACH_VALUE;
+ case ltok::BAND =>
+ want(lexer, ltok::DOUBLE_DOT)?;
+ kind = ast::for_kind::EACH_POINTER;
+ case ltok::ARROW =>
+ kind = ast::for_kind::ITERATOR;
+ case => abort(); // unreachable
};
- yield true;
- } else false;
- const bindings = alloc(binding(lexer, is_static)?);
+ } else if (kind as ast::for_kind !=
+ ast::for_kind::ACCUMULATOR
+ || tok != ltok::EQUAL) {
+ return syntaxerr(lex::mkloc(lexer),
+ "Cannot create multiple bindings in non-c-style loop");
+ };
+
+ 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 =>
+ void;
+ case void =>
+ break;
+ };
+ };
+
+ if (kind as ast::for_kind == ast::for_kind::ACCUMULATOR) {
want(lexer, ltok::SEMICOLON)?;
- yield bindings;
};
- const cond = alloc(expr(lexer)?);
- const afterthought: nullable *ast::expr =
- match (peek(lexer, ltok::SEMICOLON)?) {
- case void =>
- yield null;
+
+ yield alloc(ast::expr {
+ start = predicate_loc,
+ end = lex::prevloc(lexer),
+ expr = ast::binding_expr {
+ is_static = false,
+ kind = binding_kind,
+ bindings = bindings,
+ },
+ });
+ case void =>
+ kind = ast::for_kind::ACCUMULATOR;
+ yield null;
+ };
+
+ const cond: nullable *ast::expr = null;
+ const afterthought: nullable *ast::expr = null;
+
+ if (kind as ast::for_kind == ast::for_kind::ACCUMULATOR) {
+ cond = alloc(expr(lexer)?);
+ match (try(lexer, ltok::SEMICOLON)) {
case lex::token =>
- want(lexer, ltok::SEMICOLON)?;
- yield alloc(expr(lexer)?);
+ afterthought = alloc(expr(lexer)?);
+ case void => void;
};
+ };
want(lexer, ltok::RPAREN)?;
@@ -721,6 +792,7 @@ fn for_expr(lexer: *lex::lexer) (ast::expr | error) = {
start = tok.2,
end = lex::prevloc(lexer),
expr = ast::for_expr {
+ kind = kind as ast::for_kind,
bindings = bindings,
cond = cond,
afterthought = afterthought,
@@ -769,12 +841,12 @@ fn indexing(lexer: *lex::lexer, lvalue: ast::expr) (ast::expr | error) = {
let is_slice = false;
let start: nullable *ast::expr = null, end: nullable *ast::expr = null;
- if (try(lexer, ltok::SLICE)? is lex::token) {
+ if (try(lexer, ltok::DOUBLE_DOT)? is lex::token) {
is_slice = true;
} else {
start = alloc(expr(lexer)?);
};
- if (!is_slice && try(lexer, ltok::SLICE)? is lex::token) {
+ if (!is_slice && try(lexer, ltok::DOUBLE_DOT)? is lex::token) {
is_slice = true;
};
if (is_slice && peek(lexer, ltok::RBRACKET)? is void) {
@@ -820,7 +892,7 @@ fn plain_expression(lexer: *lex::lexer) (ast::expr | error) = {
return literal(lexer);
};
switch (tok.0) {
- case ltok::TRUE, ltok::FALSE, ltok::NULL, ltok::VOID =>
+ case ltok::TRUE, ltok::FALSE, ltok::NULL, ltok::VOID, ltok::DONE =>
return literal(lexer);
case ltok::LBRACKET =>
return plain_array(lexer)?;
diff --git a/hare/parse/type.ha b/hare/parse/type.ha
@@ -114,6 +114,8 @@ fn primitive_type(lexer: *lex::lexer) (ast::_type | error) = {
yield builtin_type::F64;
case ltok::BOOL =>
yield builtin_type::BOOL;
+ case ltok::DONE =>
+ yield builtin_type::DONE;
case ltok::VALIST =>
yield builtin_type::VALIST;
case ltok::VOID =>
@@ -480,12 +482,11 @@ export fn _type(lexer: *lex::lexer) (ast::_type | error) = {
let tok = peek(lexer)? as lex::token;
let typ: ast::_type = switch (tok.0) {
- case ltok::RUNE, ltok::STR, ltok::BOOL,
- ltok::I8, ltok::I16, 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 =>
+ case ltok::RUNE, ltok::STR, ltok::BOOL, ltok::DONE, ltok::I8, ltok::I16,
+ 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 =>
yield primitive_type(lexer)?;
case ltok::ENUM =>
yield enum_type(lexer)?;
diff --git a/hare/types/+test.ha b/hare/types/+test.ha
@@ -330,9 +330,9 @@ fn resolve(
assert(htype._align == 8);
let t = htype.repr as tagged;
assert(len(t) == 3);
- assert(t[0].repr as builtin == builtin::STR);
- assert(t[1].repr as builtin == builtin::INT);
- assert(t[2].repr as builtin == builtin::VOID);
+ assert(t[0].repr as builtin == builtin::INT);
+ assert(t[1].repr as builtin == builtin::VOID);
+ assert(t[2].repr as builtin == builtin::STR);
};
@test fn alias() void = {
@@ -372,6 +372,7 @@ fn resolve(
@test fn builtins() void = {
const builtins = [
(&builtin_bool, "bool"),
+ (&builtin_done, "done"),
(&builtin_f32, "f32"),
(&builtin_f64, "f64"),
(&builtin_i8, "i8"),
diff --git a/hare/types/builtins.ha b/hare/types/builtins.ha
@@ -12,11 +12,19 @@ export const builtin_bool: _type = _type {
...
};
+// [[_type]] representation of done.
+export const builtin_done: _type = _type {
+ repr = builtin::DONE,
+ sz = 0, _align = 0,
+ id = 3950255460,
+ ...
+};
+
// [[_type]] representation of f32.
export const builtin_f32: _type = _type {
repr = builtin::F32,
sz = 4, _align = 4,
- id = 3950255460,
+ id = 1568378015,
...
};
@@ -24,7 +32,7 @@ export const builtin_f32: _type = _type {
export const builtin_f64: _type = _type {
repr = builtin::F64,
sz = 8, _align = 8,
- id = 1568378015,
+ id = 930681398,
...
};
@@ -32,7 +40,7 @@ export const builtin_f64: _type = _type {
export const builtin_i8: _type = _type {
repr = builtin::I8,
sz = 1, _align = 1,
- id = 3312558843,
+ id = 2674862226,
...
};
@@ -40,7 +48,7 @@ export const builtin_i8: _type = _type {
export const builtin_i16: _type = _type {
repr = builtin::I16,
sz = 2, _align = 2,
- id = 930681398,
+ id = 2037165609,
...
};
@@ -48,7 +56,7 @@ export const builtin_i16: _type = _type {
export const builtin_i32: _type = _type {
repr = builtin::I32,
sz = 4, _align = 4,
- id = 2037165609,
+ id = 1399468992,
...
};
@@ -56,7 +64,7 @@ export const builtin_i32: _type = _type {
export const builtin_i64: _type = _type {
repr = builtin::I64,
sz = 8, _align = 8,
- id = 1399468992,
+ id = 3312558843,
...
};
@@ -64,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 = 2374983655,
+ id = 1737287038,
...
};
@@ -72,7 +80,7 @@ export const builtin_opaque: _type = _type {
export const builtin_never: _type = _type {
repr = builtin::NEVER,
sz = SIZE_UNDEFINED, _align = SIZE_UNDEFINED,
- id = 2374983655,
+ id = 1737287038,
...
};
@@ -80,7 +88,7 @@ export const builtin_never: _type = _type {
export const builtin_rune: _type = _type {
repr = builtin::RUNE,
sz = 4, _align = 4,
- id = 1737287038,
+ id = 2843771249,
...
};
@@ -88,7 +96,7 @@ export const builtin_rune: _type = _type {
export const builtin_u8: _type = _type {
repr = builtin::U8,
sz = 1, _align = 1,
- id = 1268499444,
+ id = 3181589295,
...
};
@@ -96,7 +104,7 @@ export const builtin_u8: _type = _type {
export const builtin_u16: _type = _type {
repr = builtin::U16,
sz = 2, _align = 2,
- id = 4119164483,
+ id = 3481467866,
...
};
@@ -104,7 +112,7 @@ export const builtin_u16: _type = _type {
export const builtin_u32: _type = _type {
repr = builtin::U32,
sz = 4, _align = 4,
- id = 3481467866,
+ id = 1906196061,
...
};
@@ -112,7 +120,7 @@ export const builtin_u32: _type = _type {
export const builtin_u64: _type = _type {
repr = builtin::U64,
sz = 8, _align = 8,
- id = 1906196061,
+ id = 1268499444,
...
};
@@ -120,6 +128,6 @@ export const builtin_u64: _type = _type {
export const builtin_void: _type = _type {
repr = builtin::VOID,
sz = 0, _align = 0,
- id = 3650376889,
+ id = 3012680272,
...
};
diff --git a/hare/types/hash.ha b/hare/types/hash.ha
@@ -8,15 +8,17 @@ use strings;
// Keep ordered with respect to bootstrap harec:include/types.h
type storage = enum u8 {
- BOOL, F32, F64, I16, I32, I64, I8, INT, NEVER, NULL, OPAQUE, RUNE, SIZE,
- STRING, U16, U32, U64, U8, UINT, UINTPTR, VOID, ALIAS, ARRAY, ENUM,
- FUNCTION, POINTER, SLICE, STRUCT, TAGGED, TUPLE, UNION, VALIST,
+ BOOL, DONE, F32, F64, I16, I32, I64, I8, INT, NEVER, NULL, OPAQUE, RUNE,
+ SIZE, STRING, U16, U32, U64, U8, UINT, UINTPTR, VOID, ALIAS, ARRAY,
+ ENUM, FUNCTION, POINTER, SLICE, STRUCT, TAGGED, TUPLE, UNION, VALIST,
};
fn builtin_storage(b: builtin) u8 = {
switch (b) {
case builtin::BOOL =>
return storage::BOOL;
+ case builtin::DONE =>
+ return storage::DONE;
case builtin::F32 =>
return storage::F32;
case builtin::F64 =>
diff --git a/hare/types/store.ha b/hare/types/store.ha
@@ -149,6 +149,8 @@ export fn lookup(
return &builtin_u64;
case builtin::VOID =>
return &builtin_void;
+ case builtin::DONE =>
+ return &builtin_done;
case => void;
};
case => void;
@@ -184,6 +186,9 @@ fn fromast(store: *typestore, atype: *ast::_type) (_type | deferred | error) = {
sz = store.arch._int;
_align = store.arch._int;
yield builtin::BOOL;
+ case ast::builtin_type::DONE =>
+ sz = 0; _align = 0;
+ yield builtin::DONE;
case ast::builtin_type::F32 =>
sz = 4; _align = 4;
yield builtin::F32;
diff --git a/hare/types/types.ha b/hare/types/types.ha
@@ -21,9 +21,9 @@ export type array = struct {
export type builtin = enum u8 {
// Keep me consistent with ast::builtin
- BOOL, F32, F64, FCONST, I16, I32, I64, I8, ICONST, INT, NEVER, NULL,
- OPAQUE, RCONST, RUNE, SIZE, STR, U16, U32, U64, U8, UINT, UINTPTR,
- VALIST, VOID,
+ 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
};
// An enum type, e.g. enum { FOO = 0 }
diff --git a/hare/unparse/decl.ha b/hare/unparse/decl.ha
@@ -162,11 +162,9 @@ fn comment(ctx: *context, syn: *synfunc, s: str) (size | io::error) = {
let n = 0z;
let s = strings::trimsuffix(s, "\n");
let s = strings::tokenize(s, "\n");
- for (true) match (strings::next_token(&s)) {
- case void =>
- break;
- case let line: str =>
- for (let j = 0z; j < ctx.indent; j += 1) {
+
+ for (let line => strings::next_token(&s)) {
+ for (let i = 0z; i < ctx.indent; i += 1) {
n += syn(ctx, "\t", synkind::COMMENT)?;
ctx.linelen += 8;
};
diff --git a/hare/unparse/expr.ha b/hare/unparse/expr.ha
@@ -203,61 +203,7 @@ fn _expr(ctx: *context, syn: *synfunc, e: *ast::expr) (size | io::error) = {
z += binexprval(ctx, syn, e.rvalue, prec)?;
return z;
case let e: ast::binding_expr =>
- let z = 0z;
- if (e.is_static) {
- z += syn(ctx, "static", synkind::KEYWORD)?;
- z += space(ctx)?;
- };
- switch (e.kind) {
- case ast::binding_kind::DEF =>
- z += syn(ctx, "def", synkind::KEYWORD)?;
- case ast::binding_kind::CONST =>
- z += syn(ctx, "const", synkind::KEYWORD)?;
- case ast::binding_kind::LET =>
- z += syn(ctx, "let", synkind::KEYWORD)?;
- };
- z += space(ctx)?;
- for (let i = 0z; i < len(e.bindings); i += 1) {
- let binding = e.bindings[i];
- match (binding.name) {
- case let s: str =>
- z += syn(ctx, s, synkind::IDENT)?;
- case let u: ast::binding_unpack =>
- z += syn(ctx, "(", synkind::PUNCTUATION)?;
- for (let i = 0z; i < len(u); i += 1) {
- match (u[i]) {
- case let s: str =>
- z += syn(ctx, s,
- synkind::IDENT)?;
- case void =>
- z += syn(ctx, "_",
- synkind::OPERATOR)?;
- };
- if (i + 1 < len(u)) {
- z += syn(ctx, ",",
- synkind::PUNCTUATION)?;
- z += space(ctx)?;
- };
- };
- z += syn(ctx, ")", synkind::PUNCTUATION)?;
- };
- match (binding._type) {
- case let t: *ast::_type =>
- z += syn(ctx, ":", synkind::PUNCTUATION)?;
- z += space(ctx)?;
- z += __type(ctx, syn, t)?;
- case null => void;
- };
- z += space(ctx)?;
- z += syn(ctx, "=", synkind::OPERATOR)?;
- z += space(ctx)?;
- z += _expr(ctx, syn, binding.init)?;
- if (i + 1 < len(e.bindings)) {
- z += syn(ctx, ",", synkind::PUNCTUATION)?;
- z += space(ctx)?;
- };
- };
- return z;
+ return binding_expr(ctx, syn, &e, "=")?;
case let e: ast::break_expr =>
let z = syn(ctx, "break", synkind::KEYWORD)?;
if (e != "") {
@@ -388,9 +334,9 @@ fn _expr(ctx: *context, syn: *synfunc, e: *ast::expr) (size | io::error) = {
};
z += syn(ctx, "{", synkind::PUNCTUATION)?;
ctx.indent += 1;
- for (let i = 0z; i < len(e.exprs); i += 1) {
+ for (let expr .. e.exprs) {
z += newline(ctx)?;
- z += stmt(ctx, syn, e.exprs[i])?;
+ z += stmt(ctx, syn, expr)?;
};
ctx.indent -= 1;
z += newline(ctx)?;
@@ -705,9 +651,9 @@ fn struct_literal(
z += space(ctx)?;
z += syn(ctx, "{", synkind::PUNCTUATION)?;
ctx.indent += 1;
- for (let i = 0z; i < len(sc.fields); i += 1) {
+ for (let field .. sc.fields) {
z += newline(ctx)?;
- match (sc.fields[i]) {
+ match (field) {
case let sv: ast::struct_value =>
z += syn(ctx, sv.name, synkind::SECONDARY)?;
match (sv._type) {
@@ -736,6 +682,70 @@ fn struct_literal(
return z;
};
+fn binding_expr(
+ ctx: *context,
+ syn: *synfunc,
+ e: *ast::binding_expr,
+ assign_op: str
+) (size | io::error) = {
+ let z = 0z;
+ if (e.is_static) {
+ z += syn(ctx, "static", synkind::KEYWORD)?;
+ z += space(ctx)?;
+ };
+ switch (e.kind) {
+ case ast::binding_kind::DEF =>
+ z += syn(ctx, "def", synkind::KEYWORD)?;
+ case ast::binding_kind::CONST =>
+ z += syn(ctx, "const", synkind::KEYWORD)?;
+ case ast::binding_kind::LET =>
+ z += syn(ctx, "let", synkind::KEYWORD)?;
+ };
+ z += space(ctx)?;
+ for (let i = 0z; i < len(e.bindings); i += 1) {
+ let binding = e.bindings[i];
+
+ match (binding.name) {
+ case let s: str =>
+ z += syn(ctx, s, synkind::IDENT)?;
+ case let u: ast::binding_unpack =>
+ z += syn(ctx, "(", synkind::PUNCTUATION)?;
+ for (let i = 0z; i < len(u); i += 1) {
+ match (u[i]) {
+ case let s: str =>
+ z += syn(ctx, s,
+ synkind::IDENT)?;
+ case void =>
+ z += syn(ctx, "_",
+ synkind::OPERATOR)?;
+ };
+ if (i + 1 < len(u)) {
+ z += syn(ctx, ",",
+ synkind::PUNCTUATION)?;
+ z += space(ctx)?;
+ };
+ };
+ z += syn(ctx, ")", synkind::PUNCTUATION)?;
+ };
+ match (binding._type) {
+ case let t: *ast::_type =>
+ z += syn(ctx, ":", synkind::PUNCTUATION)?;
+ z += space(ctx)?;
+ z += __type(ctx, syn, t)?;
+ case null => void;
+ };
+ z += space(ctx)?;
+ z += syn(ctx, assign_op, synkind::OPERATOR)?;
+ z += space(ctx)?;
+ z += _expr(ctx, syn, binding.init)?;
+ if (i + 1 < len(e.bindings)) {
+ z += syn(ctx, ",", synkind::PUNCTUATION)?;
+ z += space(ctx)?;
+ };
+ };
+ return z;
+};
+
fn for_expr(
ctx: *context,
syn: *synfunc,
@@ -749,22 +759,40 @@ fn for_expr(
z += space(ctx)?;
};
z += syn(ctx, "(", synkind::PUNCTUATION)?;
+
+ let assign_op = switch (e.kind) {
+ case ast::for_kind::ACCUMULATOR =>
+ yield "=";
+ case ast::for_kind::EACH_VALUE =>
+ yield "..";
+ case ast::for_kind::EACH_POINTER =>
+ yield "&..";
+ case ast::for_kind::ITERATOR =>
+ yield "=>";
+ };
+
match (e.bindings) {
+ case let bind_expr: *ast::expr =>
+ z += binding_expr(ctx, syn,
+ &(bind_expr.expr as ast::binding_expr), assign_op)?;
+
+ if (e.kind == ast::for_kind::ACCUMULATOR) {
+ z += syn(ctx, ";", synkind::PUNCTUATION)?;
+ z += space(ctx)?;
+ };
case null => void;
- case let e: *ast::expr =>
- z += _expr(ctx, syn, e)?;
- z += syn(ctx, ";", synkind::PUNCTUATION)?;
- z += space(ctx)?;
};
- z += _expr(ctx, syn, e.cond)?;
+ if (e.kind == ast::for_kind::ACCUMULATOR) {
+ z += _expr(ctx, syn, e.cond as *ast::expr)?;
- match (e.afterthought) {
- case null => void;
- case let e: *ast::expr =>
- z += syn(ctx, ";", synkind::PUNCTUATION)?;
- z += space(ctx)?;
- z += _expr(ctx, syn, e)?;
+ match (e.afterthought) {
+ case null => void;
+ case let e: *ast::expr =>
+ z += syn(ctx, ";", synkind::PUNCTUATION)?;
+ z += space(ctx)?;
+ z += _expr(ctx, syn, e)?;
+ };
};
z += syn(ctx, ")", synkind::PUNCTUATION)?;
@@ -791,9 +819,8 @@ fn switch_expr(
z += space(ctx)?;
z += syn(ctx, "{", synkind::PUNCTUATION)?;
- for (let i = 0z; i < len(e.cases); i += 1) {
+ for (let item .. e.cases) {
z += newline(ctx)?;
- const item = e.cases[i];
z += syn(ctx, "case", synkind::KEYWORD)?;
z += space(ctx)?;
if (len(item.options) == 0) {
@@ -837,10 +864,9 @@ fn match_expr(
z += space(ctx)?;
z += syn(ctx, "{", synkind::PUNCTUATION)?;
- for (let i = 0z; i < len(e.cases); i += 1) {
+ for (let item .. e.cases) {
z += newline(ctx)?;
z += syn(ctx, "case", synkind::KEYWORD)?;
- const item = e.cases[i];
if (len(item.name) > 0) {
z += space(ctx)?;
z += syn(ctx, "let", synkind::KEYWORD)?;
@@ -900,9 +926,9 @@ fn case_exprs(
case => void;
};
ctx.indent += 1;
- for (let j = 0z; j < len(exprs); j += 1) {
+ for (let expr .. exprs) {
z += newline(ctx)?;
- z += stmt(ctx, syn, exprs[j])?;
+ z += stmt(ctx, syn, expr)?;
};
ctx.indent -= 1;
diff --git a/hare/unparse/import.ha b/hare/unparse/import.ha
@@ -76,11 +76,11 @@ export fn import(
...
}, "use foo::bar::*;"),
];
- for (let i = 0z; i < len(tests); i += 1) {
+ for (let (ast_import, str_import) .. tests) {
let buf = memio::dynamic();
- import(&buf, &syn_nowrap, &tests[i].0)!;
+ import(&buf, &syn_nowrap, &ast_import)!;
let s = memio::string(&buf)!;
- assert(s == tests[i].1);
+ assert(s == str_import);
free(s);
};
};
diff --git a/hare/unparse/type.ha b/hare/unparse/type.ha
@@ -16,6 +16,8 @@ case ast::builtin_type::FCONST, ast::builtin_type::ICONST,
abort("ICONST, FCONST, and RCONST have no lexical representation");
case ast::builtin_type::BOOL =>
yield "bool";
+case ast::builtin_type::DONE =>
+ yield "done";
case ast::builtin_type::F32 =>
yield "f32";
case ast::builtin_type::F64 =>
@@ -116,18 +118,18 @@ fn struct_union_type(
};
ctx.indent += 1z;
- for (let i = 0z; i < len(membs); i += 1) {
+ for (let memb .. membs) {
z += fmt::fprintln(ctx.out)?;
ctx.linelen = 0;
- if (membs[i].docs != "") {
- z += comment(ctx, syn, membs[i].docs)?;
+ if (memb.docs != "") {
+ z += comment(ctx, syn, memb.docs)?;
};
for (let i = 0z; i < ctx.indent; i += 1) {
z += fmt::fprint(ctx.out, "\t")?;
ctx.linelen += 8;
};
- match (membs[i]._offset) {
+ match (memb._offset) {
case null => void;
case let ex: *ast::expr =>
z += syn(ctx, "@offset(", synkind::ATTRIBUTE)?;
@@ -136,7 +138,7 @@ fn struct_union_type(
z += space(ctx)?;
};
- match (membs[i].member) {
+ match (memb.member) {
case let se: ast::struct_embedded =>
z += __type(ctx, syn, se)?;
case let sa: ast::struct_alias =>
@@ -216,8 +218,7 @@ fn __type(ctx: *context, syn: *synfunc, t: *ast::_type) (size | io::error) = {
ctx.indent += 1;
n += fmt::fprintln(ctx.out)?;
ctx.linelen = 0;
- for (let i = 0z; i < len(e.values); i += 1) {
- let value = e.values[i];
+ for (let value .. e.values) {
let wrotedocs = false;
if (value.docs != "") {
// Check if comment should go above or next to
diff --git a/hare/unparse/unit.ha b/hare/unparse/unit.ha
@@ -12,8 +12,8 @@ export fn subunit(
s: ast::subunit,
) (size | io::error) = {
let n = 0z;
- for (let i = 0z; i < len(s.imports); i += 1) {
- n += import(out, syn, &s.imports[i])?;
+ for (let imp &.. s.imports) {
+ n += import(out, syn, imp)?;
n += fmt::fprintln(out)?;
};
if (len(s.imports) > 0) {
diff --git a/io/copy.ha b/io/copy.ha
@@ -51,16 +51,9 @@ fn copy_streams(dest: *stream, src: *stream) (size | error) = {
fn copy_fallback(dest: handle, src: handle) (size | error) = {
let w = 0z;
let buf: [4096]u8 = [0...];
- for (true) {
- match (read(src, buf[..])?) {
- case let n: size =>
- if (n == 0) {
- break;
- };
- w += writeall(dest, buf[..n])?;
- case EOF =>
- break;
- };
+
+ for (let n => read(src, buf[..])?) {
+ w += writeall(dest, buf[..n])?;
};
return w;
};
diff --git a/io/drain.ha b/io/drain.ha
@@ -6,13 +6,9 @@
export fn drain(in: handle) ([]u8 | error) = {
let sink: []u8 = [];
static let buf: [4096]u8 = [0...];
- for (true) {
- match (read(in, buf[..])?) {
- case let n: size =>
- append(sink, buf[..n]...);
- case EOF =>
- break;
- };
+
+ for (let n => read(in, buf[..])?) {
+ append(sink, buf[..n]...);
};
return sink;
};
diff --git a/io/types.ha b/io/types.ha
@@ -11,7 +11,7 @@ export type underread = !size;
export type error = !(...errors::error | underread);
// Indicates an end-of-file condition.
-export type EOF = void;
+export type EOF = done;
// Converts an I/O [[error]] into a user-friendly string.
export fn strerror(err: error) str = {
diff --git a/mime/database.ha b/mime/database.ha
@@ -41,18 +41,18 @@ fn hashtable_insert(item: *mimetype) void = {
let bucket = &mimetable[hash % len(mimetable)];
append(bucket, item);
- for (let i = 0z; i < len(item.exts); i += 1) {
- const hash = fnv::string(item.exts[i]);
+ for (let ext .. item.exts) {
+ const hash = fnv::string(ext);
let bucket = &exttable[hash % len(exttable)];
append(bucket, item);
};
};
@fini fn fini() void = {
- for (let i = 0z; i < len(heap_db); i += 1) {
- free(heap_db[i].mime);
- strings::freeall(heap_db[i].exts);
- free(heap_db[i]);
+ for (let m .. heap_db) {
+ free(m.mime);
+ strings::freeall(m.exts);
+ free(m);
};
free(heap_db);
free(static_db);
diff --git a/mime/entries+test.ha b/mime/entries+test.ha
@@ -23,8 +23,8 @@ const text_hare: mimetype = mimetype {
assert(len(result.exts) >= 1);
let extfound = false;
- for (let i = 0z; i < len(result.exts); i += 1) {
- if (result.exts[i] == "txt") {
+ for (let ext .. result.exts) {
+ if (ext == "txt") {
extfound = true;
};
};
@@ -35,8 +35,8 @@ const text_hare: mimetype = mimetype {
assert(len(result.exts) >= 1);
let extfound = false;
- for (let i = 0z; i < len(result.exts); i += 1) {
- if (result.exts[i] == "ha") {
+ for (let ext .. result.exts) {
+ if (ext == "ha") {
extfound = true;
};
};
@@ -52,8 +52,8 @@ const text_hare: mimetype = mimetype {
assert(result.mime == "text/plain");
let extfound = false;
- for (let i = 0z; i < len(result.exts); i += 1) {
- if (result.exts[i] == "txt") {
+ for (let ext .. result.exts) {
+ if (ext == "txt") {
extfound = true;
};
};
@@ -67,8 +67,8 @@ const text_hare: mimetype = mimetype {
assert(len(result.exts) >= 1);
let extfound = false;
- for (let i = 0z; i < len(result.exts); i += 1) {
- if (result.exts[i] == "ha") {
+ for (let ext .. result.exts) {
+ if (ext == "ha") {
extfound = true;
};
};
diff --git a/mime/lookup.ha b/mime/lookup.ha
@@ -9,8 +9,7 @@ use strings;
export fn lookup_mime(mime: str) const nullable *mimetype = {
const hash = fnv::string(mime);
const bucket = &mimetable[hash % len(mimetable)];
- for (let i = 0z; i < len(bucket); i += 1) {
- const item = bucket[i];
+ for (let item .. *bucket) {
if (item.mime == mime) {
return item;
};
@@ -24,8 +23,7 @@ export fn lookup_ext(ext: str) const nullable *mimetype = {
ext = strings::ltrim(ext, '.');
const hash = fnv::string(ext);
const bucket = &exttable[hash % len(exttable)];
- for (let i = 0z; i < len(bucket); i += 1) {
- const item = bucket[i];
+ for (let item .. *bucket) {
for (let j = 0z; j < len(item.exts); j += 1) {
if (item.exts[j] == ext) {
return item;
diff --git a/mime/parse.ha b/mime/parse.ha
@@ -40,7 +40,7 @@ export fn next_param(in: *type_params) ((str, str) | void | errors::invalid) = {
return errors::invalid;
};
yield s;
- case void =>
+ case done =>
return;
};
@@ -81,13 +81,7 @@ fn quoted(in: str) (str | errors::invalid) = {
fn typevalid(in: str) (void | errors::invalid) = {
const miter = strings::iter(in);
- for (true) {
- const rn = match (strings::next(&miter)) {
- case let rn: rune =>
- yield rn;
- case void =>
- break;
- };
+ for (let rn => strings::next(&miter)) {
if (!ascii::valid(rn) || rn == ' '
|| ascii::iscntrl(rn)
|| strings::contains(tspecial, rn)) {
diff --git a/mime/system.ha b/mime/system.ha
@@ -25,14 +25,7 @@ fn load_systemdb() (void | fs::error | io::error | utf8::invalid) = {
let sc = bufio::newscanner(file, types::SIZE_MAX);
defer bufio::finish(&sc);
- for (true) {
- let line = match (bufio::scan_line(&sc)?) {
- case io::EOF =>
- break;
- case let s: const str =>
- yield s;
- };
-
+ for (let line => bufio::scan_line(&sc)?) {
line = strings::trim(line);
if (strings::hasprefix(line, "#") || len(line) == 0) {
continue;
@@ -50,13 +43,7 @@ fn load_systemdb() (void | fs::error | io::error | utf8::invalid) = {
mime = strings::dup(mime),
exts = [],
});
- for (true) {
- const ext = match (strings::next_token(&tok)) {
- case let tok: str =>
- yield strings::trim(tok);
- case void =>
- break;
- };
+ for (let ext => strings::next_token(&tok)) {
append(entry.exts, strings::dup(ext));
};
register_heap(entry);
diff --git a/net/ip/ip.ha b/net/ip/ip.ha
@@ -76,7 +76,7 @@ export fn parsev4(st: str) (addr4 | invalid) = {
return invalid;
};
};
- if (i < 4 || !(strings::next_token(&tok) is void)) {
+ if (i < 4 || !(strings::next_token(&tok) is done)) {
return invalid;
};
return ret;
@@ -102,7 +102,7 @@ export fn parsev6(st: str) (addr6 | invalid) = {
let s = match (strings::next_token(&tok)) {
case let s: str =>
yield s;
- case void =>
+ case done =>
break;
};
if (s == "") {
@@ -122,7 +122,7 @@ export fn parsev6(st: str) (addr6 | invalid) = {
break;
};
};
- if (!(strings::next_token(&tok) is void)) {
+ if (!(strings::next_token(&tok) is done)) {
return invalid;
};
if (ells >= 0) {
@@ -255,7 +255,7 @@ export fn parsecidr(st: str) (subnet | invalid) = {
case =>
return invalid;
};
- if (!(strings::next_token(&tok) is void)) {
+ if (!(strings::next_token(&tok) is done)) {
return invalid;
};
return subnet {
@@ -299,8 +299,8 @@ fn fmtmask(s: io::handle, mask: addr) (size | io::error) = {
case void =>
// Format as hex, if zero runs are not contiguous
// (like golang does)
- for (let i = 0z; i < len(slice); i += 1) {
- ret += fmt::fprintf(s, "{:x}", slice[i])?;
+ for (let part .. slice) {
+ ret += fmt::fprintf(s, "{:x}", part)?;
};
case let n: size =>
// Standard CIDR integer
@@ -344,7 +344,7 @@ fn wanttoken(tok: *strings::tokenizer) (str | invalid) = {
match (strings::next_token(tok)) {
case let s: str =>
return s;
- case void =>
+ case done =>
return invalid;
};
};
@@ -382,6 +382,7 @@ export fn subnet_contains(sub: subnet, item: (addr | subnet)) bool = {
// Mismatched addr4 and addr6 addresses / masks.
return false;
};
+
for (let i = 0z; i < len(ipa); i += 1) {
if (ipa[i] & maska[i] != ipb[i] & maska[i] || maska[i] > maskb[i]) {
return false;
diff --git a/net/ip/test+test.ha b/net/ip/test+test.ha
@@ -55,8 +55,8 @@ fn ip_test(s: str, expected: (addr|invalid)) void = {
("a1:a2:a3:a4::b1:b2:b3:b4", invalid),
("", invalid),
];
- for (let i = 0z; i < len(tests); i += 1) {
- ip_test(tests[i].0, tests[i].1);
+ for (let (string, expected) .. tests) {
+ ip_test(string, expected);
};
};
@@ -83,8 +83,8 @@ fn subnet_test_simple(s: str) void = {
"192.168.1.0/24",
"192.168.1.0/32",
];
- for (let i = 0z; i < len(subnet_tests); i += 1) {
- subnet_test_simple(subnet_tests[i]);
+ for (let test .. subnet_tests) {
+ subnet_test_simple(test);
};
};
@@ -104,16 +104,14 @@ fn subnet_test_simple(s: str) void = {
("10.10.10.0/24", "10.10.10.0/23", false),
("10.10.10.0/24", "10.10.11.0/24", false),
];
- for (let i = 0z; i < len(addr_tests); i += 1) {
- const input = addr_tests[i];
- let a = parsecidr(input.0)!;
- let b = parse(input.1)!;
- assert(subnet_contains(a, b) == input.2);
+ for (let (a, b, want) .. addr_tests) {
+ let a = parsecidr(a)!;
+ let b = parse(b)!;
+ assert(subnet_contains(a, b) == want);
};
- for (let i = 0z; i < len(cidr_tests); i += 1) {
- const input = cidr_tests[i];
- let a = parsecidr(input.0)!;
- let b = parsecidr(input.1)!;
- assert(subnet_contains(a, b) == input.2);
+ for (let (a, b, want) .. cidr_tests) {
+ let a = parsecidr(a)!;
+ let b = parsecidr(b)!;
+ assert(subnet_contains(a, b) == want);
};
};
diff --git a/net/uri/fmt.ha b/net/uri/fmt.ha
@@ -96,19 +96,13 @@ fn fmtaddr(out: io::handle, addr: ip::addr) (size | io::error) = {
fn percent_encode(out: io::handle, src: str, allowed: str) (size | io::error) = {
let iter = strings::iter(src);
let n = 0z;
- for (true) {
- const r = match (strings::next(&iter)) {
- case let r: rune =>
- yield r;
- case =>
- break;
- };
+ for (let r => strings::next(&iter)) {
if (ascii::isalnum(r) || strings::contains(allowed, r)) {
n += fmt::fprint(out, r)?;
} else {
const en = utf8::encoderune(r);
- for (let i = 0z; i < len(en); i += 1) {
- n += fmt::fprintf(out, "%{:X}", en[i])?;
+ for (let elem .. en) {
+ n += fmt::fprintf(out, "%{:X}", elem)?;
};
};
};
diff --git a/net/uri/parse.ha b/net/uri/parse.ha
@@ -139,14 +139,7 @@ fn parse_authority(
let userinfo = "";
let has_userinfo = false;
- for (true) {
- const r = match (strings::next(in)) {
- case let r: rune =>
- yield r;
- case void =>
- break;
- };
-
+ for (let r => strings::next(in)) {
if (r == '[') {
if (len(memio::string(&buf)!) > 0) {
if (len(userinfo) > 0) {
@@ -239,25 +232,20 @@ fn parse_path(in: *strings::iterator, mode: path_mode) (str | invalid) = {
if (!is_pchar(r)) {
return invalid;
};
- case void =>
+ case done =>
break;
};
};
};
- for (true) {
- match (strings::next(in)) {
- case let r: rune =>
- if (r == '?' || r == '#') {
- strings::prev(in);
- break;
- };
- if (!is_pchar(r) && r != '/') {
- return invalid;
- };
- case void =>
+ for (let r => strings::next(in)) {
+ if (r == '?' || r == '#') {
+ strings::prev(in);
break;
};
+ if (!is_pchar(r) && r != '/') {
+ return invalid;
+ };
};
return percent_decode(strings::slice(©, in));
@@ -265,33 +253,23 @@ fn parse_path(in: *strings::iterator, mode: path_mode) (str | invalid) = {
fn parse_query(in: *strings::iterator) (str | invalid) = {
let copy = *in;
- for (true) {
- match (strings::next(in)) {
- case let r: rune =>
- if (r == '#') {
- strings::prev(in);
- break;
- };
- if (!is_pchar(r) && r != '/' && r != '?') {
- return invalid;
- };
- case void =>
+ for (let r => strings::next(in)) {
+ if (r == '#') {
+ strings::prev(in);
break;
};
+ if (!is_pchar(r) && r != '/' && r != '?') {
+ return invalid;
+ };
};
return strings::dup(strings::slice(©, in));
};
fn parse_fragment(in: *strings::iterator) (str | invalid) = {
let copy = *in;
- for (true) {
- match (strings::next(in)) {
- case let r: rune =>
- if (!is_pchar(r) && r != '/' && r != '?') {
- return invalid;
- };
- case void =>
- break;
+ for (let r => strings::next(in)) {
+ if (!is_pchar(r) && r != '/' && r != '?') {
+ return invalid;
};
};
@@ -300,14 +278,7 @@ fn parse_fragment(in: *strings::iterator) (str | invalid) = {
fn parse_port(in: *strings::iterator) (u16 | invalid) = {
let copy = *in;
- for (true) {
- const r = match (strings::next(in)) {
- case let r: rune =>
- yield r;
- case void =>
- break;
- };
-
+ for (let r => strings::next(in)) {
if (!ascii::isdigit(r)) {
strings::prev(in);
break;
@@ -368,7 +339,7 @@ fn percent_decode_static(out: io::handle, s: str) (void | invalid) = {
memio::appendrune(out, r)!;
};
- case void =>
+ case done =>
if(len(percent_data) > 0) {
match(strings::fromutf8(percent_data)) {
case let stro: str =>
diff --git a/os/+freebsd/dirfdfs.ha b/os/+freebsd/dirfdfs.ha
@@ -166,8 +166,8 @@ fn fs_open_file(
flags: fs::flag...
) (io::file | fs::error) = {
let oflags = fs::flag::RDONLY;
- for (let i = 0z; i < len(flags); i += 1z) {
- oflags |= flags[i];
+ for (let flag .. flags) {
+ oflags |= flag;
};
return _fs_open(fs, path, fsflags_to_bsd(oflags)?, 0);
};
@@ -188,8 +188,8 @@ fn fs_create_file(
if (len(flags) == 0z) {
oflags |= fs::flag::WRONLY | fs::flag::TRUNC;
};
- for (let i = 0z; i < len(flags); i += 1z) {
- oflags |= flags[i];
+ for (let flag .. flags) {
+ oflags |= flag;
};
oflags |= fs::flag::CREATE;
return _fs_open(fs, path, fsflags_to_bsd(oflags)?, mode)?;
@@ -368,7 +368,7 @@ fn fs_iter(fs: *fs::fs, path: str) (*fs::iterator | fs::error) = {
return &iter.iter;
};
-fn iter_next(iter: *fs::iterator) (fs::dirent | void | fs::error) = {
+fn iter_next(iter: *fs::iterator) (fs::dirent | done | fs::error) = {
let iter = iter: *os_iterator;
if (iter.buf_pos >= iter.buf_end) {
let n = match (rt::getdents(iter.fd,
@@ -379,7 +379,7 @@ fn iter_next(iter: *fs::iterator) (fs::dirent | void | fs::error) = {
yield n;
};
if (n == 0) {
- return;
+ return done;
};
iter.buf_end = n;
iter.buf_pos = 0;
diff --git a/os/+linux/dirfdfs.ha b/os/+linux/dirfdfs.ha
@@ -49,11 +49,12 @@ 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, resolve: resolve_flag...) *fs::fs = {
+export fn dirfdopen(fd: io::file, resolve_flags: resolve_flag...) *fs::fs = {
let ofs = alloc(os_filesystem { ... });
let fs = static_dirfdopen(fd, ofs);
- for (let i = 0z; i < len(resolve); i += 1) {
- ofs.resolve |= resolve[i];
+
+ for (let flag .. resolve_flags) {
+ ofs.resolve |= flag;
};
fs.close = &fs_close;
return fs;
@@ -90,12 +91,12 @@ fn static_dirfdopen(fd: io::file, filesystem: *os_filesystem) *fs::fs = {
// Clones a dirfd filesystem, optionally adding additional [[resolve_flag]]
// constraints.
-export fn dirfs_clone(fs: *fs::fs, resolve: resolve_flag...) *fs::fs = {
+export fn dirfs_clone(fs: *fs::fs, resolve_flags: resolve_flag...) *fs::fs = {
assert(fs.open == &fs_open);
let fs = fs: *os_filesystem;
let new = alloc(*fs);
- for (let i = 0z; i < len(resolve); i += 1) {
- new.resolve |= resolve[i];
+ for (let flag .. resolve_flags) {
+ fs.resolve |= flag;
};
new.dirfd = rt::fcntl(new.dirfd, rt::F_DUPFD_CLOEXEC, 0) as int;
return &new.fs;
@@ -177,8 +178,8 @@ fn fs_open_file(
flags: fs::flag...
) (io::file | fs::error) = {
let oflags = fs::flag::RDONLY: int;
- for (let i = 0z; i < len(flags); i += 1z) {
- oflags |= flags[i]: int;
+ for (let flag .. flags) {
+ oflags |= flag: int;
};
oflags ^= fs::flag::CTTY | fs::flag::NOCLOEXEC; // invert NOCTTY/CLOEXEC
@@ -211,8 +212,8 @@ fn fs_create_file(
if (len(flags) == 0) {
oflags |= fs::flag::WRONLY | fs::flag::TRUNC;
};
- for (let i = 0z; i < len(flags); i += 1z) {
- oflags |= flags[i]: int;
+ for (let flag .. flags) {
+ oflags |= flag: int;
};
oflags ^= fs::flag::CTTY | fs::flag::NOCLOEXEC; // invert NOCTTY/CLOEXEC
oflags |= fs::flag::CREATE: int;
@@ -431,7 +432,7 @@ fn fs_iter(fs: *fs::fs, path: str) (*fs::iterator | fs::error) = {
return &iter.iter;
};
-fn iter_next(iter: *fs::iterator) (fs::dirent | void | fs::error) = {
+fn iter_next(iter: *fs::iterator) (fs::dirent | done | fs::error) = {
let iter = iter: *os_iterator;
if (iter.buf_pos >= iter.buf_end) {
let n = match (rt::getdents64(iter.fd,
@@ -442,7 +443,7 @@ fn iter_next(iter: *fs::iterator) (fs::dirent | void | fs::error) = {
yield n;
};
if (n == 0) {
- return;
+ return done;
};
iter.buf_end = n;
iter.buf_pos = 0;
diff --git a/os/+openbsd/dirfdfs.ha b/os/+openbsd/dirfdfs.ha
@@ -90,8 +90,8 @@ fn fs_open_file(
flags: fs::flag...
) (io::file | fs::error) = {
let oflags = fs::flag::RDONLY;
- for (let i = 0z; i < len(flags); i += 1z) {
- oflags |= flags[i];
+ for (let flag .. flags) {
+ oflags |= flag;
};
return _fs_open(fs, path, fsflags_to_bsd(oflags)?, 0);
};
@@ -129,8 +129,8 @@ fn fs_create_file(
if (len(flags) == 0z) {
oflags |= fs::flag::WRONLY | fs::flag::TRUNC;
};
- for (let i = 0z; i < len(flags); i += 1z) {
- oflags |= flags[i];
+ for (let flag .. flags) {
+ oflags |= flag;
};
oflags |= fs::flag::CREATE;
return _fs_open(fs, path, fsflags_to_bsd(oflags)?, mode)?;
@@ -169,7 +169,7 @@ type os_iterator = struct {
buf: []u8,
};
-fn iter_next(iter: *fs::iterator) (fs::dirent | void | fs::error) = {
+fn iter_next(iter: *fs::iterator) (fs::dirent | done | fs::error) = {
let iter = iter: *os_iterator;
for (true) {
@@ -182,7 +182,7 @@ fn iter_next(iter: *fs::iterator) (fs::dirent | void | fs::error) = {
yield n;
};
if (n == 0) {
- return;
+ return done;
};
iter.buf_end = n;
iter.buf_pos = 0;
@@ -190,6 +190,7 @@ fn iter_next(iter: *fs::iterator) (fs::dirent | void | fs::error) = {
let de = &iter.buf[iter.buf_pos]: *rt::dirent;
iter.buf_pos += de.d_reclen: int;
+
// getdents() may return invalid entries which will have
// d_fileno set to 0
if (de.d_fileno == 0) {
diff --git a/os/environ.ha b/os/environ.ha
@@ -31,8 +31,8 @@ let envp: []str = [];
// Looks up an environment variable and returns its value, or void if unset.
export fn getenv(name: const str) (str | void) = {
getenvs(); // populate envp
- for (let i = 0z; i < len(envp); i += 1) {
- let (key, value) = strings::cut(envp[i], "=");
+ for (let ent .. envp) {
+ let (key, value) = strings::cut(ent, "=");
if (key == name) return value;
};
};
diff --git a/os/exec/+freebsd/exec.ha b/os/exec/+freebsd/exec.ha
@@ -96,24 +96,24 @@ 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);
- for (let i = 0z; i < len(cmd.argv); i += 1z) {
- append(argv, c::fromstr(cmd.argv[i]));
+ for (let arg .. cmd.argv) {
+ append(argv, c::fromstr(arg));
};
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);
- for (let i = 0z; i < len(cmd.env); i += 1) {
- append(env, c::fromstr(cmd.env[i]));
+ for (let e .. cmd.env) {
+ append(env, c::fromstr(e));
};
append(env, null);
envp = env: *[*]nullable *const c::char;
};
let need_devnull = false;
- for (let i = 0z; i < len(cmd.files); i += 1) {
- const from = match (cmd.files[i].0) {
+ for (let file &.. cmd.files) {
+ const from = match (file.0) {
case let file: io::file =>
yield file;
case nullfd =>
@@ -123,7 +123,7 @@ fn platform_exec(cmd: *command) error = {
continue;
};
- cmd.files[i].0 = match (rt::fcntl(from, rt::F_DUPFD_CLOEXEC, 0)) {
+ file.0 = match (rt::fcntl(from, rt::F_DUPFD_CLOEXEC, 0)) {
case let fd: int =>
yield fd;
case let err: rt::errno =>
@@ -135,18 +135,18 @@ fn platform_exec(cmd: *command) error = {
yield os::open("/dev/null")!;
} else -1;
- for (let i = 0z; i < len(cmd.files); i += 1) {
- const from = match (cmd.files[i].0) {
+ for (let file .. cmd.files) {
+ const from = match (file.0) {
case let file: io::file =>
yield file;
case nullfd =>
yield devnull;
case closefd =>
- io::close(cmd.files[i].1)?;
+ io::close(file.1)?;
continue;
};
- if (cmd.files[i].1 == from) {
+ if (file.1 == from) {
let flags = match (rt::fcntl(from, rt::F_GETFD, 0)) {
case let flags: int =>
yield flags;
@@ -155,7 +155,7 @@ fn platform_exec(cmd: *command) error = {
};
rt::fcntl(from, rt::F_SETFD, flags & ~rt::FD_CLOEXEC)!;
} else {
- match (rt::dup2(from, cmd.files[i].1)) {
+ match (rt::dup2(from, file.1)) {
case int => void;
case let e: rt::errno =>
return errors::errno(e);
diff --git a/os/exec/+linux/exec.ha b/os/exec/+linux/exec.ha
@@ -97,24 +97,24 @@ 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);
- for (let i = 0z; i < len(cmd.argv); i += 1z) {
- append(argv, c::fromstr(cmd.argv[i]));
+ for (let arg .. cmd.argv) {
+ append(argv, c::fromstr(arg));
};
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);
- for (let i = 0z; i < len(cmd.env); i += 1) {
- append(env, c::fromstr(cmd.env[i]));
+ for (let e .. cmd.env) {
+ append(env, c::fromstr(e));
};
append(env, null);
envp = env: *[*]nullable *const c::char;
};
let need_devnull = false;
- for (let i = 0z; i < len(cmd.files); i += 1) {
- const from = match (cmd.files[i].0) {
+ for (let file &.. cmd.files) {
+ const from = match (file.0) {
case let file: io::file =>
yield file;
case nullfd =>
@@ -124,7 +124,7 @@ fn platform_exec(cmd: *command) error = {
continue;
};
- cmd.files[i].0 = match (rt::fcntl(from, rt::F_DUPFD_CLOEXEC, 0)) {
+ file.0 = match (rt::fcntl(from, rt::F_DUPFD_CLOEXEC, 0)) {
case let fd: int =>
yield fd;
case let err: rt::errno =>
@@ -136,18 +136,18 @@ fn platform_exec(cmd: *command) error = {
yield os::open("/dev/null")!;
} else -1;
- for (let i = 0z; i < len(cmd.files); i += 1) {
- const from = match (cmd.files[i].0) {
+ for (let file .. cmd.files) {
+ const from = match (file.0) {
case let file: io::file =>
yield file;
case nullfd =>
yield devnull;
case closefd =>
- io::close(cmd.files[i].1)?;
+ io::close(file.1)?;
continue;
};
- if (cmd.files[i].1 == from) {
+ if (file.1 == from) {
let flags = match (rt::fcntl(from, rt::F_GETFD, 0)) {
case let flags: int =>
yield flags;
@@ -156,7 +156,7 @@ fn platform_exec(cmd: *command) error = {
};
rt::fcntl(from, rt::F_SETFD, flags & ~rt::FD_CLOEXEC)!;
} else {
- match (rt::dup2(from, cmd.files[i].1)) {
+ match (rt::dup2(from, file.1)) {
case int => void;
case let e: rt::errno =>
return errors::errno(e);
diff --git a/os/exec/+openbsd/exec.ha b/os/exec/+openbsd/exec.ha
@@ -71,24 +71,24 @@ 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);
- for (let i = 0z; i < len(cmd.argv); i += 1z) {
- append(argv, c::fromstr(cmd.argv[i]));
+ for (let arg .. cmd.argv) {
+ append(argv, c::fromstr(arg));
};
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);
- for (let i = 0z; i < len(cmd.env); i += 1) {
- append(env, c::fromstr(cmd.env[i]));
+ for (let e .. cmd.env) {
+ append(env, c::fromstr(e));
};
append(env, null);
envp = env: *[*]nullable *const c::char;
};
let need_devnull = false;
- for (let i = 0z; i < len(cmd.files); i += 1) {
- const from = match (cmd.files[i].0) {
+ for (let file &.. cmd.files) {
+ const from = match (file.0) {
case let file: io::file =>
yield file;
case nullfd =>
@@ -98,7 +98,7 @@ fn platform_exec(cmd: *command) error = {
continue;
};
- cmd.files[i].0 = match (rt::fcntl(from, rt::F_DUPFD_CLOEXEC, 0)) {
+ file.0 = match (rt::fcntl(from, rt::F_DUPFD_CLOEXEC, 0)) {
case let fd: int =>
yield fd;
case let err: rt::errno =>
@@ -110,18 +110,18 @@ fn platform_exec(cmd: *command) error = {
yield os::open("/dev/null")!;
} else -1;
- for (let i = 0z; i < len(cmd.files); i += 1) {
- const from = match (cmd.files[i].0) {
+ for (let file .. cmd.files) {
+ const from = match (file.0) {
case let file: io::file =>
yield file;
case nullfd =>
yield devnull;
case closefd =>
- io::close(cmd.files[i].1)?;
+ io::close(file.1)?;
continue;
};
- if (cmd.files[i].1 == from) {
+ if (file.1 == from) {
let flags = match (rt::fcntl(from, rt::F_GETFD, 0)) {
case let flags: int =>
yield flags;
@@ -130,7 +130,7 @@ fn platform_exec(cmd: *command) error = {
};
rt::fcntl(from, rt::F_SETFD, flags & ~rt::FD_CLOEXEC)!;
} else {
- match (rt::dup2(from, cmd.files[i].1)) {
+ match (rt::dup2(from, file.1)) {
case int => void;
case let e: rt::errno =>
return errors::errno(e);
diff --git a/os/exec/cmd.ha b/os/exec/cmd.ha
@@ -188,14 +188,9 @@ fn lookup_open(name: str) (platform_cmd | void | error) = {
};
let tok = strings::tokenize(path, ":");
- for (true) {
- const item = match (strings::next_token(&tok)) {
- case void =>
- break;
- case let s: str =>
- yield s;
- };
+ for (let item => strings::next_token(&tok)) {
path::set(&buf, item, name)!;
+
match (open(path::string(&buf))) {
case (errors::noaccess | errors::noentry) =>
continue;
@@ -235,14 +230,9 @@ export fn lookup(name: str) (str | void) = {
};
let tok = strings::tokenize(path, ":");
- for (true) {
- const item = match (strings::next_token(&tok)) {
- case void =>
- break;
- case let s: str =>
- yield s;
- };
+ for (let item => strings::next_token(&tok)) {
path::set(&buf, item, name)!;
+
match (os::access(path::string(&buf), os::amode::X_OK)) {
case let exec: bool =>
if (exec) {
diff --git a/path/buffer.ha b/path/buffer.ha
@@ -52,12 +52,13 @@ export fn local(path: str) str = {
fn _local(path: str, buf: *[MAX]u8) str = {
let buf = buf[..0];
- const path = strings::toutf8(path);
- for (let i = 0z; i < len(path); i += 1) {
- if (path[i] == '/') {
+ const bytes = strings::toutf8(path);
+
+ for (let byte .. bytes) {
+ if (byte == '/') {
static append(buf, SEP);
} else {
- static append(buf, path[i]);
+ static append(buf, byte);
};
};
return strings::fromutf8(buf)!;
diff --git a/path/ext_stack.ha b/path/ext_stack.ha
@@ -7,16 +7,16 @@ use strings;
// Add extensions onto the end of the final path segment. The separating '.'
// will be inserted for you. If the final path segment consists entirely of dots
// or the path is root, this function will return [[cant_extend]].
-export fn push_ext(buf: *buffer, ext: str...) (str | error) = {
+export fn push_ext(buf: *buffer, exts: str...) (str | error) = {
match (peek(buf)) {
case void => return cant_extend;
case let s: str => if (strings::ltrim(s, '.') == "") return cant_extend;
};
- for (let i = 0z; i < len(ext); i += 1) {
- const newend = buf.end + 1 + len(ext[i]);
+ for (let ext .. exts) {
+ const newend = buf.end + 1 + len(ext);
if (MAX < newend) return too_long;
buf.buf[buf.end] = '.';
- buf.buf[buf.end+1..newend] = strings::toutf8(ext[i]);
+ buf.buf[buf.end+1..newend] = strings::toutf8(ext);
buf.end = newend;
};
return string(buf);
diff --git a/path/iter.ha b/path/iter.ha
@@ -34,10 +34,10 @@ export fn peekiter(it: *iterator) (str | void) = {
return strings::fromutf8_unsafe(result);
};
-// Returns the next path component from an [[iterator]], or void if none
+// Returns the next path component from an [[iterator]], or done if none
// remain. Advances the iterator.
-export fn nextiter(it: *iterator) (str | void) = {
- if (len(it.cur) == 0) return void;
+export fn nextiter(it: *iterator) (str | done) = {
+ if (len(it.cur) == 0) return done;
const (result, remaining) = split_iter(it);
it.cur = remaining;
return strings::fromutf8_unsafe(result);
@@ -80,39 +80,39 @@ export fn iterrem(it: *iterator) str = strings::fromutf8_unsafe(it.cur);
assert(nextiter(&i) as str == "foo");
assert(nextiter(&i) as str == "bar");
assert(nextiter(&i) as str == "baz");
- assert(nextiter(&i) is void);
+ assert(nextiter(&i) is done);
i = riter(&buf);
assert(nextiter(&i) as str == "baz");
assert(nextiter(&i) as str == "bar");
assert(nextiter(&i) as str == "foo");
assert(nextiter(&i) as str == local("/"));
- assert(nextiter(&i) is void);
+ assert(nextiter(&i) is done);
set(&buf, local("foo/bar/baz"))!;
i = iter(&buf);
assert(nextiter(&i) as str == "foo");
assert(nextiter(&i) as str == "bar");
assert(nextiter(&i) as str == "baz");
- assert(nextiter(&i) is void);
+ assert(nextiter(&i) is done);
i = riter(&buf);
assert(nextiter(&i) as str == "baz");
assert(nextiter(&i) as str == "bar");
assert(nextiter(&i) as str == "foo");
- assert(nextiter(&i) is void);
+ assert(nextiter(&i) is done);
set(&buf, "foo")!;
i = iter(&buf);
assert(nextiter(&i) as str == "foo");
- assert(nextiter(&i) is void);
+ assert(nextiter(&i) is done);
i = riter(&buf);
assert(nextiter(&i) as str == "foo");
- assert(nextiter(&i) is void);
+ assert(nextiter(&i) is done);
set(&buf, local("/"))!;
i = iter(&buf);
assert(nextiter(&i) as str == local("/"));
- assert(nextiter(&i) is void);
+ assert(nextiter(&i) is done);
i = riter(&buf);
assert(nextiter(&i) as str == local("/"));
- assert(nextiter(&i) is void);
+ assert(nextiter(&i) is done);
};
diff --git a/path/stack.ha b/path/stack.ha
@@ -7,8 +7,9 @@ use strings;
// Appends path elements onto the end of a path buffer.
// Returns the new string value of the path.
export fn push(buf: *buffer, items: str...) (str | error) = {
- for (let i = 0z; i < len(items); i += 1) {
- let elem = strings::toutf8(items[i]);
+ for (let item .. items) {
+ let elem = strings::toutf8(item);
+
for (true) match (bytes::index(elem, SEP)) {
case void =>
buf.end = appendnorm(buf, elem)?;
diff --git a/regex/+test.ha b/regex/+test.ha
@@ -629,18 +629,12 @@ fn run_rawreplace_case(
// (`^([ab]*?)(?<!(a))c`, "abc", matchres::MATCH, 0, -1),
];
- for (let i = 0z; i < len(cases); i += 1) {
- const expr = cases[i].0;
- const string = cases[i].1;
- const should_match = cases[i].2;
- const start = cases[i].3;
- const end = if (cases[i].4 == -1) {
+ for (let (expr, string, should_match, start, end) .. cases) {
+ if (end == -1) {
// workaround to get the length in codepoints
let runes = strings::torunes(string);
defer free(runes);
- yield len(runes): int;
- } else {
- yield cases[i].4;
+ end = len(runes): int;
};
run_find_case(expr, string, should_match, start, end);
};
@@ -651,11 +645,7 @@ fn run_rawreplace_case(
["aaa bbb ccc", "bbb", "ccc"]: []str),
];
- for (let i = 0z; i < len(submatch_cases); i += 1) {
- const expr = submatch_cases[i].0;
- const string = submatch_cases[i].1;
- const should_match = submatch_cases[i].2;
- const targets = submatch_cases[i].3;
+ for (let (expr, string, should_match, targets) .. submatch_cases) {
run_submatch_case(expr, string, should_match, targets);
};
};
@@ -674,11 +664,7 @@ fn run_rawreplace_case(
["aaa", ""]: []str),
];
- for (let i = 0z; i < len(cases); i += 1) {
- const expr = cases[i].0;
- const string = cases[i].1;
- const should_match = cases[i].2;
- const targets = cases[i].3;
+ for (let (expr, string, should_match, targets) .. cases) {
run_findall_case(expr, string, should_match, targets);
};
};
@@ -702,12 +688,7 @@ fn run_rawreplace_case(
(`([[:digit:]])([[:digit:]])`, "1234", `\2`, 1, "234"),
];
- for (let i = 0z; i < len(cases); i += 1) {
- const expr = cases[i].0;
- const string = cases[i].1;
- const target = cases[i].2;
- const n = cases[i].3;
- const expected = cases[i].4;
+ for (let (expr, string, target, n, expected) .. cases) {
run_replace_case(expr, string, target, n, expected);
};
};
@@ -727,12 +708,7 @@ fn run_rawreplace_case(
(`.`, "blablabla", `x`, 0, "blablabla"),
];
- for (let i = 0z; i < len(cases); i += 1) {
- const expr = cases[i].0;
- const string = cases[i].1;
- const target = cases[i].2;
- const n = cases[i].3;
- const expected = cases[i].4;
+ for (let (expr, string, target, n, expected) .. cases) {
run_rawreplace_case(expr, string, target, n, expected);
};
};
diff --git a/regex/regex.ha b/regex/regex.ha
@@ -101,8 +101,8 @@ export type regex = struct {
// Frees resources associated with a [[regex]].
export fn finish(re: *regex) void = {
free(re.insts);
- for (let i = 0z; i < len(re.charsets); i += 1) {
- free(re.charsets[i]);
+ for (let charset .. re.charsets) {
+ free(charset);
};
free(re.charsets);
};
@@ -130,13 +130,13 @@ fn handle_bracket(
const peek1 = strings::next(iter);
const peek2 = strings::next(iter);
const peek3 = strings::next(iter);
- if (!(peek1 is void)) {
+ if (!(peek1 is done)) {
strings::prev(iter);
};
- if (!(peek2 is void)) {
+ if (!(peek2 is done)) {
strings::prev(iter);
};
- if (!(peek3 is void)) {
+ if (!(peek3 is done)) {
strings::prev(iter);
};
@@ -154,14 +154,14 @@ fn handle_bracket(
};
const is_range = peek1 is rune && peek1 as rune == '-'
- && !(peek2 is void) && !(peek3 is void)
+ && !(peek2 is done) && !(peek3 is done)
&& !(peek2 as rune == ']');
const range_end = peek2;
const is_first_char = *bracket_idx == 0 || *bracket_idx == 1
&& !*is_charset_positive;
if (r == '\\') {
- if (peek1 is void) {
+ if (peek1 is done) {
return `Trailing backslash '\'`: error;
} else {
append(charsets[len(charsets) - 1],
@@ -180,7 +180,7 @@ fn handle_bracket(
*is_charset_positive = true;
} else if (r == '^' && *bracket_idx == 0) {
*is_charset_positive = false;
- } else if (r == '[' && !(peek1 is void)
+ } else if (r == '[' && !(peek1 is done)
&& peek1 as rune == ':') {
const rest = strings::iterstr(iter);
const n_cc = len(charclass_map);
@@ -239,7 +239,7 @@ export fn compile(expr: str) (regex | error) = {
};
if (in_bracket) {
- if (next is void) {
+ if (next is done) {
return `Unmatched '['`: error;
};
const r = next: rune;
@@ -251,7 +251,7 @@ export fn compile(expr: str) (regex | error) = {
};
const r = match (next) {
- case void =>
+ case done =>
if (n_groupstarts > 0) {
return `Unmatched '('`: error;
};
@@ -261,7 +261,7 @@ export fn compile(expr: str) (regex | error) = {
switch (r) {
case '\\' =>
const peek1 = strings::next(&iter);
- if (peek1 is void) {
+ if (peek1 is done) {
return `Trailing backslash '\'`: error;
} else {
append(insts, (peek1 as rune): inst_lit);
@@ -477,10 +477,9 @@ fn is_consuming_inst(a: inst) bool = {
fn add_thread(threads: *[]thread, parent_idx: size, new_pc: size) void = {
// Do not add this thread if there is already another thread with
// the same PC
- for (let i = 0z; i < len(threads); i += 1) {
- if (threads[i].pc == new_pc
- && !threads[i].matched
- && threads[i].start_idx
+ for (let thread &.. *threads) {
+ if (thread.pc == new_pc && !thread.matched
+ && thread.start_idx
< threads[parent_idx].start_idx) {
return;
};
@@ -730,10 +729,9 @@ fn search(
// When we only want the leftmost match, delete all threads that
// start after the earliest non-zero-length matched thread
if (first_match_idx is size) {
- for (let i = 0z; i < len(threads); i += 1) {
- if (threads[i].start_idx
- > first_match_idx as size) {
- threads[i].failed = true;
+ for (let thread &.. threads) {
+ if (thread.start_idx > first_match_idx as size) {
+ thread.failed = true;
};
};
};
@@ -896,7 +894,7 @@ fn parse_replace_target(targetstr: str) ([]([]u8 | size) | error) = {
let iter = strings::iter(targetstr);
let start = 0z, end = 0z;
for (true) match (strings::next(&iter)) {
- case void =>
+ case done =>
if (start != end) {
append(target, bytes[start..]);
};
@@ -908,7 +906,7 @@ fn parse_replace_target(targetstr: str) ([]([]u8 | size) | error) = {
};
const r = match (strings::next(&iter)) {
- case void =>
+ case done =>
return "Trailing backslash": error;
case let r: rune =>
yield r;
@@ -978,8 +976,8 @@ export fn result_free(s: result) void = {
// Frees a slice of [[result]]s.
export fn result_freeall(s: []result) void = {
- for (let i = 0z; i < len(s); i += 1) {
- result_free(s[i]);
+ for (let res .. s) {
+ result_free(res);
};
free(s);
};
diff --git a/shlex/escape.ha b/shlex/escape.ha
@@ -9,15 +9,7 @@ use strings;
fn is_safe(s: str) bool = {
const iter = strings::iter(s);
- for (true) {
- const rn = match (strings::next(&iter)) {
- case let rn: rune =>
- yield rn;
- case void =>
- break;
- };
-
-
+ for (let rn => strings::next(&iter)) {
switch (rn) {
case '@', '%', '+', '=', ':', ',', '.', '/', '-' =>
void;
@@ -42,14 +34,7 @@ export fn quote(sink: io::handle, s: str) (size | io::error) = {
let z = io::writeall(sink, ['\''])?;
const iter = strings::iter(s);
- for (true) {
- const rn = match (strings::next(&iter)) {
- case let rn: rune =>
- yield rn;
- case void =>
- break;
- };
-
+ for (let rn => strings::next(&iter)) {
if (rn == '\'') {
z += io::writeall(sink, strings::toutf8(`'"'"'`))?;
} else {
diff --git a/shlex/split.ha b/shlex/split.ha
@@ -23,25 +23,15 @@ export fn split(in: const str) ([]str | syntaxerr) = {
let first = true;
let dirty = false;
- for (true) {
- const r = match (strings::next(&iter)) {
- case let r: rune =>
- yield r;
- case void =>
- break;
- };
-
+ for (let r => strings::next(&iter)) {
dirty = true;
switch (r) {
case ' ', '\t', '\n' =>
- for (true) match (strings::next(&iter)) {
- case let r: rune =>
+ for (let r => strings::next(&iter)) {
if (r != ' ' && r != '\t' && r != '\n') {
strings::prev(&iter); // Unget
break;
};
- case void =>
- break;
};
if (!first) {
const item = memio::string(&s)!;
@@ -76,7 +66,7 @@ fn scan_backslash(out: io::handle, in: *strings::iterator) (void | syntaxerr) =
const r = match (strings::next(in)) {
case let r: rune =>
yield r;
- case void =>
+ case done =>
return syntaxerr;
};
@@ -96,7 +86,7 @@ fn scan_double(out: io::handle, in: *strings::iterator) (void | syntaxerr) = {
const r = match (strings::next(in)) {
case let r: rune =>
yield r;
- case void =>
+ case done =>
return syntaxerr;
};
@@ -116,7 +106,7 @@ fn scan_single(out: io::handle, in: *strings::iterator) (void | syntaxerr) = {
const r = match (strings::next(in)) {
case let r: rune =>
yield r;
- case void =>
+ case done =>
return syntaxerr;
};
diff --git a/strings/concat.ha b/strings/concat.ha
@@ -4,12 +4,13 @@
// Concatenates multiple strings. The caller must free the return value.
export fn concat(strs: str...) str = {
let z = 0z;
- for (let i = 0z; i < len(strs); i += 1) {
- z += len(strs[i]);
+ for (let s .. strs) {
+ z += len(s);
};
+
let new: []u8 = alloc([], z);
- for (let i = 0z; i < len(strs); i += 1) {
- static append(new, toutf8(strs[i])...);
+ for (let s .. strs) {
+ static append(new, toutf8(s)...);
};
return fromutf8_unsafe(new);
};
diff --git a/strings/contains.ha b/strings/contains.ha
@@ -7,8 +7,8 @@ use encoding::utf8;
// Returns true if a string contains a rune or a sub-string, multiple of which
// can be given.
export fn contains(haystack: str, needles: (str | rune)...) bool = {
- for (let i = 0z; i < len(needles); i += 1) {
- const matched = match (needles[i]) {
+ for (let needle .. needles) {
+ const matched = match (needle) {
case let s: str =>
yield bytes::contains(toutf8(haystack),
toutf8(s));
diff --git a/strings/dup.ha b/strings/dup.ha
@@ -23,10 +23,10 @@ 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(s: []str) []str = {
- let newsl: []str = alloc([], len(s));
- for (let i = 0z; i < len(s); i += 1) {
- static append(newsl, dup(s[i]));
+export fn dupall(strs: []str) []str = {
+ let newsl: []str = alloc([], len(strs));
+ for (let s .. strs) {
+ static append(newsl, dup(s));
};
return newsl;
};
diff --git a/strings/index.ha b/strings/index.ha
@@ -36,7 +36,7 @@ fn index_rune(s: str, r: rune) (size | void) = {
if (r == n) {
return i;
};
- case void =>
+ case done =>
break;
};
};
@@ -50,7 +50,7 @@ fn rindex_rune(s: str, r: rune) (size | void) = {
if (r == n) {
return i;
};
- case void =>
+ case done =>
break;
};
};
@@ -64,17 +64,17 @@ fn index_string(s: str, needle: str) (size | void) = {
for (true) {
const rest_rune = next(&rest_iter);
const needle_rune = next(&needle_iter);
- if (rest_rune is void && !(needle_rune is void)) {
+ if (rest_rune is done && !(needle_rune is done)) {
break;
};
- if (needle_rune is void) {
+ if (needle_rune is done) {
return i;
};
if ((rest_rune as rune) != (needle_rune as rune)) {
break;
};
};
- if (next(&s_iter) is void) {
+ if (next(&s_iter) is done) {
break;
};
};
@@ -88,17 +88,17 @@ fn rindex_string(s: str, needle: str) (size | void) = {
for (true) {
const rest_rune = next(&rest_iter);
const needle_rune = next(&needle_iter);
- if (rest_rune is void && !(needle_rune is void)) {
+ if (rest_rune is done && !(needle_rune is done)) {
break;
};
- if (needle_rune is void) {
+ if (needle_rune is done) {
return i - len(needle);
};
if ((rest_rune as rune) != (needle_rune as rune)) {
break;
};
};
- if (next(&s_iter) is void) {
+ if (next(&s_iter) is done) {
break;
};
};
diff --git a/strings/iter.ha b/strings/iter.ha
@@ -37,23 +37,23 @@ export fn riter(src: str) iterator = {
return ret;
};
-// Get the next rune from an iterator, or void if there are none left.
+// Get the next rune from an iterator, or done if there are none left.
//
// Be aware that a rune is not the minimum lexographical unit of language in
// Unicode strings. If you use these runes to construct a new string,
// reordering, editing, or omitting any of the runes without careful discretion
// may cause linguistic errors to arise. To avoid this, you may need to use a
// third-party Unicode module instead.
-export fn next(iter: *iterator) (rune | void) = move(!iter.reverse, iter);
+export fn next(iter: *iterator) (rune | done) = move(!iter.reverse, iter);
-// Get the previous rune from an iterator, or void when at the start of the
+// Get the previous rune from an iterator, or done when at the start of the
// string.
-export fn prev(iter: *iterator) (rune | void) = move(iter.reverse, iter);
+export fn prev(iter: *iterator) (rune | done) = move(iter.reverse, iter);
-fn move(forward: bool, iter: *iterator) (rune | void) = {
+fn move(forward: bool, iter: *iterator) (rune | done) = {
let fun = if (forward) &utf8::next else &utf8::prev;
return match (fun(&iter.dec)) {
- case void => void;
+ case void => yield done;
case (utf8::more | utf8::invalid) =>
abort("Invalid UTF-8 string (this should not happen)");
case let r: rune =>
@@ -83,7 +83,7 @@ export fn slice(begin: *iterator, end: *iterator) str = {
@test fn iter() void = {
let s = iter("こんにちは");
- assert(prev(&s) is void);
+ assert(prev(&s) is done);
const expected1 = ['こ', 'ん'];
for (let i = 0z; i < len(expected1); i += 1) {
assert(next(&s) as rune == expected1[i]);
@@ -94,8 +94,8 @@ export fn slice(begin: *iterator, end: *iterator) str = {
for (let i = 0z; i < len(expected2); i += 1) {
assert(next(&s) as rune == expected2[i]);
};
- assert(next(&s) is void);
- assert(next(&s) is void);
+ assert(next(&s) is done);
+ assert(next(&s) is done);
assert(prev(&s) as rune == 'は');
s = riter("にちは");
@@ -103,7 +103,7 @@ export fn slice(begin: *iterator, end: *iterator) str = {
for (let i = 0z; i < len(expected3); i += 1) {
assert(next(&s) as rune == expected3[i]);
};
- assert(next(&s) is void);
+ assert(next(&s) is done);
assert(prev(&s) as rune == 'に');
};
diff --git a/strings/replace.ha b/strings/replace.ha
@@ -24,8 +24,8 @@ export fn multireplace(s: str, repls: (str, str)...) str = {
let i = 0z;
let prev = 0z; // end of previous match, so we can append in chunks
for :step (i < len(b)) {
- for (let j = 0z; j < len(repls); j += 1) {
- const replb = (toutf8(repls[j].0), toutf8(repls[j].1));
+ 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...);
diff --git a/strings/runes.ha b/strings/runes.ha
@@ -8,21 +8,17 @@ use encoding::utf8;
export fn torunes(s: str) []rune = {
let sl: []rune = [];
let iter = iter(s);
- for (true) {
- match (next(&iter)) {
- case void => break;
- case let r: rune =>
- append(sl, r);
- };
+ for (let r => next(&iter)) {
+ append(sl, r);
};
return sl;
};
// Returns a string from a slice of runes. The caller must free the return value.
-export fn fromrunes(rs: []rune) str = {
+export fn fromrunes(runes: []rune) str = {
let bytes: []u8 = [];
- for (let i = 0z; i < len(rs); i += 1) {
- const bs = utf8::encoderune(rs[i]);
+ for (let r .. runes) {
+ const bs = utf8::encoderune(r);
append(bytes, bs...);
};
return fromutf8_unsafe(bytes);
@@ -41,15 +37,17 @@ export fn fromrunes(rs: []rune) str = {
("こんにちは世界!", ['こ', 'ん', 'に', 'ち', 'は', '世', '界', '!']),
];
- for (let i = 0z; i < len(tests); i += 1) {
- const s = fromrunes(tests[i].1);
+ for (let (string, runes) .. tests) {
+ const s = fromrunes(runes);
defer free(s);
- assert(s == tests[i].0);
+ assert(s == string);
+
const rs = torunes(s);
defer free(rs);
- assert(len(rs) == len(tests[i].1));
+ assert(len(rs) == len(runes));
+
for (let j = 0z; j < len(rs); j += 1) {
- assert(rs[j] == tests[i].1[j]);
+ assert(rs[j] == runes[j]);
};
};
};
diff --git a/strings/sub.ha b/strings/sub.ha
@@ -10,7 +10,7 @@ fn utf8_byte_len_bounded(iter: *iterator, end: size) size = {
match (next(iter)) {
case let r: rune =>
continue;
- case void =>
+ case done =>
abort("index exceeds string length");
};
};
diff --git a/strings/template/template.ha b/strings/template/template.ha
@@ -30,14 +30,7 @@ export fn compile(input: str) (template | invalid) = {
let instrs: []instruction = [];
const iter = strings::iter(input);
- for (true) {
- const rn = match (strings::next(&iter)) {
- case void =>
- break;
- case let rn: rune =>
- yield rn;
- };
-
+ for (let rn => strings::next(&iter)) {
if (rn == '$') {
match (strings::next(&iter)) {
case let next_rn: rune =>
@@ -69,8 +62,8 @@ export fn compile(input: str) (template | invalid) = {
// Frees resources associated with a [[template]].
export fn finish(tmpl: *template) void = {
- for (let i = 0z; i < len(tmpl); i += 1) {
- match (tmpl[i]) {
+ for (let instr .. *tmpl) {
+ match (instr) {
case let lit: literal =>
free(lit);
case let var: variable =>
@@ -89,8 +82,8 @@ export fn execute(
params: param...
) (size | io::error) = {
let z = 0z;
- for (let i = 0z; i < len(tmpl); i += 1) {
- match (tmpl[i]) {
+ for (let instr .. *tmpl) {
+ match (instr) {
case let lit: literal =>
z += fmt::fprint(out, lit)?;
case let var: variable =>
@@ -103,9 +96,9 @@ export fn execute(
fn get_param(name: str, params: param...) fmt::formattable = {
// TODO: Consider preparing a parameter map or something
- for (let i = 0z; i < len(params); i += 1) {
- if (params[i].0 == name) {
- return params[i].1;
+ for (let (var_name, obj) .. params) {
+ if (var_name == name) {
+ return obj;
};
};
fmt::errorfln("strings::template: required parameter ${} was not provided", name)!;
diff --git a/strings/tokenize.ha b/strings/tokenize.ha
@@ -35,13 +35,13 @@ export fn rtokenize(s: str, delim: str) tokenizer =
bytes::rtokenize(toutf8(s), toutf8(delim));
// Returns the next string from a tokenizer, and advances the cursor. Returns
-// void if there are no tokens left.
-export fn next_token(s: *tokenizer) (str | void) = {
+// done if there are no tokens left.
+export fn next_token(s: *tokenizer) (str | done) = {
let s = s: *bytes::tokenizer;
return match (bytes::next_token(s)) {
case let b: []u8 =>
yield fromutf8_unsafe(b);
- case void => void;
+ case void => yield done;
};
};
@@ -78,11 +78,11 @@ export fn remaining_tokens(s: *tokenizer) str = {
assert(peek_token(&tok) as str == "");
assert(next_token(&tok) as str == "");
assert(peek_token(&tok) is void);
- assert(next_token(&tok) is void);
+ assert(next_token(&tok) is done);
let tok = tokenize("", "foo");
assert(peek_token(&tok) is void);
- assert(next_token(&tok) is void);
+ assert(next_token(&tok) is done);
let tok = rtokenize("Hello, my name is drew", " ");
assert(next_token(&tok) as str == "drew");
@@ -105,7 +105,7 @@ export fn splitn(in: str, delim: str, n: size) []str = {
match (next_token(&tok)) {
case let s: str =>
append(toks, s);
- case void =>
+ case done =>
return toks;
};
};
@@ -129,7 +129,7 @@ export fn rsplitn(in: str, delim: str, n: size) []str = {
match (next_token(&tok)) {
case let s: str =>
append(toks, s);
- case void =>
+ case done =>
return toks;
};
};
diff --git a/strings/trim.ha b/strings/trim.ha
@@ -14,15 +14,9 @@ export fn ltrim(input: str, trim: rune...) str = {
return fromutf8_unsafe(bytes::ltrim(input, whitespace...));
};
let it = iter(input);
- for :outer (true) {
- const r = match (next(&it)) {
- case let r: rune =>
- yield r;
- case void =>
- break;
- };
- for (let i = 0z; i < len(trim); i += 1) {
- if (r == trim[i]) {
+ for :outer (let r => next(&it)) {
+ for (let tr .. trim) {
+ if (r == tr) {
continue :outer;
};
};
@@ -41,15 +35,9 @@ export fn rtrim(input: str, trim: rune...) str = {
return fromutf8_unsafe(bytes::rtrim(input, whitespace...));
};
let it = riter(input);
- for :outer (true) {
- const r = match (next(&it)) {
- case let r: rune =>
- yield r;
- case void =>
- break;
- };
- for (let i = 0z; i < len(trim); i += 1) {
- if (r == trim[i]) {
+ for :outer (let r => next(&it)) {
+ for (let tr .. trim) {
+ if (r == tr) {
continue :outer;
};
};
diff --git a/test/+test.ha b/test/+test.ha
@@ -67,8 +67,8 @@ fn finish_context(ctx: *context) void = {
io::close(&ctx.stderr)!;
free(ctx.failures);
free(ctx.skipped);
- for (let i = 0z; i < len(ctx.output); i += 1) {
- finish_output(&ctx.output[i]);
+ for (let out &.. ctx.output) {
+ finish_output(out);
};
free(ctx.output);
free(ctx.cwd);
@@ -92,8 +92,8 @@ export @symbol("__test_main") fn main() size = {
if (len(os::args) == 1) {
append(enabled_tests, tests...);
} else for (let i = 0z; i < ntest; i += 1) {
- for (let j = 1z; j < len(os::args); j += 1) {
- if (fnmatch::fnmatch(os::args[j], tests[i].name)) {
+ for (let arg .. os::args) {
+ if (fnmatch::fnmatch(arg, tests[i].name)) {
append(enabled_tests, tests[i]);
break;
};
@@ -105,9 +105,9 @@ export @symbol("__test_main") fn main() size = {
};
let maxname = 0z;
- for (let i = 0z; i < len(enabled_tests); i += 1) {
- if (len(enabled_tests[i].name) > maxname) {
- maxname = len(enabled_tests[i].name);
+ for (let test .. enabled_tests) {
+ if (len(test.name) > maxname) {
+ maxname = len(test.name);
};
};
@@ -123,14 +123,13 @@ export @symbol("__test_main") fn main() size = {
fmt::printfln("Running {}/{} tests:\n", len(enabled_tests), ntest)!;
reset(&ctx);
- for (let i = 0z; i < len(enabled_tests); i += 1) {
- do_test(&ctx, enabled_tests[i]);
+ for (let test .. enabled_tests) {
+ do_test(&ctx, test);
};
fmt::println()!;
- for (let i = 0z; i < len(ctx.skipped); i += 1) {
- fmt::printfln("Skipped {}: {}", ctx.skipped[i].test,
- ctx.skipped[i].reason)!;
+ for (let skipped .. ctx.skipped) {
+ fmt::printfln("Skipped {}: {}", skipped.test, skipped.reason)!;
};
if (len(ctx.skipped) > 0) {
fmt::println()!;
@@ -138,19 +137,19 @@ export @symbol("__test_main") fn main() size = {
if (len(ctx.failures) > 0) {
fmt::println("Failures:")!;
- for (let i = 0z; i < len(ctx.failures); i += 1) {
- match (ctx.failures[i].reason.path) {
+ for (let failure .. ctx.failures) {
+ match (failure.reason.path) {
case null =>
fmt::printfln("{}: {}",
- ctx.failures[i].test,
- ctx.failures[i].reason.msg)!;
+ failure.test,
+ failure.reason.msg)!;
case let path: *str =>
fmt::printfln("{}: {}:{}:{}: {}",
- ctx.failures[i].test,
+ failure.test,
*path,
- ctx.failures[i].reason.line,
- ctx.failures[i].reason.col,
- ctx.failures[i].reason.msg)!;
+ failure.reason.line,
+ failure.reason.col,
+ failure.reason.msg)!;
};
};
fmt::println()!;
@@ -256,7 +255,7 @@ fn printable(buf: []u8) str = {
case let s: str =>
let it = strings::iter(s);
for (true) match (strings::next(&it)) {
- case void =>
+ case done =>
return strings::dup(s);
case let r: rune =>
if (ascii::valid(r) && !ascii::isprint(r)
diff --git a/test/util+test.ha b/test/util+test.ha
@@ -33,8 +33,7 @@ export fn skip(reason: str) never = {
// keywords. If all the keywords are present, return void. Otherwise, skip the
// currently running test.
export fn require(keywords: str...) void = {
- for :keywords (let i = 0z; i < len(keywords); i += 1) {
- let keyword = keywords[i];
+ for :keywords (let keyword .. keywords) {
let tokr = strings::tokenize(os::tryenv("HARETEST_INCLUDE", ""), " ");
for (true) {
match (strings::next_token(&tokr)) {
@@ -42,7 +41,7 @@ export fn require(keywords: str...) void = {
if (tok == keyword) {
continue :keywords;
};
- case void =>
+ case done =>
skip(fmt::asprintf(
"Requires HARETEST_INCLUDE='{}'",
strings::join(" ", keywords...),
diff --git a/time/chrono/leapsec.ha b/time/chrono/leapsec.ha
@@ -56,15 +56,8 @@ fn init_utc_leapsecs() (void | utciniterror) = {
// Parse UTC/TAI leap second data from [[UTC_LEAPSECS_PATH]].
// See file for format details.
fn parse_utc_leapsecs(h: io::handle) (void | utf8::invalid | io::error) = {
- for (true) {
- const line = match (bufio::read_line(h)) {
- case let err: io::error =>
- return err;
- case io::EOF =>
- return;
- case let line: []u8 =>
- yield strings::fromutf8(line)?;
- };
+ for (let line => bufio::read_line(h)?) {
+ let line = strings::fromutf8(line)?;
defer free(line);
if (strings::hasprefix(line, '#')) {
@@ -87,13 +80,7 @@ fn parse_utc_leapsecs(h: io::handle) (void | utf8::invalid | io::error) = {
fn scan_number(iter: *strings::iterator) (i64 | void) = {
let begin = *iter;
- for (true) {
- const rn = match (strings::next(iter)) {
- case void =>
- break;
- case let rn: rune =>
- yield rn;
- };
+ for (let rn => strings::next(iter)) {
switch (rn) {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' =>
continue;
@@ -107,13 +94,7 @@ fn scan_number(iter: *strings::iterator) (i64 | void) = {
};
fn scan_whitespace(iter: *strings::iterator) void = {
- for (true) {
- const rn = match (strings::next(iter)) {
- case void =>
- return;
- case let rn: rune =>
- yield rn;
- };
+ for (let rn => strings::next(iter)) {
switch (rn) {
case ' ', '\t' =>
continue;
diff --git a/time/chrono/timescale.ha b/time/chrono/timescale.ha
@@ -58,9 +58,10 @@ export fn convert(i: time::instant, tscs: *timescale...) (time::instant | analyt
// default to TAI intermediary
const convs = a.convto(&tai, t) as []time::instant;
- for (let l = 0z; l < len(convs); l += 1) {
+
+ for (let conv .. convs) {
append(tmps, (
- b.convfrom(&tai, convs[l]) as []time::instant
+ b.convfrom(&tai, conv) as []time::instant
)...);
};
};
@@ -506,8 +507,7 @@ fn mtc_convfrom(ts: *timescale, i: time::instant) ([]time::instant | void) = {
(( 1483228802i64, 0i64), [( 1483228839i64, 0i64)]),
];
- for (let idx = 0z; idx < len(testcases); idx += 1) {
- let testcase = testcases[idx];
+ for (let testcase .. testcases) {
let params = testcase.0;
let param = time::instant{ sec = params.0, nsec = params.1 };
let expect = testcase.1;
@@ -602,8 +602,7 @@ fn mtc_convfrom(ts: *timescale, i: time::instant) ([]time::instant | void) = {
(( 1483228839i64, 0i64), [( 1483228802i64, 0i64)]),
];
- for (let idx = 0z; idx < len(testcases); idx += 1) {
- let testcase = testcases[idx];
+ for (let testcase .. testcases) {
let params = testcase.0;
let param = time::instant{ sec = params.0, nsec = params.1 };
let expect = testcase.1;
diff --git a/time/chrono/timezone.ha b/time/chrono/timezone.ha
@@ -74,8 +74,8 @@ type tzname = struct {
// Frees a [[timezone]]. A [[locality]] argument can be passed.
export fn timezone_free(tz: *timezone) void = {
free(tz.name);
- for (let i = 0z; i < len(tz.zones); i += 1) {
- zone_finish(&tz.zones[i]);
+ for (let zone &.. tz.zones) {
+ zone_finish(zone);
};
free(tz.zones);
free(tz.transitions);
diff --git a/time/date/date.ha b/time/date/date.ha
@@ -275,8 +275,7 @@ export fn from_str(
];
let buf: [64]u8 = [0...];
- for (let i = 0z; i < len(testcases); i += 1) {
- const t = testcases[i];
+ for (let t .. testcases) {
const expect = t.3;
const actual = from_str(t.0, t.1, t.2...);
diff --git a/time/date/daydate.ha b/time/date/daydate.ha
@@ -282,10 +282,7 @@ fn calc_daydate__yd(y: int, yd: int) (i64 | invalid) = {
(( 1970, 1, 99), 0, true),
(( 1970, 99, 99), 0, true),
];
- for (let i = 0z; i < len(cases); i += 1) {
- const params = cases[i].0;
- const expect = cases[i].1;
- const should_error = cases[i].2;
+ for (let (params, expect, should_error) .. cases) {
const actual = calc_daydate__ymd(
params.0, params.1, params.2,
);
@@ -334,9 +331,7 @@ fn calc_daydate__yd(y: int, yd: int) (i64 | invalid) = {
((29349, 3, 6), 9999999),
];
- for (let i = 0z; i < len(cases); i += 1) {
- const ywd = cases[i].0;
- const expected = cases[i].1;
+ for (let (ywd, expected) .. cases) {
const actual = calc_daydate__ywd(ywd.0, ywd.1, ywd.2)!;
assert(actual == expected,
"incorrect calc_daydate__ywd() result");
@@ -368,10 +363,7 @@ fn calc_daydate__yd(y: int, yd: int) (i64 | invalid) = {
(29349, 25, 9999999),
];
- for (let i = 0z; i < len(cases); i += 1) {
- const y = cases[i].0;
- const yd = cases[i].1;
- const expected = cases[i].2;
+ for (let (y, yd, expected) .. cases) {
const actual = calc_daydate__yd(y, yd)!;
assert(expected == actual,
"error in date calculation from yd");
@@ -406,9 +398,7 @@ fn calc_daydate__yd(y: int, yd: int) (i64 | invalid) = {
(1000000, ( 4707, 11, 29)),
(9999999, (29349, 1, 25)),
];
- for (let i = 0z; i < len(cases); i += 1) {
- const paramt = cases[i].0;
- const expect = cases[i].1;
+ for (let (paramt, expect) .. cases) {
const actual = calc_ymd(paramt);
assert(expect.0 == actual.0, "year mismatch");
assert(expect.1 == actual.1, "month mismatch");
@@ -441,9 +431,7 @@ fn calc_daydate__yd(y: int, yd: int) (i64 | invalid) = {
(( 4707, 11, 29), 333),
((29349, 1, 25), 25),
];
- for (let i = 0z; i < len(cases); i += 1) {
- const params = cases[i].0;
- const expect = cases[i].1;
+ for (let (params, expect) .. cases) {
const actual = calc_yearday(params.0, params.1, params.2);
assert(expect == actual, "yearday miscalculation");
};
@@ -468,9 +456,7 @@ fn calc_daydate__yd(y: int, yd: int) (i64 | invalid) = {
((366, 0), 53),
];
- for (let i = 0z; i < len(cases); i += 1) {
- const params = cases[i].0;
- const expect = cases[i].1;
+ for (let (params, expect) .. cases) {
const actual = calc_week(params.0, params.1);
assert(expect == actual, "week miscalculation");
};
@@ -495,9 +481,7 @@ fn calc_daydate__yd(y: int, yd: int) (i64 | invalid) = {
((366, 0), 53),
];
- for (let i = 0z; i < len(cases); i += 1) {
- const params = cases[i].0;
- const expect = cases[i].1;
+ for (let (params, expect) .. cases) {
const actual = calc_sundayweek(params.0, params.1);
assert(expect == actual, "week miscalculation");
};
@@ -527,9 +511,7 @@ fn calc_daydate__yd(y: int, yd: int) (i64 | invalid) = {
(1000000, 4), // 4707-11-29
(9999999, 5), // 29349-01-25
];
- for (let i = 0z; i < len(cases); i += 1) {
- const paramt = cases[i].0;
- const expect = cases[i].1;
+ for (let (paramt, expect) .. cases) {
const actual = calc_weekday(paramt);
assert(expect == actual, "weekday miscalculation");
};
@@ -610,9 +592,7 @@ fn calc_daydate__yd(y: int, yd: int) (i64 | invalid) = {
(2038, 4),
(2039, 5),
];
- for (let i = 0z; i < len(cases); i += 1) {
- const paramt = cases[i].0;
- const expect = cases[i].1;
+ for (let (paramt, expect) .. cases) {
const actual = calc_janfirstweekday(paramt);
assert(expect == actual, "calc_janfirstweekday() miscalculation");
};
diff --git a/time/date/format.ha b/time/date/format.ha
@@ -231,14 +231,7 @@ export fn format(
const iter = strings::iter(layout);
let escaped = false;
let n = 0z;
- for (true) {
- let r: rune = match (strings::next(&iter)) {
- case void =>
- break;
- case let r: rune =>
- yield r;
- };
-
+ for (let r => strings::next(&iter)) {
if (escaped) {
escaped = false;
n += fmtout(h, r, d)?;
@@ -299,9 +292,7 @@ export fn format(
("%s", "757390625"),
];
- for (let i = 0z; i < len(cases); i += 1) {
- const layout = cases[i].0;
- const expected = cases[i].1;
+ for (let (layout, expected) .. cases) {
const actual = asformat(layout, &d)!;
defer free(actual);
if (actual != expected) {
diff --git a/time/date/parithm.ha b/time/date/parithm.ha
@@ -284,10 +284,7 @@ export fn truncate(d: date, u: unit) date = {
},
),
];
- for (let i = 0z; i < len(cases); i += 1) {
- const da = cases[i].0;
- const db = cases[i].1;
- const expected = cases[i].2;
+ for (let (da, db, expected) .. cases) {
const actual = pdiff(da, db);
assert(peq(actual, expected), "pdiff miscalculation");
};
@@ -322,10 +319,7 @@ export fn truncate(d: date, u: unit) date = {
time::SECOND)),
),
];
- for (let i = 0z; i < len(cases); i += 1) {
- const da = cases[i].0;
- const db = cases[i].1;
- const expected = cases[i].2;
+ for (let (da, db, expected) .. cases) {
assert(unitdiff(da, db, unit::YEAR) == expected.0,
"invalid diff_in_years() result");
assert(unitdiff(da, db, unit::MONTH) == expected.1,
diff --git a/time/date/parse.ha b/time/date/parse.ha
@@ -29,14 +29,7 @@ export fn parse(v: *virtual, layout: str, s: str) (void | parsefail) = {
const siter = strings::iter(s);
let escaped = false;
- for (true) {
- const lr: rune = match (strings::next(&liter)) {
- case void =>
- break;
- case let lr: rune =>
- yield lr;
- };
-
+ for (let lr => strings::next(&liter)) {
if (!escaped && lr == '%') {
escaped = true;
continue;
@@ -44,7 +37,7 @@ export fn parse(v: *virtual, layout: str, s: str) (void | parsefail) = {
if (!escaped) {
const sr = match (strings::next(&siter)) {
- case void =>
+ case done =>
return (liter.dec.offs, lr);
case let sr: rune =>
yield sr;
@@ -140,7 +133,7 @@ fn parse_specifier(
fn eat_rune(iter: *strings::iterator, needle: rune) (uint | failure) = {
const rn = match (strings::next(iter)) {
- case void =>
+ case done =>
return failure;
case let rn: rune =>
yield rn;
@@ -180,7 +173,7 @@ fn scan_int(iter: *strings::iterator, maxrunes: size) (int | failure) = {
let startfixed = false;
for (let i = 0z; i < maxrunes; i += 1) {
let rn: rune = match (strings::next(iter)) {
- case void =>
+ case done =>
break;
case let rn: rune =>
yield rn;
@@ -211,7 +204,7 @@ fn scan_num(iter: *strings::iterator, maxrunes: size) (i64 | failure) = {
let start = *iter;
for (let i = 0z; i < maxrunes; i += 1) {
match (strings::next(iter)) {
- case void =>
+ case done =>
return failure;
case let rn: rune =>
if (!ascii::isdigit(rn)) {
@@ -236,7 +229,7 @@ fn scan_decimal(iter: *strings::iterator, maxrunes: size) (i64 | failure) = {
let start = *iter;
for (let i = 0z; i < maxrunes; i += 1) {
let rn: rune = match (strings::next(iter)) {
- case void =>
+ case done =>
break;
case let rn: rune =>
yield rn;
@@ -269,7 +262,7 @@ fn scan_decimal(iter: *strings::iterator, maxrunes: size) (i64 | failure) = {
//
fn scan_zo(iter: *strings::iterator) (time::duration | failure) = {
const first = match (strings::next(iter)) {
- case void =>
+ case done =>
return failure;
case let first: rune =>
yield first;
@@ -281,7 +274,7 @@ fn scan_zo(iter: *strings::iterator) (time::duration | failure) = {
let zo = scan_int(iter, 2)? * time::HOUR;
match (strings::next(iter)) {
- case void =>
+ case done =>
return failure;
case let sep: rune =>
if (sep != ':') {
@@ -301,15 +294,10 @@ fn scan_zo(iter: *strings::iterator) (time::duration | failure) = {
// Scans and parses locality names, made of printable characters.
fn scan_str(iter: *strings::iterator) (str | failure) = {
let start = *iter;
- for (true) {
- match (strings::next(iter)) {
- case void =>
+ for (let rn => strings::next(iter)) {
+ if (!ascii::isgraph(rn)) {
+ strings::prev(iter);
break;
- case let rn: rune =>
- if (!ascii::isgraph(rn)) {
- strings::prev(iter);
- break;
- };
};
};
return strings::slice(&start, iter);
diff --git a/time/date/period.ha b/time/date/period.ha
@@ -30,18 +30,18 @@ export fn peq(pa: period, pb: period) bool = {
// Returns the sum [[period]] of a set of periods.
export fn sum(ps: period...) period = {
- let p = period { ... };
- for (let i = 0z; i < len(ps); i += 1) {
- p.years += ps[i].years;
- p.months += ps[i].months;
- p.weeks += ps[i].weeks;
- p.days += ps[i].days;
- p.hours += ps[i].hours;
- p.minutes += ps[i].minutes;
- p.seconds += ps[i].seconds;
- p.nanoseconds += ps[i].nanoseconds;
+ let out = period { ... };
+ for (let p &.. ps) {
+ out.years += p.years;
+ out.months += p.months;
+ out.weeks += p.weeks;
+ out.days += p.days;
+ out.hours += p.hours;
+ out.minutes += p.minutes;
+ out.seconds += p.seconds;
+ out.nanoseconds += p.nanoseconds;
};
- return p;
+ return out;
};
// Returns a [[period]] with its fields negated.
diff --git a/time/date/reckon.ha b/time/date/reckon.ha
@@ -83,8 +83,7 @@ export fn reckon(d: date, calc: calculus, ps: period...) date = {
calc |= calculus::CEIL;
};
- for (let i = 0z; i < len(ps); i += 1) if (calc & calculus::REVSIG == 0) {
- const p = ps[i];
+ for (let p .. ps) if (calc & calculus::REVSIG == 0) {
const fold = calculus::FOLD;
r.year = r.year as int + p.years: int;
@@ -103,7 +102,6 @@ export fn reckon(d: date, calc: calculus, ps: period...) date = {
reckon_seconds(&r, p.seconds, fold);
reckon_nanoseconds(&r, p.nanoseconds, fold);
} else {
- const p = ps[i];
const fold = calculus::FOLD | calculus::REVSIG;
reckon_nanoseconds(&r, p.nanoseconds, fold);
diff --git a/time/date/virtual.ha b/time/date/virtual.ha
@@ -159,8 +159,7 @@ export fn realize(
v.loc = v.vloc as chrono::locality;
} else if (v.locname is str) {
v.loc = chrono::UTC;
- for (let i = 0z; i < len(locs); i += 1) {
- const loc = locs[i];
+ for (let loc .. locs) {
if (loc.name == v.locname as str) {
v.loc = loc;
break;