commit 34fdb97585fee2ce307b1190d8e5dd0a8ccf8936
parent 0332d9d04bc654e6d74ef2550a751d8e4b18e547
Author: Drew DeVault <sir@cmpwn.com>
Date: Thu, 16 Sep 2021 17:55:09 +0200
all: overhaul switch/match syntax
This changes the syntax of switch and match expressions following
similar changes to harec et al.
match (x) {
case type =>
do_work();
yield 10;
case x: type =>
process(x);
yield 20;
case =>
abort();
};
Signed-off-by: Drew DeVault <sir@cmpwn.com>
Signed-off-by: Alexey Yerin <yyp@disroot.org>
Co-authored-by: Alexey Yerin <yyp@disroot.org>
Diffstat:
153 files changed, 7835 insertions(+), 7026 deletions(-)
diff --git a/ascii/strcmp.ha b/ascii/strcmp.ha
@@ -8,15 +8,21 @@ export fn strcmp(a: str, b: str) (int | void) = {
let a = strings::iter(a), b = strings::iter(b);
for (true) {
let ra = match (strings::next(&a)) {
- void => return match (strings::next(&b)) {
- void => 0,
- rune => -1,
- },
- r: rune => r,
+ case void =>
+ match (strings::next(&b)) {
+ case void =>
+ return 0;
+ case rune =>
+ return -1;
+ };
+ case r: rune =>
+ yield r;
};
let rb = match (strings::next(&b)) {
- void => return 1,
- r: rune => r,
+ case void =>
+ return 1;
+ case r: rune =>
+ yield r;
};
if (!isascii(ra) || !isascii(rb)) {
return;
@@ -33,15 +39,21 @@ export fn strcasecmp(a: str, b: str) (int | void) = {
let a = strings::iter(a), b = strings::iter(b);
for (true) {
let ra = match (strings::next(&a)) {
- void => return match (strings::next(&b)) {
- void => 0,
- rune => -1,
- },
- r: rune => r,
+ case void =>
+ match (strings::next(&b)) {
+ case void =>
+ return 0;
+ case rune =>
+ return -1;
+ };
+ case r: rune =>
+ yield r;
};
let rb = match (strings::next(&b)) {
- void => return 1,
- r: rune => r,
+ case void =>
+ return 1;
+ case r: rune =>
+ yield r;
};
if (!isascii(ra) || !isascii(rb)) {
return;
diff --git a/bufio/buffered.ha b/bufio/buffered.ha
@@ -105,8 +105,10 @@ export fn isbuffered(s: *io::stream) bool = {
export fn any_isbuffered(s: *io::stream) bool = {
for (!isbuffered(s)) {
s = match (io::source(s)) {
- errors::unsupported => return false,
- s: *io::stream => s,
+ case errors::unsupported =>
+ return false;
+ case s: *io::stream =>
+ yield s;
};
};
return true;
@@ -163,14 +165,15 @@ fn buffered_read(s: *io::stream, buf: []u8) (size | io::EOF | io::error) = {
let n = if (len(buf) < len(s.rbuffer)) len(buf) else len(s.rbuffer);
if (n > s.ravail) {
let z = match (io::read(s.source, s.rbuffer[s.ravail..])) {
- err: io::error => return err,
- io::EOF => {
- if (s.ravail == 0) {
- return io::EOF;
- };
- yield 0z;
- },
- z: size => z,
+ case err: io::error =>
+ return err;
+ case io::EOF =>
+ if (s.ravail == 0) {
+ return io::EOF;
+ };
+ yield 0z;
+ case z: size =>
+ yield z;
};
s.ravail += z;
n = if (n > s.ravail) s.ravail else n;
diff --git a/bufio/memstream.ha b/bufio/memstream.ha
@@ -162,24 +162,21 @@ fn seek(
) (io::off | io::error) = {
let s = s: *memstream;
switch (w) {
- io::whence::SET => {
- if (len(s.buf) < off: size) {
- abort("invalid offset");
- };
- s.pos = off: size;
- },
- io::whence::CUR => {
- if (s.pos + off: size > len(s.buf)) {
- abort("invalid offset");
- };
- s.pos += off: size;
- },
- io::whence::END => {
- if (len(s.buf) - (-off): size < len(s.buf)) {
- abort("invalid offset");
- };
- s.pos = len(s.buf) - (-off): size;
- },
+ case io::whence::SET =>
+ if (len(s.buf) < off: size) {
+ abort("invalid offset");
+ };
+ s.pos = off: size;
+ case io::whence::CUR =>
+ if (s.pos + off: size > len(s.buf)) {
+ abort("invalid offset");
+ };
+ s.pos += off: size;
+ case io::whence::END =>
+ if (len(s.buf) - (-off): size < len(s.buf)) {
+ abort("invalid offset");
+ };
+ s.pos = len(s.buf) - (-off): size;
};
return s.pos: io::off;
};
diff --git a/bufio/scanner.ha b/bufio/scanner.ha
@@ -8,9 +8,15 @@ use types;
export fn scanbyte(stream: *io::stream) (u8 | io::EOF | io::error) = {
let buf: [1]u8 = [0...];
- return match (io::read(stream, buf)?) {
- read: size => if (read > 0) buf[0] else io::EOF,
- io::EOF => io::EOF,
+ match (io::read(stream, buf)?) {
+ case read: size =>
+ if (read > 0) {
+ return buf[0];
+ } else {
+ return io::EOF;
+ };
+ case io::EOF =>
+ return io::EOF;
};
};
@@ -21,18 +27,16 @@ export fn scantok(stream: *io::stream, delim: u8...) ([]u8 | io::EOF | io::error
for (true) {
match (scanbyte(stream)?) {
- res: u8 => {
- if (bytes::contains(delim, res)) {
- break;
- };
- append(buf, res);
- },
- io::EOF => {
- if (len(buf) == 0) {
- return io::EOF;
- };
+ case res: u8 =>
+ if (bytes::contains(delim, res)) {
break;
- },
+ };
+ append(buf, res);
+ case io::EOF =>
+ if (len(buf) == 0) {
+ return io::EOF;
+ };
+ break;
};
};
@@ -48,8 +52,10 @@ export fn scanline(stream: *io::stream) ([]u8 | io::EOF | io::error) =
export fn scanrune(stream: *io::stream) (rune | utf8::invalid | io::EOF | io::error) = {
let b: [4]u8 = [0...];
match (io::read(stream, b[..1])?) {
- n: size => assert(n == 1),
- io::EOF => return io::EOF,
+ case n: size =>
+ assert(n == 1);
+ case io::EOF =>
+ return io::EOF;
};
const sz = utf8::utf8sz(b[0]);
@@ -61,16 +67,19 @@ export fn scanrune(stream: *io::stream) (rune | utf8::invalid | io::EOF | io::er
return b[0]: u32: rune;
};
- match (io::read(stream, b[1..sz])) {
- n: size => assert(n == sz - 1),
- e: (io::error | io::EOF) => return e,
+ match (io::read(stream, b[1..sz])?) {
+ case n: size =>
+ assert(n == sz - 1);
+ case io::EOF =>
+ return io::EOF;
};
let dec = utf8::decode(b[..sz]);
- return match (utf8::next(&dec)) {
- r: rune => r,
- utf8::invalid => utf8::invalid,
- (void | utf8::more) => io::EOF,
+ match (utf8::next(&dec)?) {
+ case r: rune =>
+ return r;
+ case (void | utf8::more) =>
+ return io::EOF;
};
};
@@ -130,9 +139,12 @@ export fn scanrune(stream: *io::stream) (rune | utf8::invalid | io::EOF | io::er
let want = expected[i];
match (scanrune(in)) {
- r: rune => assert(want is rune && want as rune == r),
- io::EOF => assert(want is io::EOF),
- * => abort(),
+ case r: rune =>
+ assert(want is rune && want as rune == r);
+ case io::EOF =>
+ assert(want is io::EOF);
+ case =>
+ abort();
};
};
};
diff --git a/bytes/contains.ha b/bytes/contains.ha
@@ -1,5 +1,7 @@
// Returns true if a byte slice contains a byte or a sequence of bytes.
export fn contains(haystack: []u8, needle: (u8 | []u8)) bool = match (needle) {
- b: u8 => !(index_byte(haystack, b) is void),
- b: []u8 => !(index_slice(haystack, b) is void),
+case b: u8 =>
+ yield !(index_byte(haystack, b) is void);
+case b: []u8 =>
+ yield !(index_slice(haystack, b) is void);
};
diff --git a/bytes/index.ha b/bytes/index.ha
@@ -2,8 +2,10 @@
// bytes, or void if it is not found.
export fn index(haystack: []u8, needle: (u8 | []u8)) (size | void) = {
return match (needle) {
- b: u8 => index_byte(haystack, b),
- b: []u8 => index_slice(haystack, b),
+ case b: u8 =>
+ yield index_byte(haystack, b);
+ case b: []u8 =>
+ yield index_slice(haystack, b);
};
};
@@ -16,18 +18,23 @@ fn index_byte(haystack: []u8, needle: u8) (size | void) = {
};
fn index_slice(haystack: []u8, b: []u8) (size | void) = switch (len(b)) {
- 0 => 0,
- 1 => index_byte(haystack, b[0]),
- // TODO special-case 2, 3, 4
- * => index_tw(haystack, b),
+// TODO special-case 2, 3, 4
+case 0 =>
+ yield 0;
+case 1 =>
+ yield index_byte(haystack, b[0]);
+case =>
+ yield index_tw(haystack, b);
};
// Returns the offset of the last instance of "needle" in a "haystack" of
// bytes, or void if it is not found.
export fn rindex(haystack: []u8, needle: (u8 | []u8)) (size | void) = {
- return match (needle) {
- b: u8 => rindex_byte(haystack, b),
- b: []u8 => rindex_slice(haystack, b),
+ match (needle) {
+ case b: u8 =>
+ return rindex_byte(haystack, b);
+ case b: []u8 =>
+ return rindex_slice(haystack, b);
};
};
diff --git a/bytes/tokenize.ha b/bytes/tokenize.ha
@@ -21,17 +21,16 @@ export fn tokenize(s: []u8, delim: []u8) tokenizer = {
// string starts with, or ends with, a token, an empty slice is returned at the
// beginning or end of the sequence, respectively.
export fn next_token(s: *tokenizer) ([]u8 | void) = match (peek_token(s)) {
- b: []u8 => {
- if (s.p == len(s.s)) {
- s.d = s.d[..0];
- s.s = s.s[..0];
- } else {
- s.s = s.s[s.p + len(s.d)..];
- };
- s.p = types::SIZE_MAX;
- return b;
- },
- void => void,
+case b: []u8 =>
+ if (s.p == len(s.s)) {
+ s.d = s.d[..0];
+ s.s = s.s[..0];
+ } else {
+ s.s = s.s[s.p + len(s.d)..];
+ };
+ s.p = types::SIZE_MAX;
+ return b;
+case => void;
};
// Same as next_token(), but does not advance the cursor
@@ -41,8 +40,10 @@ export fn peek_token(s: *tokenizer) ([]u8 | void) = {
};
if (s.p > len(s.s)) {
s.p = match (index(s.s, s.d)) {
- i: size => i,
- void => len(s.s),
+ case i: size =>
+ yield i;
+ case void =>
+ yield len(s.s);
};
};
return s.s[..s.p];
@@ -71,8 +72,10 @@ export fn remaining_tokens(s: *tokenizer) []u8 = {
assert(equal(peek_token(&t) as []u8, peek_token(&t) as []u8));
match (next_token(&t)) {
- b: []u8 => assert(equal([4, 5], b)),
- void => abort(),
+ case b: []u8 =>
+ assert(equal([4, 5], b));
+ case void =>
+ abort();
};
assert(peek_token(&t) is void);
@@ -83,20 +86,26 @@ export fn remaining_tokens(s: *tokenizer) []u8 = {
assert(equal(peek_token(&t) as []u8, peek_token(&t) as []u8));
match (next_token(&t)) {
- b: []u8 => assert(equal([], b)),
- void => abort(),
+ case b: []u8 =>
+ assert(equal([], b));
+ case void =>
+ abort();
};
assert(equal(peek_token(&t) as []u8, peek_token(&t) as []u8));
match (next_token(&t)) {
- b: []u8 => assert(equal([1], b)),
- void => abort(),
+ case b: []u8 =>
+ assert(equal([1], b));
+ case void =>
+ abort();
};
assert(equal(peek_token(&t) as []u8, peek_token(&t) as []u8));
match (next_token(&t)) {
- b: []u8 => assert(equal([], b)),
- void => abort(),
+ case b: []u8 =>
+ assert(equal([], b));
+ case void =>
+ abort();
};
assert(peek_token(&t) is void);
@@ -106,18 +115,24 @@ export fn remaining_tokens(s: *tokenizer) []u8 = {
t = tokenize(input3, [1, 2]);
match (next_token(&t)) {
- b: []u8 => assert(equal([1, 1], b)),
- void => abort(),
+ case b: []u8 =>
+ assert(equal([1, 1], b));
+ case void =>
+ abort();
};
match (next_token(&t)) {
- b: []u8 => assert(equal([1], b)),
- void => abort(),
+ case b: []u8 =>
+ assert(equal([1], b));
+ case void =>
+ abort();
};
match (next_token(&t)) {
- b: []u8 => assert(equal([2], b)),
- void => abort(),
+ case b: []u8 =>
+ assert(equal([2], b));
+ case void =>
+ abort();
};
assert(next_token(&t) is void);
@@ -126,13 +141,17 @@ export fn remaining_tokens(s: *tokenizer) []u8 = {
t = tokenize(input4, [1, 2]);
match (next_token(&t)) {
- b: []u8 => assert(equal([], b)),
- void => abort(),
+ case b: []u8 =>
+ assert(equal([], b));
+ case void =>
+ abort();
};
match (next_token(&t)) {
- b: []u8 => assert(equal([], b)),
- void => abort(),
+ case b: []u8 =>
+ assert(equal([], b));
+ case void =>
+ abort();
};
assert(peek_token(&t) is void);
@@ -142,13 +161,17 @@ export fn remaining_tokens(s: *tokenizer) []u8 = {
t = tokenize(input5, [24, 42]);
match (next_token(&t)) {
- b: []u8 => assert(equal([], b)),
- void => abort(),
+ case b: []u8 =>
+ assert(equal([], b));
+ case void =>
+ abort();
};
match (next_token(&t)) {
- b: []u8 => assert(equal([1], b)),
- void => abort(),
+ case b: []u8 =>
+ assert(equal([1], b));
+ case void =>
+ abort();
};
assert(equal(remaining_tokens(&t), [2, 3, 4]));
diff --git a/cmd/hare/main.ha b/cmd/hare/main.ha
@@ -17,16 +17,21 @@ export fn main() void = {
os::exit(1);
};
const task = switch (cmd.args[0]) {
- "build" => &build,
- "cache" => &cache,
- "deps" => &deps,
- "run" => &run,
- "test" => &test,
- "version" => &version,
- * => {
- getopt::printusage(os::stderr, os::args[0], help...);
- os::exit(1);
- },
+ case "build" =>
+ yield &build;
+ case "cache" =>
+ yield &cache;
+ case "deps" =>
+ yield &deps;
+ case "run" =>
+ yield &run;
+ case "test" =>
+ yield &test;
+ case "version" =>
+ yield &version;
+ case =>
+ getopt::printusage(os::stderr, os::args[0], help...);
+ os::exit(1);
};
task(cmd.args);
};
diff --git a/cmd/hare/plan.ha b/cmd/hare/plan.ha
@@ -47,9 +47,10 @@ type plan = struct {
fn mkplan(ctx: *module::context) plan = {
const rtdir = match (module::lookup(ctx, ["rt"])) {
- err: module::error => fmt::fatal("Error resolving rt: {}",
- module::strerror(err)),
- ver: module::version => ver.basedir,
+ case err: module::error =>
+ fmt::fatal("Error resolving rt: {}", module::strerror(err));
+ case ver: module::version =>
+ yield ver.basedir;
};
return plan {
context = ctx,
@@ -119,19 +120,21 @@ fn plan_execute(plan: *plan, verbose: bool) (void | !exec::exit_status) = {
};
// TODO: This can be a type assertion
let task = match (next) {
- null => abort(),
- t: *task => t,
+ case null =>
+ abort();
+ case t: *task =>
+ yield t;
};
match (execute(plan, task, verbose)) {
- err: exec::error => fmt::fatal("Error: {}: {}",
- task.cmd[0], exec::strerror(err)),
- err: !exec::exit_status => {
- fmt::errorfln("Error: {}: {}", task.cmd[0],
- exec::exitstr(err))!;
- return err;
- },
- void => void,
+ case err: exec::error =>
+ fmt::fatal("Error: {}: {}", task.cmd[0],
+ exec::strerror(err));
+ case err: !exec::exit_status =>
+ fmt::errorfln("Error: {}: {}", task.cmd[0],
+ exec::exitstr(err))!;
+ return err;
+ case void => void;
};
task.status = status::COMPLETE;
@@ -150,10 +153,10 @@ fn update_cache(plan: *plan, mod: modcache) void = {
versions = [mod.version],
};
match (module::manifest_write(plan.context, &manifest)) {
- err: module::error => fmt::fatal(
- "Error updating module cache: {}",
- module::strerror(err)),
- void => void,
+ case err: module::error =>
+ fmt::fatal("Error updating module cache: {}",
+ module::strerror(err));
+ case void => void;
};
};
diff --git a/cmd/hare/schedule.ha b/cmd/hare/schedule.ha
@@ -30,12 +30,12 @@ fn sched_module(plan: *plan, ident: ast::ident, link: *[]*task) *task = {
};
let ver = match (module::lookup(plan.context, ident)) {
- err: module::error => {
- let ident = unparse::identstr(ident);
- fmt::fatal("Error resolving {}: {}",
- ident, module::strerror(err));
- },
- ver: module::version => ver,
+ case err: module::error =>
+ let ident = unparse::identstr(ident);
+ fmt::fatal("Error resolving {}: {}", ident,
+ module::strerror(err));
+ case ver: module::version =>
+ yield ver;
};
let depends: []*task = [];
@@ -188,10 +188,11 @@ fn sched_hare_object(
// overwriting with just the latest
let manifest = match (module::manifest_load(
plan.context, namespace)) {
- err: module::error => fmt::fatal(
- "Error reading cache entry for {}: {}",
- ns, module::strerror(err)),
- m: module::manifest => m,
+ case err: module::error =>
+ fmt::fatal("Error reading cache entry for {}: {}", ns,
+ module::strerror(err));
+ case m: module::manifest =>
+ yield m;
};
defer module::manifest_finish(&manifest);
current = module::current(&manifest, &ver);
@@ -208,9 +209,10 @@ fn sched_hare_object(
path = path::join(path, namespace[i]);
};
match (os::mkdirs(path)) {
- void => void,
- err: fs::error => fmt::fatal("Error: mkdirs {}: {}",
- path, fs::strerror(err)),
+ case void => void;
+ case err: fs::error =>
+ fmt::fatal("Error: mkdirs {}: {}", path,
+ fs::strerror(err));
};
append(harec.cmd, "-t", path::join(path, td));
yield path::join(path, name);
diff --git a/cmd/hare/subcmds.ha b/cmd/hare/subcmds.ha
@@ -23,8 +23,10 @@ fn default_tags() []module::tag = {
fn addtags(tags: []module::tag, in: str) ([]module::tag | void) = {
let in = match (module::parsetags(in)) {
- void => return void,
- t: []module::tag => t,
+ case void =>
+ return void;
+ case t: []module::tag =>
+ yield t;
};
defer free(in);
append(tags, in...);
@@ -37,8 +39,10 @@ fn deltags(tags: []module::tag, in: str) ([]module::tag | void) = {
return [];
};
let in = match (module::parsetags(in)) {
- void => return void,
- t: []module::tag => t,
+ case void =>
+ return void;
+ case t: []module::tag =>
+ yield t;
};
defer free(in);
for (let i = 0z; i < len(tags); i += 1) {
@@ -85,22 +89,36 @@ fn build(args: []str) void = {
for (let i = 0z; i < len(cmd.opts); i += 1) {
let opt = cmd.opts[i];
switch (opt.0) {
- 'c' => goal = goal::OBJ,
- 'v' => verbose = true,
- 'D' => append(defines, opt.1),
- 'j' => abort(), // TODO
- 'l' => abort(), // TODO
- 'o' => output = opt.1,
- 't' => abort(), // TODO
- 'T' => tags = match (addtags(tags, opt.1)) {
- void => fmt::fatal("Error parsing tags"),
- t: []module::tag => t,
- },
- 'X' => tags = match (deltags(tags, opt.1)) {
- void => fmt::fatal("Error parsing tags"),
- t: []module::tag => t,
- },
- * => abort(),
+ case 'c' =>
+ goal = goal::OBJ;
+ case 'v' =>
+ verbose = true;
+ case 'D' =>
+ append(defines, opt.1);
+ case 'j' =>
+ abort(); // TODO
+ case 'l' =>
+ abort(); // TODO
+ case 'o' =>
+ output = opt.1;
+ case 't' =>
+ abort(); // TODO
+ case 'T' =>
+ tags = match (addtags(tags, opt.1)) {
+ case void =>
+ fmt::fatal("Error parsing tags");
+ case t: []module::tag =>
+ yield t;
+ };
+ case 'X' =>
+ tags = match (deltags(tags, opt.1)) {
+ case void =>
+ fmt::fatal("Error parsing tags");
+ case t: []module::tag =>
+ yield t;
+ };
+ case =>
+ abort();
};
};
@@ -121,10 +139,11 @@ fn build(args: []str) void = {
defer plan_finish(&plan);
const ver = match (module::scan(&ctx, input)) {
- ver: module::version => ver,
- err: module::error => fmt::fatal(
- "Error scanning input module: {}",
- module::strerror(err)),
+ case ver: module::version =>
+ yield ver;
+ case err: module::error =>
+ fmt::fatal("Error scanning input module: {}",
+ module::strerror(err));
};
const depends: []*task = [];
@@ -141,9 +160,9 @@ fn build(args: []str) void = {
};
sched_hare_exe(&plan, ver, output, depends...);
match (plan_execute(&plan, verbose)) {
- void => void,
- !exec::exit_status => fmt::fatal("{} {}: build failed",
- os::args[0], os::args[1]),
+ case void => void;
+ case !exec::exit_status =>
+ fmt::fatal("{} {}: build failed", os::args[0], os::args[1]);
};
};
@@ -196,20 +215,32 @@ fn run(args: []str) void = {
for (let i = 0z; i < len(cmd.opts); i += 1) {
let opt = cmd.opts[i];
switch (opt.0) {
- 'v' => verbose = true,
- 'D' => append(defines, opt.1),
- 'j' => abort(), // TODO
- 'l' => abort(), // TODO
- 't' => abort(), // TODO
- 'T' => tags = match (addtags(tags, opt.1)) {
- void => fmt::fatal("Error parsing tags"),
- t: []module::tag => t,
- },
- 'X' => tags = match (deltags(tags, opt.1)) {
- void => fmt::fatal("Error parsing tags"),
- t: []module::tag => t,
- },
- * => abort(),
+ case 'v' =>
+ verbose = true;
+ case 'D' =>
+ append(defines, opt.1);
+ case 'j' =>
+ abort(); // TODO
+ case 'l' =>
+ abort(); // TODO
+ case 't' =>
+ abort(); // TODO
+ case 'T' =>
+ tags = match (addtags(tags, opt.1)) {
+ case void =>
+ fmt::fatal("Error parsing tags");
+ case t: []module::tag =>
+ yield t;
+ };
+ case 'X' =>
+ tags = match (deltags(tags, opt.1)) {
+ case void =>
+ fmt::fatal("Error parsing tags");
+ case t: []module::tag =>
+ yield t;
+ };
+ case =>
+ abort();
};
};
@@ -229,10 +260,11 @@ fn run(args: []str) void = {
defer plan_finish(&plan);
const ver = match (module::scan(&ctx, input)) {
- ver: module::version => ver,
- err: module::error => fmt::fatal(
- "Error scanning input module: {}",
- module::strerror(err)),
+ case ver: module::version =>
+ yield ver;
+ case err: module::error =>
+ fmt::fatal("Error scanning input module: {}",
+ module::strerror(err));
};
let depends: []*task = [];
@@ -246,13 +278,15 @@ fn run(args: []str) void = {
const output = mkfile(&plan, "out");
sched_hare_exe(&plan, ver, output, depends...);
match (plan_execute(&plan, verbose)) {
- void => void,
- !exec::exit_status => fmt::fatal("{} {}: build failed",
- os::args[0], os::args[1]),
+ case void => void;
+ case !exec::exit_status =>
+ fmt::fatal("{} {}: build failed", os::args[0], os::args[1]);
};
const cmd = match (exec::cmd(output, runargs...)) {
- err: exec::error => fmt::fatal("exec: {}", exec::strerror(err)),
- cmd: exec::command => cmd,
+ case err: exec::error =>
+ fmt::fatal("exec: {}", exec::strerror(err));
+ case cmd: exec::command =>
+ yield cmd;
};
exec::setname(&cmd, input);
exec::exec(&cmd);
@@ -264,40 +298,47 @@ fn sched_walk(plan: *plan, ident: ast::ident, link: *[]*task) void = {
free(path);
for (true) :loop {
match (fs::next(it)) {
- ent: fs::dirent => {
- if (ent.name == "." || ent.name == "..") {
- continue;
- };
- if (ent.ftype & fs::mode::DIR != fs::mode::DIR) {
- continue;
- };
- const d = utf8::decode(ent.name);
- match (utf8::next(&d)) {
- void => break,
- (utf8::more | utf8::invalid) => continue :loop,
- r: rune => if (!ascii::isalpha(r) && r != '_') {
- continue :loop;
- },
- };
- for (true) match (utf8::next(&d)) {
- void => break,
- (utf8::more | utf8::invalid) => continue :loop,
- r: rune => if (!ascii::isalnum(r) && r != '_') {
- continue :loop;
- },
+ case ent: fs::dirent =>
+ if (ent.name == "." || ent.name == "..") {
+ continue;
+ };
+ if (ent.ftype & fs::mode::DIR != fs::mode::DIR) {
+ continue;
+ };
+ const d = utf8::decode(ent.name);
+ match (utf8::next(&d)) {
+ case void =>
+ break;
+ case (utf8::more | utf8::invalid) =>
+ continue :loop;
+ case r: rune =>
+ if (!ascii::isalpha(r) && r != '_') {
+ continue :loop;
};
- let new = ast::ident_dup(ident);
- append(new, strings::dup(ent.name));
- sched_walk(plan, new, link);
-
- match (module::lookup(plan.context, new)) {
- ver: module::version =>
- if (len(ver.inputs) == 0) continue,
- module::error => continue,
+ };
+ for (true) match (utf8::next(&d)) {
+ case void =>
+ break;
+ case (utf8::more | utf8::invalid) =>
+ continue :loop;
+ case r: rune =>
+ if (!ascii::isalnum(r) && r != '_') {
+ continue :loop;
};
- sched_module(plan, new, link);
- },
- void => break,
+ };
+ let new = ast::ident_dup(ident);
+ append(new, strings::dup(ent.name));
+ sched_walk(plan, new, link);
+
+ match (module::lookup(plan.context, new)) {
+ case ver: module::version =>
+ if (len(ver.inputs) == 0) continue;
+ case module::error =>
+ continue;
+ };
+ sched_module(plan, new, link);
+ case void =>
+ break;
};
};
};
@@ -330,21 +371,34 @@ fn test(args: []str) void = {
for (let i = 0z; i < len(cmd.opts); i += 1) {
const opt = cmd.opts[i];
switch (opt.0) {
- 'v' => verbose = true,
- 'D' => append(defines, opt.1),
- 'j' => abort(), // TODO
- 'l' => abort(), // TODO
- 't' => abort(), // TODO
- 'o' => output = opt.1,
- 'T' => tags = match (addtags(tags, opt.1)) {
- void => fmt::fatal("Error parsing tags"),
- t: []module::tag => t,
- },
- 'X' => tags = match (deltags(tags, opt.1)) {
- void => fmt::fatal("Error parsing tags"),
- t: []module::tag => t,
- },
- * => abort(),
+ case 'v' =>
+ verbose = true;
+ case 'D' =>
+ append(defines, opt.1);
+ case 'j' =>
+ abort(); // TODO
+ case 'l' =>
+ abort(); // TODO
+ case 't' =>
+ abort(); // TODO
+ case 'o' =>
+ output = opt.1;
+ case 'T' =>
+ tags = match (addtags(tags, opt.1)) {
+ case void =>
+ fmt::fatal("Error parsing tags");
+ case t: []module::tag =>
+ yield t;
+ };
+ case 'X' =>
+ tags = match (deltags(tags, opt.1)) {
+ case void =>
+ fmt::fatal("Error parsing tags");
+ case t: []module::tag =>
+ yield t;
+ };
+ case =>
+ abort();
};
};
@@ -364,10 +418,11 @@ fn test(args: []str) void = {
defer plan_finish(&plan);
const ver = match (module::scan(&ctx, input)) {
- ver: module::version => ver,
- err: module::error => fmt::fatal(
- "Error scanning input module: {}",
- module::strerror(err)),
+ case ver: module::version =>
+ yield ver;
+ case err: module::error =>
+ fmt::fatal("Error scanning input module: {}",
+ module::strerror(err));
};
let depends: []*task = [];
@@ -384,9 +439,9 @@ fn test(args: []str) void = {
sched_hare_exe(&plan, ver, strings::dup(output), depends...);
};
match (plan_execute(&plan, verbose)) {
- void => void,
- !exec::exit_status => fmt::fatal("{} {}: build failed",
- os::args[0], os::args[1]),
+ case void => void;
+ case !exec::exit_status =>
+ fmt::fatal("{} {}: build failed", os::args[0], os::args[1]);
};
if (have_output) {
@@ -394,8 +449,10 @@ fn test(args: []str) void = {
};
const cmd = match (exec::cmd(output, runargs...)) {
- err: exec::error => fmt::fatal("exec: {}", exec::strerror(err)),
- cmd: exec::command => cmd,
+ case err: exec::error =>
+ fmt::fatal("exec: {}", exec::strerror(err));
+ case cmd: exec::command =>
+ yield cmd;
};
exec::setname(&cmd, input);
exec::exec(&cmd);
@@ -429,12 +486,12 @@ fn version(args: []str) void = {
fmt::println()!;
match (os::getenv("HAREPATH")) {
- void => fmt::printfln("HAREPATH\t{}", HAREPATH)!,
- s: str => {
- fmt::printf("HAREPATH\t{}", s)!;
- bufio::flush(os::stdout)!;
- fmt::errorln("\t(from environment)")!;
- },
+ case void =>
+ fmt::printfln("HAREPATH\t{}", HAREPATH)!;
+ case s: str =>
+ fmt::printf("HAREPATH\t{}", s)!;
+ bufio::flush(os::stdout)!;
+ fmt::errorln("\t(from environment)")!;
};
};
};
diff --git a/cmd/harec/errors.ha b/cmd/harec/errors.ha
@@ -9,8 +9,10 @@ use strings;
// TODO: Expand to more kinds of errors
fn printerr(err: parse::error) void = {
match (err) {
- err: lex::syntax => printerr_syntax(err),
- err: io::error => fmt::errorln(io::strerror(err))!,
+ case err: lex::syntax =>
+ printerr_syntax(err);
+ case err: io::error =>
+ fmt::errorln(io::strerror(err))!;
};
};
diff --git a/cmd/harec/gen.ha b/cmd/harec/gen.ha
@@ -25,9 +25,12 @@ fn gen(store: *types::typestore, unit: *unit::unit) void = {
...
};
defer io::close(ctx.out);
- for (let i = 0z; i < len(unit.decls); i += 1) match (unit.decls[i].decl) {
- func: unit::decl_func => gen_func(&ctx, &unit.decls[i]),
- * => abort(), // TODO
+ for (let i = 0z; i < len(unit.decls); i += 1) {
+ match (unit.decls[i].decl) {
+ case func: unit::decl_func =>
+ gen_func(&ctx, &unit.decls[i]);
+ case => abort(); // TODO
+ };
};
};
@@ -35,8 +38,10 @@ fn gen_func(ctx: *context, decl: *unit::decl) void = {
// TODO: const fndecl = &decl.decl as *unit::decl_func;
const fndecl = decl.decl as unit::decl_func;
const body = match (fndecl.body) {
- null => return, // Prototype
- expr: *unit::expr => expr,
+ case expr: *unit::expr =>
+ yield expr;
+ case null =>
+ return; // Prototype
};
const fntype = fndecl.prototype.repr as types::func;
assert(fntype.flags == 0);
@@ -47,10 +52,13 @@ fn gen_func(ctx: *context, decl: *unit::decl) void = {
fmt::printf("{}function section \".text.{}\" \"ax\"",
if (decl.exported) "export " else "", ident)!;
const rtype = fntype.result;
- const has_rval = match (types::dealias(rtype).repr) {
- bi: types::builtin => bi != types::builtin::VOID,
- * => true,
- };
+ const has_rval =
+ match (types::dealias(rtype).repr) {
+ case bi: types::builtin =>
+ yield bi != types::builtin::VOID;
+ case =>
+ yield true;
+ };
if (has_rval) {
const qrtype = qtype_lookup(ctx, rtype, false);
fmt::printf(" {}", qtype_repr(qrtype))!;
@@ -83,14 +91,15 @@ fn gen_func(ctx: *context, decl: *unit::decl) void = {
fn gen_store(ctx: *context, object: value, value: value) void = {
match (types::dealias(object._type).repr) {
- bi: types::builtin => switch (bi) {
- builtin::STR => abort(), // TODO
- * => void,
- },
- types::_struct => abort(), // TODO
- (types::array | types::slice | types::tagged | types::tuple) =>
- abort(), // TODO
- * => void,
+ case bi: types::builtin =>
+ switch (bi) {
+ case builtin::STR => abort(); // TODO
+ case => void;
+ };
+ case types::_struct => abort(); // TODO
+ case (types::array | types::slice | types::tagged | types::tuple) =>
+ abort(); // TODO
+ case => void; // Handled below
};
const instr = qinstr_store(ctx, object._type);
emit(ctx.out, void, instr, value, object);
@@ -98,14 +107,15 @@ fn gen_store(ctx: *context, object: value, value: value) void = {
fn gen_load(ctx: *context, object: value) value = {
match (types::dealias(object._type).repr) {
- bi: types::builtin => switch (bi) {
- builtin::STR => abort(), // TODO
- * => void,
- },
- types::_struct => abort(), // TODO
- (types::array | types::slice | types::tagged | types::tuple) =>
- abort(), // TODO
- * => void,
+ case bi: types::builtin =>
+ switch (bi) {
+ case builtin::STR => abort(); // TODO
+ case => void;
+ };
+ case types::_struct => abort(); // TODO
+ case (types::array | types::slice | types::tagged | types::tuple) =>
+ abort(); // TODO
+ case => void; // Handled below
};
const instr = qinstr_load(ctx, object._type);
const temp = mktemp(ctx);
@@ -118,45 +128,48 @@ fn gen_load(ctx: *context, object: value) value = {
};
fn gen_expr(ctx: *context, expr: *unit::expr) value = {
- return match (expr.expr) {
- unit::access => gen_access(ctx, expr),
- unit::bindings => gen_binding(ctx, expr),
- unit::compound => gen_compound(ctx, expr),
- unit::constant => gen_const(ctx, expr),
- unit::_return => gen_return(ctx, expr),
+ match (expr.expr) {
+ case unit::access =>
+ return gen_access(ctx, expr);
+ case unit::bindings =>
+ return gen_binding(ctx, expr);
+ case unit::compound =>
+ return gen_compound(ctx, expr);
+ case unit::constant =>
+ return gen_const(ctx, expr);
+ case unit::_return =>
+ return gen_return(ctx, expr);
};
};
fn gen_expr_at(ctx: *context, expr: *unit::expr, at: value) void = {
match (expr.expr) {
- // TODO: Some functions will prefer _at
- * => void,
+ case => void; // TODO: Some functions will prefer _at
};
const value = gen_expr(ctx, expr);
gen_store(ctx, at, value);
};
fn gen_access_object(ctx: *context, object: *unit::object) value = {
- return switch (object.kind) {
- object_kind::CONST, object_kind::TYPE => abort(),
- object_kind::BIND => {
- const binding = binding_lookup(ctx, object);
- yield value {
- value = binding.name,
- _type = object._type,
- };
- },
- object_kind::DECL => abort(), // TODO
+ switch (object.kind) {
+ case object_kind::CONST, object_kind::TYPE => abort();
+ case object_kind::BIND =>
+ const binding = binding_lookup(ctx, object);
+ return value {
+ value = binding.name,
+ _type = object._type,
+ };
+ case object_kind::DECL => abort(); // TODO
};
};
fn gen_access_addr(ctx: *context, expr: *unit::expr) value = {
- const access = expr.expr as unit::access;
- return match (access) {
- ao: unit::access_object => gen_access_object(ctx, ao),
- ai: unit::access_index => abort(), // TODO
- af: unit::access_field => abort(), // TODO
- at: unit::access_tuple => abort(), // TODO
+ match (expr.expr as unit::access) {
+ case ao: unit::access_object =>
+ return gen_access_object(ctx, ao);
+ case ai: unit::access_index => abort(); // TODO
+ case af: unit::access_field => abort(); // TODO
+ case at: unit::access_tuple => abort(); // TODO
};
};
@@ -199,14 +212,20 @@ fn gen_compound(ctx: *context, expr: *unit::expr) value = {
fn gen_const(ctx: *context, expr: *unit::expr) value = {
const constexpr = expr.expr as unit::constant;
const val: qval = match (constexpr) {
- void => return vvoid,
- b: bool => (if (b) 1u32 else 0u32): constant,
- ast::_null => 0u64, // XXX: Arch
- r: rune => r: u32,
- v: (u64 | f64) => v,
- i: i64 => i: u64,
- s: str => abort(), // TODO
- // TODO: Aggregate types
+ case void =>
+ return vvoid;
+ case b: bool =>
+ yield (if (b) 1u32 else 0u32): constant;
+ case ast::_null =>
+ yield 0u64; // XXX: Arch
+ case r: rune =>
+ yield r: u32;
+ case v: (u64 | f64) =>
+ yield v;
+ case i: i64 =>
+ yield i: u64;
+ case s: str => abort(); // TODO
+ // TODO: Aggregate types
};
return value {
value = val,
@@ -217,10 +236,10 @@ fn gen_const(ctx: *context, expr: *unit::expr) value = {
fn gen_return(ctx: *context, expr: *unit::expr) value = {
const rexpr = expr.expr as unit::_return;
match (rexpr) {
- null => emit(ctx.out, void, qinstr::RET),
- expr: *unit::expr => {
- emit(ctx.out, void, qinstr::RET, gen_expr(ctx, expr));
- },
+ case null =>
+ emit(ctx.out, void, qinstr::RET);
+ case expr: *unit::expr =>
+ emit(ctx.out, void, qinstr::RET, gen_expr(ctx, expr));
};
return vvoid;
};
diff --git a/cmd/harec/main.ha b/cmd/harec/main.ha
@@ -26,12 +26,12 @@ export fn main() void = {
for (let i = 0z; i < len(cmd.opts); i += 1) {
let opt = cmd.opts[i];
switch (opt.0) {
- 'D' => abort(), // TODO
- 'N' => abort(), // TODO
- 'T' => abort(), // TODO
- 'o' => abort(), // TODO
- 't' => abort(), // TODO
- * => abort(),
+ case 'D' => abort(); // TODO
+ case 'N' => abort(); // TODO
+ case 'T' => abort(); // TODO
+ case 'o' => abort(); // TODO
+ case 't' => abort(); // TODO
+ case => abort();
};
};
@@ -51,9 +51,11 @@ export fn main() void = {
for (let i = 0z; i < len(cmd.args); i += 1) {
let input = match (os::open(cmd.args[i])) {
- f: io::file => f,
- err: io::error => fmt::fatal("Error opening {}: {}",
- cmd.args[i], io::strerror(err)),
+ case f: io::file =>
+ yield f;
+ case err: io::error =>
+ fmt::fatal("Error opening {}: {}",
+ cmd.args[i], io::strerror(err));
};
defer io::close(&input);
static let buf: [os::BUFSIZ]u8 = [0...];
@@ -62,18 +64,19 @@ export fn main() void = {
let lexer = lex::init(bufin, cmd.args[i]);
let su = match (parse::subunit(&lexer)) {
- err: parse::error => {
- printerr(err);
- os::exit(1);
- },
- u: ast::subunit => u,
+ case err: parse::error =>
+ printerr(err);
+ os::exit(1);
+ case u: ast::subunit =>
+ yield u;
};
append(subunits, su);
};
let unit = match (unit::check(store, [], subunits)) {
- unit::error => abort(), // TODO
- u: unit::unit => u,
+ case unit::error => abort(); // TODO
+ case u: unit::unit =>
+ yield u;
};
defer unit::unit_free(unit);
gen(store, &unit);
diff --git a/cmd/harec/qbe.ha b/cmd/harec/qbe.ha
@@ -29,111 +29,199 @@ fn emit(
) void = {
fmt::fprintf(to, "\t")!;
match (out) {
- val: qtypeval => {
- const ty = val.0, val = val.1;
- qval_emit(to, val);
- fmt::fprintf(to, " ={} ", qtype_repr(ty))!;
- },
- void => void,
+ case val: qtypeval =>
+ const ty = val.0, val = val.1;
+ qval_emit(to, val);
+ fmt::fprintf(to, " ={} ", qtype_repr(ty))!;
+ case void => void;
};
// TODO: The langauge should provide a means of converting enums to
// strings without this
fmt::fprint(to, switch (instr) {
- qinstr::ADD => "add",
- qinstr::ALLOC16 => "alloc16",
- qinstr::ALLOC4 => "alloc4",
- qinstr::ALLOC8 => "alloc8",
- qinstr::AND => "and",
- qinstr::CALL => "call",
- qinstr::CAST => "cast",
- qinstr::CEQD => "ceqd",
- qinstr::CEQL => "ceql",
- qinstr::CEQS => "ceqs",
- qinstr::CEQW => "ceqw",
- qinstr::CGED => "cged",
- qinstr::CGES => "cges",
- qinstr::CGTD => "cgtd",
- qinstr::CGTS => "cgts",
- qinstr::CLED => "cled",
- qinstr::CLES => "cles",
- qinstr::CLTD => "cltd",
- qinstr::CLTS => "clts",
- qinstr::CNED => "cned",
- qinstr::CNEL => "cnel",
- qinstr::CNES => "cnes",
- qinstr::CNEW => "cnew",
- qinstr::COD => "cod",
- qinstr::COPY => "copy",
- qinstr::COS => "cos",
- qinstr::CSGEL => "csgel",
- qinstr::CSGEW => "csgew",
- qinstr::CSGTL => "csgtl",
- qinstr::CSGTW => "csgtw",
- qinstr::CSLEL => "cslel",
- qinstr::CSLEW => "cslew",
- qinstr::CSLTL => "csltl",
- qinstr::CSLTW => "csltw",
- qinstr::CUGEL => "cugel",
- qinstr::CUGEW => "cugew",
- qinstr::CUGTL => "cugtl",
- qinstr::CUGTW => "cugtw",
- qinstr::CULEL => "culel",
- qinstr::CULEW => "culew",
- qinstr::CULTL => "cultl",
- qinstr::CULTW => "cultw",
- qinstr::CUOD => "cuod",
- qinstr::CUOS => "cuos",
- qinstr::DIV => "div",
- qinstr::DTOSI => "dtosi",
- qinstr::EXTS => "exts",
- qinstr::EXTSB => "extsb",
- qinstr::EXTSH => "extsh",
- qinstr::EXTSW => "extsw",
- qinstr::EXTUB => "extub",
- qinstr::EXTUH => "extuh",
- qinstr::EXTUW => "extuw",
- qinstr::JMP => "jmp",
- qinstr::JNZ => "jnz",
- qinstr::LOADD => "loadd",
- qinstr::LOADL => "loadl",
- qinstr::LOADS => "loads",
- qinstr::LOADSB => "loadsb",
- qinstr::LOADSH => "loadsh",
- qinstr::LOADSW => "loadsw",
- qinstr::LOADUB => "loadub",
- qinstr::LOADUH => "loaduh",
- qinstr::LOADUW => "loaduw",
- qinstr::MUL => "mul",
- qinstr::OR => "or",
- qinstr::REM => "rem",
- qinstr::RET => "ret",
- qinstr::SAR => "sar",
- qinstr::SHL => "shl",
- qinstr::SHR => "shr",
- qinstr::SLTOF => "sltof",
- qinstr::STOREB => "storeb",
- qinstr::STORED => "stored",
- qinstr::STOREH => "storeh",
- qinstr::STOREL => "storel",
- qinstr::STORES => "stores",
- qinstr::STOREW => "storew",
- qinstr::STOSI => "stosi",
- qinstr::SUB => "sub",
- qinstr::SWTOF => "swtof",
- qinstr::TRUNCD => "truncd",
- qinstr::UDIV => "udiv",
- qinstr::UREM => "urem",
- qinstr::XOR => "xor",
+ case qinstr::ADD =>
+ yield "add";
+ case qinstr::ALLOC16 =>
+ yield "alloc16";
+ case qinstr::ALLOC4 =>
+ yield "alloc4";
+ case qinstr::ALLOC8 =>
+ yield "alloc8";
+ case qinstr::AND =>
+ yield "and";
+ case qinstr::CALL =>
+ yield "call";
+ case qinstr::CAST =>
+ yield "cast";
+ case qinstr::CEQD =>
+ yield "ceqd";
+ case qinstr::CEQL =>
+ yield "ceql";
+ case qinstr::CEQS =>
+ yield "ceqs";
+ case qinstr::CEQW =>
+ yield "ceqw";
+ case qinstr::CGED =>
+ yield "cged";
+ case qinstr::CGES =>
+ yield "cges";
+ case qinstr::CGTD =>
+ yield "cgtd";
+ case qinstr::CGTS =>
+ yield "cgts";
+ case qinstr::CLED =>
+ yield "cled";
+ case qinstr::CLES =>
+ yield "cles";
+ case qinstr::CLTD =>
+ yield "cltd";
+ case qinstr::CLTS =>
+ yield "clts";
+ case qinstr::CNED =>
+ yield "cned";
+ case qinstr::CNEL =>
+ yield "cnel";
+ case qinstr::CNES =>
+ yield "cnes";
+ case qinstr::CNEW =>
+ yield "cnew";
+ case qinstr::COD =>
+ yield "cod";
+ case qinstr::COPY =>
+ yield "copy";
+ case qinstr::COS =>
+ yield "cos";
+ case qinstr::CSGEL =>
+ yield "csgel";
+ case qinstr::CSGEW =>
+ yield "csgew";
+ case qinstr::CSGTL =>
+ yield "csgtl";
+ case qinstr::CSGTW =>
+ yield "csgtw";
+ case qinstr::CSLEL =>
+ yield "cslel";
+ case qinstr::CSLEW =>
+ yield "cslew";
+ case qinstr::CSLTL =>
+ yield "csltl";
+ case qinstr::CSLTW =>
+ yield "csltw";
+ case qinstr::CUGEL =>
+ yield "cugel";
+ case qinstr::CUGEW =>
+ yield "cugew";
+ case qinstr::CUGTL =>
+ yield "cugtl";
+ case qinstr::CUGTW =>
+ yield "cugtw";
+ case qinstr::CULEL =>
+ yield "culel";
+ case qinstr::CULEW =>
+ yield "culew";
+ case qinstr::CULTL =>
+ yield "cultl";
+ case qinstr::CULTW =>
+ yield "cultw";
+ case qinstr::CUOD =>
+ yield "cuod";
+ case qinstr::CUOS =>
+ yield "cuos";
+ case qinstr::DIV =>
+ yield "div";
+ case qinstr::DTOSI =>
+ yield "dtosi";
+ case qinstr::EXTS =>
+ yield "exts";
+ case qinstr::EXTSB =>
+ yield "extsb";
+ case qinstr::EXTSH =>
+ yield "extsh";
+ case qinstr::EXTSW =>
+ yield "extsw";
+ case qinstr::EXTUB =>
+ yield "extub";
+ case qinstr::EXTUH =>
+ yield "extuh";
+ case qinstr::EXTUW =>
+ yield "extuw";
+ case qinstr::JMP =>
+ yield "jmp";
+ case qinstr::JNZ =>
+ yield "jnz";
+ case qinstr::LOADD =>
+ yield "loadd";
+ case qinstr::LOADL =>
+ yield "loadl";
+ case qinstr::LOADS =>
+ yield "loads";
+ case qinstr::LOADSB =>
+ yield "loadsb";
+ case qinstr::LOADSH =>
+ yield "loadsh";
+ case qinstr::LOADSW =>
+ yield "loadsw";
+ case qinstr::LOADUB =>
+ yield "loadub";
+ case qinstr::LOADUH =>
+ yield "loaduh";
+ case qinstr::LOADUW =>
+ yield "loaduw";
+ case qinstr::MUL =>
+ yield "mul";
+ case qinstr::OR =>
+ yield "or";
+ case qinstr::REM =>
+ yield "rem";
+ case qinstr::RET =>
+ yield "ret";
+ case qinstr::SAR =>
+ yield "sar";
+ case qinstr::SHL =>
+ yield "shl";
+ case qinstr::SHR =>
+ yield "shr";
+ case qinstr::SLTOF =>
+ yield "sltof";
+ case qinstr::STOREB =>
+ yield "storeb";
+ case qinstr::STORED =>
+ yield "stored";
+ case qinstr::STOREH =>
+ yield "storeh";
+ case qinstr::STOREL =>
+ yield "storel";
+ case qinstr::STORES =>
+ yield "stores";
+ case qinstr::STOREW =>
+ yield "storew";
+ case qinstr::STOSI =>
+ yield "stosi";
+ case qinstr::SUB =>
+ yield "sub";
+ case qinstr::SWTOF =>
+ yield "swtof";
+ case qinstr::TRUNCD =>
+ yield "truncd";
+ case qinstr::UDIV =>
+ yield "udiv";
+ case qinstr::UREM =>
+ yield "urem";
+ case qinstr::XOR =>
+ yield "xor";
})!;
for (let i = 0z; i < len(args); i += 1) {
const arg = match (args[i]) {
- v: value => v.value,
- * => args[i],
+ case v: value =>
+ yield v.value;
+ case =>
+ yield args[i];
};
match (arg) {
- v: value => abort(), // Invariant
- qv: qval => qval_emit(to, qv),
- qt: qtype => abort(), // TODO
+ case v: value => abort(); // Invariant
+ case qv: qval =>
+ yield qval_emit(to, qv);
+ case qt: qtype =>
+ abort(); // TODO
};
if (i + 1 < len(args)) {
fmt::fprint(to, ",")!;
@@ -142,85 +230,121 @@ fn emit(
fmt::fprintln(to)!;
};
-fn qval_emit(to: *io::stream, qv: qval) void = match (qv) {
- g: global => fmt::fprintf(to, " ${}", g)!,
- t: temporary => fmt::fprintf(to, " %{}", t)!,
- l: label => fmt::fprintf(to, " @{}", l)!,
- c: constant => match (c) {
- qvoid => abort(),
- v: (u32 | u64 | f32 | f64 | str) => fmt::fprintf(to, " {}", v)!,
- },
+fn qval_emit(to: *io::stream, qv: qval) void = {
+ match (qv) {
+ case g: global =>
+ fmt::fprintf(to, " ${}", g)!;
+ case t: temporary =>
+ fmt::fprintf(to, " %{}", t)!;
+ case l: label =>
+ fmt::fprintf(to, " @{}", l)!;
+ case c: constant =>
+ match (c) {
+ case qvoid => abort();
+ case v: (u32 | u64 | f32 | f64 | str) =>
+ fmt::fprintf(to, " {}", v)!;
+ };
+ };
};
-fn qinstr_alloc(ty: *types::_type) qinstr = switch (ty.align) {
- 4 => qinstr::ALLOC4,
- 8 => qinstr::ALLOC8,
- 16 => qinstr::ALLOC16,
- * => abort(),
+fn qinstr_alloc(ty: *types::_type) qinstr = {
+ switch (ty.align) {
+ case 4 =>
+ return qinstr::ALLOC4;
+ case 8 =>
+ return qinstr::ALLOC8;
+ case 16 =>
+ return qinstr::ALLOC16;
+ case => abort();
+ };
};
fn qinstr_store(
ctx: *context,
ty: *types::_type,
-) qinstr = match (ty.repr) {
- al: types::alias => qinstr_store(ctx, al.secondary: *types::_type),
- bi: types::builtin => switch (bi) {
- builtin::STR, builtin::VOID => abort(),
- builtin::F32 => qinstr::STORES,
- builtin::F64 => qinstr::STORED,
- * => switch (ty.sz) {
- 1 => qinstr::STOREB,
- 2 => qinstr::STOREH,
- 4 => qinstr::STOREW,
- 8 => qinstr::STOREL,
- * => abort(),
- },
- },
- types::pointer => if (ctx.arch.ptr == &qlong) {
- yield qinstr::STOREL;
- } else if (ctx.arch.ptr == &qword) {
- yield qinstr::STOREW;
- } else abort(),
- en: types::_enum => abort(), // TODO
- * => abort(),
+) qinstr = {
+ match (ty.repr) {
+ case al: types::alias =>
+ return qinstr_store(ctx, al.secondary: *types::_type);
+ case bi: types::builtin =>
+ switch (bi) {
+ case builtin::STR, builtin::VOID => abort();
+ case builtin::F32 =>
+ return qinstr::STORES;
+ case builtin::F64 =>
+ return qinstr::STORED;
+ case =>
+ switch (ty.sz) {
+ case 1 =>
+ return qinstr::STOREB;
+ case 2 =>
+ return qinstr::STOREH;
+ case 4 =>
+ return qinstr::STOREW;
+ case 8 =>
+ return qinstr::STOREL;
+ case => abort();
+ };
+ };
+ case types::pointer =>
+ if (ctx.arch.ptr == &qlong) {
+ return qinstr::STOREL;
+ } else if (ctx.arch.ptr == &qword) {
+ return qinstr::STOREW;
+ } else abort();
+ case en: types::_enum => abort(); // TODO
+ case => abort();
+ };
};
fn qinstr_load(
ctx: *context,
ty: *types::_type,
-) qinstr = match (ty.repr) {
- al: types::alias => qinstr_load(ctx, al.secondary: *types::_type),
- bi: types::builtin => switch (bi) {
- builtin::STR, builtin::VOID => abort(),
- builtin::F32 => qinstr::LOADS,
- builtin::F64 => qinstr::LOADD,
- * => switch (ty.sz) {
- 1 => if (types::is_signed(ty)) {
- yield qinstr::LOADSB;
- } else {
- yield qinstr::LOADUB;
- },
- 2 => if (types::is_signed(ty)) {
- yield qinstr::LOADSH;
- } else {
- yield qinstr::LOADUH;
- },
- 4 => if (types::is_signed(ty)) {
- yield qinstr::LOADSW;
- } else {
- yield qinstr::LOADUW;
- },
- 8 => qinstr::LOADL,
- * => abort(),
- },
- },
- types::pointer => if (ctx.arch.ptr == &qlong) {
- yield qinstr::LOADL;
- } else if (ctx.arch.ptr == &qword) {
- yield qinstr::LOADUW;
- } else abort(),
- en: types::_enum => abort(), // TODO
- * => abort(),
+) qinstr = {
+ match (ty.repr) {
+ case al: types::alias =>
+ return qinstr_load(ctx, al.secondary: *types::_type);
+ case bi: types::builtin =>
+ switch (bi) {
+ case builtin::STR, builtin::VOID => abort();
+ case builtin::F32 =>
+ return qinstr::LOADS;
+ case builtin::F64 =>
+ return qinstr::LOADD;
+ case =>
+ switch (ty.sz) {
+ case 1 =>
+ if (types::is_signed(ty)) {
+ return qinstr::LOADSB;
+ } else {
+ return qinstr::LOADUB;
+ };
+ case 2 =>
+ if (types::is_signed(ty)) {
+ return qinstr::LOADSH;
+ } else {
+ return qinstr::LOADUH;
+ };
+ case 4 =>
+ if (types::is_signed(ty)) {
+ return qinstr::LOADSW;
+ } else {
+ return qinstr::LOADUW;
+ };
+ case 8 =>
+ return qinstr::LOADL;
+ case => abort();
+ };
+ };
+ case types::pointer =>
+ if (ctx.arch.ptr == &qlong) {
+ return qinstr::LOADL;
+ } else if (ctx.arch.ptr == &qword) {
+ return qinstr::LOADUW;
+ } else abort();
+ case en: types::_enum => abort(); // TODO
+ case => abort();
+ };
};
type qinstr = enum {
diff --git a/cmd/harec/qtype.ha b/cmd/harec/qtype.ha
@@ -36,43 +36,56 @@ fn qtype_lookup(
ctx: *context,
_type: const *types::_type,
extype: bool,
-) const *qtype = match (_type.repr) {
- bi: builtin => switch (bi) {
- builtin::CHAR =>
- if (extype) &qbyte else &qword,
- builtin::I8, builtin::U8 =>
- if (extype) &qbyte else &qword,
- builtin::I16, builtin::U16 =>
- if (extype) &qhalf else &qword,
- builtin::BOOL => &qword,
- builtin::F32 => &qsingle,
- builtin::F64 => &qdouble,
- builtin::I32, builtin::U32, builtin::RUNE => &qword,
- builtin::I64, builtin::U64 => &qlong,
- builtin::INT, builtin::UINT,
- builtin::NULL, builtin::UINTPTR,
- builtin::SIZE => switch (_type.sz) {
- 4 => &qword,
- 8 => &qlong,
- * => abort(),
- },
- builtin::STR => qtype_aggregate(ctx, _type),
- builtin::VOID => abort(),
- },
- * => abort(),
+) const *qtype = {
+ match (_type.repr) {
+ case bi: builtin =>
+ switch (bi) {
+ case builtin::CHAR =>
+ return if (extype) &qbyte else &qword;
+ case builtin::I8, builtin::U8 =>
+ return if (extype) &qbyte else &qword;
+ case builtin::I16, builtin::U16 =>
+ return if (extype) &qhalf else &qword;
+ case builtin::BOOL =>
+ return &qword;
+ case builtin::F32 =>
+ return &qsingle;
+ case builtin::F64 =>
+ return &qdouble;
+ case builtin::I32, builtin::U32, builtin::RUNE =>
+ return &qword;
+ case builtin::I64, builtin::U64 =>
+ return &qlong;
+ case builtin::INT, builtin::UINT, builtin::NULL,
+ builtin::UINTPTR, builtin::SIZE =>
+ switch (_type.sz) {
+ case 4 =>
+ return &qword;
+ case 8 =>
+ return &qlong;
+ case => abort();
+ };
+ case builtin::STR =>
+ return qtype_aggregate(ctx, _type);
+ case builtin::VOID => abort();
+ };
+ case => abort();
+ };
};
fn qtype_aggregate(ctx: *context, _type: const *types::_type) const *qtype = {
abort(); // TODO
};
-// XXX: This dereference should not be necessary after the match
-// overhaul
-fn qtype_repr(qtype: const *qtype) const str = match (*qtype) {
- st: stype => {
+fn qtype_repr(qtype: const *qtype) const str = {
+ // XXX: This dereference should not be necessary after the match
+ // overhaul
+ match (*qtype) {
+ case st: stype =>
static let buf: [1]u8 = [0...];
- yield fmt::bsprintf(buf, "{}", st: rune);
- },
- qc: qcompound => abort(), // TODO
- void => "",
+ return fmt::bsprintf(buf, "{}", st: rune);
+ case qc: qcompound => abort(); // TODO
+ case void =>
+ return "";
+ };
};
diff --git a/cmd/haredoc/docstr.ha b/cmd/haredoc/docstr.ha
@@ -34,24 +34,33 @@ fn parsedoc(in: *io::stream) parser = {
};
fn scandoc(par: *parser) (token | void) = {
- const rn = match (bufio::scanrune(par.src)) {
- io::EOF => return,
- rn: rune => rn,
- * => abort(),
+ const rn = match (bufio::scanrune(par.src)!) {
+ case rn: rune =>
+ yield rn;
+ case io::EOF =>
+ return;
};
bufio::unreadrune(par.src, rn);
- return switch (par.state) {
- docstate::TEXT => switch (rn) {
- '[' => scanref(par),
- * => scantext(par),
- },
- docstate::PARAGRAPH => switch (rn) {
- ' ', '\t' => scansample(par),
- '[' => scanref(par),
- '-' => scanlist(par),
- * => scantext(par),
- },
+ switch (par.state) {
+ case docstate::TEXT =>
+ switch (rn) {
+ case '[' =>
+ return scanref(par);
+ case =>
+ return scantext(par);
+ };
+ case docstate::PARAGRAPH =>
+ switch (rn) {
+ case ' ', '\t' =>
+ return scansample(par);
+ case '[' =>
+ return scanref(par);
+ case '-' =>
+ return scanlist(par);
+ case =>
+ return scantext(par);
+ };
};
};
@@ -63,31 +72,29 @@ fn scantext(par: *parser) (token | void) = {
// TODO: Collapse whitespace
const buf = strio::dynamic();
for (true) {
- const rn = match (bufio::scanrune(par.src)) {
- io::EOF => break,
- utf8::invalid => abort("Invalid UTF-8"),
- err: io::error => fmt::fatal(io::strerror(err)),
- rn: rune => rn,
+ const rn = match (bufio::scanrune(par.src)!) {
+ case io::EOF => break;
+ case rn: rune =>
+ yield rn;
};
switch (rn) {
- '[' => {
- bufio::unreadrune(par.src, rn);
+ case '[' =>
+ bufio::unreadrune(par.src, rn);
+ break;
+ case '\n' =>
+ strio::appendrune(buf, rn)!;
+ const rn = match (bufio::scanrune(par.src)!) {
+ case io::EOF => break;
+ case rn: rune =>
+ yield rn;
+ };
+ if (rn == '\n') {
+ par.state = docstate::PARAGRAPH;
break;
- },
- '\n' => {
- strio::appendrune(buf, rn)!;
- const rn = match (bufio::scanrune(par.src)) {
- io::EOF => break,
- * => abort(),
- rn: rune => rn,
- };
- if (rn == '\n') {
- par.state = docstate::PARAGRAPH;
- break;
- };
- bufio::unreadrune(par.src, rn);
- },
- * => strio::appendrune(buf, rn)!,
+ };
+ bufio::unreadrune(par.src, rn);
+ case =>
+ strio::appendrune(buf, rn)!;
};
};
let result = strio::finish(buf);
@@ -98,33 +105,39 @@ fn scantext(par: *parser) (token | void) = {
};
fn scanref(par: *parser) (token | void) = {
- match (bufio::scanrune(par.src)) {
- io::EOF => return,
- rn: rune => if (rn != '[') abort(),
- * => abort(),
+ match (bufio::scanrune(par.src)!) {
+ case io::EOF =>
+ return;
+ case rn: rune =>
+ if (rn != '[') {
+ abort();
+ };
};
- match (bufio::scanrune(par.src)) {
- io::EOF => return,
- rn: rune => if (rn != '[') {
+ match (bufio::scanrune(par.src)!) {
+ case io::EOF =>
+ return;
+ case rn: rune =>
+ if (rn != '[') {
bufio::unreadrune(par.src, rn);
return strings::dup("["): text;
- },
- * => abort(),
+ };
};
const buf = strio::dynamic();
defer io::close(buf);
// TODO: Handle invalid syntax here
- for (true) match (bufio::scanrune(par.src)) {
- io::EOF => break,
- rn: rune => switch (rn) {
- ']' => {
+ for (true) {
+ match (bufio::scanrune(par.src)!) {
+ case rn: rune =>
+ switch (rn) {
+ case ']' =>
bufio::scanrune(par.src) as rune; // ]
break;
- },
- * => strio::appendrune(buf, rn)!,
- },
- * => abort(),
+ case =>
+ strio::appendrune(buf, rn)!;
+ };
+ case io::EOF => break;
+ };
};
let id = parse::identstr(strio::string(buf)) as ast::ident;
return id: reference;
@@ -132,17 +145,21 @@ fn scanref(par: *parser) (token | void) = {
fn scansample(par: *parser) (token | void) = {
let nws = 0z;
- for (true) match (bufio::scanrune(par.src)) {
- io::EOF => return,
- rn: rune => switch (rn) {
- ' ' => nws += 1,
- '\t' => nws += 8,
- * => {
+ for (true) {
+ match (bufio::scanrune(par.src)!) {
+ case io::EOF =>
+ return;
+ case rn: rune =>
+ switch (rn) {
+ case ' ' =>
+ nws += 1;
+ case '\t' =>
+ nws += 8;
+ case =>
bufio::unreadrune(par.src, rn);
break;
- },
- },
- * => abort(),
+ };
+ };
};
if (nws <= 1) {
return scantext(par);
@@ -151,37 +168,37 @@ fn scansample(par: *parser) (token | void) = {
let cont = true;
let buf = strio::dynamic();
for (cont) {
- const rn = match (bufio::scanrune(par.src)) {
- io::EOF => break,
- rn: rune => rn,
- * => abort(),
+ const rn = match (bufio::scanrune(par.src)!) {
+ case io::EOF => break;
+ case rn: rune =>
+ yield rn;
};
switch (rn) {
- * => {
- strio::appendrune(buf, rn)!;
- continue;
- },
- '\n' => strio::appendrune(buf, rn)!,
+ case '\n' =>
+ strio::appendrune(buf, rn)!;
+ case =>
+ strio::appendrune(buf, rn)!;
+ continue;
};
// Consume whitespace
for (let i = 0z; i < nws) {
- match (bufio::scanrune(par.src)) {
- io::EOF => break,
- * => abort(),
- rn: rune => switch (rn) {
- ' ' => i += 1,
- '\t' => i += 8,
- '\n' => {
- strio::appendrune(buf, rn)!;
- i = 0;
- },
- * => {
- bufio::unreadrune(par.src, rn);
- cont = false;
- break;
- },
- },
+ match (bufio::scanrune(par.src)!) {
+ case io::EOF => break;
+ case rn: rune =>
+ switch (rn) {
+ case ' ' =>
+ i += 1;
+ case '\t' =>
+ i += 8;
+ case '\n' =>
+ strio::appendrune(buf, rn)!;
+ i = 0;
+ case =>
+ bufio::unreadrune(par.src, rn);
+ cont = false;
+ break;
+ };
};
};
};
@@ -199,16 +216,18 @@ fn scansample(par: *parser) (token | void) = {
fn scanlist(par: *parser) (token | void) = {
let items: list = [];
for (true) {
- match (bufio::scanrune(par.src)) {
- io::EOF => break,
- * => abort(),
- rn: rune => if (rn != '-') break,
+ match (bufio::scanrune(par.src)!) {
+ case io::EOF => break;
+ case rn: rune =>
+ if (rn != '-') {
+ break;
+ };
};
// XXX: multi-line list items
- append(items, match (bufio::scanline(par.src)) {
- io::EOF => break,
- io::error => abort(),
- u: []u8 => strings::fromutf8(u),
+ append(items, match (bufio::scanline(par.src)!) {
+ case io::EOF => break;
+ case u: []u8 =>
+ yield strings::fromutf8(u);
});
};
return items;
diff --git a/cmd/haredoc/errors.ha b/cmd/haredoc/errors.ha
@@ -6,10 +6,17 @@ type eof = void;
type syntaxerr = void;
type error = !(lex::error | parse::error | io::error | syntaxerr | eof);
-fn strerror(err: error) str = match (err) {
- err: lex::error => lex::strerror(err),
- err: parse::error => parse::strerror(err),
- err: io::error => io::strerror(err),
- eof => "Unexpected EOF",
- syntaxerr => "Syntax error",
+fn strerror(err: error) str = {
+ match (err) {
+ case err: lex::error =>
+ return lex::strerror(err);
+ case err: parse::error =>
+ return parse::strerror(err);
+ case err: io::error =>
+ return io::strerror(err);
+ case eof =>
+ return "Unexpected EOF";
+ case syntaxerr =>
+ return "Syntax error";
+ };
};
diff --git a/cmd/haredoc/hare.ha b/cmd/haredoc/hare.ha
@@ -14,17 +14,17 @@ fn emit_hare(ctx: *context) (void | error) = {
let first = true;
match (ctx.readme) {
- readme: io::file => {
- first = false;
- for (true) match (bufio::scanline(&readme)?) {
- b: []u8 => {
- fmt::printfln("// {}", strings::fromutf8(b))?;
- free(b);
- },
- io::EOF => break,
+ case readme: io::file =>
+ first = false;
+ for (true) {
+ match (bufio::scanline(&readme)?) {
+ case io::EOF => break;
+ case b: []u8 =>
+ fmt::printfln("// {}", strings::fromutf8(b))?;
+ free(b);
};
- },
- void => void,
+ };
+ case void => void;
};
// XXX: Should we emit the dependencies, too?
@@ -64,11 +64,14 @@ fn details_hare(ctx: *context, decl: ast::decl) (void | error) = {
};
const iter = strings::tokenize(decl.docs, "\n");
- for (true) match (strings::next_token(&iter)) {
- s: str => if (len(s) != 0) {
- fmt::printfln("//{}", s)?;
- },
- void => break,
+ for (true) {
+ match (strings::next_token(&iter)) {
+ case void => break;
+ case s: str =>
+ if (len(s) != 0) {
+ fmt::printfln("//{}", s)?;
+ };
+ };
};
unparse_hare(os::stdout, decl)?;
@@ -80,53 +83,54 @@ fn details_hare(ctx: *context, decl: ast::decl) (void | error) = {
fn unparse_hare(out: *io::stream, d: ast::decl) (size | io::error) = {
let n = 0z;
match (d.decl) {
- g: []ast::decl_global => {
- n += fmt::fprint(out,
- if (g[0].is_const) "def " else "let ")?;
- for (let i = 0z; i < len(g); i += 1) {
- if (len(g[i].symbol) != 0) {
- n += fmt::fprintf(out,
- "@symbol(\"{}\") ", g[i].symbol)?;
- };
- n += unparse::ident(out, g[i].ident)?;
- n += fmt::fprint(out, ": ")?;
- n += unparse::_type(out, 0, g[i]._type)?;
- if (i + 1 < len(g)) {
- n += fmt::fprint(out, ", ")?;
- };
- };
- },
- t: []ast::decl_type => {
- n += fmt::fprint(out, "type ")?;
- for (let i = 0z; i < len(t); i += 1) {
- n += unparse::ident(out, t[i].ident)?;
- n += fmt::fprint(out, " = ")?;
- n += unparse::_type(out, 0, t[i]._type)?;
- if (i + 1 < len(t)) {
- n += fmt::fprint(out, ", ")?;
- };
+ case g: []ast::decl_global =>
+ n += fmt::fprint(out,
+ if (g[0].is_const) "def " else "let ")?;
+ for (let i = 0z; i < len(g); i += 1) {
+ if (len(g[i].symbol) != 0) {
+ n += fmt::fprintf(out,
+ "@symbol(\"{}\") ", g[i].symbol)?;
};
- },
- f: ast::decl_func => {
- n += fmt::fprint(out, switch (f.attrs) {
- ast::fndecl_attrs::NONE => "",
- ast::fndecl_attrs::FINI => "@fini ",
- ast::fndecl_attrs::INIT => "@init ",
- ast::fndecl_attrs::TEST => "@test ",
- })?;
- let p = f.prototype.repr as ast::func_type;
- if (p.attrs & ast::func_attrs::NORETURN != 0) {
- n += fmt::fprint(out, "@noreturn ")?;
+ n += unparse::ident(out, g[i].ident)?;
+ n += fmt::fprint(out, ": ")?;
+ n += unparse::_type(out, 0, g[i]._type)?;
+ if (i + 1 < len(g)) {
+ n += fmt::fprint(out, ", ")?;
};
- if (len(f.symbol) != 0) {
- n += fmt::fprintf(out, "@symbol(\"{}\") ",
- f.symbol)?;
+ };
+ case t: []ast::decl_type =>
+ n += fmt::fprint(out, "type ")?;
+ for (let i = 0z; i < len(t); i += 1) {
+ n += unparse::ident(out, t[i].ident)?;
+ n += fmt::fprint(out, " = ")?;
+ n += unparse::_type(out, 0, t[i]._type)?;
+ if (i + 1 < len(t)) {
+ n += fmt::fprint(out, ", ")?;
};
- n += fmt::fprint(out, "fn ")?;
- n += unparse::ident(out, f.ident)?;
- n += prototype_hare(out, 0,
- f.prototype.repr as ast::func_type)?;
- },
+ };
+ case f: ast::decl_func =>
+ n += fmt::fprint(out, switch (f.attrs) {
+ case ast::fndecl_attrs::NONE =>
+ yield "";
+ case ast::fndecl_attrs::FINI =>
+ yield "@fini ";
+ case ast::fndecl_attrs::INIT =>
+ yield "@init ";
+ case ast::fndecl_attrs::TEST =>
+ yield "@test ";
+ })?;
+ let p = f.prototype.repr as ast::func_type;
+ if (p.attrs & ast::func_attrs::NORETURN != 0) {
+ n += fmt::fprint(out, "@noreturn ")?;
+ };
+ if (len(f.symbol) != 0) {
+ n += fmt::fprintf(out, "@symbol(\"{}\") ",
+ f.symbol)?;
+ };
+ n += fmt::fprint(out, "fn ")?;
+ n += unparse::ident(out, f.ident)?;
+ n += prototype_hare(out, 0,
+ f.prototype.repr as ast::func_type)?;
};
n += fmt::fprint(out, ";")?;
return n;
diff --git a/cmd/haredoc/html.ha b/cmd/haredoc/html.ha
@@ -17,16 +17,25 @@ use strio;
fn html_escape(out: *io::stream, in: str) (size | io::error) = {
let z = 0z;
let iter = strings::iter(in);
- for (true) match (strings::next(&iter)) {
- void => break,
- rn: rune => z += io::write(out, switch (rn) {
- '&' => strings::toutf8("&"),
- '<' => strings::toutf8("<"),
- '>' => strings::toutf8(">"),
- '"' => strings::toutf8("""),
- '\'' => strings::toutf8("'"),
- * => utf8::encoderune(rn),
- })?,
+ for (true) {
+ match (strings::next(&iter)) {
+ case void => break;
+ case rn: rune =>
+ z += io::write(out, switch (rn) {
+ case '&' =>
+ yield strings::toutf8("&");
+ case '<' =>
+ yield strings::toutf8("<");
+ case '>' =>
+ yield strings::toutf8(">");
+ case '"' =>
+ yield strings::toutf8(""");
+ case '\'' =>
+ yield strings::toutf8("'");
+ case =>
+ yield utf8::encoderune(rn);
+ })?;
+ };
};
return z;
};
@@ -63,20 +72,21 @@ fn emit_html(ctx: *context) (void | error) = {
};
for (let i = 0z; i < len(ctx.tags); i += 1) {
const mode = switch (ctx.tags[i].mode) {
- module::tag_mode::INCLUSIVE => '+',
- module::tag_mode::EXCLUSIVE => '-',
+ case module::tag_mode::INCLUSIVE =>
+ yield '+';
+ case module::tag_mode::EXCLUSIVE =>
+ yield '-';
};
fmt::printf("{}{} ", mode, ctx.tags[i].name)?;
};
fmt::println("</span></h2>")?;
match (ctx.readme) {
- void => void,
- f: io::file => {
- fmt::println("<div class='readme'>")?;
- markup_html(ctx, &f)?;
- fmt::println("</div>")?;
- },
+ case void => void;
+ case f: io::file =>
+ fmt::println("<div class='readme'>")?;
+ markup_html(ctx, &f)?;
+ fmt::println("</div>")?;
};
if (len(ctx.version.subdirs) != 0) {
@@ -182,10 +192,14 @@ fn tocentries(decls: []ast::decl, name: str, lname: str) (void | error) = {
fn tocentry(decl: ast::decl) (void | error) = {
fmt::printf("{} ",
match (decl.decl) {
- ast::decl_func => "fn",
- []ast::decl_type => "type",
- []ast::decl_const => "const",
- []ast::decl_global => "let",
+ case ast::decl_func =>
+ yield "fn";
+ case []ast::decl_type =>
+ yield "type";
+ case []ast::decl_const =>
+ yield "const";
+ case []ast::decl_global =>
+ yield "let";
})?;
fmt::printf("<a href='#")?;
unparse::ident(os::stdout, decl_ident(decl))?;
@@ -194,20 +208,19 @@ fn tocentry(decl: ast::decl) (void | error) = {
fmt::print("</a>")?;
match (decl.decl) {
- g: []ast::decl_global => {
- let g = g[0];
- fmt::print(": ")?;
- type_html(os::stdout, 0, g._type, true)?;
- },
- c: []ast::decl_const => {
- let c = c[0];
- fmt::print(": ")?;
- type_html(os::stdout, 0, c._type, true)?;
- },
- t: []ast::decl_type => void,
- f: ast::decl_func => prototype_html(os::stdout, 0,
+ case t: []ast::decl_type => void;
+ case g: []ast::decl_global =>
+ let g = g[0];
+ fmt::print(": ")?;
+ type_html(os::stdout, 0, g._type, true)?;
+ case c: []ast::decl_const =>
+ let c = c[0];
+ fmt::print(": ")?;
+ type_html(os::stdout, 0, c._type, true)?;
+ case f: ast::decl_func =>
+ prototype_html(os::stdout, 0,
f.prototype.repr as ast::func_type,
- true)?,
+ true)?;
};
fmt::println(";")?;
return;
@@ -218,17 +231,19 @@ fn details(ctx: *context, decl: ast::decl) (void | error) = {
fmt::print("<h4 id='")?;
unparse::ident(os::stdout, decl_ident(decl))?;
fmt::print("'>")?;
- fmt::printf("{} ",
- match (decl.decl) {
- ast::decl_func => "fn",
- []ast::decl_type => "type",
- []ast::decl_const => "def",
- []ast::decl_global => "let",
+ fmt::printf("{} ", match (decl.decl) {
+ case ast::decl_func =>
+ yield "fn";
+ case []ast::decl_type =>
+ yield "type";
+ case []ast::decl_const =>
+ yield "def";
+ case []ast::decl_global =>
+ yield "let";
})?;
unparse::ident(os::stdout, decl_ident(decl))?;
// TODO: Add source URL
- fmt::print("<span class='heading-extra'>
- <a href='#")?;
+ fmt::print("<span class='heading-extra'><a href='#")?;
unparse::ident(os::stdout, decl_ident(decl))?;
fmt::print("'>[link]</a>
</span>")?;
@@ -255,8 +270,11 @@ fn details(ctx: *context, decl: ast::decl) (void | error) = {
};
fn htmlref(ctx: *context, ref: ast::ident) (void | io::error) = {
- const ik = match (resolve(ctx, ref)) {
- void => {
+ const ik =
+ match (resolve(ctx, ref)) {
+ case ik: (ast::ident, symkind) =>
+ yield ik;
+ case void =>
const ident = unparse::identstr(ref);
fmt::errorfln("Warning: Unresolved reference: {}", ident)?;
fmt::printf("<a href='#' "
@@ -265,28 +283,24 @@ fn htmlref(ctx: *context, ref: ast::ident) (void | io::error) = {
ident)?;
free(ident);
return;
- },
- ik: (ast::ident, symkind) => ik,
- };
+ };
// TODO: The reference is not necessarily in the stdlib
const kind = ik.1, id = ik.0;
const ident = unparse::identstr(id);
switch (kind) {
- symkind::LOCAL =>
- fmt::printf("<a href='#{0}' class='ref'>{0}</a>", ident)?,
- symkind::MODULE => {
- let ipath = module::identpath(id);
- defer free(ipath);
- fmt::printf("<a href='/{}' class='ref'>{}</a>",
- ipath, ident)?;
- },
- symkind::SYMBOL => {
- let ipath = module::identpath(id[..len(id) - 1]);
- defer free(ipath);
- fmt::printf("<a href='/{}#{}' class='ref'>{}</a>",
- ipath, id[len(id) - 1], ident)?;
- },
+ case symkind::LOCAL =>
+ fmt::printf("<a href='#{0}' class='ref'>{0}</a>", ident)?;
+ case symkind::MODULE =>
+ let ipath = module::identpath(id);
+ defer free(ipath);
+ fmt::printf("<a href='/{}' class='ref'>{}</a>",
+ ipath, ident)?;
+ case symkind::SYMBOL =>
+ let ipath = module::identpath(id[..len(id) - 1]);
+ defer free(ipath);
+ fmt::printf("<a href='/{}#{}' class='ref'>{}</a>",
+ ipath, id[len(id) - 1], ident)?;
};
free(ident);
};
@@ -295,15 +309,16 @@ fn markup_html(ctx: *context, in: *io::stream) (void | io::error) = {
let parser = parsedoc(in);
for (true) {
const tok = match (scandoc(&parser)) {
- void => break,
- tok: token => tok,
- };
+ case void => break;
+ case tok: token =>
+ yield tok;
+ };
match (tok) {
- paragraph => {
- fmt::println()?;
- fmt::print("<p>")?;
- },
- tx: text => if (strings::has_prefix(tx, "https://")) {
+ case paragraph =>
+ fmt::println()?;
+ fmt::print("<p>")?;
+ case tx: text =>
+ if (strings::has_prefix(tx, "https://")) {
// Temporary hack
fmt::print("<a rel='nofollow noopener' href='")?;
html_escape(os::stdout, tx)?;
@@ -314,23 +329,22 @@ fn markup_html(ctx: *context, in: *io::stream) (void | io::error) = {
} else {
html_escape(os::stdout, tx)?;
free(tx);
- },
- re: reference => htmlref(ctx, re)?,
- sa: sample => {
- fmt::print("<pre class='sample'>")?;
- html_escape(os::stdout, sa)?;
- fmt::print("</pre>")?;
- free(sa);
- },
- li: list => {
- fmt::println("<ul>")?;
- for (let i = 0z; i < len(li); i += 1) {
- fmt::println("<li>")?;
- html_escape(os::stdout, li[i])?;
- fmt::println("</li>")?;
- };
- fmt::println("</ul>")?;
- },
+ };
+ case re: reference =>
+ htmlref(ctx, re)?;
+ case sa: sample =>
+ fmt::print("<pre class='sample'>")?;
+ html_escape(os::stdout, sa)?;
+ fmt::print("</pre>")?;
+ free(sa);
+ case li: list =>
+ fmt::println("<ul>")?;
+ for (let i = 0z; i < len(li); i += 1) {
+ fmt::println("<li>")?;
+ html_escape(os::stdout, li[i])?;
+ fmt::println("</li>")?;
+ };
+ fmt::println("</ul>")?;
};
};
fmt::println()?;
@@ -341,86 +355,108 @@ fn markup_html(ctx: *context, in: *io::stream) (void | io::error) = {
fn unparse_html(out: *io::stream, d: ast::decl) (size | io::error) = {
let n = 0z;
match (d.decl) {
- c: []ast::decl_const => {
- n += fmt::fprintf(out, "<span class='keyword'>def</span> ")?;
- for (let i = 0z; i < len(c); i += 1) {
- n += unparse::ident(out, c[i].ident)?;
- n += fmt::fprint(out, ": ")?;
- n += type_html(out, 0, c[i]._type, false)?;
- if (i + 1 < len(c)) {
- n += fmt::fprint(out, ", ")?;
- };
- };
- },
- g: []ast::decl_global => {
- n += fmt::fprintf(out, "<span class='keyword'>{}</span>",
- if (g[0].is_const) "const " else "let ")?;
- for (let i = 0z; i < len(g); i += 1) {
- n += unparse::ident(out, g[i].ident)?;
- n += fmt::fprint(out, ": ")?;
- n += type_html(out, 0, g[i]._type, false)?;
- if (i + 1 < len(g)) {
- n += fmt::fprint(out, ", ")?;
- };
+ case c: []ast::decl_const =>
+ n += fmt::fprintf(out, "<span class='keyword'>def</span> ")?;
+ for (let i = 0z; i < len(c); i += 1) {
+ n += unparse::ident(out, c[i].ident)?;
+ n += fmt::fprint(out, ": ")?;
+ n += type_html(out, 0, c[i]._type, false)?;
+ if (i + 1 < len(c)) {
+ n += fmt::fprint(out, ", ")?;
};
- },
- t: []ast::decl_type => {
- n += fmt::fprint(out, "<span class='keyword'>type</span> ")?;
- for (let i = 0z; i < len(t); i += 1) {
- n += unparse::ident(out, t[i].ident)?;
- n += fmt::fprint(out, " = ")?;
- n += type_html(out, 0, t[i]._type, false)?;
- if (i + 1 < len(t)) {
- n += fmt::fprint(out, ", ")?;
- };
+ };
+ case g: []ast::decl_global =>
+ n += fmt::fprintf(out, "<span class='keyword'>{}</span>",
+ if (g[0].is_const) "const " else "let ")?;
+ for (let i = 0z; i < len(g); i += 1) {
+ n += unparse::ident(out, g[i].ident)?;
+ n += fmt::fprint(out, ": ")?;
+ n += type_html(out, 0, g[i]._type, false)?;
+ if (i + 1 < len(g)) {
+ n += fmt::fprint(out, ", ")?;
};
- },
- f: ast::decl_func => {
- n += fmt::fprint(out, switch (f.attrs) {
- ast::fndecl_attrs::NONE => "",
- ast::fndecl_attrs::FINI => "@fini ",
- ast::fndecl_attrs::INIT => "@init ",
- ast::fndecl_attrs::TEST => "@test ",
- })?;
- let p = f.prototype.repr as ast::func_type;
- if (p.attrs & ast::func_attrs::NORETURN != 0) {
- n += fmt::fprint(out, "@noreturn ")?;
+ };
+ case t: []ast::decl_type =>
+ n += fmt::fprint(out, "<span class='keyword'>type</span> ")?;
+ for (let i = 0z; i < len(t); i += 1) {
+ n += unparse::ident(out, t[i].ident)?;
+ n += fmt::fprint(out, " = ")?;
+ n += type_html(out, 0, t[i]._type, false)?;
+ if (i + 1 < len(t)) {
+ n += fmt::fprint(out, ", ")?;
};
- n += fmt::fprint(out, "<span class='keyword'>fn</span> ")?;
- n += unparse::ident(out, f.ident)?;
- n += prototype_html(out, 0,
- f.prototype.repr as ast::func_type,
- false)?;
- },
+ };
+ case f: ast::decl_func =>
+ n += fmt::fprint(out, switch (f.attrs) {
+ case ast::fndecl_attrs::NONE =>
+ yield "";
+ case ast::fndecl_attrs::FINI =>
+ yield "@fini ";
+ case ast::fndecl_attrs::INIT =>
+ yield "@init ";
+ case ast::fndecl_attrs::TEST =>
+ yield "@test ";
+ })?;
+ let p = f.prototype.repr as ast::func_type;
+ if (p.attrs & ast::func_attrs::NORETURN != 0) {
+ n += fmt::fprint(out, "@noreturn ")?;
+ };
+ n += fmt::fprint(out, "<span class='keyword'>fn</span> ")?;
+ n += unparse::ident(out, f.ident)?;
+ n += prototype_html(out, 0,
+ f.prototype.repr as ast::func_type,
+ false)?;
};
n += fmt::fprint(out, ";")?;
return n;
};
// Forked from [[hare::unparse]].
-fn builtin_type(b: ast::builtin_type) str = switch (b) {
- ast::builtin_type::BOOL => "bool",
- ast::builtin_type::CHAR => "char",
- ast::builtin_type::F32 => "f32",
- ast::builtin_type::F64 => "f64",
- ast::builtin_type::FCONST => abort("FCONST has no lexical representation"),
- ast::builtin_type::I16 => "i16",
- ast::builtin_type::I32 => "i32",
- ast::builtin_type::I64 => "i64",
- ast::builtin_type::I8 => "i8",
- ast::builtin_type::ICONST => abort("ICONST has no lexical representation"),
- ast::builtin_type::INT => "int",
- ast::builtin_type::NULL => "null",
- ast::builtin_type::RUNE => "rune",
- ast::builtin_type::SIZE => "size",
- ast::builtin_type::STR => "str",
- ast::builtin_type::U16 => "u16",
- ast::builtin_type::U32 => "u32",
- ast::builtin_type::U64 => "u64",
- ast::builtin_type::U8 => "u8",
- ast::builtin_type::UINT => "uint",
- ast::builtin_type::UINTPTR => "uintptr",
- ast::builtin_type::VOID => "void",
+fn builtin_type(b: ast::builtin_type) str = {
+ switch (b) {
+ case ast::builtin_type::FCONST, ast::builtin_type::ICONST =>
+ abort("ICONST and FCONST have no lexical representation");
+ case ast::builtin_type::BOOL =>
+ return "bool";
+ case ast::builtin_type::CHAR =>
+ return "char";
+ case ast::builtin_type::F32 =>
+ return "f32";
+ case ast::builtin_type::F64 =>
+ return "f64";
+ case ast::builtin_type::I16 =>
+ return "i16";
+ case ast::builtin_type::I32 =>
+ return "i32";
+ case ast::builtin_type::I64 =>
+ return "i64";
+ case ast::builtin_type::I8 =>
+ return "i8";
+ case ast::builtin_type::INT =>
+ return "int";
+ case ast::builtin_type::NULL =>
+ return "null";
+ case ast::builtin_type::RUNE =>
+ return "rune";
+ case ast::builtin_type::SIZE =>
+ return "size";
+ case ast::builtin_type::STR =>
+ return "str";
+ case ast::builtin_type::U16 =>
+ return "u16";
+ case ast::builtin_type::U32 =>
+ return "u32";
+ case ast::builtin_type::U64 =>
+ return "u64";
+ case ast::builtin_type::U8 =>
+ return "u8";
+ case ast::builtin_type::UINT =>
+ return "uint";
+ case ast::builtin_type::UINTPTR =>
+ return "uintptr";
+ case ast::builtin_type::VOID =>
+ return "void";
+ };
};
// Forked from [[hare::unparse]].
@@ -453,18 +489,16 @@ fn enum_html(
z += fmt::fprint(out, val.name)?;
match (val.value) {
- null => void,
- expr: *ast::expr => {
- z += fmt::fprint(out, " = ")?;
- z += unparse::expr(out, indent, *expr)?;
- },
+ case null => void;
+ case expr: *ast::expr =>
+ z += fmt::fprint(out, " = ")?;
+ z += unparse::expr(out, indent, *expr)?;
};
z += fmt::fprint(out, ",")?;
};
z += newline(out, indent)?;
z += fmt::fprint(out, "}")?;
-
return z;
};
@@ -476,14 +510,12 @@ fn struct_union_html(
) (size | io::error) = {
let z = 0z;
let members = match (t.repr) {
- t: ast::struct_type => {
- z += fmt::fprint(out, "<span class='keyword'>struct</span> {")?;
- yield t: []ast::struct_member;
- },
- t: ast::union_type => {
- z += fmt::fprint(out, "<span class='keyword'>union</span> {")?;
- yield t: []ast::struct_member;
- },
+ case t: ast::struct_type =>
+ z += fmt::fprint(out, "<span class='keyword'>struct</span> {")?;
+ yield t: []ast::struct_member;
+ case t: ast::union_type =>
+ z += fmt::fprint(out, "<span class='keyword'>union</span> {")?;
+ yield t: []ast::struct_member;
};
indent += 1;
@@ -492,25 +524,21 @@ fn struct_union_html(
z += newline(out, indent)?;
match (member._offset) {
- null => void,
- expr: *ast::expr => {
- z += fmt::fprint(out, "@offset(")?;
- z += unparse::expr(out, indent, *expr)?;
- z += fmt::fprint(out, ") ")?;
- },
+ case null => void;
+ case expr: *ast::expr =>
+ z += fmt::fprint(out, "@offset(")?;
+ z += unparse::expr(out, indent, *expr)?;
+ z += fmt::fprint(out, ") ")?;
};
match (member.member) {
- f: ast::struct_field => {
- z += fmt::fprintf(out, "{}: ", f.name)?;
- z += type_html(out, indent, *f._type, brief)?;
- },
- embed: ast::struct_embedded => {
- z += type_html(out, indent, *embed, brief)?;
- },
- indent: ast::struct_alias => {
- z += unparse::ident(out, indent)?;
- },
+ case f: ast::struct_field =>
+ z += fmt::fprintf(out, "{}: ", f.name)?;
+ z += type_html(out, indent, *f._type, brief)?;
+ case embed: ast::struct_embedded =>
+ z += type_html(out, indent, *embed, brief)?;
+ case indent: ast::struct_alias =>
+ z += unparse::ident(out, indent)?;
};
z += fmt::fprint(out, ",")?;
};
@@ -553,85 +581,85 @@ fn type_html(
};
match (_type.repr) {
- a: ast::alias_type => {
- if (a.unwrap) {
- z += fmt::fprint(out, "...")?;
- };
- z += unparse::ident(out, a.ident)?;
- },
- t: ast::builtin_type => {
- z += fmt::fprintf(out, "<span class='type'>{}</span>",
- builtin_type(t))?;
- },
- t: ast::tagged_type => {
- z += fmt::fprint(out, "(")?;
- for (let i = 0z; i < len(t); i += 1) {
- z += type_html(out, indent, *t[i], brief)?;
- if (i < len(t) - 1) {
- z += fmt::fprint(out, " | ")?;
- };
- };
- z += fmt::fprint(out, ")")?;
- },
- t: ast::tuple_type => {
- z += fmt::fprint(out, "(")?;
- for (let i = 0z; i < len(t); i += 1) {
- z += type_html(out, indent, *t[i], brief)?;
- if (i < len(t) - 1) {
- z += fmt::fprint(out, ", ")?;
- };
- };
- z += fmt::fprint(out, ")")?;
- },
- t: ast::pointer_type => {
- if (t.flags & ast::pointer_flags::NULLABLE != 0) {
- z += fmt::fprint(out, "<span class='type'>nullable</span> ")?;
+ case a: ast::alias_type =>
+ if (a.unwrap) {
+ z += fmt::fprint(out, "...")?;
+ };
+ z += unparse::ident(out, a.ident)?;
+ case t: ast::builtin_type =>
+ z += fmt::fprintf(out, "<span class='type'>{}</span>",
+ builtin_type(t))?;
+ case t: ast::tagged_type =>
+ z += fmt::fprint(out, "(")?;
+ for (let i = 0z; i < len(t); i += 1) {
+ z += type_html(out, indent, *t[i], brief)?;
+ if (i < len(t) - 1) {
+ z += fmt::fprint(out, " | ")?;
};
- z += fmt::fprint(out, "*")?;
- z += type_html(out, indent, *t.referent, brief)?;
- },
- t: ast::func_type => {
- if (t.attrs & ast::func_attrs::NORETURN == ast::func_attrs::NORETURN) {
- z += fmt::fprint(out, "@noreturn ")?;
+ };
+ z += fmt::fprint(out, ")")?;
+ case t: ast::tuple_type =>
+ z += fmt::fprint(out, "(")?;
+ for (let i = 0z; i < len(t); i += 1) {
+ z += type_html(out, indent, *t[i], brief)?;
+ if (i < len(t) - 1) {
+ z += fmt::fprint(out, ", ")?;
};
+ };
+ z += fmt::fprint(out, ")")?;
+ case t: ast::pointer_type =>
+ if (t.flags & ast::pointer_flags::NULLABLE != 0) {
+ z += fmt::fprint(out, "<span class='type'>nullable</span> ")?;
+ };
+ z += fmt::fprint(out, "*")?;
+ z += type_html(out, indent, *t.referent, brief)?;
+ case t: ast::func_type =>
+ if (t.attrs & ast::func_attrs::NORETURN == ast::func_attrs::NORETURN) {
+ z += fmt::fprint(out, "@noreturn ")?;
+ };
- z += fmt::fprint(out, "<span class='keyword'>fn</span>(")?;
- for (let i = 0z; i < len(t.params); i += 1) {
- const param = t.params[i];
- z += fmt::fprintf(out, "{}: ",
- if (len(param.name) == 0) "_" else param.name)?;
- z += type_html(out, indent, *param._type, brief)?;
-
- if (i + 1 == len(t.params)
- && t.variadism == ast::variadism::HARE) {
- // TODO: Highlight that as well
- z += fmt::fprint(out, "...")?;
- };
- if (i + 1 < len(t.params)) {
- z += fmt::fprint(out, ", ")?;
- };
- };
- if (t.variadism == ast::variadism::C) {
- z += fmt::fprint(out, ", ...")?;
+ z += fmt::fprint(out, "<span class='keyword'>fn</span>(")?;
+ for (let i = 0z; i < len(t.params); i += 1) {
+ const param = t.params[i];
+ z += fmt::fprintf(out, "{}: ",
+ if (len(param.name) == 0) "_" else param.name)?;
+ z += type_html(out, indent, *param._type, brief)?;
+
+ if (i + 1 == len(t.params)
+ && t.variadism == ast::variadism::HARE) {
+ // TODO: Highlight that as well
+ z += fmt::fprint(out, "...")?;
};
- z += fmt::fprint(out, ") ")?;
- z += type_html(out, indent, *t.result, brief)?;
- },
- t: ast::enum_type => z += enum_html(out, indent, t)?,
- t: ast::list_type => {
- z += fmt::fprint(out, "[")?;
- z += match (t.length) {
- expr: *ast::expr => unparse::expr(out, indent, *expr)?,
- ast::len_slice => 0,
- ast::len_unbounded => fmt::fprintf(out, "*")?,
- ast::len_contextual => fmt::fprintf(out, "_")?,
+ if (i + 1 < len(t.params)) {
+ z += fmt::fprint(out, ", ")?;
};
- z += fmt::fprint(out, "]")?;
+ };
+ if (t.variadism == ast::variadism::C) {
+ z += fmt::fprint(out, ", ...")?;
+ };
+ z += fmt::fprint(out, ") ")?;
+ z += type_html(out, indent, *t.result, brief)?;
+ case t: ast::enum_type =>
+ z += enum_html(out, indent, t)?;
+ case t: ast::list_type =>
+ z += fmt::fprint(out, "[")?;
+ match (t.length) {
+ case expr: *ast::expr =>
+ z += unparse::expr(out, indent, *expr)?;
+ case ast::len_slice =>
+ z += 0;
+ case ast::len_unbounded =>
+ z += fmt::fprintf(out, "*")?;
+ case ast::len_contextual =>
+ z += fmt::fprintf(out, "_")?;
+ };
+ z += fmt::fprint(out, "]")?;
- z += type_html(out, indent, *t.members, brief)?;
- },
- t: ast::struct_type => z += struct_union_html(out, indent, _type, brief)?,
- t: ast::union_type => z += struct_union_html(out, indent, _type, brief)?,
+ z += type_html(out, indent, *t.members, brief)?;
+ case t: ast::struct_type =>
+ z += struct_union_html(out, indent, _type, brief)?;
+ case t: ast::union_type =>
+ z += struct_union_html(out, indent, _type, brief)?;
};
return z;
diff --git a/cmd/haredoc/main.ha b/cmd/haredoc/main.ha
@@ -48,21 +48,31 @@ export fn main() void = {
for (let i = 0z; i < len(cmd.opts); i += 1) {
let opt = cmd.opts[i];
switch (opt.0) {
- 'F' => fmt =
- if (opt.1 == "hare") format::HARE
- else if (opt.1 == "tty") format::TTY
- else if (opt.1 == "html") format::HTML
- else if (opt.1 == "gemtext") format::GEMTEXT
- else fmt::fatal("Invalid format {}", opt.1),
- 't' => template = false,
- 'a' => show_undocumented = true,
- * => abort(),
+ case 'F' =>
+ switch (opt.1) {
+ case "hare" =>
+ fmt = format::HARE;
+ case "tty" =>
+ fmt = format::TTY;
+ case "html" =>
+ fmt = format::HTML;
+ case "gemtext" =>
+ fmt = format::GEMTEXT;
+ case =>
+ fmt::fatal("Invalid format {}", opt.1);
+ };
+ case 't' =>
+ template = false;
+ case 'a' =>
+ show_undocumented = true;
+ case => abort();
};
};
if (show_undocumented) switch (fmt) {
- format::HARE, format::TTY => void,
- * => fmt::fatal("Option -a must be used only with -Fhare or -Ftty"),
+ case format::HARE, format::TTY => void;
+ case =>
+ fmt::fatal("Option -a must be used only with -Fhare or -Ftty");
};
let decls: []ast::decl = [];
@@ -77,24 +87,28 @@ export fn main() void = {
const id: ast::ident =
if (len(cmd.args) < 1) []
else match (parse::identstr(cmd.args[0])) {
- err: parse::error => fmt::fatal(parse::strerror(err)),
- id: ast::ident => id,
+ case err: parse::error =>
+ fmt::fatal(parse::strerror(err));
+ case id: ast::ident =>
+ yield id;
};
let decl = "";
let dirname = if (len(id) < 2) id else id[..len(id) - 1];
const version = match (module::lookup(&ctx, id)) {
- ver: module::version => ver,
- err: module::error => match (module::lookup(&ctx, dirname)) {
- ver: module::version => {
- assert(len(id) >= 2);
- decl = id[len(id) - 1];
- yield ver;
- },
- err: module::error => fmt::fatal(
+ case ver: module::version =>
+ yield ver;
+ case err: module::error =>
+ yield match (module::lookup(&ctx, dirname)) {
+ case ver: module::version =>
+ assert(len(id) >= 2);
+ decl = id[len(id) - 1];
+ yield ver;
+ case err: module::error =>
+ fmt::fatal(
"Error scanning input module: {}",
- module::strerror(err)),
- },
+ module::strerror(err));
+ };
};
for (let i = 0z; i < len(version.inputs); i += 1) {
@@ -104,8 +118,10 @@ export fn main() void = {
continue;
};
match (scan(in.path)) {
- u: ast::subunit => append(decls, u.decls...),
- err: error => fmt::fatal("Error: {}", strerror(err)),
+ case u: ast::subunit =>
+ append(decls, u.decls...);
+ case err: error =>
+ fmt::fatal("Error: {}", strerror(err));
};
};
@@ -113,13 +129,17 @@ export fn main() void = {
defer free(rpath);
const readme: (io::file | void) = if (decl == "") {
yield match (os::open(rpath)) {
- err: fs::error => void,
- f: io::file => f,
+ case err: fs::error =>
+ yield void;
+ case f: io::file =>
+ yield f;
};
} else void;
+
defer match (readme) {
- void => void,
- f: io::file => io::close(&f),
+ case void => void;
+ case f: io::file =>
+ io::close(&f);
};
if (decl != "") {
@@ -153,48 +173,58 @@ export fn main() void = {
show_undocumented = show_undocumented,
};
match (emit(&ctx)) {
- void => void,
- err: error => fmt::fatal("Error: {}", strerror(err)),
+ case void => void;
+ case err: error =>
+ fmt::fatal("Error: {}", strerror(err));
};
};
fn has_decl(decl: ast::decl, name: str) bool = {
match (decl.decl) {
- d: []ast::decl_const => for (let i = 0z; i < len(d); i += 1) {
+ case d: []ast::decl_const =>
+ for (let i = 0z; i < len(d); i += 1) {
if (len(d[i].ident) == 1 && d[i].ident[0] == name) {
return true;
};
- },
- d: ast::decl_func =>
- return len(d.ident) == 1 && d.ident[0] == name,
- d: []ast::decl_global => for (let i = 0z; i < len(d); i += 1) {
+ };
+ case d: ast::decl_func =>
+ return len(d.ident) == 1 && d.ident[0] == name;
+ case d: []ast::decl_global =>
+ for (let i = 0z; i < len(d); i += 1) {
if (len(d[i].ident) == 1 && d[i].ident[0] == name) {
return true;
};
- },
- d: []ast::decl_type => for (let i = 0z; i < len(d); i += 1) {
+ };
+ case d: []ast::decl_type =>
+ for (let i = 0z; i < len(d); i += 1) {
if (len(d[i].ident) == 1 && d[i].ident[0] == name) {
return true;
};
- },
+ };
};
return false;
};
fn scan(path: str) (ast::subunit | error) = {
const input = match (os::open(path)) {
- f: io::file => f,
- err: fs::error => fmt::fatal("Error reading {}: {}",
- path, fs::strerror(err)),
+ case f: io::file =>
+ yield f;
+ case err: fs::error =>
+ fmt::fatal("Error reading {}: {}", path, fs::strerror(err));
};
defer io::close(&input);
const lexer = lex::init(&input, path, lex::flags::COMMENTS);
return parse::subunit(&lexer)?;
};
-fn emit(ctx: *context) (void | error) = switch (ctx.format) {
- format::HARE => emit_hare(ctx),
- format::TTY => emit_tty(ctx),
- format::HTML => emit_html(ctx)?,
- format::GEMTEXT => abort(), // TODO
+fn emit(ctx: *context) (void | error) = {
+ switch (ctx.format) {
+ case format::HARE =>
+ emit_hare(ctx)?;
+ case format::TTY =>
+ emit_tty(ctx)?;
+ case format::HTML =>
+ emit_html(ctx)?;
+ case format::GEMTEXT => abort(); // TODO
+ };
};
diff --git a/cmd/haredoc/resolver.ha b/cmd/haredoc/resolver.ha
@@ -20,18 +20,16 @@ fn resolve(ctx: *context, what: ast::ident) ((ast::ident, symkind) | void) = {
let partial = what[..len(what) - 1];
match (module::lookup(ctx.mctx, partial)) {
- ver: module::version => {
- return (what, symkind::SYMBOL);
- },
- module::error => void,
+ case ver: module::version =>
+ return (what, symkind::SYMBOL);
+ case module::error => void;
};
};
match (module::lookup(ctx.mctx, what)) {
- ver: module::version => {
- return (what, symkind::MODULE);
- },
- module::error => void,
+ case ver: module::version =>
+ return (what, symkind::MODULE);
+ case module::error => void;
};
return;
@@ -43,8 +41,8 @@ fn is_local(ctx: *context, what: ast::ident) bool = {
};
const summary = ctx.summary;
- for (let i = 0z; i < len(summary.types); i += 1) {
- const name = decl_ident(summary.types[i])[0];
+ for (let i = 0z; i < len(summary.constants); i += 1) {
+ const name = decl_ident(summary.constants[i])[0];
if (name == what[0]) {
return true;
};
@@ -55,6 +53,12 @@ fn is_local(ctx: *context, what: ast::ident) bool = {
return true;
};
};
+ for (let i = 0z; i < len(summary.types); i += 1) {
+ const name = decl_ident(summary.types[i])[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];
if (name == what[0]) {
diff --git a/cmd/haredoc/sort.ha b/cmd/haredoc/sort.ha
@@ -24,53 +24,54 @@ fn sort_decls(decls: []ast::decl) summary = {
};
match (decl.decl) {
- f: ast::decl_func => append(sorted.funcs, decl),
- t: []ast::decl_type =>
- for (let j = 0z; j < len(t); j += 1) {
- let bucket = &sorted.types;
- if (t[j]._type.flags & ast::type_flags::ERROR == ast::type_flags::ERROR) {
- bucket = &sorted.errors;
- };
- append(bucket, ast::decl {
- exported = true,
- loc = decl.loc,
- decl = {
- // XXX: Kind of bad
- let new: []ast::decl_type = [];
- append(new, t[j]);
- yield new;
- },
- docs = decl.docs,
- });
- },
- c: []ast::decl_const =>
- for (let j = 0z; j < len(c); j += 1) {
- append(sorted.constants, ast::decl {
- exported = true,
- loc = decl.loc,
- decl = {
- // XXX: Kind of bad
- let new: []ast::decl_const = [];
- append(new, c[j]);
- yield new;
- },
- docs = decl.docs,
- });
- },
- g: []ast::decl_global =>
- for (let j = 0z; j < len(g); j += 1) {
- append(sorted.globals, ast::decl {
- exported = true,
- loc = decl.loc,
- decl = {
- // XXX: Kind of bad
- let new: []ast::decl_global = [];
- append(new, g[j]);
- yield new;
- },
- docs = decl.docs,
- });
- },
+ case f: ast::decl_func =>
+ append(sorted.funcs, decl);
+ case t: []ast::decl_type =>
+ for (let j = 0z; j < len(t); j += 1) {
+ let bucket = &sorted.types;
+ if (t[j]._type.flags & ast::type_flags::ERROR == ast::type_flags::ERROR) {
+ bucket = &sorted.errors;
+ };
+ append(bucket, ast::decl {
+ exported = true,
+ loc = decl.loc,
+ decl = {
+ // XXX: Kind of bad
+ let new: []ast::decl_type = [];
+ append(new, t[j]);
+ yield new;
+ },
+ docs = decl.docs,
+ });
+ };
+ case c: []ast::decl_const =>
+ for (let j = 0z; j < len(c); j += 1) {
+ append(sorted.constants, ast::decl {
+ exported = true,
+ loc = decl.loc,
+ decl = {
+ // XXX: Kind of bad
+ let new: []ast::decl_const = [];
+ append(new, c[j]);
+ yield new;
+ },
+ docs = decl.docs,
+ });
+ };
+ case g: []ast::decl_global =>
+ for (let j = 0z; j < len(g); j += 1) {
+ append(sorted.globals, ast::decl {
+ exported = true,
+ loc = decl.loc,
+ decl = {
+ // XXX: Kind of bad
+ let new: []ast::decl_global = [];
+ append(new, g[j]);
+ yield new;
+ },
+ docs = decl.docs,
+ });
+ };
};
};
@@ -94,18 +95,18 @@ fn decl_cmp(a: const *void, b: const *void) int = {
return ascii::strcmp(id_a[len(id_a) - 1], id_b[len(id_b) - 1]) as int;
};
-fn decl_ident(decl: ast::decl) ast::ident = match (decl.decl) {
- f: ast::decl_func => f.ident,
- t: []ast::decl_type => {
+fn decl_ident(decl: ast::decl) ast::ident = {
+ match (decl.decl) {
+ case f: ast::decl_func =>
+ return f.ident;
+ case t: []ast::decl_type =>
assert(len(t) == 1);
- yield t[0].ident;
- },
- c: []ast::decl_const => {
+ return t[0].ident;
+ case c: []ast::decl_const =>
assert(len(c) == 1);
- yield c[0].ident;
- },
- g: []ast::decl_global => {
+ return c[0].ident;
+ case g: []ast::decl_global =>
assert(len(g) == 1);
- yield g[0].ident;
- },
+ return g[0].ident;
+ };
};
diff --git a/cmd/haredoc/tty.ha b/cmd/haredoc/tty.ha
@@ -16,19 +16,17 @@ fn emit_tty(ctx: *context) (void | error) = {
const summary = ctx.summary;
match (ctx.readme) {
- readme: io::file => {
- for (true) match (bufio::scanline(&readme)?) {
- b: []u8 => {
- firstline = false;
- fmt::printfln(
- "\x1b[1m" "// {}" "\x1b[0m",
- strings::fromutf8(b))?;
- free(b);
- },
- io::EOF => break,
- };
- },
- void => void,
+ case readme: io::file =>
+ for (true) match (bufio::scanline(&readme)?) {
+ case io::EOF => break;
+ case b: []u8 =>
+ firstline = false;
+ fmt::printfln(
+ "\x1b[1m" "// {}" "\x1b[0m",
+ strings::fromutf8(b))?;
+ free(b);
+ };
+ case void => void;
};
// XXX: Should we emit the dependencies, too?
@@ -48,11 +46,14 @@ fn emit_tty(ctx: *context) (void | error) = {
fn isws(s: str) bool = {
const iter = strings::iter(s);
- for (true) match (strings::next(&iter)) {
- r: rune => if (!ascii::isspace(r)) {
- return false;
- },
- void => break,
+ for (true) {
+ match (strings::next(&iter)) {
+ case r: rune =>
+ if (!ascii::isspace(r)) {
+ return false;
+ };
+ case void => break;
+ };
};
return true;
};
@@ -68,11 +69,14 @@ fn details_tty(ctx: *context, decl: ast::decl) (void | error) = {
firstline = false;
const iter = strings::tokenize(decl.docs, "\n");
- for (true) match (strings::next_token(&iter)) {
- s: str => if (!(strings::peek_token(&iter) is void)) {
- fmt::printfln("\x1b[1m" "//{}" "\x1b[0m", s)?;
- },
- void => break,
+ for (true) {
+ match (strings::next_token(&iter)) {
+ case s: str =>
+ if (!(strings::peek_token(&iter) is void)) {
+ fmt::printfln("\x1b[1m" "//{}" "\x1b[0m", s)?;
+ };
+ case void => break;
+ };
};
unparse_tty(os::stdout, decl)?;
@@ -84,61 +88,62 @@ fn details_tty(ctx: *context, decl: ast::decl) (void | error) = {
fn unparse_tty(out: *io::stream, d: ast::decl) (size | io::error) = {
let n = 0z;
match (d.decl) {
- g: []ast::decl_global => {
- n += fmt::fprint(out, "\x1b[34m")?;
- n += fmt::fprint(out,
- if (g[0].is_const) "def " else "let ")?;
- n += fmt::fprint(out, "\x1b[0m")?;
- for (let i = 0z; i < len(g); i += 1) {
- if (len(g[i].symbol) != 0) {
- n += fmt::fprintf(out,
- "\x1b[33m" "@symbol(\"{}\") " "\x1b[0m",
- g[i].symbol)?;
- };
- n += unparse::ident(out, g[i].ident)?;
- n += fmt::fprint(out, ": ")?;
- n += type_tty(out, 0, g[i]._type)?;
- if (i + 1 < len(g)) {
- n += fmt::fprint(out, ", ")?;
- };
- };
- },
- t: []ast::decl_type => {
- n += fmt::fprint(out, "\x1b[34m" "type " "\x1b[0m")?;
- for (let i = 0z; i < len(t); i += 1) {
- n += unparse::ident(out, t[i].ident)?;
- n += fmt::fprint(out, " = ")?;
- n += type_tty(out, 0, t[i]._type)?;
- if (i + 1 < len(t)) {
- n += fmt::fprint(out, ", ")?;
- };
- };
- },
- f: ast::decl_func => {
- n += fmt::fprint(out, "\x1b[33m")?;
- n += fmt::fprint(out, switch (f.attrs) {
- ast::fndecl_attrs::NONE => "",
- ast::fndecl_attrs::FINI => "@fini ",
- ast::fndecl_attrs::INIT => "@init ",
- ast::fndecl_attrs::TEST => "@test ",
- })?;
- n += fmt::fprint(out, "\x1b[0m")?;
-
- let p = f.prototype.repr as ast::func_type;
- if (p.attrs & ast::func_attrs::NORETURN != 0) {
- n += fmt::fprint(out,
- "\x1b[33m" "@noreturn " "\x1b[0m")?;
- };
- if (len(f.symbol) != 0) {
+ case g: []ast::decl_global =>
+ n += fmt::fprint(out, "\x1b[34m")?;
+ n += fmt::fprint(out,
+ if (g[0].is_const) "def " else "let ")?;
+ n += fmt::fprint(out, "\x1b[0m")?;
+ for (let i = 0z; i < len(g); i += 1) {
+ if (len(g[i].symbol) != 0) {
n += fmt::fprintf(out,
"\x1b[33m" "@symbol(\"{}\") " "\x1b[0m",
- f.symbol)?;
+ g[i].symbol)?;
+ };
+ n += unparse::ident(out, g[i].ident)?;
+ n += fmt::fprint(out, ": ")?;
+ n += type_tty(out, 0, g[i]._type)?;
+ if (i + 1 < len(g)) {
+ n += fmt::fprint(out, ", ")?;
+ };
+ };
+ case t: []ast::decl_type =>
+ n += fmt::fprint(out, "\x1b[34m" "type " "\x1b[0m")?;
+ for (let i = 0z; i < len(t); i += 1) {
+ n += unparse::ident(out, t[i].ident)?;
+ n += fmt::fprint(out, " = ")?;
+ n += type_tty(out, 0, t[i]._type)?;
+ if (i + 1 < len(t)) {
+ n += fmt::fprint(out, ", ")?;
};
- n += fmt::fprint(out, "\x1b[34m" "fn " "\x1b[0m")?;
- n += unparse::ident(out, f.ident)?;
- n += prototype_tty(out, 0,
- f.prototype.repr as ast::func_type)?;
- },
+ };
+ case f: ast::decl_func =>
+ n += fmt::fprint(out, "\x1b[33m")?;
+ n += fmt::fprint(out, switch (f.attrs) {
+ case ast::fndecl_attrs::NONE =>
+ yield "";
+ case ast::fndecl_attrs::FINI =>
+ yield "@fini ";
+ case ast::fndecl_attrs::INIT =>
+ yield "@init ";
+ case ast::fndecl_attrs::TEST =>
+ yield "@test ";
+ })?;
+ n += fmt::fprint(out, "\x1b[0m")?;
+
+ let p = f.prototype.repr as ast::func_type;
+ if (p.attrs & ast::func_attrs::NORETURN != 0) {
+ n += fmt::fprint(out,
+ "\x1b[33m" "@noreturn " "\x1b[0m")?;
+ };
+ if (len(f.symbol) != 0) {
+ n += fmt::fprintf(out,
+ "\x1b[33m" "@symbol(\"{}\") " "\x1b[0m",
+ f.symbol)?;
+ };
+ n += fmt::fprint(out, "\x1b[34m" "fn " "\x1b[0m")?;
+ n += unparse::ident(out, f.ident)?;
+ n += prototype_tty(out, 0,
+ f.prototype.repr as ast::func_type)?;
};
n += fmt::fprint(out, ";")?;
return n;
@@ -182,36 +187,36 @@ fn struct_union_type_tty(
) (size | io::error) = {
let z = 0z;
let membs = match (t.repr) {
- st: ast::struct_type => {
- z += fmt::fprint(out,
- "\x1b[36m" "struct" "\x1b[0m" " {")?;
- yield st: []ast::struct_member;
- },
- ut: ast::union_type => {
- z += fmt::fprint(out,
- "\x1b[36m" "union" "\x1b[0m" " {")?;
- yield ut: []ast::struct_member;
- },
+ case st: ast::struct_type =>
+ z += fmt::fprint(out,
+ "\x1b[36m" "struct" "\x1b[0m" " {")?;
+ yield st: []ast::struct_member;
+ case ut: ast::union_type =>
+ z += fmt::fprint(out,
+ "\x1b[36m" "union" "\x1b[0m" " {")?;
+ yield ut: []ast::struct_member;
};
indent += 1z;
for (let i = 0z; i < len(membs); i += 1) {
z += newline(out, indent)?;
- z += match (membs[i]._offset) {
- null => 0z,
- ex: *ast::expr => fmt::fprint(out, "\x1b[33m" "@offset(")?
- + unparse::expr(out, indent, *ex)?
- + fmt::fprint(out, ") \x1b[0m")?,
+ match (membs[i]._offset) {
+ case null => void;
+ case ex: *ast::expr =>
+ z += fmt::fprint(out, "\x1b[33m" "@offset(")?;
+ z += unparse::expr(out, indent, *ex)?;
+ z += fmt::fprint(out, ") \x1b[0m")?;
};
- z += match (membs[i].member) {
- se: ast::struct_embedded => type_tty(out, indent, *se)?,
- sa: ast::struct_alias => unparse::ident(out, sa)?,
- sf: ast::struct_field => {
- yield fmt::fprintf(out, "{}: ", sf.name)?
- + type_tty(out, indent, *sf._type)?;
- },
+ match (membs[i].member) {
+ case se: ast::struct_embedded =>
+ z += type_tty(out, indent, *se)?;
+ case sa: ast::struct_alias =>
+ z += unparse::ident(out, sa)?;
+ case sf: ast::struct_field =>
+ z += fmt::fprintf(out, "{}: ", sf.name)?;
+ z += type_tty(out, indent, *sf._type)?;
};
z += fmt::fprint(out, ",")?;
@@ -243,91 +248,87 @@ fn type_tty(
};
match (t.repr) {
- a: ast::alias_type => {
- if (a.unwrap) {
- n += fmt::fprint(out, "...")?;
- };
- n += unparse::ident(out, a.ident)?;
- },
- b: ast::builtin_type => {
- n += fmt::fprintf(out, "\x1b[36m" "{}" "\x1b[0m",
- builtin_type(b))?;
- },
- e: ast::enum_type => {
- n += fmt::fprint(out, "\x1b[36m" "enum " "\x1b[0m")?;
- if (e.storage != ast::builtin_type::INT) {
- n += fmt::fprintf(out,
- "\x1b[36m" "{}" "\x1b[0m",
- builtin_type(e.storage))?;
- };
- n += fmt::fprint(out, " {")?;
- indent += 1;
- for (let i = 0z; i < len(e.values); i += 1) {
- n += newline(out, indent)?;
- let value = e.values[i];
- n += fmt::fprint(out, value.name)?;
- match (value.value) {
- null => void,
- e: *ast::expr => {
- n += fmt::fprint(out, " = ")?;
- n += unparse::expr(out, indent, *e)?;
- },
- };
- n += fmt::fprint(out, ",")?;
- };
- indent -= 1;
+ case a: ast::alias_type =>
+ if (a.unwrap) {
+ n += fmt::fprint(out, "...")?;
+ };
+ n += unparse::ident(out, a.ident)?;
+ case b: ast::builtin_type =>
+ n += fmt::fprintf(out, "\x1b[36m" "{}" "\x1b[0m",
+ builtin_type(b))?;
+ case e: ast::enum_type =>
+ n += fmt::fprint(out, "\x1b[36m" "enum " "\x1b[0m")?;
+ if (e.storage != ast::builtin_type::INT) {
+ n += fmt::fprintf(out,
+ "\x1b[36m" "{}" "\x1b[0m",
+ builtin_type(e.storage))?;
+ };
+ n += fmt::fprint(out, " {")?;
+ indent += 1;
+ for (let i = 0z; i < len(e.values); i += 1) {
n += newline(out, indent)?;
- n += fmt::fprint(out, "}")?;
- },
- f: ast::func_type => {
- if (f.attrs & ast::func_attrs::NORETURN != 0) {
- n += fmt::fprint(out,
- "\x1b[33m" "@noreturn " "\x1b[0m")?;
- };
- n += fmt::fprint(out, "\x1b[34m" "fn" "\x1b[0m")?;
- n += prototype_tty(out, indent, f)?;
- },
- l: ast::list_type => {
- n += fmt::fprint(out, "[")?;
- n += match (l.length) {
- ast::len_slice => 0,
- ast::len_unbounded => fmt::fprint(out, "*")?,
- ast::len_contextual => fmt::fprint(out, "_")?,
- e: *ast::expr => unparse::expr(out, indent, *e)?,
- };
- n += fmt::fprint(out, "]")?;
- n += type_tty(out, indent, *l.members)?;
- },
- p: ast::pointer_type => {
- if (p.flags & ast::pointer_flags::NULLABLE != 0) {
- n += fmt::fprint(out,
- "\x1b[36m" "nullable " "\x1b[0m")?;
+ let value = e.values[i];
+ n += fmt::fprint(out, value.name)?;
+ match (value.value) {
+ case null => void;
+ case e: *ast::expr =>
+ n += fmt::fprint(out, " = ")?;
+ n += unparse::expr(out, indent, *e)?;
};
+ n += fmt::fprint(out, ",")?;
+ };
+ indent -= 1;
+ n += newline(out, indent)?;
+ n += fmt::fprint(out, "}")?;
+ case f: ast::func_type =>
+ if (f.attrs & ast::func_attrs::NORETURN != 0) {
+ n += fmt::fprint(out,
+ "\x1b[33m" "@noreturn " "\x1b[0m")?;
+ };
+ n += fmt::fprint(out, "\x1b[34m" "fn" "\x1b[0m")?;
+ n += prototype_tty(out, indent, f)?;
+ case l: ast::list_type =>
+ n += fmt::fprint(out, "[")?;
+ match (l.length) {
+ case ast::len_slice => void;
+ case ast::len_unbounded =>
n += fmt::fprint(out, "*")?;
- n += type_tty(out, indent, *p.referent)?;
- },
- ast::struct_type => n += struct_union_type_tty(out, indent, t)?,
- ast::union_type => n += struct_union_type_tty(out, indent, t)?,
- t: ast::tagged_type => {
- n += fmt::fprint(out, "(")?;
- for (let i = 0z; i < len(t); i += 1) {
- n += type_tty(out, indent, *t[i])?;
- if (i + 1 < len(t)) {
- n += fmt::fprint(out, " | ")?;
- };
+ case ast::len_contextual =>
+ n += fmt::fprint(out, "_")?;
+ case e: *ast::expr =>
+ n += unparse::expr(out, indent, *e)?;
+ };
+ n += fmt::fprint(out, "]")?;
+ n += type_tty(out, indent, *l.members)?;
+ case p: ast::pointer_type =>
+ if (p.flags & ast::pointer_flags::NULLABLE != 0) {
+ n += fmt::fprint(out,
+ "\x1b[36m" "nullable " "\x1b[0m")?;
+ };
+ n += fmt::fprint(out, "*")?;
+ n += type_tty(out, indent, *p.referent)?;
+ case ast::struct_type =>
+ n += struct_union_type_tty(out, indent, t)?;
+ case ast::union_type =>
+ n += struct_union_type_tty(out, indent, t)?;
+ case t: ast::tagged_type =>
+ n += fmt::fprint(out, "(")?;
+ for (let i = 0z; i < len(t); i += 1) {
+ n += type_tty(out, indent, *t[i])?;
+ if (i + 1 < len(t)) {
+ n += fmt::fprint(out, " | ")?;
};
- n += fmt::fprint(out, ")")?;
- },
- t: ast::tuple_type => {
- n += fmt::fprint(out, "(")?;
- for (let i = 0z; i < len(t); i += 1) {
- n += type_tty(out, indent, *t[i])?;
- if (i + 1 < len(t)) {
- n += fmt::fprint(out, ", ")?;
- };
+ };
+ n += fmt::fprint(out, ")")?;
+ case t: ast::tuple_type =>
+ n += fmt::fprint(out, "(")?;
+ for (let i = 0z; i < len(t); i += 1) {
+ n += type_tty(out, indent, *t[i])?;
+ if (i + 1 < len(t)) {
+ n += fmt::fprint(out, ", ")?;
};
- n += fmt::fprint(out, ")")?;
- },
+ };
+ n += fmt::fprint(out, ")")?;
};
return n;
};
diff --git a/compress/flate/inflate.ha b/compress/flate/inflate.ha
@@ -102,10 +102,12 @@ fn bits(d: *decompressor, want: u32) (u32 | io::error) = {
for (d.cnt < want) {
let buf: [_]u8 = [0];
match (io::read(d.in, buf)?) {
- io::EOF => return wraperror(inflate_err::EOF),
- z: size => if (z < 1) {
+ case io::EOF =>
+ return wraperror(inflate_err::EOF);
+ case z: size =>
+ if (z < 1) {
continue; // Short read, retry
- },
+ };
};
val |= buf[0] << d.cnt;
d.cnt += 8;
@@ -229,11 +231,11 @@ fn uncompressed_read(d: *decompressor) (void | io::EOF | io::error) = {
static let _buf: [1024]u8 = [0...];
let buf = if (len(_buf) > d.left: size) _buf[..d.left] else _buf[..];
let z = match (io::read(d.in, buf)?) {
- z: size => {
- d.left -= z;
- yield z;
- },
- io::EOF => return wraperror(inflate_err::EOF),
+ case z: size =>
+ d.left -= z;
+ yield z;
+ case io::EOF =>
+ return wraperror(inflate_err::EOF);
};
put(d, buf[..z]...);
};
@@ -241,13 +243,20 @@ fn uncompressed_read(d: *decompressor) (void | io::EOF | io::error) = {
fn opaque_strerror(
data: *errors::opaque_data
) const str = switch (*(data: *inflate_err)) {
- inflate_err::EOF => "Unexpected EOF",
- inflate_err::BTYPE => "Invalid block type",
- inflate_err::LEN => "Invalid block length",
- inflate_err::DISTANCE => "Invalid distance",
- inflate_err::CODE => "Invalid Huffman code",
- inflate_err::HUFFMAN => "Oversubscribed Huffman code",
- inflate_err::TABLE => "Invalid dynamic Huffman code table",
+case inflate_err::EOF =>
+ yield "Unexpected EOF";
+case inflate_err::BTYPE =>
+ yield "Invalid block type";
+case inflate_err::LEN =>
+ yield "Invalid block length";
+case inflate_err::DISTANCE =>
+ yield "Invalid distance";
+case inflate_err::CODE =>
+ yield "Invalid Huffman code";
+case inflate_err::HUFFMAN =>
+ yield "Oversubscribed Huffman code";
+case inflate_err::TABLE =>
+ yield "Invalid dynamic Huffman code table";
};
fn wraperror(err: inflate_err) errors::opaque = {
@@ -287,16 +296,18 @@ fn dynamic(d: *decompressor) (void | io::EOF | io::error) = {
};
let n = 0u16;
let times = switch (c) {
- 16 => {
- if (len(lens) == 0) {
- return wraperror(inflate_err::TABLE);
- };
- n = lens[len(lens) - 1];
- yield 3 + bits(d, 2)?;
- },
- 17 => 3 + bits(d, 3)?,
- 18 => 11 + bits(d, 7)?,
- * => abort(),
+ case 16 =>
+ if (len(lens) == 0) {
+ return wraperror(inflate_err::TABLE);
+ };
+ n = lens[len(lens) - 1];
+ yield 3 + bits(d, 2)?;
+ case 17 =>
+ yield 3 + bits(d, 3)?;
+ case 18 =>
+ yield 11 + bits(d, 7)?;
+ case =>
+ abort();
};
for (times > 0; times -= 1) {
append(lens, n);
@@ -318,34 +329,37 @@ fn next(d: *decompressor) (void | io::EOF | io::error) = {
if (bits(d, 1)? == 1) {
d.final = true;
};
- return switch (bits(d, 2)?) {
- 0b00 => {
- // Skip to next byte boundary
- d.cnt = 0;
- d.bitbuf = 0;
- let buf: [4]u8 = [0...];
- for (let n = 0z; n < 4) {
- match (io::read(d.in, buf[n..])?) {
- io::EOF => return wraperror(inflate_err::EOF),
- z: size => n += z,
- };
- };
- const length = endian::legetu16(buf[..2]);
- if (length != ~endian::legetu16(buf[2..])) {
- return wraperror(inflate_err::LEN);
+ switch (bits(d, 2)?) {
+ case 0b00 =>
+ // Skip to next byte boundary
+ d.cnt = 0;
+ d.bitbuf = 0;
+ let buf: [4]u8 = [0...];
+ for (let n = 0z; n < 4) {
+ match (io::read(d.in, buf[n..])?) {
+ case io::EOF =>
+ return wraperror(inflate_err::EOF);
+ case z: size =>
+ n += z;
};
- d.state = &uncompressed_read;
- d.left = length;
- },
- 0b01 => {
- d.hl = fixed_len;
- d.hd = fixed_dist;
- d.state = &compressed_read;
- d.left = 1;
- },
- 0b10 => dynamic(d),
- 0b11 => wraperror(inflate_err::BTYPE),
- * => abort(),
+ };
+ const length = endian::legetu16(buf[..2]);
+ if (length != ~endian::legetu16(buf[2..])) {
+ return wraperror(inflate_err::LEN);
+ };
+ d.state = &uncompressed_read;
+ d.left = length;
+ case 0b01 =>
+ d.hl = fixed_len;
+ d.hd = fixed_dist;
+ d.state = &compressed_read;
+ d.left = 1;
+ case 0b10 =>
+ return dynamic(d);
+ case 0b11 =>
+ return wraperror(inflate_err::BTYPE);
+ case =>
+ abort();
};
};
@@ -356,12 +370,14 @@ fn read(s: *io::stream, buf: []u8) (size | io::EOF | io::error) = {
for (n < len(buf)) {
if (len(s.buf) == 0) {
if (s.left == 0) match (next(s)?) {
- void => void,
- io::EOF => return if (n == 0) io::EOF else n,
+ case void => void;
+ case io::EOF =>
+ return if (n == 0) io::EOF else n;
};
match (s.state(s)?) {
- void => void,
- io::EOF => return if (n == 0) io::EOF else n,
+ case void => void;
+ case io::EOF =>
+ return if (n == 0) io::EOF else n;
};
};
const toread =
@@ -411,11 +427,10 @@ fn close(s: *io::stream) void = {
let s = inflate(ins);
defer io::close(&s);
match (io::copy(outs, &s)) {
- size => void,
- e: io::error => {
- fmt::errorln(io::strerror(e))!;
- abort();
- },
+ case size => void;
+ case e: io::error =>
+ fmt::errorln(io::strerror(e))!;
+ abort();
};
let out = bufio::finish(outs);
defer free(out);
diff --git a/compress/zlib/reader.ha b/compress/zlib/reader.ha
@@ -32,11 +32,16 @@ type decompress_err = enum {
fn opaque_strerror(
data: *errors::opaque_data
) const str = switch (*(data: *decompress_err)) {
- decompress_err::HEADER => "Invalid zlib header",
- decompress_err::CHECKSUM => "Invalid zlib checksum",
- decompress_err::EOF => "Unexpected EOF",
- decompress_err::DICT => "Invalid dictionary",
- * => abort(),
+case decompress_err::HEADER =>
+ yield "Invalid zlib header";
+case decompress_err::CHECKSUM =>
+ yield "Invalid zlib checksum";
+case decompress_err::EOF =>
+ yield "Unexpected EOF";
+case decompress_err::DICT =>
+ yield "Invalid dictionary";
+case =>
+ abort();
};
fn wraperror(err: decompress_err) errors::opaque = {
@@ -52,8 +57,10 @@ fn verifysum(s: *reader) (io::EOF | io::error) = {
for (let n = 0z; n < len(hash)) {
match (io::read(s.source, hash[n..])?) {
- io::EOF => return wraperror(decompress_err::EOF),
- z: size => n += z,
+ case io::EOF =>
+ return wraperror(decompress_err::EOF);
+ case z: size =>
+ n += z;
};
};
@@ -64,8 +71,10 @@ fn verifysum(s: *reader) (io::EOF | io::error) = {
fn read(s: *io::stream, buf: []u8) (size | io::EOF | io::error) = {
let s = s: *reader;
match (io::read(&s.flate, buf)?) {
- io::EOF => return verifysum(s),
- z: size => buf = buf[..z],
+ case io::EOF =>
+ return verifysum(s);
+ case z: size =>
+ buf = buf[..z];
};
return hash::write(&s.hash, buf);
};
@@ -80,8 +89,10 @@ export fn decompress(s: *io::stream) (reader | io::error) = {
let buf: [2]u8 = [0...];
for (let n = 0z; n < len(buf)) {
match (io::read(s, buf[n..])?) {
- io::EOF => return wraperror(decompress_err::EOF),
- z: size => n += z,
+ case io::EOF =>
+ return wraperror(decompress_err::EOF);
+ case z: size =>
+ n += z;
};
};
if (buf[0] & CM != 8) {
@@ -116,18 +127,17 @@ export fn decompress(s: *io::stream) (reader | io::error) = {
let in = bufio::fixed(*vectors[i].1, io::mode::READ);
let out = bufio::dynamic(io::mode::WRITE);
let d = match (decompress(in)) {
- s: reader => s,
- e: io::error => {
- fmt::errorln(io::strerror(e))!;
- abort();
- },
+ case s: reader =>
+ yield s;
+ case e: io::error =>
+ fmt::errorln(io::strerror(e))!;
+ abort();
};
match (io::copy(out, &d)) {
- size => void,
- e: io::error => {
- fmt::errorfln("vector {}: {}", i, io::strerror(e))!;
- abort();
- },
+ case size => void;
+ case e: io::error =>
+ fmt::errorfln("vector {}: {}", i, io::strerror(e))!;
+ abort();
};
let s = bufio::finish(out);
assert(bytes::equal(s, *vectors[i].0));
diff --git a/crypto/random/+linux.ha b/crypto/random/+linux.ha
@@ -10,19 +10,24 @@ export fn buffer(buf: []u8) void = {
let n = 0z;
for (n < len(buf)) {
match (rt::getrandom(buf[n..]: *[*]u8, len(buf), 0)) {
- err: rt::errno => switch (err) {
- rt::EINTR => void,
- * => abort(),
- },
- z: size => n += z,
+ case err: rt::errno =>
+ switch (err) {
+ case rt::EINTR => void;
+ case =>
+ abort();
+ };
+ case z: size =>
+ n += z;
};
};
};
fn rand_reader(s: *io::stream, buf: []u8) (size | io::EOF | io::error) = {
assert(s == stream);
- return match (rt::getrandom(buf: *[*]u8, len(buf), 0)) {
- err: rt::errno => errors::errno(err),
- n: size => n,
+ match (rt::getrandom(buf: *[*]u8, len(buf), 0)) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case n: size =>
+ return n;
};
};
diff --git a/crypto/random/random.ha b/crypto/random/random.ha
@@ -27,8 +27,10 @@ export let stream: *io::stream = &_stream;
let buf: [4096]u8 = [0...];
let test: []u8 = [];
match (io::read(stream, buf[..])) {
- (io::error | io::EOF) => abort(),
- n: size => test = buf[..n],
+ case (io::error | io::EOF) =>
+ abort();
+ case n: size =>
+ test = buf[..n];
};
assert(len(test) > 0);
diff --git a/crypto/sha512/sha512.ha b/crypto/sha512/sha512.ha
@@ -167,46 +167,42 @@ fn sum(h: *hash::hash, buf: []u8) void = {
fn reset(h: *hash::hash) void = {
let d = h: *digest;
switch (d.var) {
- variant::SHA384 => {
- d.h[0] = init0_384;
- d.h[1] = init1_384;
- d.h[2] = init2_384;
- d.h[3] = init3_384;
- d.h[4] = init4_384;
- d.h[5] = init5_384;
- d.h[6] = init6_384;
- d.h[7] = init7_384;
- },
- variant::SHA512_224 => {
- d.h[0] = init0_224;
- d.h[1] = init1_224;
- d.h[2] = init2_224;
- d.h[3] = init3_224;
- d.h[4] = init4_224;
- d.h[5] = init5_224;
- d.h[6] = init6_224;
- d.h[7] = init7_224;
- },
- variant::SHA512_256 => {
- d.h[0] = init0_256;
- d.h[1] = init1_256;
- d.h[2] = init2_256;
- d.h[3] = init3_256;
- d.h[4] = init4_256;
- d.h[5] = init5_256;
- d.h[6] = init6_256;
- d.h[7] = init7_256;
- },
- * => {
- d.h[0] = init0;
- d.h[1] = init1;
- d.h[2] = init2;
- d.h[3] = init3;
- d.h[4] = init4;
- d.h[5] = init5;
- d.h[6] = init6;
- d.h[7] = init7;
- }
+ case variant::SHA384 =>
+ d.h[0] = init0_384;
+ d.h[1] = init1_384;
+ d.h[2] = init2_384;
+ d.h[3] = init3_384;
+ d.h[4] = init4_384;
+ d.h[5] = init5_384;
+ d.h[6] = init6_384;
+ d.h[7] = init7_384;
+ case variant::SHA512_224 =>
+ d.h[0] = init0_224;
+ d.h[1] = init1_224;
+ d.h[2] = init2_224;
+ d.h[3] = init3_224;
+ d.h[4] = init4_224;
+ d.h[5] = init5_224;
+ d.h[6] = init6_224;
+ d.h[7] = init7_224;
+ case variant::SHA512_256 =>
+ d.h[0] = init0_256;
+ d.h[1] = init1_256;
+ d.h[2] = init2_256;
+ d.h[3] = init3_256;
+ d.h[4] = init4_256;
+ d.h[5] = init5_256;
+ d.h[6] = init6_256;
+ d.h[7] = init7_256;
+ case =>
+ d.h[0] = init0;
+ d.h[1] = init1;
+ d.h[2] = init2;
+ d.h[3] = init3;
+ d.h[4] = init4;
+ d.h[5] = init5;
+ d.h[6] = init6;
+ d.h[7] = init7;
};
d.nx = 0;
d.ln = 0;
diff --git a/dirs/xdg.ha b/dirs/xdg.ha
@@ -5,26 +5,23 @@ use io;
fn lookup(prog: str, var: str, default: str) str = {
match (os::getenv(var)) {
- s: str => {
- let path = path::join(s, prog);
- match (os::stat(path)) {
- err: fs::error => {
- os::mkdirs(path) as void;
- return path;
- },
- st: fs::filestat => {
- if (fs::isdir(st.mode)) {
- return path;
- };
- },
+ case s: str =>
+ const path = path::join(s, prog);
+ match (os::stat(path)) {
+ case err: fs::error =>
+ os::mkdirs(path)!;
+ return path;
+ case st: fs::filestat =>
+ if (fs::isdir(st.mode)) {
+ return path;
};
- },
- void => void,
+ };
+ case void => void;
};
let home = os::getenv("HOME") as str;
let path = path::join(home, default, prog);
- os::mkdirs(path) as void;
+ os::mkdirs(path)!;
return path;
};
diff --git a/encoding/base64/base64.ha b/encoding/base64/base64.ha
@@ -118,61 +118,63 @@ export fn decode(
for (true) {
let buf: [4]u8 = [0...];
match (io::read(in, buf)) {
- size => {
- for (let i = 0z; i < 2; i += 1) {
- if (decoder[buf[i]] == INVALID_OR_PAD) {
- return (count + i): invalid;
- } else {
- buf[i] = decoder[buf[i]];
- };
- };
-
- if (decoder[buf[2]] == INVALID_OR_PAD) {
- if (buf[2] != PADDING) {
- return (count + 2z): invalid;
- };
- if (buf[3] != PADDING) {
- return (count + 3z): invalid;
- };
- z += io::write(out, [
- buf[0] << 2 | buf[1] >> 4,
- ])?;
- let extra: []u8 = [0];
- return match (io::read(in, extra)) {
- size => (count + 4z): invalid,
- io::EOF => z,
- };
+ case size =>
+ for (let i = 0z; i < 2; i += 1) {
+ if (decoder[buf[i]] == INVALID_OR_PAD) {
+ return (count + i): invalid;
} else {
- buf[2] = decoder[buf[2]];
+ buf[i] = decoder[buf[i]];
};
+ };
- if (decoder[buf[3]] == INVALID_OR_PAD) {
- if (buf[3] != PADDING) {
- return (count + 3z): invalid;
- };
- z += io::write(out, [
- buf[0] << 2 | buf[1] >> 4,
- buf[1] << 4 | buf[2] >> 2,
- ])?;
- let extra: []u8 = [0];
- return match (io::read(in, extra)) {
- size => (count + 4z): invalid,
- io::EOF => z,
- };
- } else {
- buf[3] = decoder[buf[3]];
+ if (decoder[buf[2]] == INVALID_OR_PAD) {
+ if (buf[2] != PADDING) {
+ return (count + 2z): invalid;
+ };
+ if (buf[3] != PADDING) {
+ return (count + 3z): invalid;
};
+ z += io::write(out, [
+ buf[0] << 2 | buf[1] >> 4,
+ ])?;
+ let extra: []u8 = [0];
+ match (io::read(in, extra)) {
+ case size =>
+ return (count + 4z): invalid;
+ case io::EOF =>
+ return z;
+ };
+ } else {
+ buf[2] = decoder[buf[2]];
+ };
+ if (decoder[buf[3]] == INVALID_OR_PAD) {
+ if (buf[3] != PADDING) {
+ return (count + 3z): invalid;
+ };
z += io::write(out, [
buf[0] << 2 | buf[1] >> 4,
buf[1] << 4 | buf[2] >> 2,
- buf[2] << 6 | buf[3],
])?;
- count += 4;
- },
- io::EOF => {
- break;
- },
+ let extra: []u8 = [0];
+ match (io::read(in, extra)) {
+ case size =>
+ return (count + 4z): invalid;
+ case io::EOF =>
+ return z;
+ };
+ } else {
+ buf[3] = decoder[buf[3]];
+ };
+
+ z += io::write(out, [
+ buf[0] << 2 | buf[1] >> 4,
+ buf[1] << 4 | buf[2] >> 2,
+ buf[2] << 6 | buf[3],
+ ])?;
+ count += 4;
+ case io::EOF =>
+ break;
};
};
return z;
@@ -187,10 +189,13 @@ export fn decode_static(
) (size | invalid) = {
let buf = bufio::fixed(out, io::mode::WRITE);
defer io::close(buf);
- return match (decode(alphabet, in, buf)) {
- io::error => abort(),
- z: invalid => z: invalid,
- z: size => z,
+ match (decode(alphabet, in, buf)) {
+ case io::error =>
+ abort();
+ case z: invalid =>
+ return z: invalid;
+ case z: size =>
+ return z;
};
};
@@ -218,10 +223,14 @@ export fn decodeslice(alphabet: []u8, in: []u8) ([]u8 | invalid) = {
let out = bufio::dynamic(io::mode::WRITE);
let in = bufio::fixed(in, io::mode::READ);
defer io::close(in);
- return match (decode(alphabet, in, out)) {
- io::error => abort(),
- z: invalid => z: invalid,
- size => bufio::finish(out),
+ match (decode(alphabet, in, out)) {
+ case io::error =>
+ abort();
+ case z: invalid =>
+ io::close(out);
+ return z: invalid;
+ case size =>
+ return bufio::finish(out);
};
};
@@ -253,7 +262,7 @@ export fn decodeslice_static(
defer free(s);
assert(bytes::equal(s, expect[..i]));
};
-
+
const bad: [_]str = [
"A",
"AA",
diff --git a/encoding/hex/hex.ha b/encoding/hex/hex.ha
@@ -49,8 +49,10 @@ export fn decode(s: str) ([]u8 | invalid) = {
for (let i = 0z; i < len(s) / 2; i += 1) {
let oct = strings::fromutf8_unsafe(s[i * 2..i * 2 + 2]);
let u = match (strconv::stou8b(oct, 16)) {
- (strconv::invalid | strconv::overflow) => return invalid,
- u: u8 => u,
+ case (strconv::invalid | strconv::overflow) =>
+ return invalid;
+ case u: u8 =>
+ yield u;
};
append(buf, u);
};
diff --git a/encoding/utf8/decode.ha b/encoding/utf8/decode.ha
@@ -9,8 +9,10 @@ export type decoder = struct {
// Initializes a new UTF-8 decoder.
export fn decode(src: (str | []u8)) decoder = match (src) {
- s: str => decoder { src = toutf8(s), ... },
- b: []u8 => decoder { src = b, ... },
+case s: str =>
+ yield decoder { src = toutf8(s), ... };
+case b: []u8 =>
+ yield decoder { src = b, ... };
};
// Returned when more data is needed, i.e. when an incomplete UTF-8 sequence is
@@ -93,16 +95,20 @@ export fn prev(d: *decoder) (rune | void | more | invalid) = {
let decoder = decode(input);
for (let i = 0z; i < len(expected); i += 1) {
match (next(&decoder)) {
- (invalid | more | void) => abort(),
- r: rune => assert(r == expected[i]),
+ case (invalid | more | void) =>
+ abort();
+ case r: rune =>
+ assert(r == expected[i]);
};
};
assert(next(&decoder) is void);
assert(decoder.offs == len(decoder.src));
for (let i = 0z; i < len(expected); i += 1) {
match (prev(&decoder)) {
- (invalid | more | void) => abort(),
- r: rune => assert(r == expected[len(expected) - i - 1]),
+ case (invalid | more | void) =>
+ abort();
+ case r: rune =>
+ assert(r == expected[len(expected) - i - 1]);
};
};
assert(prev(&decoder) is void);
@@ -128,10 +134,13 @@ export fn valid(src: (str | []u8)) bool = {
let decoder = decode(src);
for (true) {
match (next(&decoder)) {
- void => return true,
- invalid => return false,
- more => return false,
- rune => void,
+ case void =>
+ return true;
+ case invalid =>
+ return false;
+ case more =>
+ return false;
+ case rune => void;
};
};
abort();
diff --git a/errors/rt.ha b/errors/rt.ha
@@ -4,16 +4,25 @@ use rt;
// interface which is mainly provided to support internal stdlib requirements.
export fn errno(errno: rt::errno) error = {
switch (errno) {
- rt::ECONNREFUSED => return refused,
- rt::ECANCELED => return cancelled,
- rt::EOVERFLOW => return overflow,
- rt::EACCES => return noaccess,
- rt::EINVAL => return invalid,
- rt::EEXIST => return exists,
- rt::ENOENT => return noentry,
- rt::ETIME => return timeout,
- rt::EBUSY => return busy,
- * => void,
+ case rt::ECONNREFUSED =>
+ return refused;
+ case rt::ECANCELED =>
+ return cancelled;
+ case rt::EOVERFLOW =>
+ return overflow;
+ case rt::EACCES =>
+ return noaccess;
+ case rt::EINVAL =>
+ return invalid;
+ case rt::EEXIST =>
+ return exists;
+ case rt::ENOENT =>
+ return noentry;
+ case rt::ETIME =>
+ return timeout;
+ case rt::EBUSY =>
+ return busy;
+ case => void;
};
static assert(size(rt::errno) <= size(opaque_data));
diff --git a/errors/string.ha b/errors/string.ha
@@ -9,16 +9,28 @@
// strerror function which provides more context-appropriate error messages for
// each of those types.
export fn strerror(err: error) const str = match (err) {
- busy => "The requested resource is not available",
- exists => "An attempt was made to create a resource which already exists",
- invalid => "A function was called with an invalid combination of arguments",
- noaccess => "The user does not have permission to use this resource",
- noentry => "An entry was requested which does not exist",
- overflow => "The requested operation caused a numeric overflow condition",
- unsupported => "The requested operation is not supported",
- timeout => "The requested operation timed out",
- cancelled => "The requested operation was cancelled",
- refused => "A connection attempt was refused",
- nomem => "Unable to allocate sufficient memory for the requested operation",
- op: opaque => op.strerror(&op.data),
+case busy =>
+ yield "The requested resource is not available";
+case exists =>
+ yield "An attempt was made to create a resource which already exists";
+case invalid =>
+ yield "A function was called with an invalid combination of arguments";
+case noaccess =>
+ yield "The user does not have permission to use this resource";
+case noentry =>
+ yield "An entry was requested which does not exist";
+case overflow =>
+ yield "The requested operation caused a numeric overflow condition";
+case unsupported =>
+ yield "The requested operation is not supported";
+case timeout =>
+ yield "The requested operation timed out";
+case cancelled =>
+ yield "The requested operation was cancelled";
+case refused =>
+ yield "A connection attempt was refused";
+case nomem =>
+ yield "Unable to allocate sufficient memory for the requested operation";
+case op: opaque =>
+ yield op.strerror(&op.data);
};
diff --git a/fmt/fmt.ha b/fmt/fmt.ha
@@ -172,14 +172,18 @@ export fn fprintf(
let iter = strings::iter(fmt);
for (true) {
let r: rune = match (strings::next(&iter)) {
- void => break,
- r: rune => r,
+ case void =>
+ break;
+ case r: rune =>
+ yield r;
};
if (r == '{') {
r = match (strings::next(&iter)) {
- void => abort("Invalid format string (unterminated '{')"),
- r: rune => r,
+ case void =>
+ abort("Invalid format string (unterminated '{')");
+ case r: rune =>
+ yield r;
};
let arg = if (r == '{') {
@@ -195,37 +199,48 @@ export fn fprintf(
};
const arg = match (arg) {
- arg: formattable => arg,
- * => abort("Invalid formattable"),
+ case arg: formattable =>
+ yield arg;
+ case =>
+ abort("Invalid formattable");
};
r = match (strings::next(&iter)) {
- void => abort("Invalid format string (unterminated '{')"),
- r: rune => r,
+ case void =>
+ abort("Invalid format string (unterminated '{')");
+ case r: rune =>
+ yield r;
};
let mod = &modifiers { ... };
let pi: paramindex = void;
switch (r) {
- ':' => scan_inline_modifiers(&iter, mod),
- '%' => scan_parametric_modifiers(&iter, &pi),
- '}' => void,
- * => abort("Invalid format string"),
+ case ':' =>
+ scan_inline_modifiers(&iter, mod);
+ case '%' =>
+ scan_parametric_modifiers(&iter, &pi);
+ case '}' => void;
+ case =>
+ abort("Invalid format string");
};
match (pi) {
- pi: uint => match (args[pi]) {
- pmod: *modifiers => mod = pmod,
- * => abort("Explicit parameter is not *fmt::modifier"),
- },
- nextparam => {
- i += 1;
- match (args[i - 1]) {
- pmod: *modifiers => mod = pmod,
- * => abort("Implicit parameter is not *fmt::modifier"),
- };
- },
- void => void,
+ case pi: uint =>
+ match (args[pi]) {
+ case pmod: *modifiers =>
+ mod = pmod;
+ case =>
+ abort("Explicit parameter is not *fmt::modifier");
+ };
+ case nextparam =>
+ i += 1;
+ match (args[i - 1]) {
+ case pmod: *modifiers =>
+ mod = pmod;
+ case =>
+ abort("Implicit parameter is not *fmt::modifier");
+ };
+ case void => void;
};
if (mod.base == 0) {
@@ -235,8 +250,10 @@ export fn fprintf(
n += format(s, arg, mod)?;
} else if (r == '}') {
match (strings::next(&iter)) {
- void => abort("Invalid format string (hanging '}')"),
- r: rune => assert(r == '}', "Invalid format string (hanging '}')"),
+ case void =>
+ abort("Invalid format string (hanging '}')");
+ case r: rune =>
+ assert(r == '}', "Invalid format string (hanging '}')");
};
n += io::write(s, utf8::encoderune('}'))?;
@@ -254,8 +271,10 @@ fn format(out: *io::stream, arg: formattable, mod: *modifiers) (size | io::error
let pad: []u8 = [];
if (z < mod.width: size) {
pad = utf8::encoderune(switch (mod.padding) {
- padding::ZEROES => '0',
- * => ' ',
+ case padding::ZEROES =>
+ yield '0';
+ case =>
+ yield ' ';
});
};
@@ -278,39 +297,46 @@ fn format_raw(
out: *io::stream,
arg: formattable,
mod: *modifiers,
-) (size | io::error) = match (arg) {
- s: str => io::write(out, strings::toutf8(s)),
- r: rune => io::write(out, utf8::encoderune(r)),
- b: bool => io::write(out, strings::toutf8(if (b) "true" else "false")),
- n: types::numeric => {
- let s = strconv::numerictosb(n, mod.base);
- yield io::write(out, strings::toutf8(s));
- },
- p: uintptr => {
- let s = strconv::uptrtosb(p, mod.base);
- yield io::write(out, strings::toutf8(s));
- },
- v: nullable *void => match (v) {
- v: *void => {
- let s = strconv::uptrtosb(v: uintptr,
- strconv::base::HEX_LOWER);
+) (size | io::error) = {
+ match (arg) {
+ case s: str =>
+ return io::write(out, strings::toutf8(s));
+ case r: rune =>
+ return io::write(out, utf8::encoderune(r));
+ case b: bool =>
+ return io::write(out,
+ strings::toutf8(if (b) "true" else "false"));
+ case n: types::numeric =>
+ const s = strconv::numerictosb(n, mod.base);
+ return io::write(out, strings::toutf8(s));
+ case p: uintptr =>
+ const s = strconv::uptrtosb(p, mod.base);
+ return io::write(out, strings::toutf8(s));
+ case v: nullable *void =>
+ match (v) {
+ case v: *void =>
let n = io::write(out, strings::toutf8("0x"))?;
+ const s = strconv::uptrtosb(v: uintptr,
+ strconv::base::HEX_LOWER);
n += io::write(out, strings::toutf8(s))?;
- yield n;
- },
- null => format(out, "(null)", mod),
- },
- void => io::write(out, strings::toutf8("void")),
+ return n;
+ case null =>
+ return format(out, "(null)", mod);
+ };
+ case void =>
+ return io::write(out, strings::toutf8("void"));
+ };
};
-
fn scan_uint(iter: *strings::iterator) uint = {
let num: []u8 = [];
defer free(num);
for (true) {
let r = match (strings::next(iter)) {
- void => abort("Invalid format string (unterminated '{')"),
- r: rune => r,
+ case void =>
+ abort("Invalid format string (unterminated '{')");
+ case r: rune =>
+ yield r;
};
if (ascii::isdigit(r)) {
@@ -318,9 +344,10 @@ fn scan_uint(iter: *strings::iterator) uint = {
} else {
strings::push(iter, r);
match (strconv::stou(strings::fromutf8(num))) {
- (strconv::invalid | strconv::overflow) =>
- abort("Invalid format string (invalid index)"),
- u: uint => return u,
+ case (strconv::invalid | strconv::overflow) =>
+ abort("Invalid format string (invalid index)");
+ case u: uint =>
+ return u;
};
};
};
@@ -332,19 +359,24 @@ fn scan_modifier_flags(iter: *strings::iterator, mod: *modifiers) void = {
for (true) {
let r = match (strings::next(iter)) {
- void => abort("Invalid format string (unterminated '{')"),
- r: rune => r,
+ case void =>
+ abort("Invalid format string (unterminated '{')");
+ case r: rune =>
+ yield r;
};
switch (r) {
- '0' => flags |= modflags::ZERO,
- '-' => flags |= modflags::MINUS,
- ' ' => flags |= modflags::SPACE,
- '+' => flags |= modflags::PLUS,
- * => {
- strings::push(iter, r);
- break;
- },
+ case '0' =>
+ flags |= modflags::ZERO;
+ case '-' =>
+ flags |= modflags::MINUS;
+ case ' ' =>
+ flags |= modflags::SPACE;
+ case '+' =>
+ flags |= modflags::PLUS;
+ case =>
+ strings::push(iter, r);
+ break;
};
};
@@ -365,8 +397,10 @@ fn scan_modifier_flags(iter: *strings::iterator, mod: *modifiers) void = {
fn scan_modifier_width(iter: *strings::iterator, mod: *modifiers) void = {
let r = match (strings::next(iter)) {
- void => abort("Invalid format string (unterminated '{')"),
- r: rune => r,
+ case void =>
+ abort("Invalid format string (unterminated '{')");
+ case r: rune =>
+ yield r;
};
let is_digit = ascii::isdigit(r);
@@ -379,8 +413,10 @@ fn scan_modifier_width(iter: *strings::iterator, mod: *modifiers) void = {
fn scan_modifier_precision(iter: *strings::iterator, mod: *modifiers) void = {
let r = match (strings::next(iter)) {
- void => abort("Invalid format string (unterminated '{')"),
- r: rune => r,
+ case void =>
+ abort("Invalid format string (unterminated '{')");
+ case r: rune =>
+ yield r;
};
if (r == '.') {
@@ -392,16 +428,23 @@ fn scan_modifier_precision(iter: *strings::iterator, mod: *modifiers) void = {
fn scan_modifier_base(iter: *strings::iterator, mod: *modifiers) void = {
let r = match (strings::next(iter)) {
- void => abort("Invalid format string (unterminated '{')"),
- r: rune => r,
+ case void =>
+ abort("Invalid format string (unterminated '{')");
+ case r: rune =>
+ yield r;
};
switch (r) {
- 'x' => mod.base = strconv::base::HEX_LOWER,
- 'X' => mod.base = strconv::base::HEX_UPPER,
- 'o' => mod.base = strconv::base::OCT,
- 'b' => mod.base = strconv::base::BIN,
- * => strings::push(iter, r),
+ case 'x' =>
+ mod.base = strconv::base::HEX_LOWER;
+ case 'X' =>
+ mod.base = strconv::base::HEX_UPPER;
+ case 'o' =>
+ mod.base = strconv::base::OCT;
+ case 'b' =>
+ mod.base = strconv::base::BIN;
+ case =>
+ strings::push(iter, r);
};
};
@@ -413,16 +456,20 @@ fn scan_inline_modifiers(iter: *strings::iterator, mod: *modifiers) void = {
// eat '}'
let terminated = match (strings::next(iter)) {
- void => false,
- r: rune => r == '}',
+ case void =>
+ yield false;
+ case r: rune =>
+ yield r == '}';
};
assert(terminated, "Invalid format string (unterminated '{')");
};
fn scan_parameter_index(iter: *strings::iterator, pi: *paramindex) void = {
let r = match (strings::next(iter)) {
- void => abort("Invalid format string (unterminated '{')"),
- r: rune => r,
+ case void =>
+ abort("Invalid format string (unterminated '{')");
+ case r: rune =>
+ yield r;
};
let is_digit = ascii::isdigit(r);
@@ -439,8 +486,10 @@ fn scan_parametric_modifiers(iter: *strings::iterator, pi: *paramindex) void = {
// eat '}'
let terminated = match (strings::next(iter)) {
- void => false,
- r: rune => r == '}',
+ case void =>
+ yield false;
+ case r: rune =>
+ yield r == '}';
};
assert(terminated, "Invalid format string (unterminated '{')");
};
diff --git a/fnmatch/fnmatch.ha b/fnmatch/fnmatch.ha
@@ -45,14 +45,18 @@ export fn fnmatch(pattern: str, string: str, flag: flags...) bool = {
fl |= flag[i];
};
if (fl & flags::PATHNAME != 0) {
- return match (fnmatch_pathname(pattern, string, fl)) {
- b: bool => b,
- * => false,
+ match (fnmatch_pathname(pattern, string, fl)) {
+ case b: bool =>
+ return b;
+ case =>
+ return false;
};
} else {
- return match (fnmatch_internal(pattern, string, fl)) {
- b: bool => b,
- * => false,
+ match (fnmatch_internal(pattern, string, fl)) {
+ case b: bool =>
+ return b;
+ case =>
+ return false;
};
};
};
@@ -70,14 +74,19 @@ fn fnmatch_pathname(
for (true) :outer {
start = p_iter;
for (true) match (pat_next(&p_iter, fl)?) {
- end => break :outer,
- r: rune => if (r == '/') break,
- bracket => match_bracket(&p_iter, '\0')?,
- (question | star) => void,
+ case end =>
+ break :outer;
+ case r: rune =>
+ if (r == '/') break;
+ case bracket =>
+ match_bracket(&p_iter, '\0')?;
+ case (question | star) => void;
};
let s = match (strings::next_token(&tok)) {
- void => return false,
- s: str => s,
+ case void =>
+ return false;
+ case s: str =>
+ yield s;
};
strings::prev(&p_iter);
let p = cut_tail(strings::iter_str(&start), &p_iter);
@@ -87,8 +96,10 @@ fn fnmatch_pathname(
};
};
let s = match(strings::next_token(&tok)) {
- void => return false,
- s: str => s,
+ case void =>
+ return false;
+ case s: str =>
+ yield s;
};
let p = strings::iter_str(&start);
return fnmatch_internal(p, s, fl)? && strings::next_token(&tok) is void;
@@ -119,11 +130,16 @@ export fn fnmatch_internal(
let copy = s;
let rn = strings::next(©);
let t = match (pat_next(&p, fl)?) {
- star => break,
- end => return rn is void,
- question => rn is rune,
- bracket => rn is rune && match_bracket(&p, rn: rune)?,
- r: rune => rn is rune && rn: rune == r,
+ case star =>
+ break;
+ case end =>
+ return rn is void;
+ case question =>
+ yield rn is rune;
+ case bracket =>
+ yield rn is rune && match_bracket(&p, rn: rune)?;
+ case r: rune =>
+ yield rn is rune && rn: rune == r;
};
if (!t) {
return false;
@@ -136,10 +152,13 @@ export fn fnmatch_internal(
let cnt = 0z;
for (true; cnt += 1) {
match (pat_next(&p, fl)?) {
- end => break,
- star => p_last = (p, cnt + 1),
- bracket => match_bracket(&p, '\0')?,
- (question | rune) => void,
+ case end =>
+ break;
+ case star =>
+ p_last = (p, cnt + 1);
+ case bracket =>
+ match_bracket(&p, '\0')?;
+ case (question | rune) => void;
};
};
p = p_last.0;
@@ -155,11 +174,20 @@ export fn fnmatch_internal(
for (true) {
let rn = strings::next(&s);
let matches = match (pat_next(&p, fl)?) {
- end => if (rn is void) break else return false,
- question => rn is rune,
- bracket => rn is rune && match_bracket(&p, rn: rune)?,
- r: rune => rn is rune && rn: rune == r,
- star => abort(),
+ case end =>
+ if (rn is void) {
+ break;
+ } else {
+ return false;
+ };
+ case question =>
+ yield rn is rune;
+ case bracket =>
+ yield rn is rune && match_bracket(&p, rn: rune)?;
+ case r: rune =>
+ yield rn is rune && rn: rune == r;
+ case star =>
+ abort();
};
if (!matches) {
return false;
@@ -179,15 +207,18 @@ export fn fnmatch_internal(
let copy = s;
let rn = strings::next(©);
let matched = match (pat_next(&p, fl)?) {
- end => abort(),
- question => rn is rune,
- bracket => rn is rune && match_bracket(&p, rn: rune)?,
- r: rune => rn is rune && r == rn: rune,
- star => {
- p_copy = p;
- s_copy = s;
- continue :outer;
- },
+ case end =>
+ abort();
+ case question =>
+ yield rn is rune;
+ case bracket =>
+ yield rn is rune && match_bracket(&p, rn: rune)?;
+ case r: rune =>
+ yield rn is rune && r == rn: rune;
+ case star =>
+ p_copy = p;
+ s_copy = s;
+ continue :outer;
};
if (!matched) {
break :inner;
@@ -195,8 +226,9 @@ export fn fnmatch_internal(
s = copy;
};
match (strings::next(&s_copy)) {
- void => return false,
- rune => void,
+ case void =>
+ return false;
+ case rune => void;
};
};
abort();
@@ -223,50 +255,48 @@ fn match_bracket(
};
for (let r = first; true; r = advance_or_err(it)?) {
switch (r) {
- ']' => break,
- '-' => {
- let end = advance_or_err(it)?;
- if (end == ']') {
- // '-' at the end matches itself
- strings::push(it, ']');
- last = '-';
- found ||= (c == '-');
- continue;
- };
- if (last is void) {
- return errors::invalid;
- };
- let l = last: rune;
- found ||= (l: u32 <= c: u32 && c: u32 <= end: u32);
- last = void; // forbid 'a-f-n'
- },
- '[' => {
- let next_rune = advance_or_err(it)?;
- switch (next_rune) { // TODO localization
- '=', '.' => return errors::unsupported,
- ':' => {
- let t = match_ctype(it, c)?;
- found ||= t;
- },
- * => {
- strings::push(it, next_rune);
- found ||= (c == '[');
- },
- };
- last = '[';
- },
- * => {
- found ||= (c == r);
- last = r;
- },
+ case ']' =>
+ break;
+ case '-' =>
+ let end = advance_or_err(it)?;
+ if (end == ']') {
+ // '-' at the end matches itself
+ strings::push(it, ']');
+ last = '-';
+ found ||= (c == '-');
+ continue;
+ };
+ if (last is void) {
+ return errors::invalid;
+ };
+ let l = last: rune;
+ found ||= (l: u32 <= c: u32 && c: u32 <= end: u32);
+ last = void; // forbid 'a-f-n'
+ case '[' =>
+ let next_rune = advance_or_err(it)?;
+ switch (next_rune) { // TODO localization
+ case '=', '.' =>
+ return errors::unsupported;
+ case ':' =>
+ let t = match_ctype(it, c)?;
+ found ||= t;
+ case =>
+ strings::push(it, next_rune);
+ found ||= (c == '[');
+ };
+ last = '[';
+ case =>
+ found ||= (c == r);
+ last = r;
};
};
let cnt = len(strings::iter_str(&old)) - len(strings::iter_str(it));
if (last is rune && first == last: rune && cnt >= 4) {
switch (first) {
- '=', '.', ':' => return errors::invalid,
- * => void,
+ case '=', '.', ':' =>
+ return errors::invalid;
+ case => void;
};
};
return found ^^ inv;
@@ -282,12 +312,14 @@ fn match_ctype(it: *strings::iterator, c: rune) (bool | errors::invalid) = {
};
};
if (advance_or_err(it)? != ']') {
- return errors::invalid;
+ return errors::invalid;
};
let name = strings::sub(s, 0, i - 1);
- return match (ctype_name_to_func(name)) {
- null => return errors::invalid,
- f: *fn(c: rune) bool => f(c),
+ match (ctype_name_to_func(name)) {
+ case null =>
+ return errors::invalid;
+ case f: *fn(c: rune) bool =>
+ return f(c);
};
};
@@ -306,32 +338,43 @@ fn ctype_name_to_func(name: str) nullable *fn(c: rune) bool = {
("punct", &ascii::ispunct), ("space", &ascii::isspace),
("upper", &ascii::isupper), ("xdigit",&ascii::isxdigit),
];
- return match (sort::search(map, size(funcmap), &name, &cmp)) {
- null => null: nullable *fn(c: rune) bool,
- p: *void => (p: *funcmap).1,
+ match (sort::search(map, size(funcmap), &name, &cmp)) {
+ case null =>
+ return null: nullable *fn(c: rune) bool;
+ case p: *void =>
+ return (p: *funcmap).1;
};
};
fn pat_next(pat: *strings::iterator, fl: flags) (token | errors::invalid) = {
let r = match (strings::next(pat)) {
- void => return end,
- r: rune => r,
+ case void =>
+ return end;
+ case r: rune =>
+ yield r;
};
- return switch (r) {
- '*' => star,
- '?' => question,
- '[' => bracket,
- // TODO: remove ? (harec bug workaround)
- '\\' => if (fl & flags::NOESCAPE == 0) advance_or_err(pat)?
- else '\\': token, // TODO: remove cast (harec bug workaround)
- * => r,
+ switch (r) {
+ case '*' =>
+ return star;
+ case '?' =>
+ return question;
+ case '[' =>
+ return bracket;
+ case '\\' =>
+ // TODO: remove ? (harec bug workaround)
+ return if (fl & flags::NOESCAPE == 0) advance_or_err(pat)?
+ else '\\': token; // TODO: remove cast (harec bug workaround)
+ case =>
+ return r;
};
};
fn advance_or_err(it: *strings::iterator) (rune | errors::invalid) = {
- return match (strings::next(it)) {
- r: rune => r,
- void => errors::invalid,
+ match (strings::next(it)) {
+ case r: rune =>
+ return r;
+ case void =>
+ return errors::invalid;
};
};
diff --git a/format/xml/+test.ha b/format/xml/+test.ha
@@ -87,27 +87,26 @@ fn xmltest(input: str, expected: []token, error: bool) void = {
let parser = parse(in) as *parser;
for (let i = 0z; i < len(expected); i += 1) {
let tok = match (scan(parser)) {
- tok: token => tok,
- void => abort("Expected token, got void"),
- syntaxerr => abort("Expected token, got syntax error"),
+ case tok: token =>
+ yield tok;
+ case void =>
+ abort("Expected token, got void");
+ case syntaxerr =>
+ abort("Expected token, got syntax error");
};
match (tok) {
- el: elementstart => {
- let ex = expected[i] as elementstart;
- assert(el == ex);
- },
- at: attribute => {
- let ex = expected[i] as attribute;
- assert(at.0 == ex.0 && at.1 == ex.1);
- },
- tx: text => {
- let ex = expected[i] as text;
- assert(tx == ex);
- },
- el: elementend => {
- let ex = expected[i] as elementend;
- assert(el == ex);
- },
+ case el: elementstart =>
+ let ex = expected[i] as elementstart;
+ assert(el == ex);
+ case at: attribute =>
+ let ex = expected[i] as attribute;
+ assert(at.0 == ex.0 && at.1 == ex.1);
+ case tx: text =>
+ let ex = expected[i] as text;
+ assert(tx == ex);
+ case el: elementend =>
+ let ex = expected[i] as elementend;
+ assert(el == ex);
};
};
if (error) {
diff --git a/format/xml/parser.ha b/format/xml/parser.ha
@@ -57,57 +57,61 @@ export fn parser_free(par: *parser) void = {
// extend their lifetime.
export fn scan(par: *parser) (token | void | error) = {
switch (par.state) {
- state::ROOT, state::ATTRS => want(par, OPTWS)?,
- * => void,
+ case state::ROOT, state::ATTRS => want(par, OPTWS)?;
+ case => void;
};
let rn: rune = match (bufio::scanrune(par.in)?) {
- io::EOF => if (par.state == state::ROOT) {
+ case io::EOF =>
+ if (par.state == state::ROOT) {
return syntaxerr;
- } else return void,
- rn: rune => rn,
- };
- return switch (par.state) {
- state::ROOT, state::ELEMENT => switch (rn) {
- '<' => {
- const next = match (bufio::scanrune(par.in)?) {
- io::EOF => return syntaxerr,
- rn: rune => {
- bufio::unreadrune(par.in, rn);
- yield rn;
- },
- };
- bufio::unreadrune(par.in, rn);
- switch (next) {
- '!' => return scan_comment(par),
- '?' => return scan_pi(par),
- * => void,
- };
- let el = scan_element(par)?;
- par.state = state::ATTRS;
- yield el;
- },
- * => {
- if (par.state == state::ROOT) {
- return syntaxerr;
- };
+ } else {
+ return;
+ };
+ case rn: rune =>
+ yield rn;
+ };
+ switch (par.state) {
+ case state::ROOT, state::ELEMENT =>
+ switch (rn) {
+ case '<' =>
+ const next = match (bufio::scanrune(par.in)?) {
+ case io::EOF =>
+ return syntaxerr;
+ case rn: rune =>
bufio::unreadrune(par.in, rn);
- yield scan_content(par)?;
- },
- },
- state::ATTRS => {
- if (rn == '/') {
- want(par, '>')?;
- par.state = state::ELEMENT;
- return poptag(par, "")?: elementend;
- } else if (rn == '>') {
- par.state = state::ELEMENT;
- return scan(par)?;
- } else if (!isnamestart(rn)) {
+ yield rn;
+ };
+ bufio::unreadrune(par.in, rn);
+ switch (next) {
+ case '!' =>
+ return scan_comment(par);
+ case '?' =>
+ return scan_pi(par);
+ case => void;
+ };
+ let el = scan_element(par)?;
+ par.state = state::ATTRS;
+ return el;
+ case =>
+ if (par.state == state::ROOT) {
return syntaxerr;
};
bufio::unreadrune(par.in, rn);
- yield scan_attr(par)?;
- },
+ return scan_content(par)?;
+ };
+ case state::ATTRS =>
+ if (rn == '/') {
+ want(par, '>')?;
+ par.state = state::ELEMENT;
+ return poptag(par, "")?: elementend;
+ } else if (rn == '>') {
+ par.state = state::ELEMENT;
+ return scan(par)?;
+ } else if (!isnamestart(rn)) {
+ return syntaxerr;
+ };
+ bufio::unreadrune(par.in, rn);
+ return scan_attr(par)?;
};
};
@@ -132,19 +136,20 @@ fn scan_attr(par: *parser) (token | error) = {
let quot = quote(par)?;
strio::reset(par.textbuf);
for (true) match (bufio::scanrune(par.in)?) {
- io::EOF => return syntaxerr,
- rn: rune => {
- rn = switch (rn) {
- '<' => return syntaxerr,
- '&' => {
- bufio::unreadrune(par.in, rn);
- yield scan_entity(par)?;
- },
- * => rn,
- };
- if (rn == quot) break;
- strio::appendrune(par.textbuf, rn)?;
- },
+ case io::EOF =>
+ return syntaxerr;
+ case rn: rune =>
+ rn = switch (rn) {
+ case '<' =>
+ return syntaxerr;
+ case '&' =>
+ bufio::unreadrune(par.in, rn);
+ yield scan_entity(par)?;
+ case =>
+ yield rn;
+ };
+ if (rn == quot) break;
+ strio::appendrune(par.textbuf, rn)?;
};
return (name, strio::string(par.textbuf)): attribute;
};
@@ -152,35 +157,42 @@ fn scan_attr(par: *parser) (token | error) = {
fn scan_comment(par: *parser) (token | void | error) = {
want(par, "<!")?;
match (bufio::scanrune(par.in)?) {
- io::EOF => return syntaxerr,
- rn: rune => switch (rn) {
- '-' => { // Comments
- want(par, '-')?;
- },
- '[' => {
- want(par, "CDATA[")?;
- if (par.state != state::ELEMENT) {
- return syntaxerr;
- };
- return scan_cdata(par)?;
- },
- * => return syntaxerr,
- },
+ case io::EOF =>
+ return syntaxerr;
+ case rn: rune =>
+ switch (rn) {
+ case '-' => // Comments
+ want(par, '-')?;
+ case '[' =>
+ want(par, "CDATA[")?;
+ if (par.state != state::ELEMENT) {
+ return syntaxerr;
+ };
+ return scan_cdata(par)?;
+ case =>
+ return syntaxerr;
+ };
};
for (true) {
- let rn = match (bufio::scanrune(par.in)?) {
- io::EOF => return syntaxerr,
- rn: rune => rn,
+ const rn = match (bufio::scanrune(par.in)?) {
+ case io::EOF =>
+ return syntaxerr;
+ case rn: rune =>
+ yield rn;
};
if (rn != '-') continue;
- let rn = match (bufio::scanrune(par.in)?) {
- io::EOF => return syntaxerr,
- rn: rune => rn,
+ const rn = match (bufio::scanrune(par.in)?) {
+ case io::EOF =>
+ return syntaxerr;
+ case rn: rune =>
+ yield rn;
};
if (rn != '-') continue;
- let rn = match (bufio::scanrune(par.in)?) {
- io::EOF => return syntaxerr,
- rn: rune => rn,
+ const rn = match (bufio::scanrune(par.in)?) {
+ case io::EOF =>
+ return syntaxerr;
+ case rn: rune =>
+ yield rn;
};
if (rn == '>') break;
};
@@ -190,25 +202,31 @@ fn scan_comment(par: *parser) (token | void | error) = {
fn scan_cdata(par: *parser) (text | error) = {
strio::reset(par.textbuf);
for (true) {
- let rn = match (bufio::scanrune(par.in)?) {
- io::EOF => return syntaxerr,
- rn: rune => rn,
+ const rn = match (bufio::scanrune(par.in)?) {
+ case io::EOF =>
+ return syntaxerr;
+ case rn: rune =>
+ yield rn;
};
if (rn != ']') {
strio::appendrune(par.textbuf, rn)!;
continue;
};
- let rn = match (bufio::scanrune(par.in)?) {
- io::EOF => return syntaxerr,
- rn: rune => rn,
+ const rn = match (bufio::scanrune(par.in)?) {
+ case io::EOF =>
+ return syntaxerr;
+ case rn: rune =>
+ yield rn;
};
if (rn != ']') {
strio::appendrune(par.textbuf, rn)!;
continue;
};
- let rn = match (bufio::scanrune(par.in)?) {
- io::EOF => return syntaxerr,
- rn: rune => rn,
+ const rn = match (bufio::scanrune(par.in)?) {
+ case io::EOF =>
+ return syntaxerr;
+ case rn: rune =>
+ yield rn;
};
if (rn == '>') break;
strio::appendrune(par.textbuf, rn)!;
@@ -219,21 +237,20 @@ fn scan_cdata(par: *parser) (text | error) = {
fn scan_content(par: *parser) (text | error) = {
strio::reset(par.textbuf);
for (true) match (bufio::scanrune(par.in)?) {
- io::EOF => break,
- rn: rune => {
- rn = switch (rn) {
- '<' => {
- bufio::unreadrune(par.in, rn);
- break;
- },
- '&', '%' => {
- bufio::unreadrune(par.in, rn);
- yield scan_entity(par)?;
- },
- * => rn,
- };
- strio::appendrune(par.textbuf, rn)?;
- },
+ case io::EOF =>
+ break;
+ case rn: rune =>
+ rn = switch (rn) {
+ case '<' =>
+ bufio::unreadrune(par.in, rn);
+ break;
+ case '&', '%' =>
+ bufio::unreadrune(par.in, rn);
+ yield scan_entity(par)?;
+ case =>
+ yield rn;
+ };
+ strio::appendrune(par.textbuf, rn)?;
};
return strio::string(par.textbuf);
};
@@ -242,11 +259,15 @@ fn scan_element(par: *parser) (token | error) = {
want(par, '<')?;
let close = false;
match (bufio::scanrune(par.in)?) {
- io::EOF => return syntaxerr,
- rn: rune => switch (rn) {
- '/' => close = true,
- * => bufio::unreadrune(par.in, rn),
- },
+ case io::EOF =>
+ return syntaxerr;
+ case rn: rune =>
+ switch (rn) {
+ case '/' =>
+ close = true;
+ case =>
+ bufio::unreadrune(par.in, rn);
+ };
};
let name = scan_name(par, par.namebuf)?;
if (close) {
@@ -261,33 +282,42 @@ fn scan_element(par: *parser) (token | error) = {
fn scan_entity(par: *parser) (rune | error) = {
want(par, '&')?;
let rn = match (bufio::scanrune(par.in)?) {
- io::EOF => return syntaxerr,
- rn: rune => rn,
- };
- return switch (rn) {
- '#' => scan_charref(par),
- '%' => syntaxerr, // XXX: Deliberate omission: PEReference
- * => {
- bufio::unreadrune(par.in, rn);
- yield scan_namedent(par);
- },
+ case io::EOF =>
+ return syntaxerr;
+ case rn: rune =>
+ yield rn;
+ };
+ switch (rn) {
+ case '#' =>
+ return scan_charref(par);
+ case '%' =>
+ return syntaxerr; // XXX: Deliberate omission: PEReference
+ case =>
+ bufio::unreadrune(par.in, rn);
+ return scan_namedent(par);
};
};
fn scan_charref(par: *parser) (rune | error) = {
let base = strconv::base::DEC;
match (bufio::scanrune(par.in)?) {
- io::EOF => return syntaxerr,
- rn: rune => if (rn == 'x') {
+ case io::EOF =>
+ return syntaxerr;
+ case rn: rune =>
+ if (rn == 'x') {
base = strconv::base::HEX;
- } else bufio::unreadrune(par.in, rn),
+ } else {
+ bufio::unreadrune(par.in, rn);
+ };
};
strio::reset(par.entbuf);
for (true) {
let rn = match (bufio::scanrune(par.in)?) {
- io::EOF => return syntaxerr,
- rn: rune => rn,
+ case io::EOF =>
+ return syntaxerr;
+ case rn: rune =>
+ yield rn;
};
if (ascii::isdigit(rn)) {
strio::appendrune(par.entbuf, rn)?;
@@ -300,16 +330,18 @@ fn scan_charref(par: *parser) (rune | error) = {
if (len(strio::string(par.entbuf)) == 0) {
return syntaxerr;
};
- return match (strconv::stou32b(strio::string(par.entbuf), base)) {
- u: u32 => u: rune,
- (strconv::invalid | strconv::overflow) => syntaxerr,
+ match (strconv::stou32b(strio::string(par.entbuf), base)) {
+ case u: u32 =>
+ return u: rune;
+ case (strconv::invalid | strconv::overflow) =>
+ return syntaxerr;
};
};
fn scan_namedent(par: *parser) (rune | error) = {
- let name = scan_name(par, par.entbuf)?;
+ const name = scan_name(par, par.entbuf)?;
want(par, ';')?;
- let map = [
+ const map = [
("lt", '<'),
("gt", '>'),
("amp", '&'),
@@ -330,8 +362,10 @@ fn scan_name(par: *parser, buf: *io::stream) (str | error) = {
strio::reset(buf);
const rn = match (bufio::scanrune(par.in)?) {
- io::EOF => return syntaxerr,
- rn: rune => rn,
+ case io::EOF =>
+ return syntaxerr;
+ case rn: rune =>
+ yield rn;
};
if (!isnamestart(rn)) {
return syntaxerr;
@@ -339,13 +373,15 @@ fn scan_name(par: *parser, buf: *io::stream) (str | error) = {
strio::appendrune(buf, rn)!;
for (true) match (bufio::scanrune(par.in)?) {
- io::EOF => return syntaxerr,
- rn: rune => if (isname(rn)) {
+ case io::EOF =>
+ return syntaxerr;
+ case rn: rune =>
+ if (isname(rn)) {
strio::appendrune(buf, rn)!;
} else {
bufio::unreadrune(par.in, rn);
break;
- },
+ };
};
return strio::string(buf);
@@ -365,21 +401,23 @@ fn prolog(par: *parser) (void | error) = {
let quot = quote(par)?;
want(par, OPTWS, "1.")?;
for (true) match (bufio::scanrune(par.in)?) {
- io::EOF => break,
- rn: rune => if (!ascii::isdigit(rn)) {
+ case io::EOF =>
+ break;
+ case rn: rune =>
+ if (!ascii::isdigit(rn)) {
bufio::unreadrune(par.in, rn);
break;
- },
+ };
};
want(par, quot)?;
let hadws = want(par, OPTWS)?;
let encoding = match (bufio::scanrune(par.in)) {
- io::EOF => false,
- rn: rune => {
- bufio::unreadrune(par.in, rn);
- yield hadws && rn == 'e';
- },
+ case io::EOF =>
+ yield false;
+ case rn: rune =>
+ bufio::unreadrune(par.in, rn);
+ yield hadws && rn == 'e';
};
if (encoding) {
let attr = scan_attr(par)? as attribute;
@@ -388,18 +426,22 @@ fn prolog(par: *parser) (void | error) = {
};
// XXX: Deliberate omission: all values other than utf-8
match (ascii::strcasecmp(attr.1, "utf-8")) {
- void => return utf8::invalid,
- n: int => if (n != 0) return utf8::invalid,
+ case void =>
+ return utf8::invalid;
+ case n: int =>
+ if (n != 0) {
+ return utf8::invalid;
+ };
};
};
let hadws = want(par, OPTWS)?;
let standalone = match (bufio::scanrune(par.in)) {
- io::EOF => false,
- rn: rune => {
- bufio::unreadrune(par.in, rn);
- yield hadws && rn == 's';
- },
+ case io::EOF =>
+ yield false;
+ case rn: rune =>
+ bufio::unreadrune(par.in, rn);
+ yield hadws && rn == 's';
};
if (standalone) {
let attr = scan_attr(par)? as attribute;
@@ -408,8 +450,12 @@ fn prolog(par: *parser) (void | error) = {
};
// XXX: Deliberate omission: non-standalone documents
match (ascii::strcasecmp(attr.1, "yes")) {
- void => return syntaxerr,
- n: int => if (n != 0) return syntaxerr,
+ case void =>
+ return syntaxerr;
+ case n: int =>
+ if (n != 0) {
+ return syntaxerr;
+ };
};
};
@@ -424,48 +470,55 @@ def WS: whitespace = true;
def OPTWS: whitespace = false;
fn quote(par: *parser) (rune | error) = {
- return match (bufio::scanrune(par.in)?) {
- * => return syntaxerr,
- rn: rune => switch (rn) {
- '"', '\'' => rn,
- * => return syntaxerr,
- },
+ match (bufio::scanrune(par.in)?) {
+ case rn: rune =>
+ switch (rn) {
+ case '"', '\'' =>
+ return rn;
+ case =>
+ return syntaxerr;
+ };
+ case =>
+ return syntaxerr;
};
};
fn want(par: *parser, tok: (rune | str | whitespace)...) (bool | error) = {
let hadws = false;
for (let i = 0z; i < len(tok); i += 1) match (tok[i]) {
- x: rune => {
- let have = match (bufio::scanrune(par.in)?) {
- io::EOF => return syntaxerr,
- rn: rune => rn,
- };
- if (have != x) {
- return syntaxerr;
- };
- },
- x: str => {
- let iter = strings::iter(x);
- for (true) match (strings::next(&iter)) {
- rn: rune => want(par, rn)?,
- void => break,
- };
- },
- ws: whitespace => {
- let n = 0;
- for (true; n += 1) match (bufio::scanrune(par.in)?) {
- io::EOF => break,
- rn: rune => if (!ascii::isspace(rn)) {
- bufio::unreadrune(par.in, rn);
- break;
- },
- };
- if (ws && n < 1) {
- return syntaxerr;
+ case x: rune =>
+ let have = match (bufio::scanrune(par.in)?) {
+ case io::EOF =>
+ return syntaxerr;
+ case rn: rune =>
+ yield rn;
+ };
+ if (have != x) {
+ return syntaxerr;
+ };
+ case x: str =>
+ let iter = strings::iter(x);
+ for (true) match (strings::next(&iter)) {
+ case rn: rune =>
+ want(par, rn)?;
+ case void =>
+ break;
+ };
+ case ws: whitespace =>
+ let n = 0;
+ for (true; n += 1) match (bufio::scanrune(par.in)?) {
+ case io::EOF =>
+ break;
+ case rn: rune =>
+ if (!ascii::isspace(rn)) {
+ bufio::unreadrune(par.in, rn);
+ break;
};
- hadws = n >= 1;
- },
+ };
+ if (ws && n < 1) {
+ return syntaxerr;
+ };
+ hadws = n >= 1;
};
return hadws;
};
diff --git a/format/xml/types.ha b/format/xml/types.ha
@@ -43,10 +43,11 @@ export type syntaxerr = !void; // TODO: Add line number?
export type error = !(syntaxerr | utf8::invalid | io::error);
// Converts an [[error]] to a user-friendly string representation.
-export fn strerror(err: error) const str = {
- return match (err) {
- syntaxerr => "Syntax error",
- utf8::invalid => "Document is not valid UTF-8",
- err: io::error => io::strerror(err),
- };
+export fn strerror(err: error) const str = match (err) {
+case syntaxerr =>
+ yield "Syntax error";
+case utf8::invalid =>
+ yield "Document is not valid UTF-8";
+case err: io::error =>
+ yield io::strerror(err);
};
diff --git a/fs/fs.ha b/fs/fs.ha
@@ -5,17 +5,20 @@ use path;
// Closes a filesystem. The fs cannot be used after this function is called.
export fn close(fs: *fs) void = {
match (fs.close) {
- null => void,
- f: *closefunc => f(fs),
+ case null => void;
+ case f: *closefunc =>
+ f(fs);
};
};
// Opens a file. If no flags are provided, the default read/write mode is
// RDONLY.
export fn open(fs: *fs, path: str, flags: flags...) (*io::stream | error) = {
- return match (fs.open) {
- null => errors::unsupported,
- f: *openfunc => f(fs, path, flags...),
+ match (fs.open) {
+ case null =>
+ return errors::unsupported;
+ case f: *openfunc =>
+ return f(fs, path, flags...);
};
};
@@ -25,9 +28,11 @@ export fn open(fs: *fs, path: str, flags: flags...) (*io::stream | error) = {
//
// If no flags are provided, the default read/write mode is RDONLY.
export fn open_file(fs: *fs, path: str, flags: flags...) (io::file | error) = {
- return match (fs.openfile) {
- null => errors::unsupported,
- f: *openfilefunc => f(fs, path, flags...),
+ match (fs.openfile) {
+ case null =>
+ return errors::unsupported;
+ case f: *openfilefunc =>
+ return f(fs, path, flags...);
};
};
@@ -39,9 +44,11 @@ export fn create(
mode: mode,
flags: flags...
) (*io::stream | error) = {
- return match (fs.create) {
- null => errors::unsupported,
- f: *createfunc => f(fs, path, mode, flags...),
+ match (fs.create) {
+ case null =>
+ return errors::unsupported;
+ case f: *createfunc =>
+ return f(fs, path, mode, flags...);
};
};
@@ -57,17 +64,21 @@ export fn create_file(
mode: mode,
flags: flags...
) (io::file | error) = {
- return match (fs.createfile) {
- null => errors::unsupported,
- f: *createfilefunc => f(fs, path, mode, flags...),
+ match (fs.createfile) {
+ case null =>
+ return errors::unsupported;
+ case f: *createfilefunc =>
+ return f(fs, path, mode, flags...);
};
};
// Removes a file.
export fn remove(fs: *fs, path: str) (void | error) = {
- return match (fs.remove) {
- null => errors::unsupported,
- f: *removefunc => f(fs, path),
+ match (fs.remove) {
+ case null =>
+ return errors::unsupported;
+ case f: *removefunc =>
+ return f(fs, path);
};
};
@@ -75,9 +86,11 @@ export fn remove(fs: *fs, path: str) (void | error) = {
// are both on the same filesystem. See [[move]] for an implementation which
// falls back on a "copy & remove" procedure in this situation.
export fn rename(fs: *fs, oldpath: str, newpath: str) (void | error) = {
- return match (fs.rename) {
- null => errors::unsupported,
- f: *renamefunc => f(fs, oldpath, newpath),
+ match (fs.rename) {
+ case null =>
+ return errors::unsupported;
+ case f: *renamefunc =>
+ return f(fs, oldpath, newpath);
};
};
@@ -85,10 +98,11 @@ export fn rename(fs: *fs, oldpath: str, newpath: str) (void | error) = {
// copy and remove if necessary.
export fn move(fs: *fs, oldpath: str, newpath: str) (void | error) = {
match (rename(fs, oldpath, newpath)) {
- cannotrename => void, // Fallback
- errors::unsupported => void, // Fallback
- void => return, // Success
- err: error => return err,
+ case (cannotrename | errors::unsupported) => void; // Fallback
+ case err: error =>
+ return err;
+ case void =>
+ return; // Success
};
// TODO:
// - If an error occurs, remove the new file.
@@ -107,18 +121,22 @@ export fn move(fs: *fs, oldpath: str, newpath: str) (void | error) = {
// Pass empty string to yield from the root. The order in which entries are
// returned is undefined.
export fn iter(fs: *fs, path: str) (*iterator | error) = {
- return match (fs.iter) {
- null => errors::unsupported,
- f: *iterfunc => f(fs, path),
+ match (fs.iter) {
+ case null =>
+ return errors::unsupported;
+ case f: *iterfunc =>
+ return f(fs, path);
};
};
// Obtains information about a file or directory. If the target is a symlink,
// information is returned about the link, not its target.
export fn stat(fs: *fs, path: str) (filestat | error) = {
- return match (fs.stat) {
- null => errors::unsupported,
- f: *statfunc => f(fs, path),
+ match (fs.stat) {
+ case null =>
+ return errors::unsupported;
+ case f: *statfunc =>
+ return f(fs, path);
};
};
@@ -126,17 +144,21 @@ export fn stat(fs: *fs, path: str) (filestat | error) = {
// separately from the parent filesystem, and its lifetime can outlive that of
// its parent.
export fn subdir(fs: *fs, path: str) (*fs | error) = {
- return match (fs.subdir) {
- null => errors::unsupported,
- f: *subdirfunc => f(fs, path),
+ match (fs.subdir) {
+ case null =>
+ return errors::unsupported;
+ case f: *subdirfunc =>
+ return f(fs, path);
};
};
// Creates a directory.
export fn mkdir(fs: *fs, path: str) (void | error) = {
- return match (fs.mkdir) {
- null => errors::unsupported,
- f: *mkdirfunc => f(fs, path),
+ match (fs.mkdir) {
+ case null =>
+ return errors::unsupported;
+ case f: *mkdirfunc =>
+ return f(fs, path);
};
};
@@ -145,15 +167,17 @@ export fn mkdirs(fs: *fs, path: str) (void | error) = {
let parent = path::dirname(path);
if (path != parent) {
match (mkdirs(fs, parent)) {
- errors::exists => void,
- err: error => return err,
- void => void,
+ case errors::exists => void;
+ case void => void;
+ case err: error =>
+ return err;
};
};
- return match (mkdir(fs, path)) {
- errors::exists => void,
- err: error => err,
- void => void,
+ match (mkdir(fs, path)) {
+ case errors::exists => void;
+ case void => void;
+ case err: error =>
+ return err;
};
};
@@ -163,28 +187,33 @@ export fn rmdir(fs: *fs, path: str) (void | error) = {
if (path == "") {
return errors::invalid;
};
- return match (fs.rmdir) {
- null => errors::unsupported,
- f: *rmdirfunc => f(fs, path),
+ match (fs.rmdir) {
+ case null =>
+ return errors::unsupported;
+ case f: *rmdirfunc =>
+ return f(fs, path);
};
};
// Removes a directory, and anything in it.
export fn rmdirall(fs: *fs, path: str) (void | error) = {
let it = iter(fs, path)?;
- for (true) match (next(it)) {
- ent: dirent => {
+ for (true) {
+ match (next(it)) {
+ case ent: dirent =>
if (ent.name == "." || ent.name == "..") {
continue;
};
let p = path::join(path, ent.name);
defer free(p);
+
switch (ent.ftype & mode::DIR) {
- mode::DIR => rmdirall(fs, p)?,
- * => remove(fs, p)?,
+ case mode::DIR => rmdirall(fs, p)?;
+ case => remove(fs, p)?;
};
- },
- void => break,
+ case void =>
+ break;
+ };
};
if (path != "") {
return rmdir(fs, path);
@@ -194,28 +223,32 @@ export fn rmdirall(fs: *fs, path: str) (void | error) = {
// Creates a directory and returns a subdir for it. Some filesystems support
// doing this operation atomically, but if not, a fallback is used.
export fn mksubdir(fs: *fs, path: str) (*fs | error) = {
- return match (fs.mksubdir) {
- null => {
- mkdir(fs, path)?;
- yield subdir(fs, path);
- },
- f: *mksubdirfunc => f(fs, path),
+ match (fs.mksubdir) {
+ case null =>
+ mkdir(fs, path)?;
+ return subdir(fs, path);
+ case f: *mksubdirfunc =>
+ return f(fs, path);
};
};
// Changes mode flags on a file or directory.
export fn chmod(fs: *fs, path: str, mode: mode) (void | error) = {
- return match (fs.chmod) {
- f: *chmodfunc => f(fs, path, mode),
- null => errors::unsupported,
+ match (fs.chmod) {
+ case null =>
+ return errors::unsupported;
+ case f: *chmodfunc =>
+ return f(fs, path, mode);
};
};
// Changes ownership of a file.
export fn chown(fs: *fs, path: str, uid: uint, gid: uint) (void | error) = {
- return match (fs.chown) {
- f: *chownfunc => f(fs, path, uid, gid),
- null => errors::unsupported,
+ match (fs.chown) {
+ case null =>
+ return errors::unsupported;
+ case f: *chownfunc =>
+ return f(fs, path, uid, gid);
};
};
@@ -224,8 +257,9 @@ export fn chown(fs: *fs, path: str, uid: uint, gid: uint) (void | error) = {
// the return value.
export fn resolve(fs: *fs, path: str) str = {
match (fs.resolve) {
- f: *resolvefunc => return f(fs, path),
- null => void,
+ case null => void;
+ case f: *resolvefunc =>
+ return f(fs, path);
};
abort(); // TODO
};
diff --git a/fs/mem/+test.ha b/fs/mem/+test.ha
@@ -57,8 +57,10 @@ use strconv;
defer free(it);
let count = 0z;
for (true) match (it.next(it)) {
- void => break,
- d: fs::dirent => count += 1,
+ case void =>
+ break;
+ case d: fs::dirent =>
+ count += 1;
};
assert(count == 6);
@@ -136,8 +138,10 @@ use strconv;
defer free(it);
let count = 0z;
for (true) match (it.next(it)) {
- void => break,
- d: fs::dirent => count += 1,
+ case void =>
+ break;
+ case d: fs::dirent =>
+ count += 1;
};
assert(count == limit);
diff --git a/fs/mem/mem.ha b/fs/mem/mem.ha
@@ -77,10 +77,14 @@ fn file_flags(flags: fs::flags...) ((io::mode, bool) | fs::error) = {
};
let appnd = fl & fs::flags::APPEND == fs::flags::APPEND;
let mode = switch (fl & (~fs::flags::APPEND)) {
- fs::flags::RDONLY => io::mode::READ,
- fs::flags::WRONLY => io::mode::WRITE,
- fs::flags::RDWR => io::mode::RDWR,
- * => abort("invalid flag combination"),
+ case fs::flags::RDONLY =>
+ yield io::mode::READ;
+ case fs::flags::WRONLY =>
+ yield io::mode::WRITE;
+ case fs::flags::RDWR =>
+ yield io::mode::RDWR;
+ case =>
+ abort("invalid flag combination");
};
return (mode, appnd);
};
@@ -96,8 +100,9 @@ fn create(
let parent = fs: *inode;
match (inode_find(parent, path)) {
- errors::noentry => void,
- * => return errors::exists,
+ case errors::noentry => void;
+ case =>
+ return errors::exists;
};
if (path::dirname(path) != path) {
parent = inode_find(parent, path::dirname(path))?;
@@ -129,13 +134,15 @@ fn open(
};
fn stat(fs: *fs::fs, path: str) (fs::filestat | fs::error) = {
- return match(inode_find(fs: *inode, path)?.data) {
- directory => fs::filestat { mode = fs::mode::DIR | 0o777, ... },
- f: file => fs::filestat {
+ match (inode_find(fs: *inode, path)?.data) {
+ case directory =>
+ return fs::filestat { mode = fs::mode::DIR | 0o777, ... };
+ case f: file =>
+ return fs::filestat {
mode = fs::mode::REG | 0o777,
mask = fs::stat_mask::SIZE,
sz = len(f),
- },
+ };
};
};
@@ -148,8 +155,9 @@ fn mkdir(fs: *fs::fs, path: str) (void | fs::error) = {
fn mksubdir(fs: *fs::fs, path: str) (*fs::fs | fs::error) = {
let parent = fs: *inode;
match (inode_find(parent, path)) {
- errors::noentry => void,
- * => return errors::exists,
+ case errors::noentry => void;
+ case =>
+ return errors::exists;
};
if (path::dirname(path) != path) {
parent = inode_find(parent, path::dirname(path))?;
@@ -190,15 +198,18 @@ fn iter(fs: *fs::fs, path: str) (*fs::iterator | fs::error) = {
}): *fs::iterator;
};
-fn next(iter: *fs::iterator) (fs::dirent | void) = match (_next(iter)) {
- null => void,
- ino: *inode => fs::dirent {
- name = ino.name,
- ftype = match (ino.data) {
- directory => fs::mode::DIR,
- file => fs::mode::REG,
- },
- },
+fn next(iter: *fs::iterator) (fs::dirent | void) = {
+ match (_next(iter)) {
+ case null => void;
+ case ino: *inode =>
+ return fs::dirent {
+ name = ino.name,
+ ftype = match (ino.data) {
+ case directory => yield fs::mode::DIR;
+ case file => yield fs::mode::REG;
+ },
+ };
+ };
};
fn _next(it: *fs::iterator) nullable *inode = {
@@ -211,11 +222,11 @@ fn _next(it: *fs::iterator) nullable *inode = {
let p = iter.parent.data as directory;
iter.idx += 1;
for (iter.idx < len(p.ents)) match (p.ents[iter.idx]) {
- null => iter.idx += 1,
- ino: *inode => {
- iter.curr = ino.next;
- return ino;
- },
+ case null =>
+ iter.idx += 1;
+ case ino: *inode =>
+ iter.curr = ino.next;
+ return ino;
};
return null;
};
@@ -260,15 +271,18 @@ fn close_rec(ino: *inode) void = {
};
let it = iterator { it = fs_iter, parent = ino, ... };
for (true) match (_next(&it: *fs::iterator)) {
- null => break,
- ino: *inode => {
- ino.parent = null;
- match (ino.data) {
- file => inode_free(ino),
- directory => close_rec(ino),
- * => abort("unreachable"),
- };
- },
+ case null =>
+ break;
+ case ino: *inode =>
+ ino.parent = null;
+ match (ino.data) {
+ case file =>
+ inode_free(ino);
+ case directory =>
+ close_rec(ino);
+ case =>
+ abort("unreachable");
+ };
};
inode_free(ino);
};
diff --git a/fs/mem/util.ha b/fs/mem/util.ha
@@ -32,11 +32,11 @@ fn ensure(parent: *inode) void = {
parent.data = dir;
for (let i = 0z; i < len(old); i += 1) {
for (true) match (old[i]) {
- null => break,
- ino: *inode => {
- old[i] = ino.next;
- _inode_insert(parent, ino);
- },
+ case null =>
+ break;
+ case ino: *inode =>
+ old[i] = ino.next;
+ _inode_insert(parent, ino);
};
};
};
@@ -62,15 +62,15 @@ fn unlink(parent: *inode, ino: *inode) void = {
let prev = &p.ents[ino.hash % len(p.ents): u64];
let it = *prev;
for (true) match (it) {
- null => break,
- ii: *inode => {
- if (ii.hash == ino.hash && ii.name == ino.name) {
- *prev = ii.next;
- break;
- };
- prev = &ii.next;
- it = ii.next;
- },
+ case null =>
+ break;
+ case ii: *inode =>
+ if (ii.hash == ino.hash && ii.name == ino.name) {
+ *prev = ii.next;
+ break;
+ };
+ prev = &ii.next;
+ it = ii.next;
};
p.sz -= 1;
parent.data = p;
@@ -79,8 +79,10 @@ fn unlink(parent: *inode, ino: *inode) void = {
fn inode_free(ino: *inode) void = {
match (ino.data) {
- d: directory => free(d.ents),
- f: file => free(f),
+ case d: directory =>
+ free(d.ents);
+ case f: file =>
+ free(f);
};
free(ino.name);
free(ino);
@@ -98,16 +100,18 @@ fn find_rec(dir: *inode, name: str, it: *path::iterator) (*inode | fs::error) =
let p = dir.data as directory;
let bucket = p.ents[hash_of(name) % len(p.ents): u64];
for (true) match (bucket) {
- null => break,
- ino: *inode => {
- if (name == ino.name) {
- return match (path::next(it)) {
- void => ino,
- name: str => find_rec(ino, name, it),
- };
+ case null =>
+ break;
+ case ino: *inode =>
+ if (name == ino.name) {
+ match (path::next(it)) {
+ case void =>
+ return ino;
+ case name: str =>
+ return find_rec(ino, name, it);
};
- bucket = ino.next;
- },
+ };
+ bucket = ino.next;
};
return errors::noentry;
};
diff --git a/fs/util.ha b/fs/util.ha
@@ -5,13 +5,20 @@ use strings;
// Returns a human-friendly representation of an error.
export fn strerror(err: error) const str = match (err) {
- wrongtype => "Wrong entry type for requested operation",
- cannotrename => "Unable to perform rename operation (try move instead)",
- errors::noentry => "File or directory not found",
- errors::noaccess => "Permission denied",
- errors::exists => "File or directory exists",
- errors::invalid => "Invalid argument",
- err: io::error => io::strerror(err),
+case wrongtype =>
+ yield "Wrong entry type for requested operation";
+case cannotrename =>
+ yield "Unable to perform rename operation (try move instead)";
+case errors::noentry =>
+ yield "File or directory not found";
+case errors::noaccess =>
+ yield "Permission denied";
+case errors::exists =>
+ yield "File or directory exists";
+case errors::invalid =>
+ yield "Invalid argument";
+case err: io::error =>
+ yield io::strerror(err);
};
// Converts a mode into a Unix-like mode string (e.g. "-rw-r--r--"). The string
@@ -88,8 +95,10 @@ export fn readdir(fs: *fs, path: str) ([]dirent | error) = {
let ents: []dirent = [];
for (true) {
match (next(i)) {
- d: dirent => append(ents, dirent_dup(&d)),
- void => break,
+ case d: dirent =>
+ append(ents, dirent_dup(&d));
+ case void =>
+ break;
};
};
return ents;
diff --git a/getopt/getopts.ha b/getopt/getopts.ha
@@ -126,13 +126,18 @@ export fn parse(args: []str, help: help...) command = {
const r = next as rune;
for (let j = 0z; j < len(help); j += 1) :help {
let p: parameter_help = match (help[j]) {
- cmd_help => continue :help,
- f: flag_help => if (r == f.0) {
+ case cmd_help =>
+ continue :help;
+ case f: flag_help =>
+ if (r == f.0) {
append(opts, (r, ""));
continue :flag;
- } else continue :help,
- p: parameter_help => if (r == p.0) p
- else continue :help,
+ } else {
+ continue :help;
+ };
+ case p: parameter_help =>
+ yield if (r == p.0) p else
+ continue :help;
};
if (len(d.src) == d.offs) {
if (i + 1 >= len(args)) {
@@ -156,13 +161,13 @@ export fn parse(args: []str, help: help...) command = {
os::exit(1);
};
match (next) {
- rune => abort(), // Unreachable
- void => void,
- (utf8::more | utf8::invalid) => {
- errmsg(args[0], "invalid UTF-8 in arguments",
- void, help);
- os::exit(1);
- },
+ case void => void;
+ case rune =>
+ abort(); // Unreachable
+ case (utf8::more | utf8::invalid) =>
+ errmsg(args[0], "invalid UTF-8 in arguments", void,
+ help);
+ os::exit(1);
};
};
return command {
@@ -229,29 +234,28 @@ export fn printhelp(s: *io::stream, name: str, help: []help) void = {
printusage(s, name, help);
for (let i = 0z; i < len(help); i += 1) match (help[i]) {
- cmd_help => void,
- (flag_help | parameter_help) => {
- // Only print this if there are flags to show
- fmt::fprint(s, "\n")!;
- break;
- },
+ case cmd_help => void;
+ case (flag_help | parameter_help) =>
+ // Only print this if there are flags to show
+ fmt::fprint(s, "\n")!;
+ break;
};
for (let i = 0z; i < len(help); i += 1) match (help[i]) {
- cmd_help => void,
- f: flag_help => {
- fmt::fprintfln(s, "-{}: {}", f.0: rune, f.1)!;
- },
- p: parameter_help => {
- fmt::fprintfln(s, "-{} <{}>: {}", p.0: rune, p.1, p.2)!;
- },
+ case cmd_help => void;
+ case f: flag_help =>
+ fmt::fprintfln(s, "-{}: {}", f.0: rune, f.1)!;
+ case p: parameter_help =>
+ fmt::fprintfln(s, "-{} <{}>: {}", p.0: rune, p.1, p.2)!;
};
};
fn errmsg(name: str, err: str, opt: (rune | void), help: []help) void = {
fmt::errorfln("{}: {}{}", name, err, match (opt) {
- r: rune => r,
- void => "",
+ case r: rune =>
+ yield r;
+ case void =>
+ yield "";
})!;
printusage(os::stderr, name, help);
};
diff --git a/hare/ast/decl.ha b/hare/ast/decl.ha
@@ -60,34 +60,30 @@ export type decl = struct {
// Frees resources associated with a declaration.
export fn decl_free(d: decl) void = match (d.decl) {
- g: []decl_global => {
- for (let i = 0z; i < len(g); i += 1) {
- free(g[i].symbol);
- ident_free(g[i].ident);
- type_free(g[i]._type);
- expr_free(g[i].init);
- };
- free(g);
- },
- t: []decl_type => {
- for (let i = 0z; i < len(t); i += 1) {
- ident_free(t[i].ident);
- type_free(t[i]._type);
- };
- free(t);
- },
- f: decl_func => {
- free(f.symbol);
- ident_free(f.ident);
- type_free(f.prototype);
- if (f.body is expr) expr_free(f.body as expr);
- },
- c: []decl_const => {
- for (let i = 0z; i < len(c); i += 1) {
- ident_free(c[i].ident);
- type_free(c[i]._type);
- expr_free(c[i].init);
- };
- free(c);
- },
+case g: []decl_global =>
+ for (let i = 0z; i < len(g); i += 1) {
+ free(g[i].symbol);
+ ident_free(g[i].ident);
+ type_free(g[i]._type);
+ expr_free(g[i].init);
+ };
+ free(g);
+case t: []decl_type =>
+ for (let i = 0z; i < len(t); i += 1) {
+ ident_free(t[i].ident);
+ type_free(t[i]._type);
+ };
+ free(t);
+case f: decl_func =>
+ free(f.symbol);
+ ident_free(f.ident);
+ type_free(f.prototype);
+ if (f.body is expr) expr_free(f.body as expr);
+case c: []decl_const =>
+ for (let i = 0z; i < len(c); i += 1) {
+ ident_free(c[i].ident);
+ type_free(c[i]._type);
+ expr_free(c[i].init);
+ };
+ free(c);
};
diff --git a/hare/ast/expr.ha b/hare/ast/expr.ha
@@ -276,7 +276,7 @@ export type len_expr = *expr;
export type match_case = struct {
name: str,
_type: *_type,
- value: *expr,
+ exprs: []*expr,
};
// A match expression.
@@ -285,11 +285,11 @@ export type match_case = struct {
export type match_expr = struct {
value: *expr,
cases: []match_case,
- default: nullable *expr,
+ default: []*expr,
};
// An offset expression.
-//
+//
// offset(foo.bar)
export type offset_expr = void; // TODO
@@ -324,8 +324,8 @@ export type slice_expr = struct {
//
// value => expr
export type switch_case = struct {
- options: []*expr, // [] for *
- value: *expr,
+ options: []*expr, // [] for default case
+ exprs: []*expr,
};
// A switch expression.
@@ -378,177 +378,185 @@ export type expr = struct {
// Frees resources associated with a Hare [[expr]]ession.
export fn expr_free(e: (expr | nullable *expr)) void = match (e) {
- e: nullable *expr => match (e) {
- null => void,
- e: *expr => {
- expr_free(*e);
- free(e);
- },
- },
- e: expr => match (e.expr) {
- a: access_expr => match (a) {
- i: access_identifier => ident_free(i),
- i: access_index => {
- expr_free(i.object);
- expr_free(i.index);
- },
- f: access_field => {
- expr_free(f.object);
- free(f.field);
- },
- t: access_tuple => {
- expr_free(t.object);
- expr_free(t.value);
- },
- },
- a: alloc_expr => {
- expr_free(a.init);
- expr_free(a.capacity);
- },
- a: append_expr => {
- expr_free(a.object);
- match (a.variadic) {
- null => void,
- v: *expr => expr_free(v),
- };
+case e: nullable *expr =>
+ match (e) {
+ case null => void;
+ case e: *expr =>
+ expr_free(*e);
+ free(e);
+ };
+case e: expr =>
+ match (e.expr) {
+ case a: access_expr =>
+ match (a) {
+ case i: access_identifier =>
+ ident_free(i);
+ case i: access_index =>
+ expr_free(i.object);
+ expr_free(i.index);
+ case f: access_field =>
+ expr_free(f.object);
+ free(f.field);
+ case t: access_tuple =>
+ expr_free(t.object);
+ expr_free(t.value);
+ };
+ case a: alloc_expr =>
+ expr_free(a.init);
+ expr_free(a.capacity);
+ case a: append_expr =>
+ expr_free(a.object);
+ match (a.variadic) {
+ case null => void;
+ case v: *expr =>
+ expr_free(v);
+ };
+ for (let i = 0z; i < len(a.values); i += 1) {
+ expr_free(a.values[i]);
+ };
+ free(a.values);
+ case a: assert_expr =>
+ expr_free(a.cond);
+ expr_free(a.message);
+ case a: assign_expr =>
+ expr_free(a.object);
+ expr_free(a.value);
+ case b: binarithm_expr =>
+ expr_free(b.lvalue);
+ expr_free(b.rvalue);
+ case b: binding_expr =>
+ for (let i = 0z; i < len(b.bindings); i += 1) {
+ free(b.bindings[i].name);
+ type_free(b.bindings[i]._type);
+ expr_free(b.bindings[i].init);
+ };
+ free(b.bindings);
+ case b: break_expr =>
+ free(b);
+ case c: call_expr =>
+ expr_free(c.lvalue);
+ for (let i = 0z; i < len(c.args); i += 1) {
+ expr_free(c.args[i]);
+ };
+ free(c.args);
+ case c: cast_expr =>
+ expr_free(c.value);
+ type_free(c._type);
+ case c: compound_expr =>
+ for (let i = 0z; i < len(c.exprs); i += 1) {
+ expr_free(c.exprs[i]);
+ };
+ free(c.exprs);
+ free(c.label);
+ case c: constant_expr =>
+ match (c) {
+ case (void | _null | ...lex::value) => void;
+ case a: array_constant =>
for (let i = 0z; i < len(a.values); i += 1) {
expr_free(a.values[i]);
};
free(a.values);
- },
- a: assert_expr => {
- expr_free(a.cond);
- expr_free(a.message);
- },
- a: assign_expr => {
- expr_free(a.object);
- expr_free(a.value);
- },
- b: binarithm_expr => {
- expr_free(b.lvalue);
- expr_free(b.rvalue);
- },
- b: binding_expr => {
- for (let i = 0z; i < len(b.bindings); i += 1) {
- free(b.bindings[i].name);
- type_free(b.bindings[i]._type);
- expr_free(b.bindings[i].init);
- };
- free(b.bindings);
- },
- b: break_expr => free(b),
- c: call_expr => {
- expr_free(c.lvalue);
- for (let i = 0z; i < len(c.args); i += 1) {
- expr_free(c.args[i]);
- };
- free(c.args);
- },
- c: cast_expr => {
- expr_free(c.value);
- type_free(c._type);
- },
- c: compound_expr => {
- for (let i = 0z; i < len(c.exprs); i += 1) {
- expr_free(c.exprs[i]);
+ case s: struct_constant =>
+ struct_constant_free(s);
+ case t: tuple_constant =>
+ for (let i = 0z; i < len(t); i += 1) {
+ expr_free(t[i]);
};
- free(c.exprs);
- free(c.label);
- },
- c: constant_expr => match(c) {
- (void | _null | ...lex::value) => void,
- a: array_constant => {
- for (let i = 0z; i < len(a.values); i += 1) {
- expr_free(a.values[i]);
- };
- free(a.values);
- },
- s: struct_constant => struct_constant_free(s),
- t: tuple_constant => {
- for (let i = 0z; i < len(t); i += 1) {
- expr_free(t[i]);
- };
- free(t);
- },
- },
- c: continue_expr => free(c),
- d: defer_expr => expr_free(d: *expr),
- d: delete_expr => expr_free(d.object),
- f: for_expr => {
- expr_free(f.bindings);
- expr_free(f.cond);
- expr_free(f.afterthought);
- expr_free(f.body);
- },
- f: free_expr => expr_free(f: *expr),
- i: if_expr => {
- expr_free(i.cond);
- expr_free(i.tbranch);
- expr_free(i.fbranch);
- },
- e: insert_expr => {
- expr_free(e.object);
- match (e.variadic) {
- null => void,
- v: *expr => expr_free(v),
- };
- for (let i = 0z; i < len(e.values); i += 1) {
- expr_free(e.values[i]);
+ free(t);
+ };
+ case c: continue_expr =>
+ free(c);
+ case d: defer_expr =>
+ expr_free(d: *expr);
+ case d: delete_expr =>
+ expr_free(d.object);
+ case f: for_expr =>
+ expr_free(f.bindings);
+ expr_free(f.cond);
+ expr_free(f.afterthought);
+ expr_free(f.body);
+ case f: free_expr =>
+ expr_free(f: *expr);
+ case i: if_expr =>
+ expr_free(i.cond);
+ expr_free(i.tbranch);
+ expr_free(i.fbranch);
+ case e: insert_expr =>
+ expr_free(e.object);
+ match (e.variadic) {
+ case null => void;
+ case v: *expr =>
+ expr_free(v);
+ };
+ for (let i = 0z; i < len(e.values); i += 1) {
+ expr_free(e.values[i]);
+ };
+ free(e.values);
+ case l: len_expr =>
+ expr_free(l: *expr);
+ case m: match_expr =>
+ expr_free(m.value);
+ for (let i = 0z; i < len(m.cases); i += 1) {
+ free(m.cases[i].name);
+ type_free(m.cases[i]._type);
+ const exprs = m.cases[i].exprs;
+ for (let i = 0z; i < len(exprs); i += 1) {
+ expr_free(exprs[i]);
};
- free(e.values);
- },
- l: len_expr => expr_free(l: *expr),
- m: match_expr => {
- expr_free(m.value);
- for (let i = 0z; i < len(m.cases); i += 1) {
- free(m.cases[i].name);
- type_free(m.cases[i]._type);
- expr_free(m.cases[i].value);
+ free(exprs);
+ };
+ free(m.cases);
+ for (let i = 0z; i < len(m.default); i += 1) {
+ expr_free(m.default[i]);
+ };
+ free(m.default);
+ case offset_expr =>
+ abort(); // TODO
+ case p: propagate_expr =>
+ expr_free(p.expr);
+ case r: return_expr =>
+ expr_free(r: *expr);
+ case s: size_expr =>
+ type_free(s: *_type);
+ case s: slice_expr =>
+ expr_free(s.object);
+ expr_free(s.start);
+ expr_free(s.end);
+ case s: switch_expr =>
+ expr_free(s.value);
+ for (let i = 0z; i < len(s.cases); i += 1) {
+ let opts = s.cases[i].options;
+ for (let j = 0z; j < len(opts); j += 1) {
+ expr_free(opts[j]);
};
- free(m.cases);
- },
- offset_expr => abort(), // TODO
- p: propagate_expr => expr_free(p.expr),
- r: return_expr => expr_free(r: *expr),
- s: size_expr => type_free(s: *_type),
- s: slice_expr => {
- expr_free(s.object);
- expr_free(s.start);
- expr_free(s.end);
- },
- s: switch_expr => {
- expr_free(s.value);
- for (let i = 0z; i < len(s.cases); i += 1) {
- let opts = s.cases[i].options;
- for (let j = 0z; j < len(opts); j += 1) {
- expr_free(opts[j]);
- };
- free(opts);
- expr_free(s.cases[i].value);
+ free(opts);
+
+ let exprs = s.cases[i].exprs;
+ for (let j = 0z; j < len(exprs); j += 1) {
+ expr_free(exprs[j]);
};
- free(s.cases);
- },
- u: unarithm_expr => expr_free(u.operand),
- y: yield_expr => {
- free(y.label);
- expr_free(y.value);
- },
- },
+ free(exprs);
+ };
+ free(s.cases);
+ case u: unarithm_expr =>
+ expr_free(u.operand);
+ case y: yield_expr =>
+ free(y.label);
+ expr_free(y.value);
+ };
};
fn struct_constant_free(s: struct_constant) void = {
ident_free(s.alias);
for (let i = 0z; i < len(s.fields); i += 1) {
match (s.fields[i]) {
- v: struct_value => {
- free(v.name);
- type_free(v._type);
- expr_free(v.init);
- },
- c: *struct_constant => {
- struct_constant_free(*c);
- free(c);
- },
+ case v: struct_value =>
+ free(v.name);
+ type_free(v._type);
+ expr_free(v.init);
+ case c: *struct_constant =>
+ struct_constant_free(*c);
+ free(c);
};
};
free(s.fields);
diff --git a/hare/ast/import.ha b/hare/ast/import.ha
@@ -19,17 +19,16 @@ export type import = (import_module | import_alias | import_objects);
// Frees resources associated with an [[import]].
export fn import_free(import: import) void = {
match (import) {
- m: import_module => ident_free(m: ident),
- a: import_alias => {
- ident_free(a.ident);
- free(a.alias);
- },
- o: import_objects => {
- ident_free(o.ident);
- for (let i = 0z; i < len(o.objects); i += 1) {
- free(o.objects[i]);
- };
- free(o.objects);
- },
+ case m: import_module =>
+ ident_free(m: ident);
+ case a: import_alias =>
+ ident_free(a.ident);
+ free(a.alias);
+ case o: import_objects =>
+ ident_free(o.ident);
+ for (let i = 0z; i < len(o.objects); i += 1) {
+ free(o.objects[i]);
+ };
+ free(o.objects);
};
};
diff --git a/hare/ast/type.ha b/hare/ast/type.ha
@@ -125,81 +125,84 @@ export type _type = struct {
fn struct_type_free(t: (struct_type | union_type)) void = {
let membs = match (t) {
- s: struct_type => s: []struct_member,
- u: union_type => u: []struct_member,
+ case s: struct_type =>
+ yield s: []struct_member;
+ case u: union_type =>
+ yield u: []struct_member;
};
for (let i = 0z; i < len(membs); i += 1) {
match (membs[i]._offset) {
- null => void,
- e: *expr => expr_free(e),
+ case null => void;
+ case e: *expr =>
+ expr_free(e);
};
match (membs[i].member) {
- f: struct_field => {
- free(f.name);
- type_free(f._type);
- },
- e: struct_embedded => {
- type_free(e: *_type);
- },
- a: struct_alias => ident_free(a),
+ case f: struct_field =>
+ free(f.name);
+ type_free(f._type);
+ case e: struct_embedded =>
+ type_free(e: *_type);
+ case a: struct_alias =>
+ ident_free(a);
};
};
free(membs);
};
// Frees resources associated with a [[_type]].
-export fn type_free(t: (_type | nullable *_type)) void = match (t) {
- t: nullable *_type => match (t) {
- null => void,
- t: *_type => {
+export fn type_free(t: (_type | nullable *_type)) void = {
+ match (t) {
+ case t: nullable *_type =>
+ match (t) {
+ case null => void;
+ case t: *_type =>
type_free(*t);
free(t);
- },
- },
- t: _type => match (t.repr) {
- a: alias_type => ident_free(a.ident),
- builtin_type => void,
- e: enum_type => {
+ };
+ case t: _type =>
+ match (t.repr) {
+ case a: alias_type =>
+ ident_free(a.ident);
+ case builtin_type => void;
+ case e: enum_type =>
for (let i = 0z; i < len(e.values); i += 1) {
free(e.values[i].name);
match (e.values[i].value) {
- null => void,
- v: *expr => expr_free(v),
+ case null => void;
+ case v: *expr =>
+ expr_free(v);
};
};
free(e.values);
- },
- f: func_type => {
+ case f: func_type =>
type_free(f.result);
for (let i = 0z; i < len(f.params); i += 1) {
free(f.params[i].name);
type_free(f.params[i]._type);
};
free(f.params);
- },
- l: list_type => {
+ case l: list_type =>
match (l.length) {
- e: *expr => {
- expr_free(*e);
- free(e);
- },
- * => void,
+ case e: *expr =>
+ expr_free(*e);
+ free(e);
+ case => void;
};
type_free(l.members);
- },
- p: pointer_type => type_free(p.referent),
- s: (struct_type | union_type) => struct_type_free(s),
- t: tagged_type => {
+ case p: pointer_type =>
+ type_free(p.referent);
+ case s: (struct_type | union_type) =>
+ struct_type_free(s);
+ case t: tagged_type =>
for (let i = 0z; i < len(t); i += 1) {
type_free(t[i]);
};
free(t);
- },
- t: tuple_type => {
+ case t: tuple_type =>
for (let i = 0z; i < len(t); i += 1) {
type_free(t[i]);
};
free(t);
- },
- },
+ };
+ };
};
diff --git a/hare/lex/+test.ha b/hare/lex/+test.ha
@@ -38,13 +38,21 @@ use strings;
assert(t.2.line == 1234 && t.2.col == 1234);
};
-fn vassert(expected: value, actual: value) void = match (expected) {
- expected: str => assert(actual as str == expected),
- expected: rune => assert(actual as rune == expected),
- expected: i64 => assert(actual as i64 == expected),
- expected: u64 => assert(actual as u64 == expected),
- expected: f64 => assert(actual as f64 == expected),
- void => assert(actual is void),
+fn vassert(expected: value, actual: value) void = {
+ match (expected) {
+ case expected: str =>
+ assert(actual as str == expected);
+ case expected: rune =>
+ assert(actual as rune == expected);
+ case expected: i64 =>
+ assert(actual as i64 == expected);
+ case expected: u64 =>
+ assert(actual as u64 == expected);
+ case expected: f64 =>
+ assert(actual as f64 == expected);
+ case void =>
+ assert(actual is void);
+ };
};
fn lextest(in: str, expected: []token) void = {
@@ -54,11 +62,11 @@ fn lextest(in: str, expected: []token) void = {
for (let i = 0z; i < len(expected); i += 1) {
let etok = expected[i];
let tl = match (lex(&lexer)) {
- tl: token => tl,
- err: error => {
- fmt::errorfln("{}: {}", i, strerror(err))!;
- abort();
- },
+ case tl: token =>
+ yield tl;
+ case err: error =>
+ fmt::errorfln("{}: {}", i, strerror(err))!;
+ abort();
};
assert(tl.0 == etok.0);
vassert(tl.1, etok.1);
@@ -341,16 +349,16 @@ type op = enum {
defer free(t);
for (let i = 0z; i < len(ops); i += 1) {
switch (ops[i]) {
- op::LEX => append(t, lex(&lexer)!),
- op::NEXT => append(r, next(&lexer) as (rune, location)),
- op::UNGET => {
- unget(&lexer, r[len(r) - 1]);
- delete(r[len(r) - 1]);
- },
- op::UNLEX => {
- unlex(&lexer, t[len(t) - 1]);
- delete(t[len(t) - 1]);
- },
+ case op::LEX =>
+ append(t, lex(&lexer)!);
+ case op::NEXT =>
+ append(r, next(&lexer) as (rune, location));
+ case op::UNGET =>
+ unget(&lexer, r[len(r) - 1]);
+ delete(r[len(r) - 1]);
+ case op::UNLEX =>
+ unlex(&lexer, t[len(t) - 1]);
+ delete(t[len(t) - 1]);
};
let loc = mkloc(&lexer);
let ploc = prevloc(&lexer);
diff --git a/hare/lex/lex.ha b/hare/lex/lex.ha
@@ -37,10 +37,12 @@ export type error = !(io::error | syntax);
// Returns a human-friendly string for a given error
export fn strerror(err: error) const str = {
static let buf: [2048]u8 = [0...];
- return match (err) {
- err: io::error => io::strerror(err),
- s: syntax => fmt::bsprintf(buf, "{}:{},{}: Syntax error: {}",
- s.0.path, s.0.line, s.0.col, s.1),
+ match (err) {
+ case err: io::error =>
+ return io::strerror(err);
+ case s: syntax =>
+ return fmt::bsprintf(buf, "{}:{},{}: Syntax error: {}",
+ s.0.path, s.0.line, s.0.col, s.1);
};
};
@@ -71,11 +73,10 @@ export fn comment(lex: *lexer) str = lex.comment;
// Returns the next token from the lexer.
export fn lex(lex: *lexer) (token | error) = {
match (lex.un) {
- tok: token => {
- lex.un = void;
- return tok;
- },
- void => void,
+ case tok: token =>
+ lex.un = void;
+ return tok;
+ case void => void;
};
defer {
@@ -84,8 +85,10 @@ export fn lex(lex: *lexer) (token | error) = {
};
let r = match (nextw(lex)?) {
- io::EOF => return (ltok::EOF, void, mkloc(lex)),
- r: (rune, location) => r,
+ case io::EOF =>
+ return (ltok::EOF, void, mkloc(lex));
+ case r: (rune, location) =>
+ yield r;
};
if (is_name(r.0, false)) {
@@ -98,29 +101,37 @@ export fn lex(lex: *lexer) (token | error) = {
};
let tok = switch (r.0) {
- * => return syntaxerr(r.1, "invalid character"),
- '"', '\'' => {
- unget(lex, r);
- return lex_rn_str(lex);
- },
- '.', '<', '>', '&', '|', '^' => {
- unget(lex, r);
- return lex3(lex);
- },
- '*', '%', '/', '+', '-', ':', '!', '=' => {
- unget(lex, r);
- return lex2(lex);
- },
- '~' => ltok::BNOT,
- ',' => ltok::COMMA,
- '{' => ltok::LBRACE,
- '[' => ltok::LBRACKET,
- '(' => ltok::LPAREN,
- '}' => ltok::RBRACE,
- ']' => ltok::RBRACKET,
- ')' => ltok::RPAREN,
- ';' => ltok::SEMICOLON,
- '?' => ltok::QUESTION,
+ case '"', '\'' =>
+ unget(lex, r);
+ return lex_rn_str(lex);
+ case '.', '<', '>', '&', '|', '^' =>
+ unget(lex, r);
+ return lex3(lex);
+ case '*', '%', '/', '+', '-', ':', '!', '=' =>
+ unget(lex, r);
+ return lex2(lex);
+ case '~' =>
+ yield ltok::BNOT;
+ case ',' =>
+ yield ltok::COMMA;
+ case '{' =>
+ yield ltok::LBRACE;
+ case '[' =>
+ yield ltok::LBRACKET;
+ case '(' =>
+ yield ltok::LPAREN;
+ case '}' =>
+ yield ltok::RBRACE;
+ case ']' =>
+ yield ltok::RBRACKET;
+ case ')' =>
+ yield ltok::RPAREN;
+ case ';' =>
+ yield ltok::SEMICOLON;
+ case '?' =>
+ yield ltok::QUESTION;
+ case =>
+ return syntaxerr(r.1, "invalid character");
};
return (tok, void, r.1);
};
@@ -130,9 +141,11 @@ fn is_name(r: rune, num: bool) bool =
fn ncmp(a: const *void, b: const *void) int = {
let a = a: const *str, b = b: const *str;
- return match (ascii::strcmp(*a, *b)) {
- void => abort("non-ascii name"), // TODO: Bubble me up
- i: int => i,
+ match (ascii::strcmp(*a, *b)) {
+ case void =>
+ abort("non-ascii name"); // TODO: Bubble me up
+ case i: int =>
+ return i;
};
};
@@ -141,9 +154,11 @@ fn lex_unicode(lex: *lexer, loc: location, n: size) (rune | error) = {
let buf: [9]u8 = [0...];
for (let i = 0z; i < n; i += 1z) {
let r = match (next(lex)?) {
- io::EOF => return syntaxerr(loc,
- "unexpected EOF scanning for escape"),
- r: (rune, location) => r.0,
+ case io::EOF =>
+ return syntaxerr(loc,
+ "unexpected EOF scanning for escape");
+ case r: (rune, location) =>
+ yield r.0;
};
if (!ascii::isxdigit(r)) {
return syntaxerr(loc,
@@ -157,60 +172,76 @@ fn lex_unicode(lex: *lexer, loc: location, n: size) (rune | error) = {
fn lex_rune(lex: *lexer, loc: location) (rune | error) = {
let r = match (next(lex)?) {
- io::EOF => return syntaxerr(loc,
- "unexpected EOF scanning for rune"),
- r: (rune, location) => r.0,
+ case io::EOF =>
+ return syntaxerr(loc, "unexpected EOF scanning for rune");
+ case r: (rune, location) =>
+ yield r.0;
};
if (r != '\\') {
return r;
};
r = match (next(lex)?) {
- io::EOF => return syntaxerr(loc,
- "unexpected EOF scanning for escape"),
- r: (rune, location) => r.0,
- };
- return switch (r) {
- '\\' => '\\',
- '\'' => '\'',
- '0' => '\0',
- 'a' => '\a',
- 'b' => '\b',
- 'f' => '\f',
- 'n' => '\n',
- 'r' => '\r',
- 't' => '\t',
- 'v' => '\v',
- '"' => '\"',
- 'x' => lex_unicode(lex, loc, 2),
- 'u' => lex_unicode(lex, loc, 4),
- 'U' => lex_unicode(lex, loc, 8),
+ case io::EOF =>
+ return syntaxerr(loc, "unexpected EOF scanning for escape");
+ case r: (rune, location) =>
+ yield r.0;
+ };
+ switch (r) {
+ case '\\' =>
+ return '\\';
+ case '\'' =>
+ return '\'';
+ case '0' =>
+ return '\0';
+ case 'a' =>
+ return '\a';
+ case 'b' =>
+ return '\b';
+ case 'f' =>
+ return '\f';
+ case 'n' =>
+ return '\n';
+ case 'r' =>
+ return '\r';
+ case 't' =>
+ return '\t';
+ case 'v' =>
+ return '\v';
+ case '"' =>
+ return '\"';
+ case 'x' =>
+ return lex_unicode(lex, loc, 2);
+ case 'u' =>
+ return lex_unicode(lex, loc, 4);
+ case 'U' =>
+ return lex_unicode(lex, loc, 8);
};
};
fn lex_string(lex: *lexer, loc: location) (token | error) = {
let buf = strio::dynamic();
for (true) match (next(lex)?) {
- io::EOF => return syntaxerr(loc, "unexpected EOF scanning string literal"),
- r: (rune, location) =>
- if (r.0 == '"') break
- else {
- unget(lex, r);
- let r = lex_rune(lex, loc)?;
- strio::appendrune(buf, r)?;
- },
+ case io::EOF =>
+ return syntaxerr(loc, "unexpected EOF scanning string literal");
+ case r: (rune, location) =>
+ if (r.0 == '"') break
+ else {
+ unget(lex, r);
+ let r = lex_rune(lex, loc)?;
+ strio::appendrune(buf, r)?;
+ };
};
match (nextw(lex)?) {
- io::EOF => void,
- r: (rune, location) => {
- if (r.0 == '"') {
- const tok = lex_string(lex, loc)?;
- const next = tok.1 as str;
- strio::concat(buf, next)!;
- free(next);
- } else {
- unget(lex, r);
- };
- },
+ case io::EOF => void;
+ case r: (rune, location) =>
+ if (r.0 == '"') {
+ const tok = lex_string(lex, loc)?;
+ const next = tok.1 as str;
+ strio::concat(buf, next)!;
+ free(next);
+ } else {
+ unget(lex, r);
+ };
};
return (ltok::LIT_STR, strio::finish(buf), loc);
};
@@ -218,22 +249,28 @@ fn lex_string(lex: *lexer, loc: location) (token | error) = {
fn lex_rn_str(lex: *lexer) (token | error) = {
const loc = mkloc(lex);
let r = match (next(lex)) {
- r: (rune, location) => r.0,
- (io::EOF | io::error) => abort(),
+ case r: (rune, location) =>
+ yield r.0;
+ case (io::EOF | io::error) =>
+ abort();
};
switch (r) {
- '\"' => return lex_string(lex, loc),
- '\'' => void,
- * => abort(), // Invariant
+ case '\'' => void;
+ case '\"' =>
+ return lex_string(lex, loc);
+ case =>
+ abort(); // Invariant
};
// Rune literal
let ret: token = (ltok::LIT_RUNE, lex_rune(lex, loc)?, loc);
match (next(lex)?) {
- io::EOF =>
- return syntaxerr(loc, "unexpected EOF"),
- n: (rune, location) => if (n.0 != '\'')
- return syntaxerr(n.1, "expected \"\'\""),
+ case io::EOF =>
+ return syntaxerr(loc, "unexpected EOF");
+ case n: (rune, location) =>
+ if (n.0 != '\'') {
+ return syntaxerr(n.1, "expected \"\'\"");
+ };
};
return ret;
};
@@ -241,22 +278,21 @@ fn lex_rn_str(lex: *lexer) (token | error) = {
fn lex_name(lex: *lexer, loc: location, label: bool) (token | error) = {
let buf = strio::dynamic();
match (next(lex)) {
- r: (rune, location) => {
- assert(is_name(r.0, false));
- strio::appendrune(buf, r.0)!;
- },
- (io::EOF | io::error) => abort(),
+ case r: (rune, location) =>
+ assert(is_name(r.0, false));
+ strio::appendrune(buf, r.0)!;
+ case (io::EOF | io::error) =>
+ abort();
};
for (true) match (next(lex)?) {
- io::EOF => break,
- r: (rune, location) => {
- if (!is_name(r.0, true)) {
- unget(lex, r);
- break;
- };
- strio::appendrune(buf, r.0)?;
- },
+ case io::EOF => break;
+ case r: (rune, location) =>
+ if (!is_name(r.0, true)) {
+ unget(lex, r);
+ break;
+ };
+ strio::appendrune(buf, r.0)?;
};
let n = strio::finish(buf);
@@ -264,23 +300,27 @@ fn lex_name(lex: *lexer, loc: location, label: bool) (token | error) = {
return (ltok::LABEL, n, loc);
};
- return match (sort::search(bmap[..ltok::LAST_KEYWORD+1],
+ match (sort::search(bmap[..ltok::LAST_KEYWORD+1],
size(str), &n, &ncmp)) {
- null => (ltok::NAME, n, loc),
- v: *void => {
- defer free(n);
- let tok = v: uintptr - &bmap[0]: uintptr;
- tok /= size(str): uintptr;
- yield (tok: ltok, void, loc);
- },
+ case null =>
+ return (ltok::NAME, n, loc);
+ case v: *void =>
+ defer free(n);
+ let tok = v: uintptr - &bmap[0]: uintptr;
+ tok /= size(str): uintptr;
+ return (tok: ltok, void, loc);
};
};
fn lex_comment(lexr: *lexer) (token | error) = {
if (lexr.flags & flags::COMMENTS != flags::COMMENTS) {
for (true) match (next(lexr)?) {
- io::EOF => break,
- r: (rune, location) => if (r.0 == '\n') break,
+ case io::EOF =>
+ break;
+ case r: (rune, location) =>
+ if (r.0 == '\n') {
+ break;
+ };
};
return lex(lexr);
};
@@ -288,11 +328,13 @@ fn lex_comment(lexr: *lexer) (token | error) = {
let buf = strio::dynamic();
defer io::close(buf);
for (true) match (next(lexr)?) {
- io::EOF => break,
- r: (rune, location) => {
- strio::appendrune(buf, r.0)!;
- if (r.0 == '\n') break;
- },
+ case io::EOF =>
+ break;
+ case r: (rune, location) =>
+ strio::appendrune(buf, r.0)!;
+ if (r.0 == '\n') {
+ break;
+ };
};
let new = strings::concat(lexr.comment, strio::string(buf));
free(lexr.comment);
@@ -304,14 +346,18 @@ fn lex_literal(lex: *lexer) (token | error) = {
const loc = mkloc(lex);
let chars: []u8 = [];
let r = match (next(lex)?) {
- io::EOF => return (ltok::EOF, void, loc),
- r: (rune, location) => r,
+ case io::EOF =>
+ return (ltok::EOF, void, loc);
+ case r: (rune, location) =>
+ yield r;
};
if (r.0 == '-') {
append(chars, utf8::encoderune(r.0)...);
r = match (next(lex)?) {
- io::EOF => return (ltok::EOF, void, loc),
- r: (rune, location) => r,
+ case io::EOF =>
+ return (ltok::EOF, void, loc);
+ case r: (rune, location) =>
+ yield r;
};
};
@@ -319,21 +365,31 @@ fn lex_literal(lex: *lexer) (token | error) = {
if (r.0 == '0') {
append(chars, utf8::encoderune(r.0)...);
r = match (next(lex)?) {
- io::EOF => return (ltok::LIT_ICONST, 0i64, loc),
- r: (rune, location) => r,
+ case io::EOF =>
+ return (ltok::LIT_ICONST, 0i64, loc);
+ case r: (rune, location) =>
+ yield r;
};
switch (r.0) {
- 'b' => base = 2,
- 'o' => base = 8,
- 'x' => base = 16,
- * => unget(lex, r),
+ case 'b' =>
+ base = 2;
+ case 'o' =>
+ base = 8;
+ case 'x' =>
+ base = 16;
+ case =>
+ unget(lex, r);
};
} else unget(lex, r);
let basechrs = switch (base) {
- 2 => "01",
- 8 => "01234567",
- 10 => "0123456789",
- 16 => "0123456789ABCDEFabcdef",
+ case 2 =>
+ yield "01";
+ case 8 =>
+ yield "01234567";
+ case 10 =>
+ yield "0123456789";
+ case 16 =>
+ yield "0123456789ABCDEFabcdef";
};
let suff: (size | void) = void;
@@ -342,18 +398,23 @@ fn lex_literal(lex: *lexer) (token | error) = {
let float = false;
for (true) {
r = match (next(lex)?) {
- io::EOF => break,
- r: (rune, location) => r,
+ case io::EOF =>
+ break;
+ case r: (rune, location) =>
+ yield r;
};
if (!strings::contains(basechrs, r.0)) switch (r.0) {
- '.' => if (float || exp is size || suff is size
+ case '.' =>
+ if (float || exp is size || suff is size
|| base != 10) {
unget(lex, r);
break;
} else {
r = match (next(lex)?) {
- io::EOF => break,
- r: (rune, location) => r,
+ case io::EOF =>
+ break;
+ case r: (rune, location) =>
+ yield r;
};
if (!strings::contains(basechrs, r.0)) {
unget(lex, r);
@@ -367,8 +428,9 @@ fn lex_literal(lex: *lexer) (token | error) = {
unget(lex, r);
float = true;
append(chars, utf8::encoderune('.')...);
- },
- 'e', 'E' => if (exp is size || suff is size || base != 10) {
+ };
+ case 'e', 'E' =>
+ if (exp is size || suff is size || base != 10) {
unget(lex, r);
break;
} else {
@@ -376,17 +438,21 @@ fn lex_literal(lex: *lexer) (token | error) = {
append(chars, utf8::encoderune(r.0)...);
exp = len(chars);
r = match (next(lex)?) {
- io::EOF => break,
- r: (rune, location) => r,
+ case io::EOF =>
+ break;
+ case r: (rune, location) =>
+ yield r;
};
switch (r.0) {
- '+', '-' => append(chars,
- utf8::encoderune(r.0)...),
- * => unget(lex, r),
+ case '+', '-' =>
+ append(chars, utf8::encoderune(r.0)...);
+ case =>
+ unget(lex, r);
};
basechrs = "0123456789";
- },
- 'i', 'u', 'f', 'z' => if (suff is size) {
+ };
+ case 'i', 'u', 'f', 'z' =>
+ if (suff is size) {
unget(lex, r);
break;
} else {
@@ -394,39 +460,46 @@ fn lex_literal(lex: *lexer) (token | error) = {
if (end == 0) end = len(chars);
append(chars, utf8::encoderune(r.0)...);
basechrs = "0123456789";
- },
- * => {
- unget(lex, r);
- break;
- },
+ };
+ case =>
+ unget(lex, r);
+ break;
} else append(chars, utf8::encoderune(r.0)...);
};
if (end == 0) end = len(chars);
let exp = match (exp) {
- void => "0",
- exp: size => {
- let end = match (suff) {
- void => len(chars),
- suff: size => suff,
- };
- yield strings::fromutf8(chars[exp..end]);
- },
+ case void =>
+ yield "0";
+ case exp: size =>
+ let end = match (suff) {
+ case void =>
+ yield len(chars);
+ case suff: size =>
+ yield suff;
+ };
+ yield strings::fromutf8(chars[exp..end]);
};
let exp = match (strconv::stoi(exp)) {
- exp: int => exp,
- strconv::invalid => abort(), // Shouldn't be lexed in
- strconv::overflow =>
- return syntaxerr(loc, "overflow in exponent"),
+ case exp: int =>
+ yield exp;
+ case strconv::invalid =>
+ abort(); // Shouldn't be lexed in
+ case strconv::overflow =>
+ return syntaxerr(loc, "overflow in exponent");
};
let floatend = match (suff) {
- suff: size => suff,
- void => len(chars),
+ case suff: size =>
+ yield suff;
+ case void =>
+ yield len(chars);
};
let suff = match (suff) {
- suff: size => strings::fromutf8(chars[suff..]),
- void => "",
+ case suff: size =>
+ yield strings::fromutf8(chars[suff..]);
+ case void =>
+ yield "";
};
let suff = if (suff == "u8") ltok::LIT_U8
else if (suff == "u16") ltok::LIT_U16
@@ -446,47 +519,53 @@ fn lex_literal(lex: *lexer) (token | error) = {
else return syntaxerr(loc, "invalid literal suffix");
let exp = if (exp < 0) switch (suff) {
- ltok::LIT_F32, ltok::LIT_F64, ltok::LIT_FCONST => exp: size,
- * => return syntaxerr(loc,
- "invalid negative exponent of integer"),
+ case ltok::LIT_F32, ltok::LIT_F64, ltok::LIT_FCONST =>
+ yield exp: size;
+ case => return syntaxerr(loc,
+ "invalid negative exponent of integer");
} else exp: size;
let val = strings::fromutf8(chars[..end]);
let val = switch (suff) {
- ltok::LIT_U8, ltok::LIT_U16, ltok::LIT_U32, ltok::LIT_U64,
- ltok::LIT_UINT, ltok::LIT_SIZE => strconv::stou64b(val, base),
- ltok::LIT_ICONST => match (strconv::stoi64b(val, base)) {
- i: i64 => i,
- strconv::invalid => abort(),
- strconv::overflow => if (chars[0] != '-': u32: u8) {
+ case ltok::LIT_U8, ltok::LIT_U16, ltok::LIT_U32, ltok::LIT_U64,
+ ltok::LIT_UINT, ltok::LIT_SIZE =>
+ yield strconv::stou64b(val, base);
+ case ltok::LIT_ICONST =>
+ yield match (strconv::stoi64b(val, base)) {
+ case i: i64 =>
+ yield i;
+ case strconv::invalid =>
+ abort();
+ case strconv::overflow =>
+ yield if (chars[0] != '-': u32: u8) {
suff = ltok::LIT_U64;
yield strconv::stou64b(val, base);
- } else strconv::overflow,
- },
- ltok::LIT_I8, ltok::LIT_I16, ltok::LIT_I32, ltok::LIT_I64,
- ltok::LIT_INT => strconv::stoi64b(val, base),
- ltok::LIT_F32, ltok::LIT_F64, ltok::LIT_FCONST => {
- val = strings::fromutf8(chars[..floatend]);
- yield strconv::stof64(val);
- },
+ } else strconv::overflow;
+ };
+ case ltok::LIT_I8, ltok::LIT_I16, ltok::LIT_I32, ltok::LIT_I64,
+ ltok::LIT_INT =>
+ yield strconv::stoi64b(val, base);
+ case ltok::LIT_F32, ltok::LIT_F64, ltok::LIT_FCONST =>
+ val = strings::fromutf8(chars[..floatend]);
+ yield strconv::stof64(val);
};
let val = match (val) {
- val: u64 => {
- for (let i = 0z; i < exp; i += 1) {
- val *= 10;
- };
- yield val;
- },
- val: i64 => {
- for (let i = 0z; i < exp; i += 1) {
- val *= 10;
- };
- yield val;
- },
- val: f64 => val,
- strconv::invalid => abort(), // Shouldn't be lexed in
- strconv::overflow =>
- return syntaxerr(loc, "overflow in exponent"),
+ case val: u64 =>
+ for (let i = 0z; i < exp; i += 1) {
+ val *= 10;
+ };
+ yield val;
+ case val: i64 =>
+ for (let i = 0z; i < exp; i += 1) {
+ val *= 10;
+ };
+ yield val;
+ case val: f64 =>
+ yield val;
+ case strconv::invalid =>
+ abort(); // Shouldn't be lexed in
+ case strconv::overflow =>
+ return syntaxerr(loc, "overflow in exponent");
};
return (suff, val, loc);
@@ -495,60 +574,77 @@ fn lex_literal(lex: *lexer) (token | error) = {
fn lex2(lex: *lexer) (token | error) = {
let first = next(lex)? as (rune, location);
let tok: (ltok, [](rune, ltok)) = switch (first.0) {
- '*' => (ltok::TIMES, [('=', ltok::TIMESEQ)]),
- '%' => (ltok::MODULO, [('=', ltok::MODEQ)]),
- '/' => match (next(lex)?) {
- r: (rune, location) => switch (r.0) {
- '=' => return (ltok::DIVEQ, void, first.1),
- '/' => return lex_comment(lex),
- * => {
- unget(lex, r);
- return (ltok::DIV, void, first.1);
- },
- },
- io::EOF => return (ltok::DIV, void, first.1),
- },
- '+' => (ltok::PLUS, [('=', ltok::PLUSEQ)]),
- '-' => match (next(lex)?) {
- r: (rune, location) => switch (r.0) {
- '=' => return (ltok::MINUSEQ, void, first.1),
- * => if (ascii::isdigit(r.0)) {
+ case '*' =>
+ yield (ltok::TIMES, [('=', ltok::TIMESEQ)]);
+ case '%' =>
+ yield (ltok::MODULO, [('=', ltok::MODEQ)]);
+ case '/' =>
+ match (next(lex)?) {
+ case r: (rune, location) =>
+ switch (r.0) {
+ case '=' =>
+ return (ltok::DIVEQ, void, first.1);
+ case '/' =>
+ return lex_comment(lex);
+ case =>
+ unget(lex, r);
+ return (ltok::DIV, void, first.1);
+ };
+ case io::EOF =>
+ return (ltok::DIV, void, first.1);
+ };
+ case '+' =>
+ yield (ltok::PLUS, [('=', ltok::PLUSEQ)]);
+ case '-' =>
+ match (next(lex)?) {
+ case r: (rune, location) =>
+ switch (r.0) {
+ case '=' =>
+ return (ltok::MINUSEQ, void, first.1);
+ case =>
+ if (ascii::isdigit(r.0)) {
unget(lex, r);
unget(lex, first);
return lex_literal(lex);
} else {
unget(lex, r);
return (ltok::MINUS, void, first.1);
- },
- },
- io::EOF => return (ltok::MINUS, void, first.1),
- },
- ':' => match (next(lex)?) {
- r: (rune, location) => switch (r.0) {
- ':' => return (ltok::DOUBLE_COLON, void, first.1),
- * => {
- unget(lex, r);
- return if (is_name(r.0, false)) {
- yield lex_name(lex, first.1, true)?;
- } else (ltok::COLON, void, first.1);
- },
- },
- io::EOF => return (ltok::COLON, void, first.1),
- },
- '!' => (ltok::LNOT, [('=', ltok::NEQUAL)]),
- '=' => (ltok::EQUAL, [('=', ltok::LEQUAL), ('>', ltok::CASE)]),
- * => return syntaxerr(first.1, "unknown token sequence"),
+ };
+ };
+ case io::EOF =>
+ return (ltok::MINUS, void, first.1);
+ };
+ case ':' =>
+ match (next(lex)?) {
+ case r: (rune, location) =>
+ switch (r.0) {
+ case ':' =>
+ return (ltok::DOUBLE_COLON, void, first.1);
+ case =>
+ unget(lex, r);
+ return if (is_name(r.0, false)) {
+ yield lex_name(lex, first.1, true)?;
+ } else (ltok::COLON, void, first.1);
+ };
+ case io::EOF =>
+ return (ltok::COLON, void, first.1);
+ };
+ case '!' =>
+ yield (ltok::LNOT, [('=', ltok::NEQUAL)]);
+ case '=' =>
+ yield (ltok::EQUAL, [('=', ltok::LEQUAL), ('>', ltok::ARROW)]);
+ case =>
+ return syntaxerr(first.1, "unknown token sequence");
};
match (next(lex)?) {
- r: (rune, location) => {
- for (let i = 0z; i < len(tok.1); i += 1) {
- if (tok.1[i].0 == r.0) {
- return (tok.1[i].1, void, first.1);
- };
+ case r: (rune, location) =>
+ for (let i = 0z; i < len(tok.1); i += 1) {
+ if (tok.1[i].0 == r.0) {
+ return (tok.1[i].1, void, first.1);
};
- unget(lex, r);
- },
- io::EOF => void,
+ };
+ unget(lex, r);
+ case io::EOF => void;
};
return (tok.0, void, first.1);
};
@@ -556,29 +652,40 @@ fn lex2(lex: *lexer) (token | error) = {
fn lex3(lex: *lexer) (token | error) = {
let r = next(lex)? as (rune, location);
let toks = switch (r.0) {
- '.' => {
- let tok = if (try(lex, '.') is void) ltok::DOT
- else if (try(lex, '.') is void) ltok::SLICE
- else ltok::ELLIPSIS;
- return (tok, void, r.1);
- },
- '<' => [ltok::LESS, ltok::LESSEQ, ltok::LSHIFT, ltok::LSHIFTEQ],
- '>' => [ltok::GREATER, ltok::GREATEREQ, ltok::RSHIFT,
- ltok::RSHIFTEQ],
- '&' => [ltok::BAND, ltok::BANDEQ, ltok::LAND, ltok::LANDEQ],
- '|' => [ltok::BOR, ltok::BOREQ, ltok::LOR, ltok::LOREQ],
- '^' => [ltok::BXOR, ltok::BXOREQ, ltok::LXOR, ltok::LXOREQ],
- * => return syntaxerr(r.1, "unknown token sequence"),
+ case '.' =>
+ let tok = if (try(lex, '.') is void) ltok::DOT
+ else if (try(lex, '.') is void) ltok::SLICE
+ else ltok::ELLIPSIS;
+ return (tok, void, r.1);
+ case '<' =>
+ yield [ltok::LESS, ltok::LESSEQ, ltok::LSHIFT, ltok::LSHIFTEQ];
+ case '>' =>
+ yield [ltok::GREATER, ltok::GREATEREQ, ltok::RSHIFT,
+ ltok::RSHIFTEQ];
+ case '&' =>
+ yield [ltok::BAND, ltok::BANDEQ, ltok::LAND, ltok::LANDEQ];
+ case '|' =>
+ yield [ltok::BOR, ltok::BOREQ, ltok::LOR, ltok::LOREQ];
+ case '^' =>
+ yield [ltok::BXOR, ltok::BXOREQ, ltok::LXOR, ltok::LXOREQ];
+ case =>
+ return syntaxerr(r.1, "unknown token sequence");
};
let idx = match (try(lex, r.0, '=')?) {
- void => 0, // X
- n: (rune, location) => switch (n.0) {
- '=' => 1, // X=
- * => match (try(lex, '=')?) {
- void => 2, // XX
- (rune, location) => 3, // XX=
- },
- },
+ case void =>
+ yield 0; // X
+ case n: (rune, location) =>
+ yield switch (n.0) {
+ case '=' =>
+ yield 1; // X=
+ case =>
+ yield match (try(lex, '=')?) {
+ case void =>
+ yield 2; // XX
+ case (rune, location) =>
+ yield 3; // XX=
+ };
+ };
};
return (toks[idx], void, r.1);
};
@@ -593,44 +700,47 @@ export fn unlex(lex: *lexer, tok: token) void = {
fn next(lex: *lexer) ((rune, location) | io::EOF | io::error) = {
match (lex.rb[0]) {
- void => void,
- r: ((rune, location) | io::EOF) => {
- lex.rb[0] = lex.rb[1];
- lex.rb[1] = void;
- return r;
- },
+ case void => void;
+ case r: ((rune, location) | io::EOF) =>
+ lex.rb[0] = lex.rb[1];
+ lex.rb[1] = void;
+ return r;
};
- return match (bufio::scanrune(lex.in)) {
- e: (io::EOF | io::error) => e,
- r: rune => {
- const loc = mkloc(lex);
- let tmp = lex.prevrlocs;
- lex.prevrlocs[1..] = tmp[..len(tmp) - 1];
- lex.prevrlocs[0] = loc;
- lexloc(lex, r);
- return (r, loc);
- },
+ match (bufio::scanrune(lex.in)) {
+ case e: (io::EOF | io::error) =>
+ return e;
+ case r: rune =>
+ const loc = mkloc(lex);
+ let tmp = lex.prevrlocs;
+ lex.prevrlocs[1..] = tmp[..len(tmp) - 1];
+ lex.prevrlocs[0] = loc;
+ lexloc(lex, r);
+ return (r, loc);
};
};
fn nextw(lex: *lexer) ((rune, location) | io::EOF | io::error) = {
for (true) match (next(lex)) {
- e: (io::error | io::EOF) => return e,
- r: (rune, location) => if (!ascii::isspace(r.0)) {
+ case e: (io::error | io::EOF) =>
+ return e;
+ case r: (rune, location) =>
+ if (!ascii::isspace(r.0)) {
return r;
} else {
free(lex.comment);
lex.comment = "";
- },
+ };
};
abort();
};
fn try(lex: *lexer, want: rune...) ((rune, location) | void | io::error) = {
let r = match (next(lex)?) {
- io::EOF => return void,
- r: (rune, location) => r,
+ case io::EOF =>
+ return;
+ case r: (rune, location) =>
+ yield r;
};
assert(len(want) > 0);
for (let i = 0z; i < len(want); i += 1) {
@@ -643,12 +753,13 @@ fn try(lex: *lexer, want: rune...) ((rune, location) | void | io::error) = {
fn lexloc(lex: *lexer, r: rune) void = {
switch (r) {
- '\n' => {
- lex.loc.0 += 1;
- lex.loc.1 = 1;
- },
- '\t' => lex.loc.1 += 8 - lex.loc.1 % 8 + 1,
- * => lex.loc.1 += 1,
+ case '\n' =>
+ lex.loc.0 += 1;
+ lex.loc.1 = 1;
+ case '\t' =>
+ lex.loc.1 += 8 - lex.loc.1 % 8 + 1;
+ case =>
+ lex.loc.1 += 1;
};
};
@@ -660,25 +771,33 @@ fn unget(lex: *lexer, r: ((rune, location) | io::EOF)) void = {
lex.rb[0] = r;
};
-export fn mkloc(lex: *lexer) location = match (lex.un) {
- t: token => lex.prevunlocs[1].1,
- void => match (lex.rb[0]) {
- r: (rune, location) => r.1,
- void => location {
- path = lex.path,
- line = lex.loc.0,
- col = lex.loc.1,
- },
- },
+export fn mkloc(lex: *lexer) location = {
+ match (lex.un) {
+ case t: token =>
+ return lex.prevunlocs[1].1;
+ case void =>
+ match (lex.rb[0]) {
+ case r: (rune, location) =>
+ return r.1;
+ case void =>
+ return location {
+ path = lex.path,
+ line = lex.loc.0,
+ col = lex.loc.1,
+ };
+ };
+ };
};
-export fn prevloc(lex: *lexer) location = match (lex.un) {
- t: token => lex.prevunlocs[1].0,
- void => {
+export fn prevloc(lex: *lexer) location = {
+ match (lex.un) {
+ case t: token =>
+ return lex.prevunlocs[1].0;
+ case void =>
let i = 0z;
for (i < len(lex.rb); i += 1) if (lex.rb[i] is void) break;
return lex.prevrlocs[i];
- },
+ };
};
fn syntaxerr(loc: location, why: str) error = (loc, why);
diff --git a/hare/lex/token.ha b/hare/lex/token.ha
@@ -19,6 +19,7 @@ export type ltok = enum uint {
ASSERT,
BOOL,
BREAK,
+ CASE,
CHAR,
CONST,
CONTINUE,
@@ -70,6 +71,7 @@ export type ltok = enum uint {
LAST_KEYWORD = YIELD,
// Operators
+ ARROW,
BAND,
BANDEQ,
BNOT,
@@ -77,7 +79,6 @@ export type ltok = enum uint {
BOREQ,
BXOR,
BXOREQ,
- CASE,
COLON,
COMMA,
DIV,
@@ -164,6 +165,7 @@ const bmap: [_]str = [
"assert",
"bool",
"break",
+ "case",
"char",
"const",
"continue",
@@ -212,6 +214,7 @@ const bmap: [_]str = [
"use",
"void",
"yield",
+ "=>",
"&",
"&=",
"~",
@@ -288,27 +291,48 @@ export fn tokstr(tok: token) const str = {
if (tok.0 <= ltok::LAST_BTOK) {
return bmap[tok.0: int];
};
- return switch (tok.0) {
- ltok::LIT_U8 => "u8",
- ltok::LIT_U16 => "u16",
- ltok::LIT_U32 => "u32",
- ltok::LIT_U64 => "u64",
- ltok::LIT_UINT => "uint",
- ltok::LIT_SIZE => "size",
- ltok::LIT_I8 => "i8",
- ltok::LIT_I16 => "i16",
- ltok::LIT_I32 => "i32",
- ltok::LIT_I64 => "i64",
- ltok::LIT_INT => "int",
- ltok::LIT_ICONST => "iconst",
- ltok::LIT_F32 => "f32",
- ltok::LIT_F64 => "f64",
- ltok::LIT_FCONST => "fconst",
- ltok::LIT_RUNE => "rune",
- ltok::LIT_STR => "str",
- ltok::NAME => tok.1 as str,
- ltok::LABEL => abort(), // TODO
- ltok::EOF => "EOF",
- * => abort(),
+ switch (tok.0) {
+ case ltok::LIT_U8 =>
+ return "u8";
+ case ltok::LIT_U16 =>
+ return "u16";
+ case ltok::LIT_U32 =>
+ return "u32";
+ case ltok::LIT_U64 =>
+ return "u64";
+ case ltok::LIT_UINT =>
+ return "uint";
+ case ltok::LIT_SIZE =>
+ return "size";
+ case ltok::LIT_I8 =>
+ return "i8";
+ case ltok::LIT_I16 =>
+ return "i16";
+ case ltok::LIT_I32 =>
+ return "i32";
+ case ltok::LIT_I64 =>
+ return "i64";
+ case ltok::LIT_INT =>
+ return "int";
+ case ltok::LIT_ICONST =>
+ return "iconst";
+ case ltok::LIT_F32 =>
+ return "f32";
+ case ltok::LIT_F64 =>
+ return "f64";
+ case ltok::LIT_FCONST =>
+ return "fconst";
+ case ltok::LIT_RUNE =>
+ return "rune";
+ case ltok::LIT_STR =>
+ return "str";
+ case ltok::NAME =>
+ return tok.1 as str;
+ case ltok::LABEL =>
+ abort(); // TODO
+ case ltok::EOF =>
+ return "EOF";
+ case =>
+ abort();
};
};
diff --git a/hare/module/context.ha b/hare/module/context.ha
@@ -32,25 +32,27 @@ export fn context_init(tags: []tag, defs: []str, harepath: str) context = {
tags = tags,
defines = defs,
paths = match (os::getenv("HAREPATH")) {
- void => alloc([
+ case void =>
+ yield alloc([
strings::dup(harepath),
dirs::data("hare"),
strings::dup("."),
- ]),
- s: str => {
- let sl = strings::split(s, ":");
- let path: []str = alloc([], len(sl) + 1);
- for (let i = 0z; i < len(sl); i += 1) {
- append(path, strings::dup(sl[i]));
- };
- append(path, strings::dup("."));
- free(sl);
- yield path;
- },
+ ]);
+ case s: str =>
+ let sl = strings::split(s, ":");
+ let path: []str = alloc([], len(sl) + 1);
+ for (let i = 0z; i < len(sl); i += 1) {
+ append(path, strings::dup(sl[i]));
+ };
+ append(path, strings::dup("."));
+ free(sl);
+ yield path;
},
cache: str = match (os::getenv("HARECACHE")) {
- void => dirs::cache("hare"),
- s: str => strings::dup(s),
+ case void =>
+ yield dirs::cache("hare");
+ case s: str =>
+ yield strings::dup(s);
},
...
};
diff --git a/hare/module/manifest.ha b/hare/module/manifest.ha
@@ -53,9 +53,12 @@ export fn manifest_load(ctx: *context, ident: ast::ident) (manifest | error) = {
defer free(mpath);
let file = match (fs::open(ctx.fs, mpath, fs::flags::RDONLY)) {
- errors::noentry => return manifest,
- err: fs::error => return err,
- file: *io::stream => file,
+ case errors::noentry =>
+ return manifest;
+ case err: fs::error =>
+ return err;
+ case file: *io::stream =>
+ yield file;
};
defer io::close(file);
@@ -65,15 +68,19 @@ export fn manifest_load(ctx: *context, ident: ast::ident) (manifest | error) = {
let file = bufio::buffered(file, buf, []);
for (true) {
let line = match (bufio::scanline(file)?) {
- io::EOF => break,
- line: []u8 => line,
+ case io::EOF =>
+ break;
+ case line: []u8 =>
+ yield line;
};
defer free(line);
let line = match (strings::try_fromutf8(line)) {
+ case utf8::invalid =>
// Treat an invalid manifest as empty
- utf8::invalid => return manifest,
- s: str => s,
+ return manifest;
+ case s: str =>
+ yield s;
};
if (strings::has_prefix(line, "#")) {
@@ -82,49 +89,76 @@ export fn manifest_load(ctx: *context, ident: ast::ident) (manifest | error) = {
let tok = strings::tokenize(line, " ");
let kind = match (strings::next_token(&tok)) {
- void => continue,
- s: str => s,
+ case void =>
+ continue;
+ case s: str =>
+ yield s;
};
- if (kind == "version") {
+ switch (kind) {
+ case "version" =>
let ver = match (strings::next_token(&tok)) {
- void => return manifest,
- s: str => s,
+ case void =>
+ return manifest;
+ case s: str =>
+ yield s;
};
match (strconv::stoi(ver)) {
- v: int => if (v != VERSION) {
+ case v: int =>
+ if (v != VERSION) {
return manifest;
- },
- * => return manifest,
+ };
+ case =>
+ return manifest;
};
- } else if (kind == "input") {
+ case "input" =>
let hash = match (strings::next_token(&tok)) {
- void => return manifest, s: str => s,
+ case void =>
+ return manifest;
+ case s: str =>
+ yield s;
}, path = match (strings::next_token(&tok)) {
- void => return manifest, s: str => s,
+ case void =>
+ return manifest;
+ case s: str =>
+ yield s;
}, inode = match (strings::next_token(&tok)) {
- void => return manifest, s: str => s,
+ case void =>
+ return manifest;
+ case s: str =>
+ yield s;
}, mtime = match (strings::next_token(&tok)) {
- void => return manifest, s: str => s,
+ case void =>
+ return manifest;
+ case s: str =>
+ yield s;
};
let hash = match (hex::decode(hash)) {
- * => return manifest,
- b: []u8 => b,
+ case b: []u8 =>
+ yield b;
+ case =>
+ return manifest;
};
let inode = match (strconv::stoz(inode)) {
- * => return manifest,
- z: size => z,
+ case z: size =>
+ yield z;
+ case =>
+ return manifest;
};
let mtime = match (strconv::stoi64(mtime)) {
- * => return manifest,
- i: i64 => time::from_unix(i),
+ case i: i64 =>
+ yield time::from_unix(i);
+ case =>
+ return manifest;
};
let parsed = parse_name(path);
let ftype = match (type_for_ext(path)) {
- void => return manifest,
- ft: filetype => ft,
+ case void =>
+ return manifest;
+ case ft: filetype =>
+ yield ft;
};
append(inputs, input {
@@ -139,30 +173,41 @@ export fn manifest_load(ctx: *context, ident: ast::ident) (manifest | error) = {
basename = strings::dup(parsed.0),
tags = parsed.2,
});
- } else if (kind == "module") {
+ case "module" =>
let modhash = match (strings::next_token(&tok)) {
- void => return manifest, s: str => s,
+ case void =>
+ return manifest;
+ case s: str =>
+ yield s;
};
let modhash = match (hex::decode(modhash)) {
- * => return manifest,
- b: []u8 => b,
+ case b: []u8 =>
+ yield b;
+ case =>
+ return manifest;
};
let minputs: []input = [];
for (true) {
let hash = match (strings::next_token(&tok)) {
- void => break,
- s: str => s,
+ case void =>
+ break;
+ case s: str =>
+ yield s;
};
let hash = match (hex::decode(hash)) {
- * => return manifest,
- b: []u8 => b,
+ case b: []u8 =>
+ yield b;
+ case =>
+ return manifest;
};
defer free(hash);
let input = match (getinput(inputs, hash)) {
- null => return manifest,
- i: *input => i,
+ case null =>
+ return manifest;
+ case i: *input =>
+ yield i;
};
append(minputs, *input);
};
@@ -171,14 +216,15 @@ export fn manifest_load(ctx: *context, ident: ast::ident) (manifest | error) = {
hash = modhash,
inputs = minputs,
});
- } else {
+ case =>
return manifest;
};
// Check for extra tokens
match (strings::next_token(&tok)) {
- void => void,
- s: str => return manifest,
+ case void => void;
+ case str =>
+ return manifest;
};
};
@@ -206,8 +252,10 @@ export fn current(manifest: *manifest, version: *version) bool = {
};
};
let cached = match (cached) {
- null => return false,
- v: *version => v,
+ case null =>
+ return false;
+ case v: *version =>
+ yield v;
};
assert(len(cached.inputs) == len(version.inputs));
diff --git a/hare/module/scan.ha b/hare/module/scan.ha
@@ -30,37 +30,40 @@ export fn scan(ctx: *context, path: str) (version | error) = {
};
hash::write(&sha, [if (found) 1 else 0]);
let iter = match (fs::iter(ctx.fs, path)) {
- fs::wrongtype => {
- // Single file case
- let inputs: []input = [];
- let deps: []ast::ident = [];
- let ft = match (type_for_ext(path)) {
- void => return module_not_found,
- ft: filetype => ft,
- };
- let st = fs::stat(ctx.fs, path)?;
- let in = input {
- path = fs::resolve(ctx.fs, path),
- stat = st,
- ft = ft,
- hash = scan_file(ctx, path, &deps)?,
- ...
- };
- append(inputs, in);
+ case fs::wrongtype =>
+ // Single file case
+ let inputs: []input = [];
+ let deps: []ast::ident = [];
+ let ft = match (type_for_ext(path)) {
+ case void =>
+ return module_not_found;
+ case ft: filetype =>
+ yield ft;
+ };
+ let st = fs::stat(ctx.fs, path)?;
+ let in = input {
+ path = fs::resolve(ctx.fs, path),
+ stat = st,
+ ft = ft,
+ hash = scan_file(ctx, path, &deps)?,
+ ...
+ };
+ append(inputs, in);
- let sumbuf: [sha256::SIZE]u8 = [0...];
- hash::write(&sha, in.hash);
- hash::sum(&sha, sumbuf);
+ let sumbuf: [sha256::SIZE]u8 = [0...];
+ hash::write(&sha, in.hash);
+ hash::sum(&sha, sumbuf);
- return version {
- hash = sumbuf,
- basedir = path::dirname(fs::resolve(ctx.fs, path)),
- depends = deps,
- inputs = inputs,
- };
- },
- err: fs::error => return err,
- iter: *fs::iterator => iter,
+ return version {
+ hash = sumbuf,
+ basedir = path::dirname(fs::resolve(ctx.fs, path)),
+ depends = deps,
+ inputs = inputs,
+ };
+ case err: fs::error =>
+ return err;
+ case iter: *fs::iterator =>
+ yield iter;
};
let ver = version {
basedir = strings::dup(path),
@@ -93,8 +96,10 @@ fn parse_name(name: str) (str, str, []tag) = {
else p: size;
let tags = strings::sub(base, i, strings::end);
let tags = match (parsetags(tags)) {
- void => return (base, ext, []),
- t: []tag => t,
+ case void =>
+ return (base, ext, []);
+ case t: []tag =>
+ yield t;
};
let base = strings::sub(base, 0, i);
return (base, ext, tags);
@@ -128,14 +133,19 @@ fn scan_directory(
for (true) {
let ent = match (fs::next(iter)) {
- void => break,
- ent: fs::dirent => ent,
+ case void =>
+ break;
+ case ent: fs::dirent =>
+ yield ent;
};
switch (ent.ftype) {
- fs::mode::LINK => abort(), // TODO
- fs::mode::DIR => append(dirs, strings::dup(ent.name)),
- fs::mode::REG => append(files, strings::dup(ent.name)),
+ case fs::mode::LINK =>
+ abort(); // TODO
+ case fs::mode::DIR =>
+ append(dirs, strings::dup(ent.name));
+ case fs::mode::REG =>
+ append(files, strings::dup(ent.name));
};
};
@@ -291,8 +301,9 @@ export fn lookup(ctx: *context, name: ast::ident) (version | error) = {
let cand = path::join(ctx.paths[i - 1], ipath);
defer free(cand);
match (scan(ctx, cand)) {
- v: version => return v,
- e: error => void,
+ case v: version =>
+ return v;
+ case error => void;
};
};
return module_not_found;
@@ -321,9 +332,12 @@ fn scan_file(
let imports = parse::imports(&lexer)?;
for (let i = 0z; i < len(imports); i += 1) {
let ident = match (imports[i]) {
- m: ast::import_module => m: ast::ident,
- a: ast::import_alias => a.ident,
- o: ast::import_objects => o.ident,
+ case m: ast::import_module =>
+ yield m: ast::ident;
+ case a: ast::import_alias =>
+ yield a.ident;
+ case o: ast::import_objects =>
+ yield o.ident;
};
if (!have_ident(deps, ident)) {
append(deps, ident);
@@ -357,28 +371,31 @@ export fn parsetags(in: str) ([]tag | void) = {
for (true) {
let t = tag { ... };
let m = match (strings::next(&iter)) {
- void => break,
- r: rune => r,
+ case void =>
+ break;
+ case r: rune =>
+ yield r;
};
t.mode = switch (m) {
- * => {
- tags_free(tags);
- return;
- },
- '+' => tag_mode::INCLUSIVE,
- '-' => tag_mode::EXCLUSIVE,
+ case =>
+ tags_free(tags);
+ return;
+ case '+' =>
+ yield tag_mode::INCLUSIVE;
+ case '-' =>
+ yield tag_mode::EXCLUSIVE;
};
let buf = strio::dynamic();
for (true) match (strings::next(&iter)) {
- void => break,
- r: rune => {
- if (ascii::isalnum(r) || r == '_') {
- strio::appendrune(buf, r)!;
- } else {
- strings::push(&iter, r);
- break;
- };
- },
+ case void =>
+ break;
+ case r: rune =>
+ if (ascii::isalnum(r) || r == '_') {
+ strio::appendrune(buf, r)!;
+ } else {
+ strings::push(&iter, r);
+ break;
+ };
};
t.name = strio::finish(buf);
append(tags, t);
@@ -406,8 +423,10 @@ export fn tagcompat(have: []tag, want: []tag) bool = {
};
};
switch (want[i].mode) {
- tag_mode::INCLUSIVE => if (!present) return false,
- tag_mode::EXCLUSIVE => if (present) return false,
+ case tag_mode::INCLUSIVE =>
+ if (!present) return false;
+ case tag_mode::EXCLUSIVE =>
+ if (present) return false;
};
};
return true;
diff --git a/hare/module/types.ha b/hare/module/types.ha
@@ -68,12 +68,17 @@ export type error = !(
export fn strerror(err: error) const str = {
// Should be more than enough for PATH_MAX * 2
static let buf: [4096]u8 = [0...];
- return match (err) {
- err: fs::error => fs::strerror(err),
- err: io::error => io::strerror(err),
- err: parse::error => parse::strerror(err),
- module_not_found => "Module not found",
- amb: ambiguous => fmt::bsprintf(buf,
- "Cannot choose between {} and {}", amb.0, amb.1),
+ match (err) {
+ case err: fs::error =>
+ return fs::strerror(err);
+ case err: io::error =>
+ return io::strerror(err);
+ case err: parse::error =>
+ return parse::strerror(err);
+ case module_not_found =>
+ return "Module not found";
+ case amb: ambiguous =>
+ return fmt::bsprintf(buf, "Cannot choose between {} and {}",
+ amb.0, amb.1);
};
};
diff --git a/hare/parse/+test/expr.ha b/hare/parse/+test/expr.ha
@@ -217,11 +217,12 @@
@test fn switch_expr() void = {
roundtrip("export fn main() void = {
switch (x) {
- 1234, 4321 => y,
- 1337 => {
- z;
- },
- * => q,
+ case 1234, 4321 =>
+ return y;
+ case 1337 =>
+ return z;
+ case =>
+ return q;
};
};
");
@@ -230,22 +231,26 @@
@test fn match_expr() void = {
roundtrip("export fn main() void = {
match (x) {
- i: size => y,
- str => {
- z;
- },
- foo => bar,
- foo: int => bar,
- foo::bar => baz,
- null => void,
- *int => void,
+ case i: size =>
+ return y;
+ case foo =>
+ return bar;
+ case foo: int =>
+ return bar;
+ case foo::bar =>
+ return baz;
+ case null =>
+ void;
+ case *int =>
+ void;
};
match (x) {
- s: matchdata => y,
- str => {
- z;
- },
- * => q,
+ case s: matchdata =>
+ return y;
+ case str =>
+ return z;
+ case =>
+ return q;
};
};
");
diff --git a/hare/parse/+test/loc.ha b/hare/parse/+test/loc.ha
@@ -12,18 +12,20 @@ fn expr_testloc(srcs: str...) void = for (let i = 0z; i < len(srcs); i += 1) {
defer io::close(buf);
let lexer = lex::init(buf, "<test>");
let exp = match (expression(&lexer)) {
- exp: ast::expr => exp,
- err: error => {
- fmt::errorln(strerror(err))!;
- abort();
- },
+ case exp: ast::expr =>
+ yield exp;
+ case err: error =>
+ fmt::errorln(strerror(err))!;
+ abort();
};
defer ast::expr_free(exp);
let runes = 0z;
let d = utf8::decode(srcs[i]);
for (true) match (utf8::next(&d)!) {
- void => break,
- rune => runes += 1,
+ case void =>
+ break;
+ case rune =>
+ runes += 1;
};
assert(exp.start.line == 1 && exp.start.col == 1);
assert(exp.end.line == 1 && exp.end.col == runes);
@@ -55,11 +57,11 @@ fn expr_testloc(srcs: str...) void = for (let i = 0z; i < len(srcs); i += 1) {
expr_testloc("if (foo) bar", "if (foo) bar else baz");
expr_testloc("len(foo)");
expr_testloc("{ foo; bar; }");
- expr_testloc("match (foo) { * => bar }");
+ expr_testloc("match (foo) { case => bar; }");
expr_testloc("foo?");
expr_testloc("return foo");
expr_testloc("size(int)");
- expr_testloc("switch (foo) { * => bar }");
+ expr_testloc("switch (foo) { case => bar; }");
expr_testloc("foo[bar..baz]");
expr_testloc("&foo");
@@ -69,11 +71,11 @@ fn expr_testloc(srcs: str...) void = for (let i = 0z; i < len(srcs); i += 1) {
defer io::close(buf);
let lexer = lex::init(buf, "<test>");
let exp = match (expression(&lexer)) {
- exp: ast::expr => exp,
- err: error => {
- fmt::errorln(strerror(err))!;
- abort();
- },
+ case exp: ast::expr =>
+ yield exp;
+ case err: error =>
+ fmt::errorln(strerror(err))!;
+ abort();
};
defer ast::expr_free(exp);
assert(exp.start.line == 1 && exp.start.col == 1);
@@ -93,18 +95,20 @@ fn type_testloc(srcs: str...) void = for (let i = 0z; i < len(srcs); i += 1) {
defer io::close(buf);
let lexer = lex::init(buf, "<test>");
let typ = match (_type(&lexer)) {
- typ: ast::_type => typ,
- err: error => {
- fmt::errorln(strerror(err))!;
- abort();
- },
+ case typ: ast::_type =>
+ yield typ;
+ case err: error =>
+ fmt::errorln(strerror(err))!;
+ abort();
};
defer ast::type_free(typ);
let runes = 0z;
let d = utf8::decode(srcs[i]);
for (true) match (utf8::next(&d)!) {
- void => break,
- rune => runes += 1,
+ case void =>
+ break;
+ case rune =>
+ runes += 1;
};
assert(typ.start.line == 1 && typ.start.col == 1);
assert(typ.end.line == 1 && typ.end.col == runes);
diff --git a/hare/parse/+test/roundtrip.ha b/hare/parse/+test/roundtrip.ha
@@ -15,11 +15,11 @@ fn roundtrip(src: str) void = {
let u = ast::subunit {
imports = [],
decls: []ast::decl = match (decls(&lexer)) {
- decls: []ast::decl => decls,
- err: error => {
- fmt::errorln(strerror(err))!;
- abort();
- },
+ case decls: []ast::decl =>
+ yield decls;
+ case err: error =>
+ fmt::errorln(strerror(err))!;
+ abort();
},
};
defer ast::subunit_free(u);
diff --git a/hare/parse/+test/unit.ha b/hare/parse/+test/unit.ha
@@ -141,11 +141,11 @@ use strings;
defer io::close(buf);
let lexer = lex::init(buf, "<test>", lex::flags::COMMENTS);
let decls = match (decls(&lexer)) {
- decls: []ast::decl => decls,
- err: error => {
- fmt::errorln(strerror(err))!;
- abort();
- },
+ case decls: []ast::decl =>
+ yield decls;
+ case err: error =>
+ fmt::errorln(strerror(err))!;
+ abort();
};
defer for (let i = 0z; i < len(decls); i += 1) {
ast::decl_free(decls[i]);
diff --git a/hare/parse/decl.ha b/hare/parse/decl.ha
@@ -11,16 +11,17 @@ fn attr_symbol(lexer: *lex::lexer) (str | error) = {
let s = t.1 as str;
let d = strings::iter(s);
match (strings::next(&d)) {
- void => void,
- r: rune => synassert(t.2,
- ascii::isalpha(r) || r == '.' || r == '_',
- "Invalid symbol")?,
+ case void => void;
+ case r: rune =>
+ synassert(t.2, ascii::isalpha(r) || r == '.'
+ || r == '_', "Invalid symbol")?;
};
for (true) match (strings::next(&d)) {
- void => break,
- r: rune => synassert(t.2,
- ascii::isalnum(r) || r == '$' || r == '.' || r == '_',
- "Invalid symbol")?,
+ case void =>
+ break;
+ case r: rune =>
+ synassert(t.2, ascii::isalnum(r) || r == '$'
+ || r == '.' || r == '_', "Invalid symbol")?;
};
want(lexer, ltok::RPAREN)?;
return s;
@@ -58,16 +59,20 @@ fn decl_global(
let decl: []ast::decl_global = [];
for (true) {
const symbol = match (try(lexer, ltok::ATTR_SYMBOL)?) {
- void => "",
- lex::token => attr_symbol(lexer)?,
+ case void =>
+ yield "";
+ case lex::token =>
+ yield attr_symbol(lexer)?;
};
const ident = ident(lexer)?;
want(lexer, ltok::COLON)?;
const _type = _type(lexer)?;
const init: nullable *ast::expr =
match (try(lexer, ltok::EQUAL)?) {
- lex::token => alloc(expression(lexer)?),
- void => null,
+ case lex::token =>
+ yield alloc(expression(lexer)?);
+ case void =>
+ yield null;
};
const btok = try(lexer, ltok::COMMA)?;
append(decl, ast::decl_global {
@@ -77,9 +82,8 @@ fn decl_global(
_type = _type,
init = init,
});
- match (btok) {
- void => break,
- * => void,
+ if (btok is void) {
+ break;
};
};
return decl;
@@ -96,9 +100,8 @@ fn decl_type(lexer: *lex::lexer) ([]ast::decl_type | error) = {
ident = ident,
_type = _type,
});
- match (btok) {
- void => break,
- * => void,
+ if (btok is void) {
+ break;
};
};
return decl;
@@ -111,15 +114,23 @@ fn decl_func(lexer: *lex::lexer) (ast::decl_func | error) = {
ltok::ATTR_NORETURN, ltok::ATTR_SYMBOL
];
for (true) match (try(lexer, attrs...)?) {
- void => break,
- t: lex::token => switch (t.0) {
- ltok::ATTR_FINI => attr = ast::fndecl_attrs::FINI,
- ltok::ATTR_INIT => attr = ast::fndecl_attrs::INIT,
- ltok::ATTR_TEST => attr = ast::fndecl_attrs::TEST,
- ltok::ATTR_NORETURN => noreturn = true,
- ltok::ATTR_SYMBOL => sym = attr_symbol(lexer)?,
- * => abort("unreachable"),
- },
+ case void =>
+ break;
+ case t: lex::token =>
+ switch (t.0) {
+ case ltok::ATTR_FINI =>
+ attr = ast::fndecl_attrs::FINI;
+ case ltok::ATTR_INIT =>
+ attr = ast::fndecl_attrs::INIT;
+ case ltok::ATTR_TEST =>
+ attr = ast::fndecl_attrs::TEST;
+ case ltok::ATTR_NORETURN =>
+ noreturn = true;
+ case ltok::ATTR_SYMBOL =>
+ sym = attr_symbol(lexer)?;
+ case =>
+ abort("unreachable");
+ };
};
want(lexer, ltok::FN)?;
@@ -134,18 +145,18 @@ fn decl_func(lexer: *lex::lexer) (ast::decl_func | error) = {
let tok = want(lexer, ltok::EQUAL, ltok::SEMICOLON)?;
let body = switch (tok.0) {
- ltok::EQUAL => {
- synassert(ident_loc, len(ident) == 1,
- "Unexpected identifier, was expecting name")?;
- const params = prototype.params;
- for (let i = 0z; i < len(params); i += 1) {
- synassert(params[i].loc,
- len(params[i].name) > 0,
- "Expected parameter name in function declaration")?;
- };
- yield expression(lexer)?;
- },
- ltok::SEMICOLON => lex::unlex(lexer, tok),
+ case ltok::EQUAL =>
+ synassert(ident_loc, len(ident) == 1,
+ "Unexpected identifier, was expecting name")?;
+ const params = prototype.params;
+ for (let i = 0z; i < len(params); i += 1) {
+ synassert(params[i].loc,
+ len(params[i].name) > 0,
+ "Expected parameter name in function declaration")?;
+ };
+ yield expression(lexer)?;
+ case ltok::SEMICOLON =>
+ yield lex::unlex(lexer, tok);
};
return ast::decl_func {
@@ -169,11 +180,11 @@ export fn decls(lexer: *lex::lexer) ([]ast::decl | error) = {
if (peek(lexer, ltok::EOF)? is lex::token) break;
let comment = "";
let exported = match (try(lexer, ltok::EXPORT)?) {
- void => false,
- lex::token => {
- comment = strings::dup(lex::comment(lexer));
- yield true;
- },
+ case void =>
+ yield false;
+ case lex::token =>
+ comment = strings::dup(lex::comment(lexer));
+ yield true;
};
const toks = [ltok::CONST, ltok::LET, ltok::DEF, ltok::TYPE];
const next = try(lexer, toks...)?;
@@ -181,14 +192,18 @@ export fn decls(lexer: *lex::lexer) ([]ast::decl | error) = {
comment = strings::dup(lex::comment(lexer));
};
let decl = match (next) {
- void => decl_func(lexer)?,
- t: lex::token => switch (t.0) {
- ltok::TYPE => decl_type(lexer)?,
- ltok::LET, ltok::CONST =>
- decl_global(lexer, t.0)?,
- ltok::DEF => decl_const(lexer, t.0)?,
- * => abort(),
- },
+ case void =>
+ yield decl_func(lexer)?;
+ case t: lex::token =>
+ yield switch (t.0) {
+ case ltok::TYPE =>
+ yield decl_type(lexer)?;
+ case ltok::LET, ltok::CONST =>
+ yield decl_global(lexer, t.0)?;
+ case ltok::DEF =>
+ yield decl_const(lexer, t.0)?;
+ case => abort();
+ };
};
append(decls, ast::decl {
exported = exported,
diff --git a/hare/parse/expr.ha b/hare/parse/expr.ha
@@ -6,10 +6,7 @@ use strings;
// Parses an expression.
export fn expression(lexer: *lex::lexer) (ast::expr | error) = {
const loc = lex::mkloc(lexer);
- const indirect = match (try(lexer, ltok::TIMES)?) {
- void => false,
- lex::token => true,
- };
+ const indirect = try(lexer, ltok::TIMES)? is lex::token;
// All assignment-op tokens
const atoks: []ltok = [
@@ -39,25 +36,35 @@ export fn expression(lexer: *lex::lexer) (ast::expr | error) = {
ltok::SWITCH, ltok::IF, ltok::LABEL, ltok::FOR,
ltok::BREAK, ltok::CONTINUE, ltok::RETURN, ltok::LET,
ltok::CONST, ltok::YIELD)?) {
- void => binarithm(lexer, void, 0)?,
- tok: lex::token => switch (tok.0) {
- ltok::LABEL, ltok::LBRACE => compound_expr(lexer)?,
- ltok::MATCH => match_expr(lexer)?,
- ltok::SWITCH => switch_expr(lexer)?,
- ltok::IF => if_expr(lexer)?,
- ltok::FOR => for_expr(lexer)?,
- ltok::BREAK,
- ltok::CONTINUE,
- ltok::RETURN => control(lexer)?,
- ltok::LET, ltok::CONST => binding(lexer, false)?,
- ltok::YIELD => yield_expr(lexer)?,
- * => abort(), // Invariant
- },
+ case void =>
+ yield binarithm(lexer, void, 0)?;
+ case tok: lex::token =>
+ yield switch (tok.0) {
+ case ltok::LABEL, ltok::LBRACE =>
+ yield compound_expr(lexer)?;
+ case ltok::MATCH =>
+ yield match_expr(lexer)?;
+ case ltok::SWITCH =>
+ yield switch_expr(lexer)?;
+ case ltok::IF =>
+ yield if_expr(lexer)?;
+ case ltok::FOR =>
+ yield for_expr(lexer)?;
+ case ltok::BREAK, ltok::CONTINUE, ltok::RETURN =>
+ yield control(lexer)?;
+ case ltok::LET, ltok::CONST =>
+ yield binding(lexer, false)?;
+ case ltok::YIELD =>
+ yield yield_expr(lexer)?;
+ case => abort(); // Invariant
+ };
};
const tok = match (try(lexer, atoks...)?) {
- tok: lex::token => tok,
- * => return expr,
+ case tok: lex::token =>
+ yield tok;
+ case =>
+ return expr;
};
synassert(lex::mkloc(lexer),
@@ -65,20 +72,34 @@ export fn expression(lexer: *lex::lexer) (ast::expr | error) = {
"Expected an object-selector or slice for assignment target")?;
const expr = ast::assign_expr {
op = switch (tok.0) {
- ltok::EQUAL => void,
- ltok::BANDEQ => ast::binarithm_op::BAND,
- ltok::BOREQ => ast::binarithm_op::BOR,
- ltok::BXOREQ => ast::binarithm_op::BXOR,
- ltok::DIVEQ => ast::binarithm_op::DIV,
- ltok::LANDEQ => ast::binarithm_op::LAND,
- ltok::LOREQ => ast::binarithm_op::LOR,
- ltok::LSHIFTEQ => ast::binarithm_op::LSHIFT,
- ltok::LXOREQ => ast::binarithm_op::LXOR,
- ltok::MINUSEQ => ast::binarithm_op::MINUS,
- ltok::MODEQ => ast::binarithm_op::MODULO,
- ltok::PLUSEQ => ast::binarithm_op::PLUS,
- ltok::RSHIFTEQ => ast::binarithm_op::RSHIFT,
- ltok::TIMESEQ => ast::binarithm_op::TIMES,
+ case ltok::EQUAL =>
+ yield void;
+ case ltok::BANDEQ =>
+ yield ast::binarithm_op::BAND;
+ case ltok::BOREQ =>
+ yield ast::binarithm_op::BOR;
+ case ltok::BXOREQ =>
+ yield ast::binarithm_op::BXOR;
+ case ltok::DIVEQ =>
+ yield ast::binarithm_op::DIV;
+ case ltok::LANDEQ =>
+ yield ast::binarithm_op::LAND;
+ case ltok::LOREQ =>
+ yield ast::binarithm_op::LOR;
+ case ltok::LSHIFTEQ =>
+ yield ast::binarithm_op::LSHIFT;
+ case ltok::LXOREQ =>
+ yield ast::binarithm_op::LXOR;
+ case ltok::MINUSEQ =>
+ yield ast::binarithm_op::MINUS;
+ case ltok::MODEQ =>
+ yield ast::binarithm_op::MODULO;
+ case ltok::PLUSEQ =>
+ yield ast::binarithm_op::PLUS;
+ case ltok::RSHIFTEQ =>
+ yield ast::binarithm_op::RSHIFT;
+ case ltok::TIMESEQ =>
+ yield ast::binarithm_op::TIMES;
},
object = alloc(expr),
value = alloc(expression(lexer)?),
@@ -96,37 +117,41 @@ fn assert_expr(lexer: *lex::lexer, is_static: bool) (ast::expr | error) = {
const tok = want(lexer, ltok::ABORT, ltok::ASSERT)?;
let expr = switch (tok.0) {
- ltok::ABORT => {
- want(lexer, ltok::LPAREN)?;
- const msg: nullable *ast::expr =
- if (peek(lexer, ltok::RPAREN)? is lex::token) {
- yield null;
- } else alloc(expression(lexer)?);
- want(lexer, ltok::RPAREN)?;
-
- yield ast::assert_expr {
- cond = null,
- message = msg,
- is_static = is_static,
+ case ltok::ABORT =>
+ want(lexer, ltok::LPAREN)?;
+ const msg: nullable *ast::expr =
+ match (peek(lexer, ltok::RPAREN)?) {
+ case lex::token =>
+ yield null;
+ case =>
+ yield alloc(expression(lexer)?);
};
- },
- ltok::ASSERT => {
- want(lexer, ltok::LPAREN)?;
- const cond: nullable *ast::expr =
- alloc(expression(lexer)?);
- const msg: nullable *ast::expr =
- if (try(lexer, ltok::COMMA)? is lex::token) {
- yield alloc(expression(lexer)?);
- } else null;
- want(lexer, ltok::RPAREN)?;
+ want(lexer, ltok::RPAREN)?;
- yield ast::assert_expr {
- cond = cond,
- message = msg,
- is_static = is_static,
+ yield ast::assert_expr {
+ cond = null,
+ message = msg,
+ is_static = is_static,
+ };
+ case ltok::ASSERT =>
+ want(lexer, ltok::LPAREN)?;
+ const cond: nullable *ast::expr =
+ alloc(expression(lexer)?);
+ const msg: nullable *ast::expr =
+ match (try(lexer, ltok::COMMA)?) {
+ case lex::token =>
+ yield alloc(expression(lexer)?);
+ case =>
+ yield null;
};
- },
- * => abort(), // unreachable
+ want(lexer, ltok::RPAREN)?;
+
+ yield ast::assert_expr {
+ cond = cond,
+ message = msg,
+ is_static = is_static,
+ };
+ case => abort(); // unreachable
};
return ast::expr {
@@ -177,24 +202,23 @@ fn append_insert_expr(
const expr = alloc(expression(lexer)?);
switch (want(lexer, ltok::COMMA, ltok::ELLIPSIS, ltok::RPAREN)?.0) {
- ltok::COMMA => append(values, expr),
- ltok::ELLIPSIS => {
- variadic = expr;
- try(lexer, ltok::COMMA)?;
- want(lexer, ltok::RPAREN)?;
- break;
- },
- ltok::RPAREN => {
- append(values, expr);
- break;
- },
- * => abort(),
+ case ltok::COMMA =>
+ append(values, expr);
+ case ltok::ELLIPSIS =>
+ variadic = expr;
+ try(lexer, ltok::COMMA)?;
+ want(lexer, ltok::RPAREN)?;
+ break;
+ case ltok::RPAREN =>
+ append(values, expr);
+ break;
+ case => abort();
};
};
synassert(lex::mkloc(lexer), variadic != null || len(values) != 0,
"Expected values to append")?;
-
+
const expr = if (tok.0 == ltok::APPEND) ast::append_expr {
object = alloc(object),
variadic = variadic,
@@ -217,21 +241,18 @@ fn append_insert_expr(
fn measurement(lexer: *lex::lexer) (ast::expr | error) = {
const tok = want(lexer, ltok::LEN, ltok::SIZE, ltok::OFFSET)?;
const expr = switch (tok.0) {
- ltok::LEN => {
- want(lexer, ltok::LPAREN)?;
- let e = expression(lexer)?;
- want(lexer, ltok::RPAREN)?;
-
- yield alloc(e): ast::len_expr;
- },
- ltok::SIZE => {
- want(lexer, ltok::LPAREN)?;
- let ty = _type(lexer)?;
- want(lexer, ltok::RPAREN)?;
-
- yield alloc(ty): ast::size_expr;
- },
- ltok::OFFSET => abort(), // TODO
+ case ltok::LEN =>
+ want(lexer, ltok::LPAREN)?;
+ let e = expression(lexer)?;
+ want(lexer, ltok::RPAREN)?;
+ yield alloc(e): ast::len_expr;
+ case ltok::SIZE =>
+ want(lexer, ltok::LPAREN)?;
+ let ty = _type(lexer)?;
+ want(lexer, ltok::RPAREN)?;
+ yield alloc(ty): ast::size_expr;
+ case ltok::OFFSET =>
+ abort(); // TODO
};
return ast::expr {
@@ -249,8 +270,10 @@ fn binarithm(
// Precedence climbing parser
// https://en.wikipedia.org/wiki/Operator-precedence_parser
let lvalue = match (lvalue) {
- void => cast(lexer, void)?,
- expr: ast::expr => expr,
+ case void =>
+ yield cast(lexer, void)?;
+ case expr: ast::expr =>
+ yield expr;
};
let tok = lex::lex(lexer)?;
@@ -284,10 +307,7 @@ fn binarithm(
fn binding(lexer: *lex::lexer, is_static: bool) (ast::expr | error) = {
const loc = lex::mkloc(lexer);
- const is_const = switch (want(lexer, ltok::LET, ltok::CONST)?.0) {
- ltok::LET => false,
- ltok::CONST => true,
- };
+ const is_const = want(lexer, ltok::LET, ltok::CONST)?.0 == ltok::CONST;
let bindings: []ast::binding = [];
for (true) {
@@ -304,8 +324,8 @@ fn binding(lexer: *lex::lexer, is_static: bool) (ast::expr | error) = {
init = init,
});
match (try(lexer, ltok::COMMA)?) {
- void => break,
- lex::token => void,
+ case void => break;
+ case lex::token => void;
};
};
@@ -322,49 +342,58 @@ fn binding(lexer: *lex::lexer, is_static: bool) (ast::expr | error) = {
fn builtin(lexer: *lex::lexer) (ast::expr | error) = {
const tok = match (peek(lexer, ltok::ALLOC, ltok::APPEND, ltok::FREE,
- ltok::DELETE, ltok::ABORT, ltok::ASSERT, ltok::INSERT,
- ltok::STATIC, ltok::SIZE, ltok::LEN, ltok::OFFSET,
- ltok::DEFER)?) {
- tok: lex::token => tok,
- void => return postfix(lexer, void),
+ ltok::DELETE, ltok::ABORT, ltok::ASSERT, ltok::INSERT,
+ ltok::STATIC, ltok::SIZE, ltok::LEN, ltok::OFFSET,
+ ltok::DEFER)?) {
+ case tok: lex::token =>
+ yield tok;
+ case void =>
+ return postfix(lexer, void);
};
return switch (tok.0) {
- ltok::ALLOC => alloc_expr(lexer),
- ltok::APPEND, ltok::INSERT => append_insert_expr(lexer, false),
- ltok::DELETE => delete_expr(lexer, false),
- ltok::FREE => free_expr(lexer),
- ltok::ABORT, ltok::ASSERT => assert_expr(lexer, false),
- ltok::STATIC => {
- want(lexer, ltok::STATIC)?;
- let tok = match (peek(lexer, ltok::LET, ltok::CONST,
- ltok::ABORT, ltok::ASSERT, ltok::APPEND,
- ltok::INSERT, ltok::DELETE)?) {
- tok: lex::token => tok,
- // TODO: The following is lame
- void => return syntaxerr(tok.2,
- "Expected let, const, or assert"),
- };
- yield switch (tok.0) {
- ltok::LET, ltok::CONST => binding(lexer, true),
- ltok::ABORT,
- ltok::ASSERT => assert_expr(lexer, true),
- ltok::APPEND,
- ltok::INSERT => append_insert_expr(lexer, true),
- ltok::DELETE => delete_expr(lexer, true),
- * => abort(),
- };
- },
- ltok::SIZE, ltok::LEN, ltok::OFFSET => measurement(lexer),
- ltok::DEFER => {
- want(lexer, ltok::DEFER)?;
- let expr = alloc(expression(lexer)?);
- yield ast::expr {
- start = tok.2,
- end = lex::prevloc(lexer),
- expr = expr: ast::defer_expr,
- };
- },
- * => abort(), // Invariant
+ case ltok::ALLOC =>
+ yield alloc_expr(lexer);
+ case ltok::APPEND, ltok::INSERT =>
+ yield append_insert_expr(lexer, false);
+ case ltok::DELETE =>
+ yield delete_expr(lexer, false);
+ case ltok::FREE =>
+ yield free_expr(lexer);
+ case ltok::ABORT, ltok::ASSERT =>
+ yield assert_expr(lexer, false);
+ case ltok::STATIC =>
+ want(lexer, ltok::STATIC)?;
+ let tok = match (peek(lexer, ltok::LET, ltok::CONST,
+ ltok::ABORT, ltok::ASSERT, ltok::APPEND, ltok::INSERT,
+ ltok::DELETE)?) {
+ case tok: lex::token =>
+ yield tok;
+ case void =>
+ // TODO: The following is lame:
+ return syntaxerr(tok.2, "Expected let, const, or assert");
+ };
+ yield switch (tok.0) {
+ case ltok::LET, ltok::CONST =>
+ yield binding(lexer, true);
+ case ltok::ABORT, ltok::ASSERT =>
+ yield assert_expr(lexer, true);
+ case ltok::APPEND, ltok::INSERT =>
+ yield append_insert_expr(lexer, true);
+ case ltok::DELETE =>
+ yield delete_expr(lexer, true);
+ case => abort();
+ };
+ case ltok::SIZE, ltok::LEN, ltok::OFFSET =>
+ yield measurement(lexer);
+ case ltok::DEFER =>
+ want(lexer, ltok::DEFER)?;
+ let expr = alloc(expression(lexer)?);
+ yield ast::expr {
+ start = tok.2,
+ end = lex::prevloc(lexer),
+ expr = expr: ast::defer_expr,
+ };
+ case => abort(); // Invariant
};
};
@@ -374,25 +403,24 @@ fn call(lexer: *lex::lexer, lvalue: ast::expr) (ast::expr | error) = {
for (true) {
match (try(lexer, ltok::RPAREN)?) {
- lex::token => break,
- void => void,
+ case lex::token => break;
+ case void => void;
};
append(args, alloc(expression(lexer)?));
match (try(lexer, ltok::ELLIPSIS)?) {
- lex::token => {
- variadic = true;
- try(lexer, ltok::COMMA)?;
- want(lexer, ltok::RPAREN)?;
- break;
- },
- void => void,
+ case lex::token =>
+ variadic = true;
+ try(lexer, ltok::COMMA)?;
+ want(lexer, ltok::RPAREN)?;
+ break;
+ case void => void;
};
switch (want(lexer, ltok::COMMA, ltok::RPAREN)?.0) {
- ltok::RPAREN => break,
- * => void,
+ case ltok::RPAREN => break;
+ case => void;
};
};
@@ -409,19 +437,25 @@ fn call(lexer: *lex::lexer, lvalue: ast::expr) (ast::expr | error) = {
fn cast(lexer: *lex::lexer, lvalue: (ast::expr | void)) (ast::expr | error) = {
const lvalue = match (lvalue) {
- void => unarithm(lexer)?,
- e: ast::expr => e,
+ case void =>
+ yield unarithm(lexer)?;
+ case e: ast::expr =>
+ yield e;
};
- const tok = match (try(lexer, ltok::COLON,
- ltok::AS, ltok::IS)?) {
- void => return lvalue,
- tok: lex::token => tok.0,
+ const tok = match (try(lexer, ltok::COLON, ltok::AS, ltok::IS)?) {
+ case void =>
+ return lvalue;
+ case tok: lex::token =>
+ yield tok.0;
};
const kind = switch (tok) {
- ltok::COLON => ast::cast_kind::CAST,
- ltok::AS => ast::cast_kind::ASSERTION,
- ltok::IS => ast::cast_kind::TEST,
- * => abort(),
+ case ltok::COLON =>
+ yield ast::cast_kind::CAST;
+ case ltok::AS =>
+ yield ast::cast_kind::ASSERTION;
+ case ltok::IS =>
+ yield ast::cast_kind::TEST;
+ case => abort();
};
let typ = alloc(_type(lexer)?);
return cast(lexer, ast::expr {
@@ -438,16 +472,22 @@ fn cast(lexer: *lex::lexer, lvalue: (ast::expr | void)) (ast::expr | error) = {
fn constant(lexer: *lex::lexer) (ast::expr | error) = {
const tok = want(lexer)?;
const expr: ast::value = switch (tok.0) {
- ltok::LIT_U8, ltok::LIT_U16, ltok::LIT_U32, ltok::LIT_U64,
+ case ltok::LIT_U8, ltok::LIT_U16, ltok::LIT_U32, ltok::LIT_U64,
ltok::LIT_UINT, ltok::LIT_SIZE, ltok::LIT_I8, ltok::LIT_I16,
ltok::LIT_I32, ltok::LIT_I64, ltok::LIT_INT, ltok::LIT_ICONST,
ltok::LIT_F32, ltok::LIT_F64, ltok::LIT_FCONST, ltok::LIT_RUNE,
- ltok::LIT_STR => tok.1,
- ltok::VOID => void,
- ltok::TRUE => true,
- ltok::FALSE => false,
- ltok::NULL => ast::_null,
- * => return syntaxerr(lex::mkloc(lexer), "Expected constant expression"),
+ ltok::LIT_STR =>
+ yield tok.1;
+ case ltok::VOID =>
+ yield void;
+ case ltok::TRUE =>
+ yield true;
+ case ltok::FALSE =>
+ yield false;
+ case ltok::NULL =>
+ yield ast::_null;
+ case =>
+ return syntaxerr(lex::mkloc(lexer), "Expected constant expression");
};
return ast::expr {
start = tok.2,
@@ -460,17 +500,24 @@ fn control(lexer: *lex::lexer) (ast::expr | error) = {
let tok = want(lexer, ltok::BREAK, ltok::CONTINUE, ltok::RETURN)?;
let label = if (tok.0 == ltok::BREAK || tok.0 == ltok::CONTINUE) {
yield match (try(lexer, ltok::LABEL)?) {
- tok: lex::token => tok.1 as str,
- void => "",
+ case tok: lex::token =>
+ yield tok.1 as str;
+ case void =>
+ yield "";
};
} else "";
const expr = switch (tok.0) {
- ltok::BREAK => label: ast::break_expr,
- ltok::CONTINUE => label: ast::continue_expr,
- ltok::RETURN => match (peek(lexer, ltok::COMMA, ltok::SEMICOLON)?) {
- void => alloc(expression(lexer)?): ast::return_expr,
- lex::token => null: ast::return_expr,
- },
+ case ltok::BREAK =>
+ yield label: ast::break_expr;
+ case ltok::CONTINUE =>
+ yield label: ast::continue_expr;
+ case ltok::RETURN =>
+ yield match (peek(lexer, ltok::COMMA, ltok::SEMICOLON)?) {
+ case void =>
+ yield alloc(expression(lexer)?): ast::return_expr;
+ case lex::token =>
+ yield null: ast::return_expr;
+ };
};
return ast::expr {
start = tok.2,
@@ -500,17 +547,18 @@ fn compound_expr(lexer: *lex::lexer) (ast::expr | error) = {
const start = want(lexer, ltok::LBRACE, ltok::LABEL)?;
const label = switch (start.0) {
- ltok::LABEL => {
- want(lexer, ltok::LBRACE)?;
- yield start.1 as str;
- },
- * => "",
+ case ltok::LABEL =>
+ want(lexer, ltok::LBRACE)?;
+ yield start.1 as str;
+ case =>
+ yield "";
};
for (let more = true; more) {
const item = match (peek(lexer, ltok::RBRACE)?) {
- lex::token => break,
- void => expression(lexer)?,
+ case lex::token => break;
+ case void =>
+ yield expression(lexer)?;
};
append(items, alloc(item));
want(lexer, ltok::SEMICOLON)?;
@@ -531,31 +579,28 @@ fn for_expr(lexer: *lex::lexer) (ast::expr | error) = {
const tok = want(lexer, ltok::FOR)?;
want(lexer, ltok::LPAREN)?;
- const bindings: nullable *ast::expr = match (peek(
- lexer, ltok::LET, ltok::CONST)?) {
- void => null,
- lex::token => {
+ const bindings: nullable *ast::expr =
+ match (peek(lexer, ltok::LET, ltok::CONST)?) {
+ case void =>
+ yield null;
+ case lex::token =>
const bindings = alloc(binding(lexer, false)?);
want(lexer, ltok::SEMICOLON)?;
yield bindings;
- },
- };
-
+ };
const cond = alloc(expression(lexer)?);
-
- const afterthought: nullable *ast::expr = match (peek(
- lexer, ltok::SEMICOLON)) {
- void => null,
- lex::token => {
+ const afterthought: nullable *ast::expr =
+ match (peek(lexer, ltok::SEMICOLON)) {
+ case void =>
+ yield null;
+ case lex::token =>
want(lexer, ltok::SEMICOLON)?;
yield alloc(expression(lexer)?);
- },
- };
+ };
want(lexer, ltok::RPAREN)?;
const body = alloc(expression(lexer)?);
-
return ast::expr {
start = tok.2,
end = lex::prevloc(lexer),
@@ -587,8 +632,10 @@ fn if_expr(lexer: *lex::lexer) (ast::expr | error) = {
want(lexer, ltok::RPAREN)?;
const tbranch = alloc(expression(lexer)?);
const fbranch: nullable *ast::expr = match (try(lexer, ltok::ELSE)?) {
- void => null,
- lex::token => alloc(expression(lexer)?),
+ case void =>
+ yield null;
+ case lex::token =>
+ yield alloc(expression(lexer)?);
};
return ast::expr {
start = start.2,
@@ -605,17 +652,16 @@ 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;
- match (try(lexer, ltok::SLICE)?) {
- void => start = alloc(expression(lexer)?),
- lex::token => is_slice = true,
+ if (try(lexer, ltok::SLICE)? is lex::token) {
+ is_slice = true;
+ } else {
+ start = alloc(expression(lexer)?);
};
- if (!is_slice) match (try(lexer, ltok::SLICE)?) {
- void => void,
- lex::token => is_slice = true,
+ if (!is_slice && try(lexer, ltok::SLICE)? is lex::token) {
+ is_slice = true;
};
- if (is_slice) match (peek(lexer, ltok::RBRACKET)?) {
- lex::token => void,
- void => end = alloc(expression(lexer)?),
+ if (is_slice && peek(lexer, ltok::RBRACKET)? is void) {
+ end = alloc(expression(lexer)?);
};
want(lexer, ltok::RBRACKET)?;
@@ -648,48 +694,49 @@ fn plain_expression(lexer: *lex::lexer) (ast::expr | error) = {
if (tok.0 >= ltok::LIT_U8 && tok.0 <= ltok::LAST_LITERAL) {
return constant(lexer);
};
- return switch (tok.0) {
- ltok::TRUE, ltok::FALSE, ltok::NULL, ltok::VOID =>
- constant(lexer),
- ltok::LBRACKET => plain_array(lexer)?,
- ltok::STRUCT => {
- let s = plain_struct(lexer, [])?;
+ switch (tok.0) {
+ case ltok::TRUE, ltok::FALSE, ltok::NULL, ltok::VOID =>
+ return constant(lexer);
+ case ltok::LBRACKET =>
+ return plain_array(lexer)?;
+ case ltok::STRUCT =>
+ let s = plain_struct(lexer, [])?;
+ return ast::expr {
+ start = tok.2,
+ end = lex::prevloc(lexer),
+ expr = s,
+ };
+ case ltok::LPAREN =>
+ want(lexer, ltok::LPAREN)?;
+ let ex = expression(lexer)?;
+ switch (want(lexer, ltok::RPAREN, ltok::COMMA)?.0) {
+ case ltok::RPAREN =>
+ return ex;
+ case ltok::COMMA =>
+ return plain_tuple(lexer, ex, tok.2)?;
+ case => abort();
+ };
+ case ltok::NAME =>
+ let id = ident(lexer)?;
+ match (peek(lexer, ltok::LBRACE)?) {
+ case void =>
return ast::expr {
start = tok.2,
end = lex::prevloc(lexer),
- expr = s,
+ expr = id: ast::access_identifier,
};
- },
- ltok::LPAREN => {
- want(lexer, ltok::LPAREN)?;
- let ex = expression(lexer)?;
- return switch (want(lexer, ltok::RPAREN, ltok::COMMA)?.0) {
- ltok::RPAREN => ex,
- ltok::COMMA => plain_tuple(lexer, ex, tok.2)?,
- * => abort(),
- };
- },
- ltok::NAME => {
- let id = ident(lexer)?;
- return match (peek(lexer, ltok::LBRACE)?) {
- void => ast::expr {
- start = tok.2,
- end = lex::prevloc(lexer),
- expr = id: ast::access_identifier,
- },
- lex::token => {
- let s = plain_struct(lexer, id)?;
- yield ast::expr {
- start = tok.2,
- end = lex::prevloc(lexer),
- expr = s,
- };
- },
+ case lex::token =>
+ let s = plain_struct(lexer, id)?;
+ return ast::expr {
+ start = tok.2,
+ end = lex::prevloc(lexer),
+ expr = s,
};
- },
- * => syntaxerr(lex::mkloc(lexer),
+ };
+ case =>
+ return syntaxerr(lex::mkloc(lexer),
"Unexpected {}, was expecting an expression",
- lex::tokstr(tok)),
+ lex::tokstr(tok));
};
};
@@ -700,27 +747,26 @@ fn plain_array(lexer: *lex::lexer) (ast::expr | error) = {
let expand = false;
for (true) {
match (try(lexer, ltok::RBRACKET)?) {
- lex::token => break,
- void => void,
+ case lex::token => break;
+ case void => void;
};
append(values, alloc(expression(lexer)?));
match (try(lexer, ltok::COMMA, ltok::ELLIPSIS)?) {
- void => {
+ case void =>
+ want(lexer, ltok::RBRACKET)?;
+ break;
+ case tok: lex::token =>
+ switch (tok.0) {
+ case ltok::ELLIPSIS =>
+ expand = true;
+ try(lexer, ltok::COMMA)?;
want(lexer, ltok::RBRACKET)?;
break;
- },
- tok: lex::token => switch (tok.0) {
- ltok::COMMA => void,
- ltok::ELLIPSIS => {
- expand = true;
- try(lexer, ltok::COMMA)?;
- want(lexer, ltok::RBRACKET)?;
- break;
- },
- * => abort(),
- },
+ case ltok::COMMA => void;
+ case => abort();
+ };
};
};
return ast::expr {
@@ -748,27 +794,24 @@ fn plain_struct(
const tok = want(lexer, ltok::ELLIPSIS,
ltok::NAME, ltok::STRUCT)?;
switch (tok.0) {
- ltok::ELLIPSIS => {
- synassert(lex::mkloc(lexer), len(alias) != 0,
- "Cannot use auto-fill with anonymous struct")?;
- autofill = true;
- try(lexer, ltok::COMMA)?;
- want(lexer, ltok::RBRACE)?;
- break;
- },
- ltok::NAME, ltok::STRUCT => {
- lex::unlex(lexer, tok);
- append(fields, struct_field(lexer)?);
- },
+ case ltok::ELLIPSIS =>
+ synassert(lex::mkloc(lexer), len(alias) != 0,
+ "Cannot use auto-fill with anonymous struct")?;
+ autofill = true;
+ try(lexer, ltok::COMMA)?;
+ want(lexer, ltok::RBRACE)?;
+ break;
+ case ltok::NAME, ltok::STRUCT =>
+ lex::unlex(lexer, tok);
+ append(fields, struct_field(lexer)?);
};
switch (want(lexer, ltok::COMMA, ltok::RBRACE)?.0) {
- ltok::COMMA => {
- if (try(lexer, ltok::RBRACE) is lex::token) {
- break;
- };
- },
- ltok::RBRACE => break,
+ case ltok::RBRACE => break;
+ case ltok::COMMA =>
+ if (try(lexer, ltok::RBRACE) is lex::token) {
+ break;
+ };
};
};
@@ -784,46 +827,44 @@ fn struct_field(
) (ast::struct_value | *ast::struct_constant | error) = {
const tok = want(lexer, ltok::NAME, ltok::STRUCT)?;
switch (tok.0) {
- ltok::NAME => {
- const name = strings::dup(tok.1 as str);
- const tok = match (try(lexer, ltok::COLON,
- ltok::DOUBLE_COLON, ltok::EQUAL)?) {
- tok: lex::token => tok,
- void => {
- let id: ast::ident = alloc([name]);
- return alloc(plain_struct(lexer, id)?);
- },
+ case ltok::NAME =>
+ const name = strings::dup(tok.1 as str);
+ const tok = match (try(lexer, ltok::COLON,
+ ltok::DOUBLE_COLON, ltok::EQUAL)?) {
+ case tok: lex::token =>
+ yield tok;
+ case void =>
+ let id: ast::ident = alloc([name]);
+ return alloc(plain_struct(lexer, id)?);
+ };
+
+ switch (tok.0) {
+ case ltok::COLON =>
+ const _type = alloc(_type(lexer)?);
+ want(lexer, ltok::EQUAL)?;
+ const init = alloc(expression(lexer)?);
+ return ast::struct_value {
+ name = name,
+ _type = _type,
+ init = init,
};
- return switch (tok.0) {
- ltok::COLON => {
- const _type = alloc(_type(lexer)?);
- want(lexer, ltok::EQUAL)?;
- const init = alloc(expression(lexer)?);
- yield ast::struct_value {
- name = name,
- _type = _type,
- init = init,
- };
- },
- ltok::DOUBLE_COLON => {
- let id: ast::ident = alloc([name]);
- let rest = ident(lexer)?;
- append(id, rest...);
- return alloc(plain_struct(lexer, id)?);
- },
- ltok::EQUAL => ast::struct_value {
- name = name,
- _type = null,
- init = alloc(expression(lexer)?),
- },
- * => abort(), // Invariant
+ case ltok::DOUBLE_COLON =>
+ let id: ast::ident = alloc([name]);
+ let rest = ident(lexer)?;
+ append(id, rest...);
+ return alloc(plain_struct(lexer, id)?);
+ case ltok::EQUAL =>
+ return ast::struct_value {
+ name = name,
+ _type = null,
+ init = alloc(expression(lexer)?),
};
- },
- ltok::STRUCT => {
- lex::unlex(lexer, tok);
- return alloc(plain_struct(lexer, [])?);
- },
- * => abort(), // Invariant
+ case => abort(); // Invariant
+ };
+ case ltok::STRUCT =>
+ lex::unlex(lexer, tok);
+ return alloc(plain_struct(lexer, [])?);
+ case => abort(); // Invariant
};
};
@@ -837,18 +878,17 @@ fn plain_tuple(
for (true) {
match (try(lexer, ltok::RPAREN)?) {
- lex::token => break,
- void => void,
+ case lex::token => break;
+ case void => void;
};
append(values, alloc(expression(lexer)?));
match (try(lexer, ltok::COMMA)?) {
- void => {
- want(lexer, ltok::RPAREN)?;
- break;
- },
- lex::token => void,
+ case lex::token => void;
+ case void =>
+ want(lexer, ltok::RPAREN)?;
+ break;
};
};
@@ -862,51 +902,66 @@ fn plain_tuple(
fn postfix(lexer: *lex::lexer, lvalue: (ast::expr | void)) (ast::expr | error) = {
let lvalue = match (lvalue) {
- void => plain_expression(lexer)?,
- ex: ast::expr => ex,
- };
-
- return postfix(lexer, match (try(lexer, ltok::LPAREN,
- ltok::DOT, ltok::LBRACKET, ltok::QUESTION, ltok::LNOT)) {
- tok: lex::token => switch (tok.0) {
- ltok::LPAREN => call(lexer, lvalue)?,
- ltok::DOT => postfix_dot(lexer, lvalue)?,
- ltok::LBRACKET => indexing(lexer, lvalue)?,
- ltok::QUESTION => ast::expr {
- start = lvalue.start,
- end = lex::prevloc(lexer),
- expr = ast::propagate_expr {
- is_abort = false,
- expr = alloc(lvalue),
- },
+ case void =>
+ yield plain_expression(lexer)?;
+ case ex: ast::expr =>
+ yield ex;
+ };
+
+ let tok = match (try(lexer, ltok::LPAREN, ltok::DOT,
+ ltok::LBRACKET, ltok::QUESTION, ltok::LNOT)) {
+ case void =>
+ return lvalue;
+ case tok: lex::token =>
+ yield tok;
+ };
+
+ let next = switch (tok.0) {
+ case ltok::LPAREN =>
+ yield call(lexer, lvalue)?;
+ case ltok::DOT =>
+ yield postfix_dot(lexer, lvalue)?;
+ case ltok::LBRACKET =>
+ yield indexing(lexer, lvalue)?;
+ case ltok::QUESTION =>
+ yield ast::expr {
+ start = lvalue.start,
+ end = lex::prevloc(lexer),
+ expr = ast::propagate_expr {
+ is_abort = false,
+ expr = alloc(lvalue),
},
- ltok::LNOT => ast::expr {
- start = lvalue.start,
- end = lex::prevloc(lexer),
- expr = ast::propagate_expr {
- is_abort = true,
- expr = alloc(lvalue),
- },
+ };
+ case ltok::LNOT =>
+ yield ast::expr {
+ start = lvalue.start,
+ end = lex::prevloc(lexer),
+ expr = ast::propagate_expr {
+ is_abort = true,
+ expr = alloc(lvalue),
},
- * => abort(),
- },
- void => return lvalue,
- });
+ };
+ case => abort();
+ };
+
+ return postfix(lexer, next);
};
fn postfix_dot(
lexer: *lex::lexer,
lvalue: ast::expr,
-) (ast::expr | error) = match (try(lexer, ltok::NAME)?) {
- tok: lex::token => ast::expr {
- start = lvalue.start,
- end = lex::prevloc(lexer),
- expr = ast::access_field {
- object = alloc(lvalue),
- field = tok.1 as str,
- },
- },
- void => {
+) (ast::expr | error) = {
+ match (try(lexer, ltok::NAME)?) {
+ case tok: lex::token =>
+ return ast::expr {
+ start = lvalue.start,
+ end = lex::prevloc(lexer),
+ expr = ast::access_field {
+ object = alloc(lvalue),
+ field = tok.1 as str,
+ },
+ };
+ case void =>
let con = constant(lexer)?;
let val = con.expr as ast::constant_expr;
synassert(lex::mkloc(lexer), val is ast::value,
@@ -914,7 +969,7 @@ fn postfix_dot(
let val = val as ast::value;
synassert(lex::mkloc(lexer), val is i64,
"Expected integer constant")?;
- yield ast::expr {
+ return ast::expr {
start = lvalue.start,
end = lex::prevloc(lexer),
expr = ast::access_tuple {
@@ -922,7 +977,7 @@ fn postfix_dot(
value = alloc(con),
},
};
- },
+ };
};
fn switch_expr(lexer: *lex::lexer) (ast::expr | error) = {
@@ -936,19 +991,15 @@ fn switch_expr(lexer: *lex::lexer) (ast::expr | error) = {
let cases: []ast::switch_case = [];
for (true) {
- if (try(lexer, ltok::RBRACE)? is lex::token) break;
+ want(lexer, ltok::CASE)?;
let opts: []*ast::expr = [];
- if (try(lexer, ltok::TIMES)? is lex::token) {
- want(lexer, ltok::CASE)?;
- } else {
+ if (try(lexer, ltok::ARROW)? is void) {
for (true) {
- if (try(lexer, ltok::CASE) is lex::token) break;
-
append(opts, alloc(expression(lexer)?));
- if (!(try(lexer, ltok::COMMA) is lex::token)) {
- want(lexer, ltok::CASE)?;
+ if (try(lexer, ltok::COMMA)? is void) {
+ want(lexer, ltok::ARROW)?;
break;
};
};
@@ -956,13 +1007,18 @@ fn switch_expr(lexer: *lex::lexer) (ast::expr | error) = {
"Expected a list of options")?;
};
+ let exprs: []*ast::expr = [];
+ for (peek(lexer, ltok::CASE, ltok::RBRACE)? is void) {
+ append(exprs, alloc(expression(lexer)?));
+ want(lexer, ltok::SEMICOLON)?;
+ };
+
append(cases, ast::switch_case {
options = opts,
- value = alloc(expression(lexer)?),
+ exprs = exprs,
});
- if (!(try(lexer, ltok::COMMA) is lex::token)) {
- want(lexer, ltok::RBRACE)?;
+ if (try(lexer, ltok::RBRACE)? is lex::token) {
break;
};
};
@@ -983,24 +1039,28 @@ fn match_case(lexer: *lex::lexer) (ast::match_case | error) = {
let tok = peek(lexer)? as lex::token;
let loc = tok.2;
let nt = switch (tok.0) {
- ltok::NULL => {
- want(lexer, ltok::NULL)?;
- yield ("", ast::_type {
- start = loc,
- end = lex::prevloc(lexer),
- flags = 0,
- repr = ast::builtin_type::NULL,
- });
- },
- * => nametype(lexer)?,
+ case ltok::NULL =>
+ want(lexer, ltok::NULL)?;
+ yield ("", ast::_type {
+ start = loc,
+ end = lex::prevloc(lexer),
+ flags = 0,
+ repr = ast::builtin_type::NULL,
+ });
+ case =>
+ yield nametype(lexer)?;
+ };
+ want(lexer, ltok::ARROW)?;
+ let exprs: []*ast::expr = [];
+ for (peek(lexer, ltok::CASE, ltok::RBRACE)? is void) {
+ append(exprs, alloc(expression(lexer)?));
+ want(lexer, ltok::SEMICOLON)?;
};
- want(lexer, ltok::CASE)?;
- let expr = expression(lexer)?;
return ast::match_case {
name = nt.0,
_type = alloc(nt.1),
- value = alloc(expr),
+ exprs = exprs,
};
};
@@ -1012,41 +1072,26 @@ fn match_expr(lexer: *lex::lexer) (ast::expr | error) = {
want(lexer, ltok::LBRACE)?;
let cases: []ast::match_case = [];
- let default: nullable *ast::expr = null;
+ let default: []*ast::expr = [];
for (true) {
- match (try(lexer, ltok::TIMES)?) {
- void => append(cases, match_case(lexer)?),
- t: lex::token => match (try(lexer, ltok::CASE)?) {
- void => {
- let case = match_case(lexer)?;
- case._type = alloc(ast::_type {
- start = t.2,
- end = case._type.end,
- flags = 0,
- repr = ast::pointer_type {
- referent = case._type,
- flags = 0,
- },
- });
- append(cases, case);
- },
- lex::token => if (default == null) {
- default = alloc(expression(lexer)?);
- } else return syntaxerr(t.2,
- "More than one default match case"),
- },
- };
+ want(lexer, ltok::CASE)?;
- match (try(lexer, ltok::COMMA)?) {
- void => {
- want(lexer, ltok::RBRACE)?;
- break;
- },
- lex::token => void,
+ match (try(lexer, ltok::ARROW)?) {
+ case t: lex::token =>
+ if (len(default) != 0) {
+ return syntaxerr(t.2,
+ "More than one default match case");
+ };
+ for (peek(lexer, ltok::CASE, ltok::RBRACE)? is void) {
+ append(default, alloc(expression(lexer)?));
+ want(lexer, ltok::SEMICOLON)?;
+ };
+ case void =>
+ append(cases, match_case(lexer)?);
};
- match (try(lexer, ltok::RBRACE)?) {
- void => void,
- lex::token => break,
+
+ if (try(lexer, ltok::RBRACE)? is lex::token) {
+ break;
};
};
@@ -1063,20 +1108,30 @@ fn match_expr(lexer: *lex::lexer) (ast::expr | error) = {
fn unarithm(lexer: *lex::lexer) (ast::expr | error) = {
const tok = match (try(lexer,
- ltok::PLUS, ltok::MINUS, ltok::BNOT,
- ltok::LNOT, ltok::TIMES, ltok::BAND)) {
- void => return builtin(lexer),
- tok: lex::token => tok,
+ ltok::PLUS, ltok::MINUS, ltok::BNOT,
+ ltok::LNOT, ltok::TIMES, ltok::BAND)) {
+ case void =>
+ return builtin(lexer);
+ case tok: lex::token =>
+ yield tok;
};
+
const op = switch (tok.0) {
- ltok::PLUS => ast::unarithm_op::PLUS,
- ltok::MINUS => ast::unarithm_op::MINUS,
- ltok::BNOT => ast::unarithm_op::BNOT,
- ltok::LNOT => ast::unarithm_op::LNOT,
- ltok::TIMES => ast::unarithm_op::DEREF,
- ltok::BAND => ast::unarithm_op::ADDR,
- * => abort(),
+ case ltok::PLUS =>
+ yield ast::unarithm_op::PLUS;
+ case ltok::MINUS =>
+ yield ast::unarithm_op::MINUS;
+ case ltok::BNOT =>
+ yield ast::unarithm_op::BNOT;
+ case ltok::LNOT =>
+ yield ast::unarithm_op::LNOT;
+ case ltok::TIMES =>
+ yield ast::unarithm_op::DEREF;
+ case ltok::BAND =>
+ yield ast::unarithm_op::ADDR;
+ case => abort();
};
+
let operand = unarithm(lexer)?;
return ast::expr {
start = tok.2,
@@ -1093,15 +1148,20 @@ fn yield_expr(lexer: *lex::lexer) (ast::expr | error) = {
let label = "";
let value: nullable *ast::expr = null;
match (try(lexer, ltok::SEMICOLON, ltok::LABEL)?) {
- void => value = alloc(expression(lexer)?),
- t: lex::token => switch (t.0) {
- ltok::SEMICOLON => lex::unlex(lexer, t),
- ltok::LABEL => {
- label = t.1 as str;
- if (try(lexer, ltok::COMMA)? is void) yield;
+ case void =>
+ value = alloc(expression(lexer)?);
+ case t: lex::token =>
+ switch (t.0) {
+ case ltok::SEMICOLON =>
+ lex::unlex(lexer, t);
+ case ltok::LABEL =>
+ label = t.1 as str;
+ match (try(lexer, ltok::COMMA)?) {
+ case void => void;
+ case lex::token =>
value = alloc(expression(lexer)?);
- },
- },
+ };
+ };
};
return ast::expr {
start = start.2,
@@ -1113,40 +1173,75 @@ fn yield_expr(lexer: *lex::lexer) (ast::expr | error) = {
};
};
-fn binop_for_tok(tok: lex::token) ast::binarithm_op = switch (tok.0) {
- ltok::BAND => ast::binarithm_op::BAND,
- ltok::BOR => ast::binarithm_op::BOR,
- ltok::BXOR => ast::binarithm_op::BXOR,
- ltok::DIV => ast::binarithm_op::DIV,
- ltok::GREATER => ast::binarithm_op::GT,
- ltok::GREATEREQ => ast::binarithm_op::GTEQ,
- ltok::LAND => ast::binarithm_op::LAND,
- ltok::LEQUAL => ast::binarithm_op::LEQUAL,
- ltok::LESS => ast::binarithm_op::LESS,
- ltok::LESSEQ => ast::binarithm_op::LESSEQ,
- ltok::LOR => ast::binarithm_op::LOR,
- ltok::LSHIFT => ast::binarithm_op::LSHIFT,
- ltok::LXOR => ast::binarithm_op::LXOR,
- ltok::MINUS => ast::binarithm_op::MINUS,
- ltok::MODULO => ast::binarithm_op::MODULO,
- ltok::NEQUAL => ast::binarithm_op::NEQUAL,
- ltok::PLUS => ast::binarithm_op::PLUS,
- ltok::RSHIFT => ast::binarithm_op::RSHIFT,
- ltok::TIMES => ast::binarithm_op::TIMES,
- * => abort(),
+fn binop_for_tok(tok: lex::token) ast::binarithm_op = {
+ switch (tok.0) {
+ case ltok::BAND =>
+ return ast::binarithm_op::BAND;
+ case ltok::BOR =>
+ return ast::binarithm_op::BOR;
+ case ltok::BXOR =>
+ return ast::binarithm_op::BXOR;
+ case ltok::DIV =>
+ return ast::binarithm_op::DIV;
+ case ltok::GREATER =>
+ return ast::binarithm_op::GT;
+ case ltok::GREATEREQ =>
+ return ast::binarithm_op::GTEQ;
+ case ltok::LAND =>
+ return ast::binarithm_op::LAND;
+ case ltok::LEQUAL =>
+ return ast::binarithm_op::LEQUAL;
+ case ltok::LESS =>
+ return ast::binarithm_op::LESS;
+ case ltok::LESSEQ =>
+ return ast::binarithm_op::LESSEQ;
+ case ltok::LOR =>
+ return ast::binarithm_op::LOR;
+ case ltok::LSHIFT =>
+ return ast::binarithm_op::LSHIFT;
+ case ltok::LXOR =>
+ return ast::binarithm_op::LXOR;
+ case ltok::MINUS =>
+ return ast::binarithm_op::MINUS;
+ case ltok::MODULO =>
+ return ast::binarithm_op::MODULO;
+ case ltok::NEQUAL =>
+ return ast::binarithm_op::NEQUAL;
+ case ltok::PLUS =>
+ return ast::binarithm_op::PLUS;
+ case ltok::RSHIFT =>
+ return ast::binarithm_op::RSHIFT;
+ case ltok::TIMES =>
+ return ast::binarithm_op::TIMES;
+ case => abort();
+ };
};
-fn precedence(tok: lex::token) int = switch (tok.0) {
- ltok::LOR => 0,
- ltok::LXOR => 1,
- ltok::LAND => 2,
- ltok::LEQUAL, ltok::NEQUAL => 3,
- ltok::LESS, ltok::LESSEQ, ltok::GREATER, ltok::GREATEREQ => 4,
- ltok::BOR => 5,
- ltok::BXOR => 6,
- ltok::BAND => 7,
- ltok::LSHIFT, ltok::RSHIFT => 8,
- ltok::PLUS, ltok::MINUS => 9,
- ltok::TIMES, ltok::DIV, ltok::MODULO => 10,
- * => -1,
+fn precedence(tok: lex::token) int = {
+ switch (tok.0) {
+ case ltok::LOR =>
+ return 0;
+ case ltok::LXOR =>
+ return 1;
+ case ltok::LAND =>
+ return 2;
+ case ltok::LEQUAL, ltok::NEQUAL =>
+ return 3;
+ case ltok::LESS, ltok::LESSEQ, ltok::GREATER, ltok::GREATEREQ =>
+ return 4;
+ case ltok::BOR =>
+ return 5;
+ case ltok::BXOR =>
+ return 6;
+ case ltok::BAND =>
+ return 7;
+ case ltok::LSHIFT, ltok::RSHIFT =>
+ return 8;
+ case ltok::PLUS, ltok::MINUS =>
+ return 9;
+ case ltok::TIMES, ltok::DIV, ltok::MODULO =>
+ return 10;
+ case =>
+ return -1;
+ };
};
diff --git a/hare/parse/ident.ha b/hare/parse/ident.ha
@@ -10,14 +10,16 @@ fn ident_trailing(lexer: *lex::lexer) ((ast::ident, bool) | error) = {
let z = 0z;
for (true) {
let name = match (try(lexer, ltok::NAME)?) {
- t: lex::token => t.1 as str,
- void => return (ident: ast::ident, true),
+ case t: lex::token =>
+ yield t.1 as str;
+ case void =>
+ return (ident: ast::ident, true);
};
append(ident, name);
z += len(name);
match (try(lexer, ltok::DOUBLE_COLON)?) {
- void => break,
- * => void, // Grab the next ident
+ case void => break;
+ case => void; // Grab the next ident
};
z += 1;
};
diff --git a/hare/parse/import.ha b/hare/parse/import.ha
@@ -6,13 +6,17 @@ fn name_list(lexer: *lex::lexer) ([]str | error) = {
let names: []str = [];
for (true) {
append(names, want(lexer, ltok::NAME)?.1 as str);
+
switch (want(lexer, ltok::COMMA, ltok::RBRACE)?.0) {
- ltok::COMMA => match (try(lexer, ltok::RBRACE)?) {
- void => void,
- * => return names,
- },
- ltok::RBRACE => return names,
- * => abort(), // Unreachable
+ case ltok::COMMA =>
+ match (try(lexer, ltok::RBRACE)?) {
+ case void => void;
+ case =>
+ return names;
+ };
+ case ltok::RBRACE =>
+ return names;
+ case => abort(); // Unreachable
};
};
abort();
@@ -23,41 +27,37 @@ export fn imports(lexer: *lex::lexer) ([]ast::import | error) = {
let imports: []ast::import = [];
for (true) {
match (try(lexer, ltok::USE)?) {
- void => break,
- * => void,
+ case void => break;
+ case => void;
};
let name = ident_trailing(lexer)?;
-
switch (want(lexer, ltok::SEMICOLON, ltok::LBRACE,
- ltok::EQUAL)?.0) {
- ltok::SEMICOLON => {
- synassert(lex::mkloc(lexer), !name.1,
- "Unexpected trailing :: in ident")?;
- append(imports, name.0: ast::import_module);
- },
- ltok::LBRACE => {
- synassert(lex::mkloc(lexer), name.1,
- "Expected trailing :: in ident")?;
- let objects = name_list(lexer)?;
- append(imports, ast::import_objects {
- ident = name.0,
- objects = objects,
- });
- want(lexer, ltok::SEMICOLON)?;
- },
- ltok::EQUAL => {
- synassert(lex::mkloc(lexer),
- len(name.0) == 1 && !name.1,
- "Expected name, not ident")?;
- let ident = ident(lexer)?;
- append(imports, ast::import_alias {
- ident = ident,
- alias = name.0[0],
- });
- want(lexer, ltok::SEMICOLON)?;
- },
- * => abort(), // Unreachable
+ ltok::EQUAL)?.0) {
+ case ltok::SEMICOLON =>
+ synassert(lex::mkloc(lexer), !name.1,
+ "Unexpected trailing :: in ident")?;
+ append(imports, name.0: ast::import_module);
+ case ltok::LBRACE =>
+ synassert(lex::mkloc(lexer), name.1,
+ "Expected trailing :: in ident")?;
+ let objects = name_list(lexer)?;
+ append(imports, ast::import_objects {
+ ident = name.0,
+ objects = objects,
+ });
+ want(lexer, ltok::SEMICOLON)?;
+ case ltok::EQUAL =>
+ synassert(lex::mkloc(lexer),
+ len(name.0) == 1 && !name.1,
+ "Expected name, not ident")?;
+ let ident = ident(lexer)?;
+ append(imports, ast::import_alias {
+ ident = ident,
+ alias = name.0[0],
+ });
+ want(lexer, ltok::SEMICOLON)?;
+ case => abort(); // Unreachable
};
};
return imports;
diff --git a/hare/parse/parse.ha b/hare/parse/parse.ha
@@ -91,41 +91,40 @@ fn synassert(loc: lex::location, cond: bool, msg: str) (void | error) = {
fn nametype(lexer: *lex::lexer) ((str, ast::_type) | error) = {
let tok = peek(lexer)? as lex::token;
const start = tok.2;
- return switch (tok.0) {
- ltok::NAME => {
- let name = tok.1 as str;
- want(lexer, ltok::NAME)?;
- tok = peek(lexer)? as lex::token;
- yield switch (tok.0) {
- ltok::COLON => {
- want(lexer, ltok::COLON)?;
- yield (name, _type(lexer)?);
+ switch (tok.0) {
+ case ltok::NAME =>
+ let name = tok.1 as str;
+ want(lexer, ltok::NAME)?;
+ tok = peek(lexer)? as lex::token;
+ switch (tok.0) {
+ case ltok::COLON =>
+ want(lexer, ltok::COLON)?;
+ return (name, _type(lexer)?);
+ case ltok::DOUBLE_COLON =>
+ want(lexer, ltok::DOUBLE_COLON)?;
+ let id = ident(lexer)?;
+ insert(id[0], name);
+ return ("", ast::_type {
+ start = start,
+ end = lex::prevloc(lexer),
+ flags = 0,
+ repr = ast::alias_type {
+ unwrap = false,
+ ident = id,
},
- ltok::DOUBLE_COLON => {
- want(lexer, ltok::DOUBLE_COLON)?;
- let id = ident(lexer)?;
- insert(id[0], name);
- yield ("", ast::_type {
- start = start,
- end = lex::prevloc(lexer),
- flags = 0,
- repr = ast::alias_type {
- unwrap = false,
- ident = id,
- },
- });
+ });
+ case =>
+ return ("", ast::_type {
+ start = start,
+ end = lex::prevloc(lexer),
+ flags = 0,
+ repr = ast::alias_type {
+ unwrap = false,
+ ident = alloc([name]),
},
- * => ("", ast::_type {
- start = start,
- end = lex::prevloc(lexer),
- flags = 0,
- repr = ast::alias_type {
- unwrap = false,
- ident = alloc([name]),
- },
- }),
- };
- },
- * => ("", _type(lexer)?),
+ });
+ };
+ case =>
+ return ("", _type(lexer)?);
};
};
diff --git a/hare/parse/type.ha b/hare/parse/type.ha
@@ -10,20 +10,24 @@ fn prototype(lexer: *lex::lexer) (ast::func_type | error) = {
for (try(lexer, ltok::RPAREN)? is void) {
let loc = lex::mkloc(lexer);
match (try(lexer, ltok::ELLIPSIS)?) {
- void => void,
- lex::token => {
- synassert(loc, len(params) > 0,
- "Expected at least one non-variadic parameter for C-style variadism")?;
- variadism = ast::variadism::C;
- try(lexer, ltok::COMMA)?;
- want(lexer, ltok::RPAREN)?;
- break;
- },
+ case void =>
+ yield void;
+ case lex::token =>
+ synassert(loc, len(params) > 0,
+ "Expected at least one non-variadic parameter for C-style variadism")?;
+ variadism = ast::variadism::C;
+ try(lexer, ltok::COMMA)?;
+ want(lexer, ltok::RPAREN)?;
+ break;
};
+
let name = match (try(lexer, ltok::UNDERSCORE)?) {
- void => want(lexer, ltok::NAME)?.1 as str,
- lex::token => "",
+ case void =>
+ yield want(lexer, ltok::NAME)?.1 as str;
+ case lex::token =>
+ yield "";
};
+
want(lexer, ltok::COLON)?;
append(params, ast::func_param {
loc = loc,
@@ -31,20 +35,19 @@ fn prototype(lexer: *lex::lexer) (ast::func_type | error) = {
_type = alloc(_type(lexer)?),
});
match (try(lexer, ltok::ELLIPSIS)?) {
- void => void,
- lex::token => {
- variadism = ast::variadism::HARE;
- try(lexer, ltok::COMMA)?;
- want(lexer, ltok::RPAREN)?;
- break;
- },
+ case void =>
+ yield void;
+ case lex::token =>
+ variadism = ast::variadism::HARE;
+ try(lexer, ltok::COMMA)?;
+ want(lexer, ltok::RPAREN)?;
+ break;
};
match (try(lexer, ltok::COMMA)?) {
- void => {
- want(lexer, ltok::RPAREN)?;
- break;
- },
- lex::token => void,
+ case void =>
+ want(lexer, ltok::RPAREN)?;
+ break;
+ case lex::token => void;
};
};
let t = _type(lexer)?;
@@ -58,44 +61,67 @@ fn prototype(lexer: *lex::lexer) (ast::func_type | error) = {
fn integer_type(
lexer: *lex::lexer,
-) (builtin_type | error) = switch (want(lexer)?.0) {
- ltok::CHAR => builtin_type::CHAR,
- ltok::I16 => builtin_type::I16,
- ltok::I32 => builtin_type::I32,
- ltok::I64 => builtin_type::I64,
- ltok::I64 => builtin_type::I64,
- ltok::I8 => builtin_type::I8,
- ltok::INT => builtin_type::INT,
- ltok::SIZE => builtin_type::SIZE,
- ltok::U16 => builtin_type::U16,
- ltok::U32 => builtin_type::U32,
- ltok::U64 => builtin_type::U64,
- ltok::U64 => builtin_type::U64,
- ltok::U8 => builtin_type::U8,
- ltok::UINT => builtin_type::UINT,
- ltok::UINTPTR => builtin_type::UINTPTR,
- * => syntaxerr(lex::mkloc(lexer), "Expected integer type"),
+) (builtin_type | error) = {
+ switch (want(lexer)?.0) {
+ case ltok::CHAR =>
+ return builtin_type::CHAR;
+ case ltok::I16 =>
+ return builtin_type::I16;
+ case ltok::I32 =>
+ return builtin_type::I32;
+ case ltok::I64 =>
+ return builtin_type::I64;
+ case ltok::I64 =>
+ return builtin_type::I64;
+ case ltok::I8 =>
+ return builtin_type::I8;
+ case ltok::INT =>
+ return builtin_type::INT;
+ case ltok::SIZE =>
+ return builtin_type::SIZE;
+ case ltok::U16 =>
+ return builtin_type::U16;
+ case ltok::U32 =>
+ return builtin_type::U32;
+ case ltok::U64 =>
+ return builtin_type::U64;
+ case ltok::U64 =>
+ return builtin_type::U64;
+ case ltok::U8 =>
+ return builtin_type::U8;
+ case ltok::UINT =>
+ return builtin_type::UINT;
+ case ltok::UINTPTR =>
+ return builtin_type::UINTPTR;
+ case =>
+ return syntaxerr(lex::mkloc(lexer), "Expected integer type");
+ };
};
fn primitive_type(lexer: *lex::lexer) (ast::_type | error) = {
let tok = want(lexer)?;
let builtin = switch (tok.0) {
- ltok::CHAR, ltok::I16, ltok::I32, ltok::I64,
- ltok::I64, ltok::I8, ltok::INT, ltok::SIZE, ltok::U16,
- ltok::U32, ltok::U64, ltok::U64, ltok::U8, ltok::UINT,
- ltok::UINTPTR => {
- lex::unlex(lexer, tok);
- yield integer_type(lexer)?;
- },
- ltok::RUNE => builtin_type::RUNE,
- ltok::STR => builtin_type::STR,
- ltok::F32 => builtin_type::F32,
- ltok::F64 => builtin_type::F64,
- ltok::BOOL => builtin_type::BOOL,
- ltok::VOID => builtin_type::VOID,
- * => return syntaxerr(lex::mkloc(lexer),
+ case ltok::CHAR, ltok::I16, ltok::I32, ltok::I64, ltok::I64, ltok::I8,
+ ltok::INT, ltok::SIZE, ltok::U16, ltok::U32, ltok::U64,
+ ltok::U64, ltok::U8, ltok::UINT, ltok::UINTPTR =>
+ lex::unlex(lexer, tok);
+ yield integer_type(lexer)?;
+ case ltok::RUNE =>
+ yield builtin_type::RUNE;
+ case ltok::STR =>
+ yield builtin_type::STR;
+ case ltok::F32 =>
+ yield builtin_type::F32;
+ case ltok::F64 =>
+ yield builtin_type::F64;
+ case ltok::BOOL =>
+ yield builtin_type::BOOL;
+ case ltok::VOID =>
+ yield builtin_type::VOID;
+ case =>
+ return syntaxerr(lex::mkloc(lexer),
"Unexected {}, was expecting primitive type",
- lex::tokstr(tok)),
+ lex::tokstr(tok));
};
return ast::_type {
start = tok.2,
@@ -107,10 +133,7 @@ fn primitive_type(lexer: *lex::lexer) (ast::_type | error) = {
fn alias_type(lexer: *lex::lexer) (ast::_type | error) = {
const start = lex::mkloc(lexer);
- let unwrap = match (try(lexer, ltok::ELLIPSIS)?) {
- void => false,
- * => true,
- };
+ let unwrap = try(lexer, ltok::ELLIPSIS)? is lex::token;
let ident = ident(lexer)?;
return ast::_type {
start = start,
@@ -126,8 +149,10 @@ fn alias_type(lexer: *lex::lexer) (ast::_type | error) = {
fn pointer_type(lexer: *lex::lexer) (ast::_type | error) = {
const start = lex::mkloc(lexer);
let flags = match (try(lexer, ltok::NULLABLE)?) {
- void => 0: ast::pointer_flags,
- * => ast::pointer_flags::NULLABLE,
+ case void =>
+ yield 0: ast::pointer_flags;
+ case =>
+ yield ast::pointer_flags::NULLABLE;
};
want(lexer, ltok::TIMES)?;
let _type = _type(lexer)?;
@@ -151,12 +176,9 @@ fn tagged_type(
append(tagged, alloc(first));
for (try(lexer, ltok::RPAREN)? is void) {
append(tagged, alloc(_type(lexer)?));
- match (try(lexer, ltok::BOR)?) {
- void => {
- want(lexer, ltok::RPAREN)?;
- break;
- },
- lex::token => void,
+ if (try(lexer, ltok::BOR)? is void) {
+ want(lexer, ltok::RPAREN)?;
+ break;
};
};
return ast::_type {
@@ -176,12 +198,9 @@ fn tuple_type(
append(tuple, alloc(first));
for (try(lexer, ltok::RPAREN)? is void) {
append(tuple, alloc(_type(lexer)?));
- match (try(lexer, ltok::COMMA)?) {
- void => {
- want(lexer, ltok::RPAREN)?;
- break;
- },
- lex::token => void,
+ if (try(lexer, ltok::COMMA)? is void) {
+ want(lexer, ltok::RPAREN)?;
+ break;
};
};
return ast::_type {
@@ -195,8 +214,10 @@ fn tuple_type(
fn fn_type(lexer: *lex::lexer) (ast::_type | error) = {
const start = lex::mkloc(lexer);
let attrs = match (try(lexer, ltok::ATTR_NORETURN)?) {
- void => 0: ast::func_attrs,
- * => ast::func_attrs::NORETURN,
+ case void =>
+ yield 0: ast::func_attrs;
+ case =>
+ yield ast::func_attrs::NORETURN;
};
want(lexer, ltok::FN)?;
let proto = prototype(lexer)?;
@@ -222,37 +243,35 @@ fn struct_union_type(lexer: *lex::lexer) (ast::_type | error) = {
};
let offs: nullable *ast::expr = match (try(lexer, ltok::ATTR_OFFSET)?) {
- void => null,
- lex::token => {
- want(lexer, ltok::LPAREN)?;
- let ex = expression(lexer)?;
- want(lexer, ltok::RPAREN)?;
- yield alloc(ex);
- },
+ case void =>
+ yield null;
+ case lex::token =>
+ want(lexer, ltok::LPAREN)?;
+ let ex = expression(lexer)?;
+ want(lexer, ltok::RPAREN)?;
+ yield alloc(ex);
};
let tok = want(lexer, ltok::NAME, ltok::STRUCT, ltok::UNION)?;
switch (tok.0) {
- ltok::NAME => {
- lex::unlex(lexer, tok);
- let memb = struct_embed_or_field(lexer, offs)?;
- append(membs, memb);
- },
- ltok::STRUCT, ltok::UNION => {
- lex::unlex(lexer, tok);
- let subtype = struct_union_type(lexer)?;
- append(membs, ast::struct_member {
- _offset = offs,
- member = alloc(subtype),
- });
- },
- * => abort(),
+ case ltok::NAME =>
+ lex::unlex(lexer, tok);
+ let memb = struct_embed_or_field(lexer, offs)?;
+ append(membs, memb);
+ case ltok::STRUCT, ltok::UNION =>
+ lex::unlex(lexer, tok);
+ let subtype = struct_union_type(lexer)?;
+ append(membs, ast::struct_member {
+ _offset = offs,
+ member = alloc(subtype),
+ });
+ case => abort();
};
- switch (want(lexer, ltok::COMMA, ltok::RBRACE)?.0) {
- ltok::COMMA => void,
- ltok::RBRACE => break,
- * => abort(),
+ switch (want(lexer, ltok::RBRACE, ltok::COMMA)?.0) {
+ case ltok::RBRACE => break;
+ case ltok::COMMA => void;
+ case => abort();
};
};
@@ -261,9 +280,11 @@ fn struct_union_type(lexer: *lex::lexer) (ast::_type | error) = {
end = lex::prevloc(lexer),
flags = 0,
repr = switch (kind.0) {
- ltok::STRUCT => membs: ast::struct_type,
- ltok::UNION => membs: ast::union_type,
- * => abort(),
+ case ltok::STRUCT =>
+ yield membs: ast::struct_type;
+ case ltok::UNION =>
+ yield membs: ast::union_type;
+ case => abort();
},
};
};
@@ -284,25 +305,25 @@ fn struct_embed_or_field(
let name = want(lexer, ltok::NAME)?;
let id: ast::ident = match (try(lexer, ltok::COLON, ltok::DOUBLE_COLON)?) {
- void => alloc([name.1 as str]),
- tok: lex::token => switch (tok.0) {
- ltok::COLON => {
- let field = ast::struct_field {
- name = name.1 as str,
- _type = alloc(_type(lexer)?),
- };
- return ast::struct_member {
- _offset = offs,
- member = field,
- };
- },
- ltok::DOUBLE_COLON => {
- let id = ident(lexer)?;
- insert(id[0], name.1 as str);
- yield id;
- },
- * => abort(),
- },
+ case void =>
+ yield alloc([name.1 as str]);
+ case tok: lex::token =>
+ yield switch (tok.0) {
+ case ltok::COLON =>
+ let field = ast::struct_field {
+ name = name.1 as str,
+ _type = alloc(_type(lexer)?),
+ };
+ return ast::struct_member {
+ _offset = offs,
+ member = field,
+ };
+ case ltok::DOUBLE_COLON =>
+ let id = ident(lexer)?;
+ insert(id[0], name.1 as str);
+ yield id;
+ case => abort();
+ };
};
return ast::struct_member {
@@ -314,21 +335,26 @@ fn struct_embed_or_field(
fn array_slice_type(lexer: *lex::lexer) (ast::_type | error) = {
let start = want(lexer, ltok::LBRACKET)?;
- let length = match (try(lexer,
- ltok::UNDERSCORE, ltok::TIMES, ltok::RBRACKET)?) {
- void => alloc(expression(lexer)?),
- tok: lex::token => switch (tok.0) {
- ltok::UNDERSCORE => ast::len_contextual,
- ltok::TIMES => ast::len_unbounded,
- ltok::RBRACKET => ast::len_slice,
- * => abort(),
- },
+ let length = match (try(lexer, ltok::UNDERSCORE,
+ ltok::TIMES, ltok::RBRACKET)?) {
+ case void =>
+ yield alloc(expression(lexer)?);
+ case tok: lex::token =>
+ yield switch (tok.0) {
+ case ltok::UNDERSCORE =>
+ yield ast::len_contextual;
+ case ltok::TIMES =>
+ yield ast::len_unbounded;
+ case ltok::RBRACKET =>
+ yield ast::len_slice;
+ case => abort();
+ };
};
- match (length) {
- ast::len_slice => void,
- * => want(lexer, ltok::RBRACKET)?,
+ if (!(length is ast::len_slice)) {
+ want(lexer, ltok::RBRACKET)?;
};
+
let _type = _type(lexer)?;
return ast::_type {
start = start.2,
@@ -345,12 +371,12 @@ fn enum_type(lexer: *lex::lexer) (ast::_type | error) = {
let start = want(lexer, ltok::ENUM)?;
const storage = match (try(lexer, ltok::LBRACE)?) {
- void => {
- let storage = integer_type(lexer)?;
- want(lexer, ltok::LBRACE)?;
- yield storage;
- },
- lex::token => builtin_type::INT,
+ case void =>
+ let storage = integer_type(lexer)?;
+ want(lexer, ltok::LBRACE)?;
+ yield storage;
+ case lex::token =>
+ yield builtin_type::INT;
};
let membs: []ast::enum_field = [];
@@ -373,9 +399,9 @@ fn enum_type(lexer: *lex::lexer) (ast::_type | error) = {
});
switch (want(lexer, ltok::COMMA, ltok::RBRACE)?.0) {
- ltok::COMMA => void,
- ltok::RBRACE => break,
- * => abort(),
+ case ltok::COMMA => void;
+ case ltok::RBRACE => break;
+ case => abort();
};
};
@@ -393,41 +419,48 @@ fn enum_type(lexer: *lex::lexer) (ast::_type | error) = {
// Parses a type, e.g. '[]int'.
export fn _type(lexer: *lex::lexer) (ast::_type | error) = {
let flags: ast::type_flags = 0;
- match (try(lexer, ltok::CONST)?) {
- void => void,
- * => flags |= ast::type_flags::CONST,
+ if (try(lexer, ltok::CONST)? is lex::token) {
+ flags |= ast::type_flags::CONST;
};
- match (try(lexer, ltok::LNOT)?) {
- void => void,
- * => flags |= ast::type_flags::ERROR,
+
+ if (try(lexer, ltok::LNOT)? is lex::token) {
+ flags |= ast::type_flags::ERROR;
};
+
let tok = peek(lexer)? as lex::token;
let typ: ast::_type = switch (tok.0) {
- ltok::CHAR, ltok::I16, ltok::I32, ltok::I64,
- ltok::I64, ltok::I8, ltok::INT, ltok::SIZE,
- ltok::U16, ltok::U32, ltok::U64, ltok::U64,
- ltok::U8, ltok::UINT, ltok::UINTPTR, ltok::RUNE,
- ltok::STR, ltok::F32, ltok::F64, ltok::BOOL,
- ltok::VOID => primitive_type(lexer)?,
- ltok::ENUM => enum_type(lexer)?,
- ltok::NULLABLE, ltok::TIMES => pointer_type(lexer)?,
- ltok::STRUCT, ltok::UNION => struct_union_type(lexer)?,
- ltok::LBRACKET => array_slice_type(lexer)?,
- ltok::LPAREN => {
- want(lexer, ltok::LPAREN)?;
- let t = _type(lexer)?;
- yield switch (want(lexer, ltok::BOR,
- ltok::COMMA)?.0) {
- ltok::BOR => tagged_type(lexer, t, tok.2)?,
- ltok::COMMA => tuple_type(lexer, t, tok.2)?,
- * => abort("unreachable"),
- };
- },
- ltok::ATTR_NORETURN, ltok::FN => fn_type(lexer)?,
- ltok::ELLIPSIS, ltok::NAME => alias_type(lexer)?,
- * => return syntaxerr(lex::mkloc(lexer),
+ case ltok::CHAR, ltok::I16, ltok::I32, ltok::I64, ltok::I64, ltok::I8,
+ ltok::INT, ltok::SIZE, ltok::U16, ltok::U32, ltok::U64,
+ ltok::U8, ltok::UINT, ltok::UINTPTR, ltok::RUNE,
+ ltok::STR, ltok::F32, ltok::F64, ltok::BOOL,
+ ltok::VOID =>
+ yield primitive_type(lexer)?;
+ case ltok::ENUM =>
+ yield enum_type(lexer)?;
+ case ltok::NULLABLE, ltok::TIMES =>
+ yield pointer_type(lexer)?;
+ case ltok::STRUCT, ltok::UNION =>
+ yield struct_union_type(lexer)?;
+ case ltok::LBRACKET =>
+ yield array_slice_type(lexer)?;
+ case ltok::LPAREN =>
+ want(lexer, ltok::LPAREN)?;
+ let t = _type(lexer)?;
+ yield switch (want(lexer, ltok::BOR, ltok::COMMA)?.0) {
+ case ltok::BOR =>
+ yield tagged_type(lexer, t, tok.2)?;
+ case ltok::COMMA =>
+ yield tuple_type(lexer, t, tok.2)?;
+ case => abort("unreachable");
+ };
+ case ltok::ATTR_NORETURN, ltok::FN =>
+ yield fn_type(lexer)?;
+ case ltok::ELLIPSIS, ltok::NAME =>
+ yield alias_type(lexer)?;
+ case =>
+ return syntaxerr(lex::mkloc(lexer),
"Unexpected {}, was expecting type",
- lex::tokstr(tok)),
+ lex::tokstr(tok));
};
typ.flags |= flags;
diff --git a/hare/types/class.ha b/hare/types/class.ha
@@ -1,49 +1,67 @@
// Returns true if the given type is a signed type.
export fn is_signed(ty: const *_type) bool = {
- return match (ty.repr) {
+ match (ty.repr) {
+ case al: alias =>
// TODO: al.secondary as *_type
- al: alias => is_signed(al.secondary: const *_type),
- bi: builtin => switch (bi) {
- builtin::F32, builtin::F64,
- builtin::I16, builtin::I32, builtin::I64, builtin::I8,
- builtin::INT => true,
- * => false,
- },
- e: _enum => switch (e.storage) {
- builtin::I16, builtin::I32, builtin::I64, builtin::I8,
- builtin::INT => true,
- * => false,
- },
- * => false,
+ return is_signed(al.secondary: const *_type);
+ case bi: builtin =>
+ switch (bi) {
+ case builtin::F32, builtin::F64, builtin::I16, builtin::I32,
+ builtin::I64, builtin::I8, builtin::INT =>
+ return true;
+ case =>
+ return false;
+ };
+ case e: _enum =>
+ switch (e.storage) {
+ case builtin::I16, builtin::I32, builtin::I64, builtin::I8,
+ builtin::INT =>
+ return true;
+ case =>
+ return false;
+ };
+ case =>
+ return false;
};
};
// Returns true if the given type is a floating-point type.
export fn is_float(ty: const *_type) bool = {
- return match (ty.repr) {
+ match (ty.repr) {
+ case al: alias =>
// TODO: al.secondary as *_type
- al: alias => is_float(al.secondary: const *_type),
- bi: builtin => switch (bi) {
- builtin::F32, builtin::F64 => true,
- * => false,
- },
- * => false,
+ return is_float(al.secondary: const *_type);
+ case bi: builtin =>
+ switch (bi) {
+ case builtin::F32, builtin::F64 =>
+ return true;
+ case =>
+ return false;
+ };
+ case =>
+ return false;
};
};
// Returns true if the given type is an integer type.
export fn is_integer(ty: const *_type) bool = {
- return match (ty.repr) {
+ match (ty.repr) {
+ case al: alias =>
// TODO: al.secondary as *_type
- al: alias => is_integer(al.secondary: const *_type),
- bi: builtin => switch (bi) {
- builtin::INT, builtin::UINT,
- builtin::I16, builtin::I32, builtin::I64, builtin::I8,
- builtin::U16, builtin::U32, builtin::U64, builtin::U8,
- builtin::CHAR, builtin::SIZE, builtin::UINTPTR => true,
- * => false,
- },
- _enum => true,
- * => false,
+ return is_integer(al.secondary: const *_type);
+ case bi: builtin =>
+ switch (bi) {
+ case builtin::INT, builtin::UINT, builtin::I16,
+ builtin::I32, builtin::I64, builtin::I8, builtin::U16,
+ builtin::U32, builtin::U64, builtin::U8, builtin::CHAR,
+ builtin::SIZE, builtin::UINTPTR =>
+ return true;
+ case =>
+ return false;
+ };
+ case _enum =>
+ return true;
+ case =>
+ return false;
};
};
diff --git a/hare/types/hash.ha b/hare/types/hash.ha
@@ -11,43 +11,78 @@ type storage = enum u8 {
FUNCTION, POINTER, SLICE, STRING, STRUCT, TAGGED, TUPLE, UNION,
};
-fn builtin_storage(b: builtin) u8 = switch (b) {
- builtin::BOOL => storage::BOOL,
- builtin::CHAR => storage::CHAR,
- builtin::F32 => storage::F32,
- builtin::F64 => storage::F64,
- builtin::I16 => storage::I16,
- builtin::I32 => storage::I32,
- builtin::I64 => storage::I64,
- builtin::I8 => storage::I8,
- builtin::INT => storage::INT,
- builtin::NULL => storage::NULL,
- builtin::RUNE => storage::RUNE,
- builtin::SIZE => storage::SIZE,
- builtin::STR => storage::STRING,
- builtin::U16 => storage::U16,
- builtin::U32 => storage::U32,
- builtin::U64 => storage::U64,
- builtin::U8 => storage::U8,
- builtin::UINT => storage::UINT,
- builtin::UINTPTR => storage::UINTPTR,
- builtin::VOID => storage::VOID,
+fn builtin_storage(b: builtin) u8 = {
+ switch (b) {
+ case builtin::BOOL =>
+ return storage::BOOL;
+ case builtin::CHAR =>
+ return storage::CHAR;
+ case builtin::F32 =>
+ return storage::F32;
+ case builtin::F64 =>
+ return storage::F64;
+ case builtin::I16 =>
+ return storage::I16;
+ case builtin::I32 =>
+ return storage::I32;
+ case builtin::I64 =>
+ return storage::I64;
+ case builtin::I8 =>
+ return storage::I8;
+ case builtin::INT =>
+ return storage::INT;
+ case builtin::NULL =>
+ return storage::NULL;
+ case builtin::RUNE =>
+ return storage::RUNE;
+ case builtin::SIZE =>
+ return storage::SIZE;
+ case builtin::STR =>
+ return storage::STRING;
+ case builtin::U16 =>
+ return storage::U16;
+ case builtin::U32 =>
+ return storage::U32;
+ case builtin::U64 =>
+ return storage::U64;
+ case builtin::U8 =>
+ return storage::U8;
+ case builtin::UINT =>
+ return storage::UINT;
+ case builtin::UINTPTR =>
+ return storage::UINTPTR;
+ case builtin::VOID =>
+ return storage::VOID;
+ };
};
-fn type_storage(t: *_type) u8 = match (t.repr) {
- alias => storage::ALIAS,
- array => storage::ARRAY,
- b: builtin => builtin_storage(b),
- _enum => storage::ENUM,
- func => storage::FUNCTION,
- pointer => storage::POINTER,
- slice => storage::SLICE,
- st: _struct =>
- if (st.kind == struct_union::STRUCT)
- storage::STRUCT
- else storage::UNION,
- tuple => storage::TUPLE,
- tagged => storage::TAGGED,
+fn type_storage(t: *_type) u8 = {
+ match (t.repr) {
+ case alias =>
+ return storage::ALIAS;
+ case array =>
+ return storage::ARRAY;
+ case b: builtin =>
+ return builtin_storage(b);
+ case _enum =>
+ return storage::ENUM;
+ case func =>
+ return storage::FUNCTION;
+ case pointer =>
+ return storage::POINTER;
+ case slice =>
+ return storage::SLICE;
+ case st: _struct =>
+ if (st.kind == struct_union::STRUCT) {
+ return storage::STRUCT;
+ } else {
+ return storage::UNION;
+ };
+ case tuple =>
+ return storage::TUPLE;
+ case tagged =>
+ return storage::TAGGED;
+ };
};
fn write8(h: *hash::hash, u: u8) void = {
@@ -77,49 +112,50 @@ export fn hash(t: *_type) u32 = {
write8(&id, t.flags);
match (t.repr) {
- a: alias => for (let i = len(a.id); i > 0; i -= 1) {
+ case a: alias =>
+ for (let i = len(a.id); i > 0; i -= 1) {
hash::write(&id, strings::toutf8(a.id[i - 1]));
write8(&id, 0);
- },
- a: array => {
- write32(&id, hash(a.member));
- static assert(size(u64) == size(size)); // TODO
- write64(&id, a.length);
- },
- builtin => void,
- e: _enum => {
- write8(&id, builtin_storage(e.storage));
- for (let i = 0z; i < len(e.values); i += 1) {
- hash::write(&id, strings::toutf8(e.values[i].0));
- write64(&id, e.values[i].1);
- };
- },
- f: func => {
- write32(&id, hash(f.result));
- write8(&id, f.variadism: u8);
- write8(&id, f.flags: u8);
- for (let i = 0z; i < len(f.params); i += 1) {
- write32(&id, hash(f.params[i]));
- };
- },
- p: pointer => {
- write8(&id, p.flags);
- write32(&id, hash(p.referent));
- },
- s: slice => write32(&id, hash(s)),
- st: _struct => for (let i = 0z; i < len(st.fields); i += 1) {
+ };
+ case a: array =>
+ write32(&id, hash(a.member));
+ static assert(size(u64) == size(size)); // TODO
+ write64(&id, a.length);
+ case builtin => void;
+ case e: _enum =>
+ write8(&id, builtin_storage(e.storage));
+ for (let i = 0z; i < len(e.values); i += 1) {
+ hash::write(&id, strings::toutf8(e.values[i].0));
+ write64(&id, e.values[i].1);
+ };
+ case f: func =>
+ write32(&id, hash(f.result));
+ write8(&id, f.variadism: u8);
+ write8(&id, f.flags: u8);
+ for (let i = 0z; i < len(f.params); i += 1) {
+ write32(&id, hash(f.params[i]));
+ };
+ case p: pointer =>
+ write8(&id, p.flags);
+ write32(&id, hash(p.referent));
+ case s: slice =>
+ write32(&id, hash(s));
+ case st: _struct =>
+ for (let i = 0z; i < len(st.fields); i += 1) {
const field = st.fields[i];
hash::write(&id, strings::toutf8(field.name));
write32(&id, hash(field._type));
static assert(size(u64) == size(size)); // TODO
write64(&id, field.offs);
- },
- tu: tuple => for (let i = 0z; i < len(tu); i += 1) {
+ };
+ case tu: tuple =>
+ for (let i = 0z; i < len(tu); i += 1) {
write32(&id, hash(tu[i]._type));
- },
- ta: tagged => for (let i = 0z; i < len(ta); i += 1) {
+ };
+ case ta: tagged =>
+ for (let i = 0z; i < len(ta); i += 1) {
write32(&id, hash(ta[i]));
- },
+ };
};
return fnv::sum32(&id);
diff --git a/hare/types/lookup.ha b/hare/types/lookup.ha
@@ -3,11 +3,11 @@ use hare::ast;
// Unwraps a type which may be aliased and returns the underlying type.
export fn dealias(t: *_type) const *_type = {
for (true) match (t.repr) {
- a: alias => {
- assert(a.secondary != null);
- t = a.secondary: const *_type;
- },
- * => break,
+ case a: alias =>
+ assert(a.secondary != null);
+ t = a.secondary: const *_type;
+ case =>
+ break;
};
return t;
};
diff --git a/hare/types/store.ha b/hare/types/store.ha
@@ -69,23 +69,37 @@ export fn lookup(
) (const *_type | deferred | error) = {
const ty = fromast(store, ty)?;
if (ty.flags == 0) match (ty.repr) {
- b: builtin => switch (b) {
- builtin::CHAR => return &builtin_char,
- builtin::F32 => return &builtin_f32,
- builtin::F64 => return &builtin_f64,
- builtin::I8 => return &builtin_i8,
- builtin::I16 => return &builtin_i16,
- builtin::I32 => return &builtin_i32,
- builtin::I64 => return &builtin_i64,
- builtin::RUNE => return &builtin_rune,
- builtin::U8 => return &builtin_u8,
- builtin::U16 => return &builtin_u16,
- builtin::U32 => return &builtin_u32,
- builtin::U64 => return &builtin_u64,
- builtin::VOID => return &builtin_void,
- * => void,
- },
- * => void,
+ case b: builtin =>
+ switch (b) {
+ case builtin::CHAR =>
+ return &builtin_char;
+ case builtin::F32 =>
+ return &builtin_f32;
+ case builtin::F64 =>
+ return &builtin_f64;
+ case builtin::I8 =>
+ return &builtin_i8;
+ case builtin::I16 =>
+ return &builtin_i16;
+ case builtin::I32 =>
+ return &builtin_i32;
+ case builtin::I64 =>
+ return &builtin_i64;
+ case builtin::RUNE =>
+ return &builtin_rune;
+ case builtin::U8 =>
+ return &builtin_u8;
+ case builtin::U16 =>
+ return &builtin_u16;
+ case builtin::U32 =>
+ return &builtin_u32;
+ case builtin::U64 =>
+ return &builtin_u64;
+ case builtin::VOID =>
+ return &builtin_void;
+ case => void;
+ };
+ case => void;
};
const id = hash(&ty);
@@ -104,186 +118,162 @@ export fn lookup(
fn fromast(store: *typestore, atype: *ast::_type) (_type | deferred | error) = {
let sz = SIZE_UNDEFINED, align = SIZE_UNDEFINED;
const repr = match (atype.repr) {
- a: ast::alias_type => {
- // TODO: This is incomplete
- assert(!a.unwrap);
- yield alias {
- id = ast::ident_dup(a.ident),
- secondary = null,
- };
- },
+ case a: ast::alias_type =>
+ // TODO: This is incomplete
+ assert(!a.unwrap);
+ yield alias {
+ id = ast::ident_dup(a.ident),
+ secondary = null,
+ };
+ case b: ast::builtin_type =>
// TODO: Tuple unpacking could improve this
- b: ast::builtin_type => switch (b) {
- ast::builtin_type::BOOL => {
- sz = store.arch._int;
- align = store.arch._int;
- yield builtin::BOOL;
- },
- ast::builtin_type::CHAR => {
- sz = 1; align = 1;
- yield builtin::CHAR;
- },
- ast::builtin_type::F32 => {
- sz = 4; align = 4;
- yield builtin::F32;
- },
- ast::builtin_type::F64 => {
- sz = 8; align = 8;
- yield builtin::F64;
- },
- ast::builtin_type::I16 => {
- sz = 2; align = 2;
- yield builtin::I16;
- },
- ast::builtin_type::I32 => {
- sz = 4; align = 4;
- yield builtin::I32;
- },
- ast::builtin_type::I64 => {
- sz = 8; align = 8;
- yield builtin::I64;
- },
- ast::builtin_type::I8 => {
- sz = 1; align = 1;
- yield builtin::I8;
- },
- ast::builtin_type::INT => {
- sz = store.arch._int;
- align = store.arch._int;
- yield builtin::INT;
- },
- ast::builtin_type::RUNE => {
- sz = 4; align = 4;
- yield builtin::RUNE;
- },
- ast::builtin_type::SIZE => {
- sz = store.arch._size;
- align = store.arch._size;
- yield builtin::SIZE;
- },
- ast::builtin_type::STR => {
- sz = store.arch._pointer;
- sz += sz % store.arch._size + store.arch._size;
- sz += store.arch._size;
- align = if (store.arch._size > store.arch._pointer)
- store.arch._size
- else
- store.arch._pointer;
- yield builtin::STR;
- },
- ast::builtin_type::U16 => {
- sz = 2; align = 2;
- yield builtin::U16;
- },
- ast::builtin_type::U32 => {
- sz = 4; align = 4;
- yield builtin::U32;
- },
- ast::builtin_type::U64 => {
- sz = 8; align = 8;
- yield builtin::U64;
- },
- ast::builtin_type::U8 => {
- sz = 1; align = 1;
- yield builtin::U8;
- },
- ast::builtin_type::UINT => {
- sz = store.arch._int;
- align = store.arch._int;
- yield builtin::UINT;
- },
- ast::builtin_type::UINTPTR => {
- sz = store.arch._pointer;
- align = store.arch._pointer;
- yield builtin::UINTPTR;
- },
- ast::builtin_type::VOID => {
- sz = 0; align = 0;
- yield builtin::VOID;
- },
- ast::builtin_type::NULL => {
- sz = store.arch._pointer;
- align = store.arch._pointer;
- yield builtin::NULL;
- },
- ast::builtin_type::ICONST,
- ast::builtin_type::FCONST => abort(), // TODO?
- },
- f: ast::func_type => func_from_ast(store, &f)?,
- p: ast::pointer_type => {
+ yield switch (b) {
+ case ast::builtin_type::BOOL =>
+ sz = store.arch._int;
+ align = store.arch._int;
+ yield builtin::BOOL;
+ case ast::builtin_type::CHAR =>
+ sz = 1; align = 1;
+ yield builtin::CHAR;
+ case ast::builtin_type::F32 =>
+ sz = 4; align = 4;
+ yield builtin::F32;
+ case ast::builtin_type::F64 =>
+ sz = 8; align = 8;
+ yield builtin::F64;
+ case ast::builtin_type::I16 =>
+ sz = 2; align = 2;
+ yield builtin::I16;
+ case ast::builtin_type::I32 =>
+ sz = 4; align = 4;
+ yield builtin::I32;
+ case ast::builtin_type::I64 =>
+ sz = 8; align = 8;
+ yield builtin::I64;
+ case ast::builtin_type::I8 =>
+ sz = 1; align = 1;
+ yield builtin::I8;
+ case ast::builtin_type::INT =>
+ sz = store.arch._int;
+ align = store.arch._int;
+ yield builtin::INT;
+ case ast::builtin_type::RUNE =>
+ sz = 4; align = 4;
+ yield builtin::RUNE;
+ case ast::builtin_type::SIZE =>
+ sz = store.arch._size;
+ align = store.arch._size;
+ yield builtin::SIZE;
+ case ast::builtin_type::STR =>
+ sz = store.arch._pointer;
+ sz += sz % store.arch._size + store.arch._size;
+ sz += store.arch._size;
+ align = if (store.arch._size > store.arch._pointer)
+ store.arch._size
+ else
+ store.arch._pointer;
+ yield builtin::STR;
+ case ast::builtin_type::U16 =>
+ sz = 2; align = 2;
+ yield builtin::U16;
+ case ast::builtin_type::U32 =>
+ sz = 4; align = 4;
+ yield builtin::U32;
+ case ast::builtin_type::U64 =>
+ sz = 8; align = 8;
+ yield builtin::U64;
+ case ast::builtin_type::U8 =>
+ sz = 1; align = 1;
+ yield builtin::U8;
+ case ast::builtin_type::UINT =>
+ sz = store.arch._int;
+ align = store.arch._int;
+ yield builtin::UINT;
+ case ast::builtin_type::UINTPTR =>
sz = store.arch._pointer;
align = store.arch._pointer;
- yield pointer {
- referent = lookup(store, p.referent)?,
- flags = p.flags: pointer_flags,
- };
- },
- st: ast::struct_type => {
- let st = struct_from_ast(store, st, false)?;
+ yield builtin::UINTPTR;
+ case ast::builtin_type::VOID =>
sz = 0; align = 0;
- for (let i = 0z; i < len(st.fields); i += 1) {
- const field = st.fields[i];
- if (field.offs + field._type.sz > sz) {
- sz = field.offs + field._type.sz;
- };
- if (field._type.align > align) {
- align = field._type.align;
- };
+ yield builtin::VOID;
+ case ast::builtin_type::NULL =>
+ sz = store.arch._pointer;
+ align = store.arch._pointer;
+ yield builtin::NULL;
+ case ast::builtin_type::ICONST, ast::builtin_type::FCONST =>
+ abort(); // TODO?
+ };
+ case f: ast::func_type =>
+ yield func_from_ast(store, &f)?;
+ case p: ast::pointer_type =>
+ sz = store.arch._pointer;
+ align = store.arch._pointer;
+ yield pointer {
+ referent = lookup(store, p.referent)?,
+ flags = p.flags: pointer_flags,
+ };
+ case st: ast::struct_type =>
+ let st = struct_from_ast(store, st, false)?;
+ sz = 0; align = 0;
+ for (let i = 0z; i < len(st.fields); i += 1) {
+ const field = st.fields[i];
+ if (field.offs + field._type.sz > sz) {
+ sz = field.offs + field._type.sz;
};
- yield st;
- },
- un: ast::union_type => {
- let st = struct_from_ast(store, un, true)?;
- sz = 0; align = 0;
- for (let i = 0z; i < len(st.fields); i += 1) {
- const field = st.fields[i];
- if (field.offs + field._type.sz > sz) {
- sz = field.offs + field._type.sz;
- };
- if (field._type.align > align) {
- align = field._type.align;
- };
+ if (field._type.align > align) {
+ align = field._type.align;
};
- yield st;
- },
- ta: ast::tagged_type => {
- let ta = tagged_from_ast(store, ta)?;
- sz = 0; align = 0;
- for (let i = 0z; i < len(ta); i += 1) {
- if (ta[i].sz > sz) {
- sz = ta[i].sz;
- };
- if (ta[i].align > align) {
- align = ta[i].align;
- };
+ };
+ yield st;
+ case un: ast::union_type =>
+ let st = struct_from_ast(store, un, true)?;
+ sz = 0; align = 0;
+ for (let i = 0z; i < len(st.fields); i += 1) {
+ const field = st.fields[i];
+ if (field.offs + field._type.sz > sz) {
+ sz = field.offs + field._type.sz;
};
- if (store.arch._int > align) {
- align = store.arch._int;
+ if (field._type.align > align) {
+ align = field._type.align;
};
- sz += store.arch._int % align + store.arch._int;
- yield ta;
- },
- tu: ast::tuple_type => {
- let tu = tuple_from_ast(store, tu)?;
- sz = 0; align = 0;
- for (let i = 0z; i < len(tu); i += 1) {
- const value = tu[i];
- if (value.offs + value._type.sz > sz) {
- sz = value.offs + value._type.sz;
- };
- if (value._type.align > align) {
- align = value._type.align;
- };
+ };
+ yield st;
+ case ta: ast::tagged_type =>
+ let ta = tagged_from_ast(store, ta)?;
+ sz = 0; align = 0;
+ for (let i = 0z; i < len(ta); i += 1) {
+ if (ta[i].sz > sz) {
+ sz = ta[i].sz;
};
- yield tu;
- },
- lt: ast::list_type => {
- let r = list_from_ast(store, <)?;
- sz = r.0;
- align = r.1;
- yield r.2;
- },
- et: ast::enum_type => abort(), // TODO
+ if (ta[i].align > align) {
+ align = ta[i].align;
+ };
+ };
+ if (store.arch._int > align) {
+ align = store.arch._int;
+ };
+ sz += store.arch._int % align + store.arch._int;
+ yield ta;
+ case tu: ast::tuple_type =>
+ let tu = tuple_from_ast(store, tu)?;
+ sz = 0; align = 0;
+ for (let i = 0z; i < len(tu); i += 1) {
+ const value = tu[i];
+ if (value.offs + value._type.sz > sz) {
+ sz = value.offs + value._type.sz;
+ };
+ if (value._type.align > align) {
+ align = value._type.align;
+ };
+ };
+ yield tu;
+ case lt: ast::list_type =>
+ let r = list_from_ast(store, <)?;
+ sz = r.0;
+ align = r.1;
+ yield r.2;
+ case et: ast::enum_type =>
+ abort(); // TODO
};
if (sz != SIZE_UNDEFINED && sz != 0 && sz % align != 0) {
sz += align - (sz - align) % align;
@@ -303,9 +293,12 @@ fn func_from_ast(
let f = func {
result = lookup(store, ft.result)?,
variadism = switch (ft.variadism) {
- ast::variadism::NONE => variadism::NONE,
- ast::variadism::C => variadism::C,
- ast::variadism::HARE => variadism::HARE,
+ case ast::variadism::NONE =>
+ yield variadism::NONE;
+ case ast::variadism::C =>
+ yield variadism::C;
+ case ast::variadism::HARE =>
+ yield variadism::HARE;
},
flags = 0,
params = alloc([], len(ft.params)),
@@ -326,41 +319,40 @@ fn list_from_ast(
let sz = SIZE_UNDEFINED, align = SIZE_UNDEFINED;
let memb = lookup(store, lt.members)?;
let t = match (lt.length) {
- ast::len_slice => {
- sz = store.arch._pointer;
- if (sz % store.arch._size != 0) {
- sz += store.arch._size - (sz % store.arch._size);
- };
- sz += store.arch._size * 2;
- align = if (store.arch._pointer > store.arch._size)
- store.arch._pointer
- else store.arch._size;
- yield memb: slice;
- },
+ case ast::len_slice =>
+ sz = store.arch._pointer;
+ if (sz % store.arch._size != 0) {
+ sz += store.arch._size - (sz % store.arch._size);
+ };
+ sz += store.arch._size * 2;
+ align = if (store.arch._pointer > store.arch._size)
+ store.arch._pointer
+ else store.arch._size;
+ yield memb: slice;
+ case (ast::len_unbounded | ast::len_contextual) =>
// Note: contextual length is handled by hare::unit when
// initializing bindings. We treat it like unbounded here and
// it's fixed up later on.
- (ast::len_unbounded | ast::len_contextual) => {
- align = memb.align;
- yield array {
- length = SIZE_UNDEFINED,
- member = memb,
- };
- },
- ex: *ast::expr => {
- const resolv = match (store.resolve) {
- null => return noresolver,
- r: *resolver => r,
- };
- const length = resolv(store.rstate, store, ex)?;
- sz = memb.sz * length;
- assert(sz / length == memb.sz, "overflow");
- align = memb.align;
- yield array {
- length = length,
- member = memb,
- };
- },
+ align = memb.align;
+ yield array {
+ length = SIZE_UNDEFINED,
+ member = memb,
+ };
+ case ex: *ast::expr =>
+ const resolv = match (store.resolve) {
+ case null =>
+ return noresolver;
+ case r: *resolver =>
+ yield r;
+ };
+ const length = resolv(store.rstate, store, ex)?;
+ sz = memb.sz * length;
+ assert(sz / length == memb.sz, "overflow");
+ align = memb.align;
+ yield array {
+ length = length,
+ member = memb,
+ };
};
return (sz, align, t);
};
@@ -375,27 +367,35 @@ fn _struct_from_ast(
const nfields = len(fields);
for (let i = 0z; i < len(membs); i += 1) {
*offs = match (membs[i]._offset) {
- ex: *ast::expr => match (store.resolve) {
- null => return noresolver,
- res: *resolver => res(store.rstate, store, ex)?,
- },
- null => *offs,
+ case ex: *ast::expr =>
+ yield match (store.resolve) {
+ case null =>
+ return noresolver;
+ case res: *resolver =>
+ yield res(store.rstate, store, ex)?;
+ };
+ case null =>
+ yield *offs;
};
const memb = match (membs[i].member) {
- se: ast::struct_embedded => {
- let membs: []ast::struct_member = match (se.repr) {
- st: ast::struct_type => st,
- ut: ast::union_type => ut,
- * => abort(), // Invariant
- };
- _struct_from_ast(store, membs,
- se.repr is ast::union_type,
- fields, offs)?;
- continue;
- },
- se: ast::struct_alias => abort(), // TODO
- sf: ast::struct_field => sf,
+ case se: ast::struct_embedded =>
+ let membs: []ast::struct_member = match (se.repr) {
+ case st: ast::struct_type =>
+ yield st;
+ case ut: ast::union_type =>
+ yield ut;
+ case =>
+ abort(); // Invariant
+ };
+ _struct_from_ast(store, membs,
+ se.repr is ast::union_type,
+ fields, offs)?;
+ continue;
+ case se: ast::struct_alias =>
+ abort(); // TODO
+ case sf: ast::struct_field =>
+ yield sf;
};
const _type = lookup(store, memb._type)?;
@@ -446,8 +446,10 @@ fn tagged_collect(
types: *[]const *_type,
) (void | deferred | error) = {
for (let i = 0z; i < len(atype); i += 1) match (atype[i].repr) {
- ta: ast::tagged_type => tagged_collect(store, ta, types)?,
- * => append(types, lookup(store, atype[i])?),
+ case ta: ast::tagged_type =>
+ tagged_collect(store, ta, types)?;
+ case =>
+ append(types, lookup(store, atype[i])?);
};
};
@@ -506,15 +508,21 @@ fn field_cmp(a: const *void, b: const *void) int = {
fn type_finish(t: *_type) void = {
match (t.repr) {
- a: alias => ast::ident_free(a.id),
- array => void,
- builtin => void,
- e: _enum => free(e.values),
- f: func => free(f.params),
- pointer => void,
- s: slice => void,
- st: _struct => free(st.fields),
- tu: tuple => free(tu),
- ta: tagged => free(ta),
+ case a: alias =>
+ ast::ident_free(a.id);
+ case array => void;
+ case builtin => void;
+ case e: _enum =>
+ free(e.values);
+ case f: func =>
+ free(f.params);
+ case pointer => void;
+ case s: slice => void;
+ case st: _struct =>
+ free(st.fields);
+ case tu: tuple =>
+ free(tu);
+ case ta: tagged =>
+ free(ta);
};
};
diff --git a/hare/unit/process.ha b/hare/unit/process.ha
@@ -13,8 +13,10 @@ fn process(ctx: *context, subunits: const []ast::subunit) (unit | error) = {
for (let j = 0z; j < len(subunit.decls); j += 1) {
let adecl = &subunit.decls[j];
let decl = match (process_decl(ctx, adecl)) {
- d: decl => d,
- error => abort(), // TODO
+ case d: decl =>
+ yield d;
+ case error =>
+ abort(); // TODO
};
append(unit.decls, decl);
};
@@ -28,11 +30,15 @@ fn process_decl(
decl: *ast::decl,
) (decl | error) = {
// TODO: match on &decl.decl
- return match (decl.decl) {
- co: []ast::decl_const => abort(), // TODO
- gl: []ast::decl_global => abort(), // TODO
- ty: []ast::decl_type => abort(), // TODO
- fu: ast::decl_func => process_func(ctx, decl, fu),
+ match (decl.decl) {
+ case co: []ast::decl_const =>
+ abort(); // TODO
+ case gl: []ast::decl_global =>
+ abort(); // TODO
+ case ty: []ast::decl_type =>
+ abort(); // TODO
+ case fu: ast::decl_func =>
+ return process_func(ctx, decl, fu);
};
};
@@ -50,8 +56,10 @@ fn process_func(
ctx.fntype = &fntype;
const body: nullable *expr = match (afndecl.body) {
- abody: ast::expr => process_expr(ctx, &abody)?,
- void => null,
+ case abody: ast::expr =>
+ yield process_expr(ctx, &abody)?;
+ case void =>
+ yield null;
};
return decl {
@@ -72,49 +80,82 @@ fn process_func(
fn process_expr(
ctx: *context,
expr: *ast::expr,
-) (*expr | error) = match (expr.expr) {
- ast::access_expr => process_access(ctx, expr),
- ast::alloc_expr => abort(), // TODO
- ast::append_expr => abort(), // TODO
- ast::assert_expr => abort(), // TODO
- ast::assign_expr => abort(), // TODO
- ast::binarithm_expr => abort(), // TODO
- ast::binding_expr => process_binding(ctx, expr),
- ast::break_expr => abort(), // TODO
- ast::call_expr => abort(), // TODO
- ast::cast_expr => abort(), // TODO
- ast::compound_expr => process_compound(ctx, expr),
- ast::constant_expr => process_constant(ctx, expr),
- ast::continue_expr => abort(), // TODO
- ast::defer_expr => abort(), // TODO
- ast::delete_expr => abort(), // TODO
- ast::for_expr => abort(), // TODO
- ast::free_expr => abort(), // TODO
- ast::if_expr => abort(), // TODO
- ast::match_expr => abort(), // TODO
- ast::len_expr => abort(), // TODO
- ast::size_expr => abort(), // TODO
- ast::offset_expr => abort(), // TODO
- ast::propagate_expr => abort(), // TODO
- ast::return_expr => process_return(ctx, expr),
- ast::slice_expr => abort(), // TODO
- ast::switch_expr => abort(), // TODO
- ast::unarithm_expr => abort(), // TODO
+) (*expr | error) = {
+ match (expr.expr) {
+ case ast::access_expr =>
+ return process_access(ctx, expr);
+ case ast::alloc_expr =>
+ abort(); // TODO
+ case ast::append_expr =>
+ abort(); // TODO
+ case ast::assert_expr =>
+ abort(); // TODO
+ case ast::assign_expr =>
+ abort(); // TODO
+ case ast::binarithm_expr =>
+ abort(); // TODO
+ case ast::binding_expr =>
+ return process_binding(ctx, expr);
+ case ast::break_expr =>
+ abort(); // TODO
+ case ast::call_expr =>
+ abort(); // TODO
+ case ast::cast_expr =>
+ abort(); // TODO
+ case ast::compound_expr =>
+ return process_compound(ctx, expr);
+ case ast::constant_expr =>
+ return process_constant(ctx, expr);
+ case ast::continue_expr =>
+ abort(); // TODO
+ case ast::defer_expr =>
+ abort(); // TODO
+ case ast::delete_expr =>
+ abort(); // TODO
+ case ast::for_expr =>
+ abort(); // TODO
+ case ast::free_expr =>
+ abort(); // TODO
+ case ast::if_expr =>
+ abort(); // TODO
+ case ast::match_expr =>
+ abort(); // TODO
+ case ast::len_expr =>
+ abort(); // TODO
+ case ast::size_expr =>
+ abort(); // TODO
+ case ast::offset_expr =>
+ abort(); // TODO
+ case ast::propagate_expr =>
+ abort(); // TODO
+ case ast::return_expr =>
+ return process_return(ctx, expr);
+ case ast::slice_expr =>
+ abort(); // TODO
+ case ast::switch_expr =>
+ abort(); // TODO
+ case ast::unarithm_expr =>
+ abort(); // TODO
+ };
};
fn process_access(ctx: *context, aexpr: *ast::expr) (*expr | error) = {
const access = aexpr.expr as ast::access_expr;
const op: (const *types::_type, access) = match (access) {
- ai: ast::access_identifier => {
- const object = match (ctx_lookup(ctx, ai)) {
- null => abort(), // TODO: Error
- obj: *object => obj,
- };
- yield (object._type, object);
- },
- ai: ast::access_index => abort(), // TODO
- af: ast::access_field => abort(), // TODO
- at: ast::access_tuple => abort(), // TODO
+ case ai: ast::access_identifier =>
+ const object = match (ctx_lookup(ctx, ai)) {
+ case null =>
+ abort(); // TODO: Error
+ case obj: *object =>
+ yield obj;
+ };
+ yield (object._type, object);
+ case ai: ast::access_index =>
+ abort(); // TODO
+ case af: ast::access_field =>
+ abort(); // TODO
+ case at: ast::access_tuple =>
+ abort(); // TODO
};
return alloc(expr {
start = aexpr.start,
@@ -152,8 +193,10 @@ fn process_binding(ctx: *context, aexpr: *ast::expr) (*expr | error) = {
const item = bind.bindings[i];
const init = process_expr(ctx, item.init)?;
const _type = match (item._type) {
- null => abort(), // TODO
- ty: *ast::_type => types::lookup(ctx.store, ty)!,
+ case null =>
+ abort(); // TODO
+ case ty: *ast::_type =>
+ yield types::lookup(ctx.store, ty)!;
};
const object = scope_insert(ctx, object {
kind = object_kind::BIND,
@@ -219,23 +262,35 @@ fn process_constant(ctx: *context, aexpr: *ast::expr) (*expr | error) = {
const constexpr = aexpr.expr as ast::constant_expr;
// TODO: Tuple unpacking
const er: (const *types::_type, constant) = match (constexpr) {
- v: ast::value => (
+ case v: ast::value =>
+ yield (
// TODO: iconst/fconst lowering
types::lookup_builtin(ctx.store, match (v) {
- ast::_null => ast::builtin_type::NULL,
- b: bool => ast::builtin_type::BOOL,
- s: str => ast::builtin_type::STR,
- r: rune => ast::builtin_type::RUNE,
- i: i64 => ast::builtin_type::INT,
- u: u64 => ast::builtin_type::UINT,
- f: f64 => ast::builtin_type::F64,
- void => ast::builtin_type::VOID,
+ case ast::_null =>
+ yield ast::builtin_type::NULL;
+ case b: bool =>
+ yield ast::builtin_type::BOOL;
+ case s: str =>
+ yield ast::builtin_type::STR;
+ case r: rune =>
+ yield ast::builtin_type::RUNE;
+ case i: i64 =>
+ yield ast::builtin_type::INT;
+ case u: u64 =>
+ yield ast::builtin_type::UINT;
+ case f: f64 =>
+ yield ast::builtin_type::F64;
+ case void =>
+ yield ast::builtin_type::VOID;
}),
v,
- ),
- ast::array_constant => abort(), // TODO
- ast::struct_constant => abort(), // TODO
- ast::tuple_constant => abort(), // TODO
+ );
+ case ast::array_constant =>
+ abort(); // TODO
+ case ast::struct_constant =>
+ abort(); // TODO
+ case ast::tuple_constant =>
+ abort(); // TODO
};
return alloc(expr {
start = aexpr.start,
@@ -284,19 +339,25 @@ fn process_constant(ctx: *context, aexpr: *ast::expr) (*expr | error) = {
("13.37", types::builtin::F64, 13.37f64),
];
for (let i = 0z; i < len(cases); i += 1) {
- const case = cases[i];
- const aexpr = parse_expr(case.0);
+ const _case = cases[i];
+ const aexpr = parse_expr(_case.0);
defer ast::expr_free(aexpr);
const expr = process_constant(&ctx, aexpr)!;
- assert(expr.result.repr as types::builtin == case.1);
+ assert(expr.result.repr as types::builtin == _case.1);
const constexpr = expr.expr as constant;
- match (case.2) {
- s: str => assert(constexpr as str == s),
- r: rune => assert(constexpr as rune == r),
- i: i64 => assert(constexpr as i64 == i),
- u: u64 => assert(constexpr as u64 == u),
- f: f64 => assert(constexpr as f64 == f),
- void => abort(),
+ match (_case.2) {
+ case s: str =>
+ assert(constexpr as str == s);
+ case r: rune =>
+ assert(constexpr as rune == r);
+ case i: i64 =>
+ assert(constexpr as i64 == i);
+ case u: u64 =>
+ assert(constexpr as u64 == u);
+ case f: f64 =>
+ assert(constexpr as f64 == f);
+ case void =>
+ abort();
};
};
};
@@ -304,8 +365,10 @@ fn process_constant(ctx: *context, aexpr: *ast::expr) (*expr | error) = {
fn process_return(ctx: *context, aexpr: *ast::expr) (*expr | error) = {
const ret = aexpr.expr as ast::return_expr;
const rval = match (ret) {
- null => null,
- aexpr: *ast::expr => process_expr(ctx, aexpr)?,
+ case null =>
+ yield null;
+ case aexpr: *ast::expr =>
+ yield process_expr(ctx, aexpr)?;
};
// TODO: assert(types::assignable(ctx.fntype.result, rval.type));
return alloc(expr {
diff --git a/hare/unit/scan.ha b/hare/unit/scan.ha
@@ -12,9 +12,11 @@ fn scan(ctx: *context, subunits: const []ast::subunit) (void | error) = {
for (let j = 0z; j < len(subunit.decls); j += 1) {
let decl = &subunit.decls[j];
match (scan_decl(ctx, decl)) {
- void => void,
- types::deferred => abort(), // TODO
- error => abort(), // TODO
+ case void => void;
+ case types::deferred =>
+ abort(); // TODO
+ case error =>
+ abort(); // TODO
};
};
scope_pop(ctx);
@@ -26,11 +28,15 @@ fn scan_decl(
decl: *ast::decl,
) (void | types::deferred | error) = {
// TODO: match on &decl.decl
- return match (decl.decl) {
- co: []ast::decl_const => abort(), // TODO
- gl: []ast::decl_global => abort(), // TODO
- ty: []ast::decl_type => abort(), // TODO
- fu: ast::decl_func => scan_func(ctx, decl, fu),
+ match (decl.decl) {
+ case co: []ast::decl_const =>
+ abort(); // TODO
+ case gl: []ast::decl_global =>
+ abort(); // TODO
+ case ty: []ast::decl_type =>
+ abort(); // TODO
+ case fu: ast::decl_func =>
+ return scan_func(ctx, decl, fu);
};
};
@@ -41,9 +47,12 @@ fn scan_func(
) (void | types::deferred | error) = {
assert(func.attrs & ast::fndecl_attrs::TEST == 0); // TODO
const fntype = match (types::lookup(ctx.store, &func.prototype)) {
- err: types::error => return err,
- types::deferred => return types::deferred,
- fntype: const *types::_type => fntype,
+ case err: types::error =>
+ return err;
+ case types::deferred =>
+ return types::deferred;
+ case fntype: const *types::_type =>
+ yield fntype;
};
scope_insert(ctx, object {
kind = object_kind::DECL,
diff --git a/hare/unit/scope.ha b/hare/unit/scope.ha
@@ -97,8 +97,10 @@ fn scope_lookup(scope: *scope, ident: ast::ident) nullable *object = {
return bucket[i];
};
};
- return match (scope.parent) {
- null => null,
- scope: *scope => scope_lookup(scope, ident),
+ match (scope.parent) {
+ case null =>
+ return null;
+ case scope: *scope =>
+ return scope_lookup(scope, ident);
};
};
diff --git a/hare/unparse/decl.ha b/hare/unparse/decl.ha
@@ -10,80 +10,78 @@ export fn decl(out: *io::stream, d: ast::decl) (size | io::error) = {
n += fmt::fprint(out, "export ")?;
};
match (d.decl) {
- c: []ast::decl_const => {
- n += fmt::fprint(out, "def ")?;
- for (let i = 0z; i < len(c); i += 1) {
- n += ident(out, c[i].ident)?;
- n += fmt::fprint(out, ": ")?;
- n += _type(out, 0, c[i]._type)?;
- n += fmt::fprint(out, " = ")?;
- n += expr(out, 0, *c[i].init)?;
- if (i + 1 < len(c)) {
- n += fmt::fprint(out, ", ")?;
- };
+ case c: []ast::decl_const =>
+ n += fmt::fprint(out, "def ")?;
+ for (let i = 0z; i < len(c); i += 1) {
+ n += ident(out, c[i].ident)?;
+ n += fmt::fprint(out, ": ")?;
+ n += _type(out, 0, c[i]._type)?;
+ n += fmt::fprint(out, " = ")?;
+ n += expr(out, 0, *c[i].init)?;
+ if (i + 1 < len(c)) {
+ n += fmt::fprint(out, ", ")?;
};
- },
- g: []ast::decl_global => {
- n += fmt::fprint(out,
- if (g[0].is_const) "const " else "let ")?;
- for (let i = 0z; i < len(g); i += 1) {
- if (len(g[i].symbol) != 0) {
- n += fmt::fprintf(out,
- "@symbol(\"{}\") ", g[i].symbol)?;
- };
- n += ident(out, g[i].ident)?;
- n += fmt::fprint(out, ": ")?;
- n += _type(out, 0, g[i]._type)?;
- match (g[i].init) {
- null => void,
- ex: *ast::expr => {
- n += fmt::fprint(out, " = ")?;
- n += expr(out, 0, *ex)?;
- },
- };
- if (i + 1 < len(g)) {
- n += fmt::fprint(out, ", ")?;
- };
+ };
+ case g: []ast::decl_global =>
+ n += fmt::fprint(out,
+ if (g[0].is_const) "const " else "let ")?;
+ for (let i = 0z; i < len(g); i += 1) {
+ if (len(g[i].symbol) != 0) {
+ n += fmt::fprintf(out,
+ "@symbol(\"{}\") ", g[i].symbol)?;
};
- },
- t: []ast::decl_type => {
- n += fmt::fprint(out, "type ")?;
- for (let i = 0z; i < len(t); i += 1) {
- n += ident(out, t[i].ident)?;
+ n += ident(out, g[i].ident)?;
+ n += fmt::fprint(out, ": ")?;
+ n += _type(out, 0, g[i]._type)?;
+ match (g[i].init) {
+ case null => void;
+ case ex: *ast::expr =>
n += fmt::fprint(out, " = ")?;
- n += _type(out, 0, t[i]._type)?;
- if (i + 1 < len(t)) {
- n += fmt::fprint(out, ", ")?;
- };
+ n += expr(out, 0, *ex)?;
};
- },
- f: ast::decl_func => {
- n += fmt::fprint(out, switch (f.attrs) {
- ast::fndecl_attrs::NONE => "",
- ast::fndecl_attrs::FINI => "@fini ",
- ast::fndecl_attrs::INIT => "@init ",
- ast::fndecl_attrs::TEST => "@test ",
- })?;
- let p = f.prototype.repr as ast::func_type;
- if (p.attrs & ast::func_attrs::NORETURN != 0) {
- n += fmt::fprint(out, "@noreturn ")?;
+ if (i + 1 < len(g)) {
+ n += fmt::fprint(out, ", ")?;
};
- if (len(f.symbol) != 0) {
- n += fmt::fprintf(out, "@symbol(\"{}\") ",
- f.symbol)?;
+ };
+ case t: []ast::decl_type =>
+ n += fmt::fprint(out, "type ")?;
+ for (let i = 0z; i < len(t); i += 1) {
+ n += ident(out, t[i].ident)?;
+ n += fmt::fprint(out, " = ")?;
+ n += _type(out, 0, t[i]._type)?;
+ if (i + 1 < len(t)) {
+ n += fmt::fprint(out, ", ")?;
};
- n += fmt::fprint(out, "fn ")?;
- n += ident(out, f.ident)?;
- const fntype = f.prototype.repr as ast::func_type;
- n += prototype(out, 0, fntype)?;
- match (f.body) {
- void => void,
- e: ast::expr => {
- n += fmt::fprint(out, " = ")?;
- n += expr(out, 0, e)?;
- },
- };
- },
+ };
+ case f: ast::decl_func =>
+ n += fmt::fprint(out, switch (f.attrs) {
+ case ast::fndecl_attrs::NONE =>
+ yield "";
+ case ast::fndecl_attrs::FINI =>
+ yield "@fini ";
+ case ast::fndecl_attrs::INIT =>
+ yield "@init ";
+ case ast::fndecl_attrs::TEST =>
+ yield "@test ";
+ })?;
+ let p = f.prototype.repr as ast::func_type;
+ if (p.attrs & ast::func_attrs::NORETURN != 0) {
+ n += fmt::fprint(out, "@noreturn ")?;
+ };
+ if (len(f.symbol) != 0) {
+ n += fmt::fprintf(out, "@symbol(\"{}\") ",
+ f.symbol)?;
+ };
+ n += fmt::fprint(out, "fn ")?;
+ n += ident(out, f.ident)?;
+ const fntype = f.prototype.repr as ast::func_type;
+ n += prototype(out, 0, fntype)?;
+ match (f.body) {
+ case void => void;
+ case e: ast::expr =>
+ n += fmt::fprint(out, " = ")?;
+ n += expr(out, 0, e)?;
+ };
};
n += fmt::fprint(out, ";")?;
return n;
diff --git a/hare/unparse/expr.ha b/hare/unparse/expr.ha
@@ -13,358 +13,374 @@ export fn expr(
indent: size,
e: ast::expr
) (size | io::error) = {
- return match (e.expr) {
- e: ast::access_expr => match (e) {
- id: ast::access_identifier => ident(out, id),
- ix: ast::access_index => {
- let z = expr(out, indent, *ix.object)?;
- z += fmt::fprintf(out, "[")?;
- z += expr(out, indent, *ix.index)?;
- z += fmt::fprintf(out, "]")?;
- yield z;
- },
- fi: ast::access_field => {
- let z = expr(out, indent, *fi.object)?;
- z += fmt::fprintf(out, ".{}", fi.field)?;
- yield z;
- },
- tp: ast::access_tuple => {
- let z = expr(out, indent, *tp.object)?;
- z += fmt::fprintf(out, ".")?;
- z += expr(out, indent, *tp.value)?;
- yield z;
- },
- },
- e: ast::alloc_expr => {
- let z = fmt::fprint(out, "alloc(")?;
- z += expr(out, indent, *e.init)?;
- match (e.capacity) {
- null => void,
- e: *ast::expr => {
- z += fmt::fprint(out, ", ")?;
- z += expr(out, indent, *e)?;
- },
- };
- z += fmt::fprint(out, ")")?;
- yield z;
- },
- e: ast::append_expr => {
- let z = if (e.is_static) fmt::fprint(out, "static ")?
- else 0z;
- z += fmt::fprint(out, "append(")?;
- z += expr(out, indent, *e.object)?;
+ match (e.expr) {
+ case e: ast::access_expr =>
+ match (e) {
+ case id: ast::access_identifier =>
+ return ident(out, id);
+ case ix: ast::access_index =>
+ let z = expr(out, indent, *ix.object)?;
+ z += fmt::fprintf(out, "[")?;
+ z += expr(out, indent, *ix.index)?;
+ z += fmt::fprintf(out, "]")?;
+ return z;
+ case fi: ast::access_field =>
+ let z = expr(out, indent, *fi.object)?;
+ z += fmt::fprintf(out, ".{}", fi.field)?;
+ return z;
+ case tp: ast::access_tuple =>
+ let z = expr(out, indent, *tp.object)?;
+ z += fmt::fprintf(out, ".")?;
+ z += expr(out, indent, *tp.value)?;
+ return z;
+ };
+ case e: ast::alloc_expr =>
+ let z = fmt::fprint(out, "alloc(")?;
+ z += expr(out, indent, *e.init)?;
+ match (e.capacity) {
+ case null => void;
+ case e: *ast::expr =>
z += fmt::fprint(out, ", ")?;
- for (let i = 0z; i < len(e.values); i += 1) {
- let val = e.values[i];
- z += expr(out, indent, *val)?;
- if (i + 1 < len(e.values)) {
- z += fmt::fprint(out, ", ")?;
- };
- };
- match (e.variadic) {
- null => void,
- v: *ast::expr => {
- if (len(e.values) != 0) {
- z += fmt::fprint(out, ", ")?;
- };
- z += expr(out, indent, *v)?;
- z += fmt::fprint(out, "...")?;
- },
- };
- z += fmt::fprint(out, ")")?;
- yield z;
- },
- e: ast::assert_expr => {
- let z = fmt::fprint(
- out, if (e.is_static) "static " else "")?;
- // assert without a condition = abort
- z += match (e.cond) {
- e: *ast::expr => {
- yield fmt::fprint(out, "assert(")? +
- expr(out, indent, *e)?;
- },
- null => fmt::fprint(out, "abort(")?,
+ z += expr(out, indent, *e)?;
+ };
+ z += fmt::fprint(out, ")")?;
+ return z;
+ case e: ast::append_expr =>
+ let z = if (e.is_static) fmt::fprint(out, "static ")? else 0z;
+ z += fmt::fprint(out, "append(")?;
+ z += expr(out, indent, *e.object)?;
+ z += fmt::fprint(out, ", ")?;
+ for (let i = 0z; i < len(e.values); i += 1) {
+ let val = e.values[i];
+ z += expr(out, indent, *val)?;
+ if (i + 1 < len(e.values)) {
+ z += fmt::fprint(out, ", ")?;
};
- z += match (e.message) {
- m: *ast::expr => {
- let z = 0z;
- match (e.cond) {
- *ast::expr => {
- z += fmt::fprint(out, ", ")?;
- },
- null => void,
- };
- z += expr(out, indent, *m)?;
- yield z;
- },
- null => 0,
+ };
+ match (e.variadic) {
+ case null => void;
+ case v: *ast::expr =>
+ if (len(e.values) != 0) {
+ z += fmt::fprint(out, ", ")?;
};
- z += fmt::fprint(out, ")")?;
- yield z;
- },
- e: ast::assign_expr => {
+ z += expr(out, indent, *v)?;
+ z += fmt::fprint(out, "...")?;
+ };
+ z += fmt::fprint(out, ")")?;
+ return z;
+ case e: ast::assert_expr =>
+ let z = fmt::fprint(
+ out, if (e.is_static) "static " else "")?;
+ // assert without a condition = abort
+ z += match (e.cond) {
+ case e: *ast::expr =>
+ yield fmt::fprint(out, "assert(")? +
+ expr(out, indent, *e)?;
+ case null =>
+ yield fmt::fprint(out, "abort(")?;
+ };
+ z += match (e.message) {
+ case m: *ast::expr =>
let z = 0z;
- if (e.indirect) {
- z += fmt::fprint(out, "*")?;
- };
- z += expr(out, indent, *e.object)?;
- const op = match (e.op) {
- void => "=",
- op: ast::binarithm_op => switch (op) {
- ast::binarithm_op::BAND => "&=",
- ast::binarithm_op::LAND => "&&=",
- ast::binarithm_op::BOR => "|=",
- ast::binarithm_op::LOR => "||=",
- ast::binarithm_op::DIV => "/=",
- ast::binarithm_op::LSHIFT => "<<=",
- ast::binarithm_op::MINUS => "-=",
- ast::binarithm_op::MODULO => "%=",
- ast::binarithm_op::PLUS => "+=",
- ast::binarithm_op::RSHIFT => ">>=",
- ast::binarithm_op::TIMES => "*=",
- ast::binarithm_op::BXOR => "^=",
- ast::binarithm_op::LXOR => "^^=",
- * => abort(),
- },
- };
- z += fmt::fprintf(out, " {} ", op)?;
- z += expr(out, indent, *e.value)?;
- yield z;
- },
- e: ast::binarithm_expr => {
- let z = expr(out, indent, *e.lvalue)?;
- z += fmt::fprintf(out, " {} ", switch (e.op) {
- ast::binarithm_op::BAND => "&",
- ast::binarithm_op::BOR => "|",
- ast::binarithm_op::DIV => "/",
- ast::binarithm_op::GT => ">",
- ast::binarithm_op::GTEQ => ">=",
- ast::binarithm_op::LAND => "&&",
- ast::binarithm_op::LEQUAL => "==",
- ast::binarithm_op::LESS => "<",
- ast::binarithm_op::LESSEQ => "<=",
- ast::binarithm_op::LOR => "||",
- ast::binarithm_op::LSHIFT => "<<",
- ast::binarithm_op::LXOR => "^^",
- ast::binarithm_op::MINUS => "-",
- ast::binarithm_op::MODULO => "%",
- ast::binarithm_op::NEQUAL => "!=",
- ast::binarithm_op::PLUS => "+",
- ast::binarithm_op::RSHIFT => ">>",
- ast::binarithm_op::TIMES => "*",
- ast::binarithm_op::BXOR => "^",
- })?;
- z += expr(out, indent, *e.rvalue)?;
- yield z;
- },
- e: ast::binding_expr => {
- let z = fmt::fprintf(out, "{}{}",
- if (e.is_static) "static " else "",
- if (e.is_const) "const " else "let ")?;
- for (let i = 0z; i < len(e.bindings); i += 1) {
- let binding = e.bindings[i];
- z += match (binding._type) {
- null => fmt::fprint(out, binding.name)?,
- t: *ast::_type => {
- let z = 0z;
- z += fmt::fprintf(out, "{}: ",
- binding.name)?;
- z += _type(out, indent, *t)?;
- yield z;
- },
- };
- z += fmt::fprint(out, " = ")?;
- z += expr(out, indent, *binding.init)?;
- if (i + 1 < len(e.bindings)) {
- z += fmt::fprint(out, ", ")?;
- };
+ match (e.cond) {
+ case null => void;
+ case *ast::expr =>
+ z += fmt::fprint(out, ", ")?;
};
+ z += expr(out, indent, *m)?;
yield z;
- },
- e: ast::break_expr => {
- let z = fmt::fprint(out, "break")?;
- if (e != "") {
- z += fmt::fprintf(out, " :{}", e)?;
+ case null =>
+ yield 0;
+ };
+ z += fmt::fprint(out, ")")?;
+ return z;
+ case e: ast::assign_expr =>
+ let z = 0z;
+ if (e.indirect) {
+ z += fmt::fprint(out, "*")?;
+ };
+ z += expr(out, indent, *e.object)?;
+ const op = match (e.op) {
+ case void =>
+ yield "=";
+ case op: ast::binarithm_op =>
+ yield switch (op) {
+ case ast::binarithm_op::BAND =>
+ yield "&=";
+ case ast::binarithm_op::LAND =>
+ yield "&&=";
+ case ast::binarithm_op::BOR =>
+ yield "|=";
+ case ast::binarithm_op::LOR =>
+ yield "||=";
+ case ast::binarithm_op::DIV =>
+ yield "/=";
+ case ast::binarithm_op::LSHIFT =>
+ yield "<<=";
+ case ast::binarithm_op::MINUS =>
+ yield "-=";
+ case ast::binarithm_op::MODULO =>
+ yield "%=";
+ case ast::binarithm_op::PLUS =>
+ yield "+=";
+ case ast::binarithm_op::RSHIFT =>
+ yield ">>=";
+ case ast::binarithm_op::TIMES =>
+ yield "*=";
+ case ast::binarithm_op::BXOR =>
+ yield "^=";
+ case ast::binarithm_op::LXOR =>
+ yield "^^=";
};
- yield z;
- },
- e: ast::call_expr => {
- let z = expr(out, indent, *e.lvalue)?;
- z += fmt::fprintf(out, "(")?;
- for (let i = 0z; i < len(e.args); i += 1) {
- z += expr(out, indent, *e.args[i])?;
- if (i + 1 < len(e.args)) {
- z += fmt::fprintf(out, ", ")?;
- };
+ };
+ z += fmt::fprintf(out, " {} ", op)?;
+ z += expr(out, indent, *e.value)?;
+ return z;
+ case e: ast::binarithm_expr =>
+ let z = expr(out, indent, *e.lvalue)?;
+ z += fmt::fprintf(out, " {} ", switch (e.op) {
+ case ast::binarithm_op::BAND =>
+ yield "&";
+ case ast::binarithm_op::BOR =>
+ yield "|";
+ case ast::binarithm_op::DIV =>
+ yield "/";
+ case ast::binarithm_op::GT =>
+ yield ">";
+ case ast::binarithm_op::GTEQ =>
+ yield ">=";
+ case ast::binarithm_op::LAND =>
+ yield "&&";
+ case ast::binarithm_op::LEQUAL =>
+ yield "==";
+ case ast::binarithm_op::LESS =>
+ yield "<";
+ case ast::binarithm_op::LESSEQ =>
+ yield "<=";
+ case ast::binarithm_op::LOR =>
+ yield "||";
+ case ast::binarithm_op::LSHIFT =>
+ yield "<<";
+ case ast::binarithm_op::LXOR =>
+ yield "^^";
+ case ast::binarithm_op::MINUS =>
+ yield "-";
+ case ast::binarithm_op::MODULO =>
+ yield "%";
+ case ast::binarithm_op::NEQUAL =>
+ yield "!=";
+ case ast::binarithm_op::PLUS =>
+ yield "+";
+ case ast::binarithm_op::RSHIFT =>
+ yield ">>";
+ case ast::binarithm_op::TIMES =>
+ yield "*";
+ case ast::binarithm_op::BXOR =>
+ yield "^";
+ })?;
+ z += expr(out, indent, *e.rvalue)?;
+ return z;
+ case e: ast::binding_expr =>
+ let z = fmt::fprintf(out, "{}{}",
+ if (e.is_static) "static " else "",
+ if (e.is_const) "const " else "let ")?;
+ for (let i = 0z; i < len(e.bindings); i += 1) {
+ let binding = e.bindings[i];
+ z += match (binding._type) {
+ case null =>
+ yield fmt::fprint(out, binding.name)?;
+ case t: *ast::_type =>
+ let z = 0z;
+ z += fmt::fprintf(out, "{}: ",
+ binding.name)?;
+ z += _type(out, indent, *t)?;
+ yield z;
};
- if (e.variadic) {
- z += fmt::fprintf(out, "...")?;
+ z += fmt::fprint(out, " = ")?;
+ z += expr(out, indent, *binding.init)?;
+ if (i + 1 < len(e.bindings)) {
+ z += fmt::fprint(out, ", ")?;
};
- z += fmt::fprintf(out, ")")?;
- yield z;
- },
- e: ast::cast_expr => {
- let z = expr(out, indent, *e.value)?;
- const op = switch (e.kind) {
- ast::cast_kind::CAST => ": ",
- ast::cast_kind::ASSERTION => " as ",
- ast::cast_kind::TEST => " is ",
- };
- z += fmt::fprintf(out, "{}", op)?;
- z += _type(out, indent, *e._type)?;
- yield z;
- },
- e: ast::constant_expr => constant(out, indent, e)?,
- e: ast::continue_expr => {
- let z = fmt::fprint(out, "continue")?;
- if (e != "") {
- z += fmt::fprintf(out, " :{}", e)?;
+ };
+ return z;
+ case e: ast::break_expr =>
+ let z = fmt::fprint(out, "break")?;
+ if (e != "") {
+ z += fmt::fprintf(out, " :{}", e)?;
+ };
+ return z;
+ case e: ast::call_expr =>
+ let z = expr(out, indent, *e.lvalue)?;
+ z += fmt::fprintf(out, "(")?;
+ for (let i = 0z; i < len(e.args); i += 1) {
+ z += expr(out, indent, *e.args[i])?;
+ if (i + 1 < len(e.args)) {
+ z += fmt::fprintf(out, ", ")?;
};
- yield z;
- },
- e: ast::defer_expr =>
- fmt::fprint(out, "defer ")? + expr(out, indent, *e)?,
- e: ast::delete_expr => {
- let z = if (e.is_static) fmt::fprint(out, "static ")?
- else 0z;
- z += fmt::fprint(out, "delete(")?;
- z += expr(out, indent, *e.object)?;
- z += fmt::fprint(out, ")")?;
- yield z;
- },
- e: ast::for_expr => for_expr(out, indent, e)?,
- e: ast::free_expr =>
- fmt::fprint(out, "free(")?
+ };
+ if (e.variadic) {
+ z += fmt::fprintf(out, "...")?;
+ };
+ z += fmt::fprintf(out, ")")?;
+ return z;
+ case e: ast::cast_expr =>
+ let z = expr(out, indent, *e.value)?;
+ const op = switch (e.kind) {
+ case ast::cast_kind::CAST =>
+ yield ": ";
+ case ast::cast_kind::ASSERTION =>
+ yield " as ";
+ case ast::cast_kind::TEST =>
+ yield " is ";
+ };
+ z += fmt::fprintf(out, "{}", op)?;
+ z += _type(out, indent, *e._type)?;
+ return z;
+ case e: ast::constant_expr =>
+ return constant(out, indent, e)?;
+ case e: ast::continue_expr =>
+ let z = fmt::fprint(out, "continue")?;
+ if (e != "") {
+ z += fmt::fprintf(out, " :{}", e)?;
+ };
+ return z;
+ case e: ast::defer_expr =>
+ return fmt::fprint(out, "defer ")? + expr(out, indent, *e)?;
+ case e: ast::delete_expr =>
+ let z = if (e.is_static) fmt::fprint(out, "static ")? else 0z;
+ z += fmt::fprint(out, "delete(")?;
+ z += expr(out, indent, *e.object)?;
+ z += fmt::fprint(out, ")")?;
+ return z;
+ case e: ast::for_expr =>
+ return for_expr(out, indent, e)?;
+ case e: ast::free_expr =>
+ return fmt::fprint(out, "free(")?
+ expr(out, indent, *e)?
- + fmt::fprint(out, ")")?,
- e: ast::if_expr => {
- let z = fmt::fprint(out, "if (")?;
- z += expr(out, indent, *e.cond)?;
- z += fmt::fprint(out, ") ")?;
- z += expr(out, indent, *e.tbranch)?;
- match (e.fbranch) {
- null => void,
- e: *ast::expr => {
- z += fmt::fprint(out, " else ")?;
- z += expr(out, indent, *e)?;
- },
- };
- yield z;
- },
- e: ast::insert_expr => {
- let z = if (e.is_static) fmt::fprint(out, "static ")?
- else 0z;
- z += fmt::fprint(out, "insert(")?;
- z += expr(out, indent, *e.object)?;
- z += fmt::fprint(out, ", ")?;
- for (let i = 0z; i < len(e.values); i += 1) {
- let val = e.values[i];
- z += expr(out, indent, *val)?;
- if (i + 1 < len(e.values)) {
- z += fmt::fprint(out, ", ")?;
- };
- };
- match (e.variadic) {
- null => void,
- v: *ast::expr => {
- if (len(e.values) != 0) {
- z += fmt::fprint(out, ", ")?;
- };
- z += expr(out, indent, *v)?;
- z += fmt::fprint(out, "...")?;
- },
- };
- z += fmt::fprint(out, ")")?;
- yield z;
- },
- e: ast::compound_expr => {
- let z = 0z;
- if (e.label != "") {
- z += fmt::fprintf(out, ":{} ", e.label)?;
- };
- z += fmt::fprintf(out, "{{")?;
- for (let i = 0z; i < len(e.exprs); i += 1) {
- z += newline(out, indent + 1)?;
- z += expr(out, indent + 1, *e.exprs[i])?;
- z += fmt::fprintf(out, ";")?;
- };
- z += newline(out, indent)?;
- z += fmt::fprintf(out, "}}")?;
- yield z;
- },
- e: ast::match_expr => match_expr(out, indent, e)?,
- e: ast::len_expr => {
- let z = fmt::fprint(out, "len(")?;
+ + fmt::fprint(out, ")")?;
+ case e: ast::if_expr =>
+ let z = fmt::fprint(out, "if (")?;
+ z += expr(out, indent, *e.cond)?;
+ z += fmt::fprint(out, ") ")?;
+ z += expr(out, indent, *e.tbranch)?;
+ match (e.fbranch) {
+ case null => void;
+ case e: *ast::expr =>
+ z += fmt::fprint(out, " else ")?;
z += expr(out, indent, *e)?;
- z += fmt::fprint(out, ")")?;
- yield z;
- },
- e: ast::size_expr => {
- let z = fmt::fprint(out, "size(")?;
- z += _type(out, indent, *e)?;
- z += fmt::fprint(out, ")")?;
- yield z;
- },
- ast::offset_expr => abort(),
- e: ast::propagate_expr => {
- let z = expr(out, indent, *e.expr)?;
- z += fmt::fprintf(out, if (e.is_abort) "!" else "?")?;
- yield z;
- },
- e: ast::return_expr => {
- let z = fmt::fprint(out, "return")?;
- match (e) {
- null => void,
- e: *ast::expr => {
- z += fmt::fprint(out, " ")?;
- z += expr(out, indent, *e)?;
- },
- };
- yield z;
- },
- e: ast::slice_expr => {
- let z = expr(out, indent, *e.object)?;
- z += fmt::fprint(out, "[")?;
- z += match (e.start) {
- null => 0z,
- e: *ast::expr => expr(out, indent, *e)?,
- };
- z += fmt::fprint(out, "..")?;
- z += match (e.end) {
- null => 0z,
- e: *ast::expr => expr(out, indent, *e)?,
- };
- z += fmt::fprint(out, "]")?;
- yield z;
- },
- e: ast::switch_expr => switch_expr(out, indent, e)?,
- e: ast::unarithm_expr => {
- let z = fmt::fprintf(out, "{}", switch (e.op) {
- ast::unarithm_op::ADDR => "&",
- ast::unarithm_op::BNOT => "~",
- ast::unarithm_op::DEREF => "*",
- ast::unarithm_op::LNOT => "!",
- ast::unarithm_op::MINUS => "-",
- ast::unarithm_op::PLUS => "+",
- })?;
- z += expr(out, indent, *e.operand)?;
- yield z;
- },
- e: ast::yield_expr => {
- let z = fmt::fprint(out, "yield")?;
- if (e.label != "") {
- z += fmt::fprintf(out, " :{}", e.label)?;
+ };
+ return z;
+ case e: ast::insert_expr =>
+ let z = if (e.is_static) fmt::fprint(out, "static ")? else 0z;
+ z += fmt::fprint(out, "insert(")?;
+ z += expr(out, indent, *e.object)?;
+ z += fmt::fprint(out, ", ")?;
+ for (let i = 0z; i < len(e.values); i += 1) {
+ let val = e.values[i];
+ z += expr(out, indent, *val)?;
+ if (i + 1 < len(e.values)) {
+ z += fmt::fprint(out, ", ")?;
};
- match (e.value) {
- null => void,
- v: *ast::expr => {
- z += fmt::fprint(out, if (e.label == "")
- " " else ", ")?;
- z += expr(out, indent, *v)?;
- },
+ };
+ match (e.variadic) {
+ case null => void;
+ case v: *ast::expr =>
+ if (len(e.values) != 0) {
+ z += fmt::fprint(out, ", ")?;
};
- yield z;
- },
+ z += expr(out, indent, *v)?;
+ z += fmt::fprint(out, "...")?;
+ };
+ z += fmt::fprint(out, ")")?;
+ return z;
+ case e: ast::compound_expr =>
+ let z = 0z;
+ if (e.label != "") {
+ z += fmt::fprintf(out, ":{} ", e.label)?;
+ };
+ z += fmt::fprintf(out, "{{")?;
+ for (let i = 0z; i < len(e.exprs); i += 1) {
+ z += newline(out, indent + 1)?;
+ z += expr(out, indent + 1, *e.exprs[i])?;
+ z += fmt::fprintf(out, ";")?;
+ };
+ z += newline(out, indent)?;
+ z += fmt::fprintf(out, "}}")?;
+ return z;
+ case e: ast::match_expr =>
+ return match_expr(out, indent, e)?;
+ case e: ast::len_expr =>
+ let z = fmt::fprint(out, "len(")?;
+ z += expr(out, indent, *e)?;
+ z += fmt::fprint(out, ")")?;
+ return z;
+ case e: ast::size_expr =>
+ let z = fmt::fprint(out, "size(")?;
+ z += _type(out, indent, *e)?;
+ z += fmt::fprint(out, ")")?;
+ return z;
+ case ast::offset_expr => abort(); // TODO
+ case e: ast::propagate_expr =>
+ let z = expr(out, indent, *e.expr)?;
+ z += fmt::fprintf(out, if (e.is_abort) "!" else "?")?;
+ return z;
+ case e: ast::return_expr =>
+ let z = fmt::fprint(out, "return")?;
+ match (e) {
+ case null => void;
+ case e: *ast::expr =>
+ z += fmt::fprint(out, " ")?;
+ z += expr(out, indent, *e)?;
+ };
+ return z;
+ case e: ast::slice_expr =>
+ let z = expr(out, indent, *e.object)?;
+ z += fmt::fprint(out, "[")?;
+ match (e.start) {
+ case null => void;
+ case e: *ast::expr =>
+ z += expr(out, indent, *e)?;
+ };
+ z += fmt::fprint(out, "..")?;
+ match (e.end) {
+ case null => void;
+ case e: *ast::expr =>
+ z += expr(out, indent, *e)?;
+ };
+ z += fmt::fprint(out, "]")?;
+ return z;
+ case e: ast::switch_expr =>
+ return switch_expr(out, indent, e)?;
+ case e: ast::unarithm_expr =>
+ let z = fmt::fprintf(out, "{}", switch (e.op) {
+ case ast::unarithm_op::ADDR =>
+ yield "&";
+ case ast::unarithm_op::BNOT =>
+ yield "~";
+ case ast::unarithm_op::DEREF =>
+ yield "*";
+ case ast::unarithm_op::LNOT =>
+ yield "!";
+ case ast::unarithm_op::MINUS =>
+ yield "-";
+ case ast::unarithm_op::PLUS =>
+ yield "+";
+ })?;
+ z += expr(out, indent, *e.operand)?;
+ return z;
+ case e: ast::yield_expr =>
+ let z = fmt::fprint(out, "yield")?;
+ if (e.label != "") {
+ z += fmt::fprintf(out, " :{}", e.label)?;
+ };
+ match (e.value) {
+ case null => void;
+ case v: *ast::expr =>
+ z += fmt::fprint(out, if (e.label == "")
+ " " else ", ")?;
+ z += expr(out, indent, *v)?;
+ };
+ return z;
};
};
@@ -373,41 +389,47 @@ fn constant(
indent: size,
e: ast::constant_expr,
) (size | io::error) = {
- return match (e) {
- void => fmt::fprint(out, "void"),
- v: ast::value => fmt::fprint(out, match (v) {
- void => abort(),
- ast::_null => "null",
- v: (i64 | u64 | f64) => v,
- b: bool => return fmt::fprint(out, b),
- // TODO: Escape these:
- s: str => return fmt::fprintf(out, "\"{}\"", s),
- r: rune => return fmt::fprintf(out, "'{}'", r),
- }),
- ac: ast::array_constant => {
- let z = fmt::fprint(out, "[")?;
- for (let i = 0z; i < len(ac.values); i += 1) {
- z += expr(out, indent, *ac.values[i])?;
- if (i + 1 < len(ac.values)) {
- z += fmt::fprint(out, ", ")?;
- };
+ match (e) {
+ case void =>
+ return fmt::fprint(out, "void");
+ case v: ast::value =>
+ return fmt::fprint(out, match (v) {
+ case void => abort();
+ case ast::_null =>
+ yield "null";
+ case v: (i64 | u64 | f64) =>
+ yield v;
+ case b: bool =>
+ return fmt::fprint(out, b);
+ // TODO: Escape these:
+ case s: str =>
+ return fmt::fprintf(out, "\"{}\"", s);
+ case r: rune =>
+ return fmt::fprintf(out, "'{}'", r);
+ });
+ case ac: ast::array_constant =>
+ let z = fmt::fprint(out, "[")?;
+ for (let i = 0z; i < len(ac.values); i += 1) {
+ z += expr(out, indent, *ac.values[i])?;
+ if (i + 1 < len(ac.values)) {
+ z += fmt::fprint(out, ", ")?;
};
- z += fmt::fprintf(out, "{}]",
- if (ac.expand) "..." else "")?;
- yield z;
- },
- sc: ast::struct_constant => struct_constant(out, indent, sc)?,
- tu: ast::tuple_constant => {
- let z = fmt::fprint(out, "(")?;
- for (let i = 0z; i < len(tu); i += 1) {
- z += expr(out, indent, *tu[i])?;
- if (i + 1 < len(tu)) {
- z += fmt::fprint(out, ", ")?;
- };
+ };
+ z += fmt::fprintf(out, "{}]",
+ if (ac.expand) "..." else "")?;
+ return z;
+ case sc: ast::struct_constant =>
+ return struct_constant(out, indent, sc)?;
+ case tu: ast::tuple_constant =>
+ let z = fmt::fprint(out, "(")?;
+ for (let i = 0z; i < len(tu); i += 1) {
+ z += expr(out, indent, *tu[i])?;
+ if (i + 1 < len(tu)) {
+ z += fmt::fprint(out, ", ")?;
};
- z += fmt::fprint(out, ")")?;
- yield z;
- },
+ };
+ z += fmt::fprint(out, ")")?;
+ return z;
};
};
@@ -427,19 +449,18 @@ fn struct_constant(
for (let i = 0z; i < len(sc.fields); i += 1) {
newline(out, indent)?;
match (sc.fields[i]) {
- sv: ast::struct_value => {
- z += match (sv._type) {
- null => fmt::fprintf(out, "{}", sv.name)?,
- t: *ast::_type =>
- fmt::fprintf(out, "{}: ", sv.name)?
- + _type(out, indent, *t)?,
- };
- z += fmt::fprint(out, " = ")?;
- z += expr(out, indent, *sv.init)?;
- },
- sc: *ast::struct_constant => {
- z += constant(out, indent, *sc)?;
- },
+ case sv: ast::struct_value =>
+ match (sv._type) {
+ case null =>
+ z += fmt::fprintf(out, "{}", sv.name)?;
+ case t: *ast::_type =>
+ z += fmt::fprintf(out, "{}: ", sv.name)?;
+ z += _type(out, indent, *t)?;
+ };
+ z += fmt::fprint(out, " = ")?;
+ z += expr(out, indent, *sv.init)?;
+ case sc: *ast::struct_constant =>
+ z += constant(out, indent, *sc)?;
};
z += fmt::fprint(out, ",")?;
};
@@ -459,17 +480,22 @@ fn for_expr(
e: ast::for_expr,
) (size | io::error) = {
let z = fmt::fprintf(out, "for (")?;
- z += match (e.bindings) {
- null => 0z,
- e: *ast::expr => expr(out, indent, *e)?
- + fmt::fprint(out, "; ")?,
+ match (e.bindings) {
+ case null => void;
+ case e: *ast::expr =>
+ z += expr(out, indent, *e)?;
+ z += fmt::fprint(out, "; ")?;
};
+
z += expr(out, indent, *e.cond)?;
- z += match (e.afterthought) {
- null => 0z,
- e: *ast::expr => fmt::fprint(out, "; ")?
- + expr(out, indent, *e)?,
+
+ match (e.afterthought) {
+ case null => void;
+ case e: *ast::expr =>
+ z += fmt::fprint(out, "; ")?;
+ z += expr(out, indent, *e)?;
};
+
z += fmt::fprintf(out, ") ")?;
return z + expr(out, indent, *e.body)?;
};
@@ -486,21 +512,25 @@ fn switch_expr(
for (let i = 0z; i < len(e.cases); i += 1) {
z += newline(out, indent)?;
- const case = e.cases[i];
- if (len(case.options) == 0) {
- z += fmt::fprint(out, "* => ")?;
+ const item = e.cases[i];
+ z += fmt::fprint(out, "case ")?;
+ if (len(item.options) == 0) {
+ z += fmt::fprint(out, "=>")?;
} else {
- for (let j = 0z; j < len(case.options); j += 1) {
- const opt = case.options[j];
+ for (let j = 0z; j < len(item.options); j += 1) {
+ const opt = item.options[j];
z += expr(out, indent, *opt)?;
- if (j + 1 < len(case.options)) {
+ if (j + 1 < len(item.options)) {
z += fmt::fprint(out, ", ")?;
};
};
- z += fmt::fprint(out, " => ")?;
+ z += fmt::fprint(out, " =>")?;
+ };
+ for (let j = 0z; j < len(item.exprs); j += 1) {
+ z += newline(out, indent + 1)?;
+ z += expr(out, indent + 1, *item.exprs[j])?;
+ z += fmt::fprint(out, ";")?;
};
- z += expr(out, indent, *case.value)?;
- z += fmt::fprint(out, ",")?;
};
indent -= 1;
@@ -517,31 +547,33 @@ fn match_expr(
let z = fmt::fprint(out, "match (")?;
z += expr(out, indent, *e.value)?;
z += fmt::fprint(out, ") {")?;
- indent += 1;
for (let i = 0z; i < len(e.cases); i += 1) {
z += newline(out, indent)?;
- const case = e.cases[i];
- if (len(case.name) > 0) {
- z += fmt::fprintf(out, "{}: ", case.name)?;
+ z += fmt::fprint(out, "case ")?;
+ const item = e.cases[i];
+ if (len(item.name) > 0) {
+ z += fmt::fprintf(out, "{}: ", item.name)?;
+ };
+ z += _type(out, indent, *item._type)?;
+ z += fmt::fprint(out, " =>")?;
+ for (let i = 0z; i < len(item.exprs); i += 1) {
+ z += newline(out, indent + 1)?;
+ z += expr(out, indent + 1, *item.exprs[i])?;
+ z += fmt::fprint(out, ";")?;
};
- z += _type(out, indent, *case._type)?;
- z += fmt::fprint(out, " => ")?;
- z += expr(out, indent, *case.value)?;
- z += fmt::fprint(out, ",")?;
};
- match (e.default) {
- e: *ast::expr => {
- z += newline(out, indent)?;
- z += fmt::fprint(out, "* => ")?;
- z += expr(out, indent, *e)?;
- z += fmt::fprint(out, ",")?;
- },
- null => void,
+ if (len(e.default) != 0) {
+ z += newline(out, indent)?;
+ z += fmt::fprint(out, "case =>")?;
+ for (let i = 0z; i < len(e.default); i += 1) {
+ z += newline(out, indent + 1)?;
+ z += expr(out, indent + 1, *e.default[i])?;
+ z += fmt::fprint(out, ";")?;
+ };
};
- indent -= 1;
z += newline(out, indent)?;
z += fmt::fprint(out, "}")?;
return z;
diff --git a/hare/unparse/import.ha b/hare/unparse/import.ha
@@ -8,21 +8,20 @@ export fn import(out: *io::stream, i: ast::import) (size | io::error) = {
let n = 0z;
n += fmt::fprint(out, "use ")?;
match (i) {
- m: ast::import_module => n += ident(out, m)?,
- a: ast::import_alias => {
- n += fmt::fprint(out, a.alias, "= ")?;
- n += ident(out, a.ident)?;
- },
- o: ast::import_objects => {
- n += ident(out, o.ident)?;
- n += fmt::fprint(out, "::{")?;
- for (let i = 0z; i < len(o.objects); i += 1) {
- n += fmt::fprintf(out, "{}{}", o.objects[i],
- if (i + 1 < len(o.objects)) ", "
- else "")?;
- };
- n += fmt::fprint(out, "}")?;
- },
+ case m: ast::import_module =>
+ n += ident(out, m)?;
+ case a: ast::import_alias =>
+ n += fmt::fprint(out, a.alias, "= ")?;
+ n += ident(out, a.ident)?;
+ case o: ast::import_objects =>
+ n += ident(out, o.ident)?;
+ n += fmt::fprint(out, "::{")?;
+ for (let i = 0z; i < len(o.objects); i += 1) {
+ n += fmt::fprintf(out, "{}{}", o.objects[i],
+ if (i + 1 < len(o.objects)) ", "
+ else "")?;
+ };
+ n += fmt::fprint(out, "}")?;
};
n += fmt::fprint(out, ";")?;
return n;
diff --git a/hare/unparse/type.ha b/hare/unparse/type.ha
@@ -5,28 +5,48 @@ use hare::lex;
use strio;
fn builtin_type(b: ast::builtin_type) str = switch (b) {
- ast::builtin_type::BOOL => "bool",
- ast::builtin_type::CHAR => "char",
- ast::builtin_type::F32 => "f32",
- ast::builtin_type::F64 => "f64",
- ast::builtin_type::FCONST => abort("FCONST has no lexical representation"),
- ast::builtin_type::I16 => "i16",
- ast::builtin_type::I32 => "i32",
- ast::builtin_type::I64 => "i64",
- ast::builtin_type::I8 => "i8",
- ast::builtin_type::ICONST => abort("ICONST has no lexical representation"),
- ast::builtin_type::INT => "int",
- ast::builtin_type::NULL => "null",
- ast::builtin_type::RUNE => "rune",
- ast::builtin_type::SIZE => "size",
- ast::builtin_type::STR => "str",
- ast::builtin_type::U16 => "u16",
- ast::builtin_type::U32 => "u32",
- ast::builtin_type::U64 => "u64",
- ast::builtin_type::U8 => "u8",
- ast::builtin_type::UINT => "uint",
- ast::builtin_type::UINTPTR => "uintptr",
- ast::builtin_type::VOID => "void",
+case ast::builtin_type::FCONST, ast::builtin_type::ICONST =>
+ abort("ICONST and FCONST have no lexical representation");
+case ast::builtin_type::BOOL =>
+ yield "bool";
+case ast::builtin_type::CHAR =>
+ yield "char";
+case ast::builtin_type::F32 =>
+ yield "f32";
+case ast::builtin_type::F64 =>
+ yield "f64";
+case ast::builtin_type::I16 =>
+ yield "i16";
+case ast::builtin_type::I32 =>
+ yield "i32";
+case ast::builtin_type::I64 =>
+ yield "i64";
+case ast::builtin_type::I8 =>
+ yield "i8";
+case ast::builtin_type::INT =>
+ yield "int";
+case ast::builtin_type::NULL =>
+ yield "null";
+case ast::builtin_type::RUNE =>
+ yield "rune";
+case ast::builtin_type::SIZE =>
+ yield "size";
+case ast::builtin_type::STR =>
+ yield "str";
+case ast::builtin_type::U16 =>
+ yield "u16";
+case ast::builtin_type::U32 =>
+ yield "u32";
+case ast::builtin_type::U64 =>
+ yield "u64";
+case ast::builtin_type::U8 =>
+ yield "u8";
+case ast::builtin_type::UINT =>
+ yield "uint";
+case ast::builtin_type::UINTPTR =>
+ yield "uintptr";
+case ast::builtin_type::VOID =>
+ yield "void";
};
fn prototype(
@@ -64,34 +84,34 @@ fn struct_union_type(
) (size | io::error) = {
let z = 0z;
let membs = match (t.repr) {
- st: ast::struct_type => {
- z += fmt::fprint(out, "struct {")?;
- yield st: []ast::struct_member;
- },
- ut: ast::union_type => {
- z += fmt::fprint(out, "union {")?;
- yield ut: []ast::struct_member;
- },
+ case st: ast::struct_type =>
+ z += fmt::fprint(out, "struct {")?;
+ yield st: []ast::struct_member;
+ case ut: ast::union_type =>
+ z += fmt::fprint(out, "union {")?;
+ yield ut: []ast::struct_member;
};
indent += 1z;
for (let i = 0z; i < len(membs); i += 1) {
z += newline(out, indent)?;
- z += match (membs[i]._offset) {
- null => 0z,
- ex: *ast::expr => fmt::fprint(out, "@offset(")?
- + expr(out, indent, *ex)?
- + fmt::fprint(out, ") ")?,
+ match (membs[i]._offset) {
+ case null => void;
+ case ex: *ast::expr =>
+ z += fmt::fprint(out, "@offset(")?;
+ z += expr(out, indent, *ex)?;
+ z += fmt::fprint(out, ") ")?;
};
- z += match (membs[i].member) {
- se: ast::struct_embedded => _type(out, indent, *se)?,
- sa: ast::struct_alias => ident(out, sa)?,
- sf: ast::struct_field => {
- yield fmt::fprintf(out, "{}: ", sf.name)?
- + _type(out, indent, *sf._type)?;
- },
+ match (membs[i].member) {
+ case se: ast::struct_embedded =>
+ z += _type(out, indent, *se)?;
+ case sa: ast::struct_alias =>
+ z += ident(out, sa)?;
+ case sf: ast::struct_field =>
+ z += fmt::fprintf(out, "{}: ", sf.name)?;
+ z += _type(out, indent, *sf._type)?;
};
z += fmt::fprint(out, ",")?;
@@ -118,85 +138,83 @@ export fn _type(
n += fmt::fprint(out, "!")?;
};
match (t.repr) {
- a: ast::alias_type => {
- if (a.unwrap) {
- n += fmt::fprint(out, "...")?;
- };
- n += ident(out, a.ident)?;
- },
- b: ast::builtin_type => n += fmt::fprint(out, builtin_type(b))?,
- e: ast::enum_type => {
- if (e.storage != ast::builtin_type::INT) {
- n += fmt::fprint(out, "enum",
- builtin_type(e.storage), "{")?;
- } else {
- n += fmt::fprint(out, "enum {")?;
- };
- indent += 1;
- for (let i = 0z; i < len(e.values); i += 1) {
- n += newline(out, indent)?;
- let value = e.values[i];
- n += fmt::fprint(out, value.name)?;
- match (value.value) {
- null => void,
- e: *ast::expr => {
- n += fmt::fprint(out, " = ")?;
- n += expr(out, indent, *e)?;
- },
- };
- n += fmt::fprint(out, ",")?;
- };
- indent -= 1;
+ case a: ast::alias_type =>
+ if (a.unwrap) {
+ n += fmt::fprint(out, "...")?;
+ };
+ n += ident(out, a.ident)?;
+ case b: ast::builtin_type =>
+ n += fmt::fprint(out, builtin_type(b))?;
+ case e: ast::enum_type =>
+ if (e.storage != ast::builtin_type::INT) {
+ n += fmt::fprint(out, "enum",
+ builtin_type(e.storage), "{")?;
+ } else {
+ n += fmt::fprint(out, "enum {")?;
+ };
+ indent += 1;
+ for (let i = 0z; i < len(e.values); i += 1) {
n += newline(out, indent)?;
- n += fmt::fprint(out, "}")?;
- },
- f: ast::func_type => {
- if (f.attrs & ast::func_attrs::NORETURN != 0) {
- n += fmt::fprint(out, "@noreturn ")?;
- };
- n += fmt::fprint(out, "fn")?;
- n += prototype(out, indent, f)?;
- },
- l: ast::list_type => {
- n += fmt::fprint(out, "[")?;
- n += match (l.length) {
- ast::len_slice => 0,
- ast::len_unbounded => fmt::fprint(out, "*")?,
- ast::len_contextual => fmt::fprint(out, "_")?,
- e: *ast::expr => expr(out, indent, *e)?,
- };
- n += fmt::fprint(out, "]")?;
- n += _type(out, indent, *l.members)?;
- },
- p: ast::pointer_type => {
- if (p.flags & ast::pointer_flags::NULLABLE != 0) {
- n += fmt::fprint(out, "nullable ")?;
+ let value = e.values[i];
+ n += fmt::fprint(out, value.name)?;
+ match (value.value) {
+ case null => void;
+ case e: *ast::expr =>
+ n += fmt::fprint(out, " = ")?;
+ n += expr(out, indent, *e)?;
};
+ n += fmt::fprint(out, ",")?;
+ };
+ indent -= 1;
+ n += newline(out, indent)?;
+ n += fmt::fprint(out, "}")?;
+ case f: ast::func_type =>
+ if (f.attrs & ast::func_attrs::NORETURN != 0) {
+ n += fmt::fprint(out, "@noreturn ")?;
+ };
+ n += fmt::fprint(out, "fn")?;
+ n += prototype(out, indent, f)?;
+ case l: ast::list_type =>
+ n += fmt::fprint(out, "[")?;
+ match (l.length) {
+ case ast::len_slice => void;
+ case ast::len_unbounded =>
n += fmt::fprint(out, "*")?;
- n += _type(out, indent, *p.referent)?;
- },
- ast::struct_type => n += struct_union_type(out, indent, t)?,
- ast::union_type => n += struct_union_type(out, indent, t)?,
- t: ast::tagged_type => {
- n += fmt::fprint(out, "(")?;
- for (let i = 0z; i < len(t); i += 1) {
- n += _type(out, indent, *t[i])?;
- if (i + 1 < len(t)) {
- n += fmt::fprint(out, " | ")?;
- };
+ case ast::len_contextual =>
+ n += fmt::fprint(out, "_")?;
+ case e: *ast::expr =>
+ n += expr(out, indent, *e)?;
+ };
+ n += fmt::fprint(out, "]")?;
+ n += _type(out, indent, *l.members)?;
+ case p: ast::pointer_type =>
+ if (p.flags & ast::pointer_flags::NULLABLE != 0) {
+ n += fmt::fprint(out, "nullable ")?;
+ };
+ n += fmt::fprint(out, "*")?;
+ n += _type(out, indent, *p.referent)?;
+ case ast::struct_type =>
+ n += struct_union_type(out, indent, t)?;
+ case ast::union_type =>
+ n += struct_union_type(out, indent, t)?;
+ case t: ast::tagged_type =>
+ n += fmt::fprint(out, "(")?;
+ for (let i = 0z; i < len(t); i += 1) {
+ n += _type(out, indent, *t[i])?;
+ if (i + 1 < len(t)) {
+ n += fmt::fprint(out, " | ")?;
};
- n += fmt::fprint(out, ")")?;
- },
- t: ast::tuple_type => {
- n += fmt::fprint(out, "(")?;
- for (let i = 0z; i < len(t); i += 1) {
- n += _type(out, indent, *t[i])?;
- if (i + 1 < len(t)) {
- n += fmt::fprint(out, ", ")?;
- };
+ };
+ n += fmt::fprint(out, ")")?;
+ case t: ast::tuple_type =>
+ n += fmt::fprint(out, "(")?;
+ for (let i = 0z; i < len(t); i += 1) {
+ n += _type(out, indent, *t[i])?;
+ if (i + 1 < len(t)) {
+ n += fmt::fprint(out, ", ")?;
};
- n += fmt::fprint(out, ")")?;
- },
+ };
+ n += fmt::fprint(out, ")")?;
};
return n;
};
diff --git a/io/+linux/file.ha b/io/+linux/file.ha
@@ -62,8 +62,10 @@ export fn fd(f: *file) int = f.fd;
export fn unwrapfd(s: *stream) (int | void) = {
for (!is_file(s)) {
s = match (io::source(s)) {
- errors::unsupported => return,
- s: *io::stream => s,
+ case errors::unsupported =>
+ return;
+ case s: *io::stream =>
+ yield s;
};
};
return fd(s: *file);
@@ -71,20 +73,26 @@ export fn unwrapfd(s: *stream) (int | void) = {
fn fd_read(s: *stream, buf: []u8) (size | EOF | error) = {
let stream = s: *file;
- return match (rt::read(stream.fd, buf: *[*]u8, len(buf))) {
- err: rt::errno => errors::errno(err),
- n: size => switch (n) {
- 0 => EOF,
- * => n,
- },
+ match (rt::read(stream.fd, buf: *[*]u8, len(buf))) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case n: size =>
+ switch (n) {
+ case 0 =>
+ return EOF;
+ case =>
+ return n;
+ };
};
};
fn fd_write(s: *stream, buf: const []u8) (size | error) = {
let stream = s: *file;
- return match (rt::write(stream.fd, buf: *const [*]u8, len(buf))) {
- err: rt::errno => errors::errno(err),
- n: size => n,
+ match (rt::write(stream.fd, buf: *const [*]u8, len(buf))) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case n: size =>
+ return n;
};
};
@@ -110,19 +118,23 @@ fn fd_copy(to: *stream, from: *stream) (size | error) = {
for (true) {
let n = match (rt::sendfile(to.fd, from.fd,
null, SENDFILE_MAX)) {
- err: rt::errno => switch (err) {
- rt::EINVAL => {
+ case err: rt::errno =>
+ switch (err) {
+ case rt::EINVAL =>
if (sum == 0) {
return errors::unsupported;
};
return errors::errno(err);
- },
- * => return errors::errno(err),
- },
- n: size => switch (n) {
- 0 => return sum,
- * => n,
- },
+ case =>
+ return errors::errno(err);
+ };
+ case n: size =>
+ yield switch (n) {
+ case 0 =>
+ break;
+ case =>
+ yield n;
+ };
};
sum += n;
};
@@ -135,8 +147,10 @@ fn fd_seek(
whence: whence,
) (off | error) = {
let stream = s: *file;
- return match (rt::lseek(stream.fd, off: i64, whence: uint)) {
- err: rt::errno => errors::errno(err),
- n: i64 => n: off,
+ match (rt::lseek(stream.fd, off: i64, whence: uint)) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case n: i64 =>
+ return n: off;
};
};
diff --git a/io/+test/copy.ha b/io/+test/copy.ha
@@ -35,12 +35,12 @@ fn strconv::ztos(z: size) str;
@test fn copy() void = {
let a = test_copier_open(), b = test_copier_open();
match (copy(&b, &a)) {
- n: size => {
- assert(n == 42);
- assert(a.r == 42);
- assert(b.w == 42);
- },
- error => abort(),
+ case n: size =>
+ assert(n == 42);
+ assert(a.r == 42);
+ assert(b.w == 42);
+ case error =>
+ abort();
};
close(&a: *stream);
close(&b: *stream);
@@ -50,11 +50,11 @@ fn strconv::ztos(z: size) str;
a.copier = &test_copier_copy;
b.copier = &test_copier_copy;
match (copy(&b, &a)) {
- n: size => {
- assert(n == 1337);
- assert(b.w == 62893);
- },
- error => abort(),
+ case n: size =>
+ assert(n == 1337);
+ assert(b.w == 62893);
+ case error =>
+ abort();
};
close(&a: *stream);
close(&b: *stream);
@@ -65,12 +65,12 @@ fn strconv::ztos(z: size) str;
a.copier = &test_copy_unsupported;
b.copier = &test_copy_unsupported;
match (copy(&b, &a)) {
- n: size => {
- assert(n == 42);
- assert(a.r == 42);
- assert(b.w == 42);
- },
- error => abort(),
+ case n: size =>
+ assert(n == 42);
+ assert(a.r == 42);
+ assert(b.w == 42);
+ case error =>
+ abort();
};
// Fallback (+short writes)
@@ -80,13 +80,13 @@ fn strconv::ztos(z: size) str;
b.copier = &test_copy_unsupported;
b.writer = &teststream_write_short;
match (copy(&b, &a)) {
- n: size => {
- assert(n == 42);
- assert(a.r == 42);
- assert(a.nreads == 1);
- assert(b.w == 42);
- assert(b.nwrites > 1);
- },
- error => abort(),
+ case n: size =>
+ assert(n == 42);
+ assert(a.r == 42);
+ assert(a.nreads == 1);
+ assert(b.w == 42);
+ assert(b.nwrites > 1);
+ case error =>
+ abort();
};
};
diff --git a/io/+test/limit.ha b/io/+test/limit.ha
@@ -6,29 +6,39 @@ use errors;
let rlimit = limitreader(&source, 20);
match (write(&rlimit, buf)) {
- errors::unsupported => void,
- * => abort(),
+ case errors::unsupported => void;
+ case =>
+ abort();
};
match (read(&rlimit, buf)) {
- n: size => assert(n == 15),
- error => abort(),
+ case n: size =>
+ assert(n == 15);
+ case error =>
+ abort();
};
match (read(&rlimit, buf)) {
- n: size => assert(n == 5),
- error => abort(),
+ case n: size =>
+ assert(n == 5);
+ case error =>
+ abort();
};
let wlimit = limitwriter(&source, 20);
match (read(&wlimit, buf)) {
- errors::unsupported => void,
- * => abort(),
+ case errors::unsupported => void;
+ case =>
+ abort();
};
match (write(&wlimit, buf)) {
- n: size => assert(n == 15),
- error => abort(),
+ case n: size =>
+ assert(n == 15);
+ case error =>
+ abort();
};
match (write(&wlimit, buf)) {
- n: size => assert(n == 5),
- error => abort(),
+ case n: size =>
+ assert(n == 5);
+ case error =>
+ abort();
};
};
diff --git a/io/copy.ha b/io/copy.ha
@@ -4,26 +4,32 @@ use errors;
// return if the source stream is infinite.
export fn copy(dest: *stream, src: *stream) (error | size) = {
match (dest.copier) {
- null => void,
- c: *copier => match (c(dest, src)) {
- err: error => match (err) {
- errors::unsupported => void, // Use fallback
- * => return err,
- },
- s: size => return s,
- },
+ case null => void;
+ case c: *copier =>
+ match (c(dest, src)) {
+ case err: error =>
+ match (err) {
+ case errors::unsupported => void; // Use fallback
+ case =>
+ return err;
+ };
+ case s: size =>
+ return s;
+ };
};
let w = 0z;
static let buf: [4096]u8 = [0...];
for (true) {
match (read(src, buf[..])?) {
- n: size => for (let i = 0z; i < n) {
+ case n: size =>
+ for (let i = 0z; i < n) {
let r = write(dest, buf[i..n])?;
w += r;
i += r;
- },
- EOF => break,
+ };
+ case EOF =>
+ break;
};
};
return w;
diff --git a/io/drain.ha b/io/drain.ha
@@ -4,8 +4,10 @@ export fn drain(in: *io::stream) ([]u8 | io::error) = {
static let buf: [4096]u8 = [0...];
for (true) {
match (read(in, buf[..])?) {
- n: size => append(sink, buf[..n]...),
- EOF => break,
+ case n: size =>
+ append(sink, buf[..n]...);
+ case EOF =>
+ break;
};
};
return sink;
diff --git a/io/stream.ha b/io/stream.ha
@@ -36,50 +36,61 @@ export type stream = struct {
// Reads up to len(buf) bytes from the reader into the given buffer, returning
// the number of bytes read.
export fn read(s: *stream, buf: []u8) (size | EOF | error) = {
- return match (s.reader) {
- null => errors::unsupported,
- r: *reader => r(s, buf),
+ match (s.reader) {
+ case null =>
+ return errors::unsupported;
+ case r: *reader =>
+ return r(s, buf);
};
};
// Writes up to len(buf) bytes to the stream from the given buffer, returning
// the number of bytes written.
export fn write(s: *stream, buf: const []u8) (size | error) = {
- return match (s.writer) {
- null => errors::unsupported,
- w: *writer => w(s, buf),
+ match (s.writer) {
+ case null =>
+ return errors::unsupported;
+ case w: *writer =>
+ return w(s, buf);
};
};
// Closes the stream.
export fn close(s: *stream) void = {
- return match (s.closer) {
- null => void,
- c: *closer => c(s),
+ match (s.closer) {
+ case null => void;
+ case c: *closer =>
+ c(s);
};
};
// Sets the offset within the stream.
export fn seek(s: *stream, off: off, w: whence) (off | error) = {
- return match (s.seeker) {
- null => errors::unsupported,
- sk: *seeker => sk(s, off, w),
+ match (s.seeker) {
+ case null =>
+ return errors::unsupported;
+ case sk: *seeker =>
+ return sk(s, off, w);
};
};
// Returns the current offset within the stream.
export fn tell(s: *stream) (off | error) = {
- return match (s.seeker) {
- null => errors::unsupported,
- sk: *seeker => sk(s, 0, whence::CUR),
+ match (s.seeker) {
+ case null =>
+ return errors::unsupported;
+ case sk: *seeker =>
+ return sk(s, 0, whence::CUR);
};
};
// Returns the underlying stream for a stream which wraps another stream.
export fn source(s: *stream) (*io::stream | errors::unsupported) = {
- return match (s.unwrap) {
- null => errors::unsupported,
- uw: *unwrap => uw(s),
+ match (s.unwrap) {
+ case null =>
+ return errors::unsupported;
+ case uw: *unwrap =>
+ return uw(s);
};
};
diff --git a/io/tee.ha b/io/tee.ha
@@ -19,10 +19,11 @@ export fn tee(source: *stream, sink: *stream) teestream = {
fn tee_read(s: *stream, buf: []u8) (size | EOF | error) = {
let s = s: *teestream;
- let z = match (read(s.source, buf)) {
- err: error => return err,
- EOF => return EOF,
- z: size => z,
+ let z = match (read(s.source, buf)?) {
+ case EOF =>
+ return EOF;
+ case z: size =>
+ yield z;
};
for (let n = 0z; n < z) {
n += write(s.sink, buf[n..z])?;
diff --git a/linux/io_uring/cqe.ha b/linux/io_uring/cqe.ha
@@ -13,12 +13,12 @@ export fn cqe_seen(ring: *io_uring, cqe: *cqe) void = cq_advance(ring, 1);
// Waits until a CQE is available, then returns it. The caller must pass the
// returned CQE to [[cqe_seen]] to advance the queue.
export fn wait(ring: *io_uring) (*cqe | error) = {
- return match (get_cqe(ring, 0, 1)) {
- err: error => err,
- cq: nullable *cqe => {
- assert(cq != null); // XXX: Correct?
- yield cq: *cqe;
- },
+ match (get_cqe(ring, 0, 1)) {
+ case err: error =>
+ return err;
+ case cq: nullable *cqe =>
+ assert(cq != null); // XXX: Correct?
+ return cq: *cqe;
};
};
@@ -82,9 +82,11 @@ fn get_cqe(
};
match (rt::io_uring_enter(ring.fd,
- submit, wait, flags: uint, null)) {
- err: rt::errno => return errors::errno(err),
- n: uint => submit -= n,
+ submit, wait, flags: uint, null)) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case n: uint =>
+ submit -= n;
};
};
return cq;
diff --git a/linux/io_uring/queue.ha b/linux/io_uring/queue.ha
@@ -18,9 +18,13 @@ export fn get_sqe(ring: *io_uring) nullable *sqe = {
// Returns the next available [[sqe]] for this [[io_uring]], or aborts the
// program if the queue is full.
-export fn must_get_sqe(ring: *io_uring) *sqe = match (get_sqe(ring)) {
- null => abort("I/O queue full"),
- sq: *sqe => sq,
+export fn must_get_sqe(ring: *io_uring) *sqe = {
+ match (get_sqe(ring)) {
+ case null =>
+ abort("I/O queue full");
+ case sq: *sqe =>
+ return sq;
+ };
};
fn needs_enter(ring: *io_uring, flags: *enter_flags) bool = {
@@ -79,10 +83,12 @@ fn do_submit(
) (uint | error) = {
let flags: enter_flags = enter_flags::GETEVENTS;
if (needs_enter(ring, &flags) || wait != 0) {
- return match (rt::io_uring_enter(ring.fd,
+ match (rt::io_uring_enter(ring.fd,
submitted, wait, flags, null)) {
- err: rt::errno => errors::errno(err),
- n: uint => n,
+ case err: rt::errno =>
+ return errors::errno(err);
+ case n: uint =>
+ return n;
};
} else {
return submitted;
diff --git a/linux/io_uring/register.ha b/linux/io_uring/register.ha
@@ -9,19 +9,21 @@ use types;
// rt::mmap).
export fn register_buffers(ring: *io_uring, iov: []rt::iovec) (void | error) = {
assert(len(iov) <= types::UINT_MAX);
- return match (rt::io_uring_register(ring.fd, regop::REGISTER_BUFFERS,
+ match (rt::io_uring_register(ring.fd, regop::REGISTER_BUFFERS,
iov: *[*]rt::iovec, len(iov): uint)) {
- err: rt::errno => errors::errno(err),
- int => void,
+ case err: rt::errno =>
+ return errors::errno(err);
+ case int => void;
};
};
// Unregisters all fixed buffers associated with an [[io_uring]].
export fn unregister_buffers(ring: *io_uring) (void | error) = {
- return match (rt::io_uring_register(ring.fd,
+ match (rt::io_uring_register(ring.fd,
regop::UNREGISTER_BUFFERS, null, 0)) {
- err: rt::errno => errors::errno(err),
- int => void,
+ case err: rt::errno =>
+ return errors::errno(err);
+ case int => void;
};
};
@@ -30,10 +32,11 @@ export fn unregister_buffers(ring: *io_uring) (void | error) = {
// [[register_files_update]].
export fn register_files(ring: *io_uring, files: []int) (void | error) = {
assert(len(files) <= types::UINT_MAX);
- return match (rt::io_uring_register(ring.fd, regop::REGISTER_FILES,
+ match (rt::io_uring_register(ring.fd, regop::REGISTER_FILES,
files: *[*]int, len(files): uint)) {
- err: rt::errno => errors::errno(err),
- int => void,
+ case err: rt::errno =>
+ return errors::errno(err);
+ case int => void;
};
};
@@ -44,48 +47,53 @@ export fn register_files_update(
updates: []files_update,
) (void | error) = {
assert(len(updates) <= types::UINT_MAX);
- return match (rt::io_uring_register(ring.fd, regop::REGISTER_FILES_UPDATE,
+ match (rt::io_uring_register(ring.fd, regop::REGISTER_FILES_UPDATE,
updates: *[*]files_update, len(updates): uint)) {
- err: rt::errno => errors::errno(err),
- int => void,
+ case err: rt::errno =>
+ return errors::errno(err);
+ case int => void;
};
};
// Unregisters all files associated with an [[io_uring]].
export fn unregister_files(ring: *io_uring) (void | error) = {
- return match (rt::io_uring_register(ring.fd,
+ match (rt::io_uring_register(ring.fd,
regop::UNREGISTER_FILES, null, 0)) {
- err: rt::errno => errors::errno(err),
- int => void,
+ case err: rt::errno =>
+ return errors::errno(err);
+ case int => void;
};
};
// Registers an eventfd(2) with this [[io_uring]] to be notified of completion
// events.
export fn register_eventfd(ring: *io_uring, fd: int) (void | error) = {
- return match (rt::io_uring_register(ring.fd,
+ match (rt::io_uring_register(ring.fd,
regop::REGISTER_EVENTFD, &fd, 1)) {
- err: rt::errno => errors::errno(err),
- int => void,
+ case err: rt::errno =>
+ return errors::errno(err);
+ case int => void;
};
};
// Similar to [[register_eventfd]], but only notifies of events which complet
// asyncronously.
export fn register_eventfd_async(ring: *io_uring, fd: int) (void | error) = {
- return match (rt::io_uring_register(ring.fd,
+ match (rt::io_uring_register(ring.fd,
regop::REGISTER_EVENTFD_ASYNC, &fd, 1)) {
- err: rt::errno => errors::errno(err),
- int => void,
+ case err: rt::errno =>
+ return errors::errno(err);
+ case int => void;
};
};
// Unregisters the eventfd(2) associated with this [[io_uring]].
export fn unregister_eventfd(ring: *io_uring) (void | error) = {
- return match (rt::io_uring_register(ring.fd,
+ match (rt::io_uring_register(ring.fd,
regop::UNREGISTER_EVENTFD, null, 0)) {
- err: rt::errno => errors::errno(err),
- int => void,
+ case err: rt::errno =>
+ return errors::errno(err);
+ case int => void;
};
};
@@ -104,20 +112,23 @@ export fn unregister_eventfd(ring: *io_uring) (void | error) = {
// [[io_uring]], returning an ID. Set the personality field of an [[sqe]] to use
// that personality for an I/O submission.
export fn register_personality(ring: *io_uring) int = {
- return match (rt::io_uring_register(ring.fd,
+ match (rt::io_uring_register(ring.fd,
regop::REGISTER_PERSONALITY, null, 0)) {
- rt::errno => abort("Unexpected io_uring REGISTER_PERSONALITY error"),
- i: int => i,
+ case rt::errno =>
+ abort("Unexpected io_uring REGISTER_PERSONALITY error");
+ case i: int =>
+ return i;
};
};
// Unregisters a personality previously configured with
// [[register_personality]].
export fn unregister_personality(ring: *io_uring, id: int) (void | error) = {
- return match (rt::io_uring_register(ring.fd,
+ match (rt::io_uring_register(ring.fd,
regop::UNREGISTER_PERSONALITY, null, id: uint)) {
- err: rt::errno => errors::errno(err),
- int => void,
+ case err: rt::errno =>
+ return errors::errno(err);
+ case int => void;
};
};
@@ -125,10 +136,11 @@ export fn unregister_personality(ring: *io_uring, id: int) (void | error) = {
// state via [[setup_flags::R_DISABLED]]. Future access to this io_uring is
// subject to any configured restrictions.
export fn register_enable_rings(ring: *io_uring) (void | error) = {
- return match (rt::io_uring_register(ring.fd,
+ match (rt::io_uring_register(ring.fd,
regop::REGISTER_ENABLE_RINGS, null, 0)) {
- err: rt::errno => errors::errno(err),
- int => void,
+ case err: rt::errno =>
+ return errors::errno(err);
+ case int => void;
};
};
@@ -138,9 +150,10 @@ export fn register_enable_rings(ring: *io_uring) (void | error) = {
// [[setup_flags::R_DISABLED]].
export fn register_restrictions(ring: *io_uring, res: []restriction) (void | error) = {
assert(len(res) < types::UINT_MAX);
- return match (rt::io_uring_register(ring.fd, regop::REGISTER_RESTRICTIONS,
+ match (rt::io_uring_register(ring.fd, regop::REGISTER_RESTRICTIONS,
res: *[*]restriction, len(res): uint)) {
- err: rt::errno => errors::errno(err),
- int => void,
+ case err: rt::errno =>
+ return errors::errno(err);
+ case int => void;
};
};
diff --git a/linux/io_uring/setup.ha b/linux/io_uring/setup.ha
@@ -6,8 +6,10 @@ use rt;
// fields are initialized by the kernel.
export fn setup(entries: u32, params: *params) (io_uring | error) = {
const fd = match (rt::io_uring_setup(entries, params)) {
- err: rt::errno => return errors::errno(err),
- fd: int => fd,
+ case err: rt::errno =>
+ return errors::errno(err);
+ case fd: int =>
+ yield fd;
};
let uring = io_uring {
@@ -34,8 +36,10 @@ export fn setup(entries: u32, params: *params) (io_uring | error) = {
rt::PROT_READ | rt::PROT_WRITE,
rt::MAP_SHARED | rt::MAP_POPULATE,
fd, OFF_SQ_RING)) {
- err: rt::errno => return errors::errno(err),
- ptr: *void => ptr,
+ case err: rt::errno =>
+ return errors::errno(err);
+ case ptr: *void =>
+ yield ptr;
};
cq.ring_ptr = if (uring.features & features::SINGLE_MMAP == features::SINGLE_MMAP) {
@@ -44,8 +48,10 @@ export fn setup(entries: u32, params: *params) (io_uring | error) = {
rt::PROT_READ | rt::PROT_WRITE,
rt::MAP_SHARED | rt::MAP_POPULATE,
fd, OFF_CQ_RING)) {
- err: rt::errno => return errors::errno(err),
- ptr: *void => ptr,
+ case err: rt::errno =>
+ return errors::errno(err);
+ case ptr: *void =>
+ yield ptr;
};
const ring_ptr = sq.ring_ptr: uintptr;
@@ -61,8 +67,10 @@ export fn setup(entries: u32, params: *params) (io_uring | error) = {
rt::PROT_READ | rt::PROT_WRITE,
rt::MAP_SHARED | rt::MAP_POPULATE,
fd, OFF_SQES)) {
- err: rt::errno => return errors::errno(err),
- ptr: *void => ptr: *[*]sqe,
+ case err: rt::errno =>
+ return errors::errno(err);
+ case ptr: *void =>
+ yield ptr: *[*]sqe;
};
const ring_ptr = cq.ring_ptr: uintptr;
diff --git a/linux/signalfd/signalfd.ha b/linux/signalfd/signalfd.ha
@@ -36,20 +36,22 @@ export fn signalfd(
mask: *const rt::sigset,
flags: int,
) (int | errors::error) = {
- return match (rt::signalfd(fd, mask, flags)) {
- fd: int => fd,
- err: rt::errno => errors::errno(err),
+ match (rt::signalfd(fd, mask, flags)) {
+ case fd: int =>
+ return fd;
+ case err: rt::errno =>
+ return errors::errno(err);
};
};
// Reads pending signal info from a signalfd.
export fn readsignal(fd: int) (siginfo | errors::error) = {
let si = siginfo { ... };
- return match (rt::read(fd, &si, size(siginfo))) {
- err: rt::errno => errors::errno(err),
- z: size => {
- assert(z == size(siginfo));
- return si;
- },
+ match (rt::read(fd, &si, size(siginfo))) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case z: size =>
+ assert(z == size(siginfo));
+ return si;
};
};
diff --git a/linux/vdso/vdso.ha b/linux/vdso/vdso.ha
@@ -39,8 +39,10 @@ fn get_vdso_ctx() nullable *vdso_ctx = {
vdso_checked = true;
const eh = match (sys_infoehdr()) {
- null => return null,
- x: *elf::header64 => x,
+ case null =>
+ return null;
+ case x: *elf::header64 =>
+ yield x;
};
const ehui = eh: uintptr;
@@ -51,13 +53,13 @@ fn get_vdso_ctx() nullable *vdso_ctx = {
for (let i: u16 = 0; i < eh.e_phnum; i += 1) {
const ph = phui: *elf::phdr64;
switch (ph.p_type) {
- elf::pt::LOAD =>
- baseseg = ehui +
- ph.p_offset: uintptr -
- ph.p_vaddr: uintptr,
- elf::pt::DYNAMIC =>
- dynvec = ehui + ph.p_offset: uintptr,
- * => void,
+ case elf::pt::LOAD =>
+ baseseg = ehui +
+ ph.p_offset: uintptr -
+ ph.p_vaddr: uintptr;
+ case elf::pt::DYNAMIC =>
+ dynvec = ehui + ph.p_offset: uintptr;
+ case => void;
};
phui += eh.e_phentsize: uintptr;
};
@@ -77,12 +79,18 @@ fn get_vdso_ctx() nullable *vdso_ctx = {
for (let i = 0; dynv[i].d_tag != elf::dt::NULL; i += 1) {
const tabptr = (segbase + dynv[i].d_val: uintptr): *void;
switch (dynv[i].d_tag) {
- elf::dt::STRTAB => stringtab = tabptr: *char,
- elf::dt::SYMTAB => symtab = tabptr: *[*]elf::sym64,
- elf::dt::HASH => hashhdr = tabptr: *elf::hashhdr,
- elf::dt::VERSYM => versym = tabptr: *[*]u16,
- elf::dt::VERDEF => verdef = tabptr: *elf::verdef64,
- * => continue,
+ case elf::dt::STRTAB =>
+ stringtab = tabptr: *char;
+ case elf::dt::SYMTAB =>
+ symtab = tabptr: *[*]elf::sym64;
+ case elf::dt::HASH =>
+ hashhdr = tabptr: *elf::hashhdr;
+ case elf::dt::VERSYM =>
+ versym = tabptr: *[*]u16;
+ case elf::dt::VERDEF =>
+ verdef = tabptr: *elf::verdef64;
+ case =>
+ continue;
};
};
@@ -111,12 +119,16 @@ fn get_vdso_ctx() nullable *vdso_ctx = {
fn vdso_checkver(ctx: *vdso_ctx, version: str, num: u32) bool = {
let prev = null: *elf::verdef64;
let cur = match (ctx.verdef) {
- null => return true,
- vd: *elf::verdef64 => vd,
+ case null =>
+ return true;
+ case vd: *elf::verdef64 =>
+ yield vd;
};
const versym = match (ctx.versym) {
- null => return true,
- vs: *[*]u16 => vs[num] & 0x7fff
+ case null =>
+ return true;
+ case vs: *[*]u16 =>
+ yield vs[num] & 0x7ff;
};
for (cur != prev) {
if (cur.vd_flags & elf::ver_flg::BASE: u16 == 0 &&
@@ -135,8 +147,10 @@ fn vdso_checkver(ctx: *vdso_ctx, version: str, num: u32) bool = {
export fn getsym(symname: str, symver: str) nullable *void = {
const ctx = match (get_vdso_ctx()) {
- null => return null,
- x: *vdso_ctx => x,
+ case null =>
+ return null;
+ case x: *vdso_ctx =>
+ yield x;
};
const sym_types = (1 << elf::stt::NOTYPE |
diff --git a/math/floats.ha b/math/floats.ha
@@ -187,9 +187,11 @@ export fn isneginf(n: f64) bool = {
// Returns true if the given floating-point number is normal.
export fn isnormal(n: types::floating) bool = {
- return match (n) {
- n: f32 => isnormalf32(n),
- n: f64 => isnormalf64(n),
+ match (n) {
+ case n: f32 =>
+ return isnormalf32(n);
+ case n: f64 =>
+ return isnormalf64(n);
};
};
@@ -211,9 +213,11 @@ export fn isnormalf32(n: f32) bool = {
// Returns true if the given floating-point number is subnormal.
export fn issubnormal(n: types::floating) bool = {
- return match (n) {
- n: f32 => issubnormalf32(n),
- n: f64 => issubnormalf64(n),
+ match (n) {
+ case n: f32 =>
+ return issubnormalf32(n);
+ case n: f64 =>
+ return issubnormalf64(n);
};
};
@@ -295,9 +299,11 @@ export fn absf32(n: f32) f32 = {
// Returns the absolute value of floating-point number n.
export fn absf(n: types::floating) f64 = {
- return match (n) {
- n: f64 => absf64(n),
- n: f32 => (absf32(n): f64),
+ match (n) {
+ case n: f64 =>
+ return absf64(n);
+ case n: f32 =>
+ return (absf32(n): f64);
};
};
@@ -338,9 +344,11 @@ export fn signf32(x: f32) i64 = {
// Returns 1 if x is positive and -1 if x is negative. Note that zero is also
// signed.
export fn signf(x: types::floating) i64 = {
- return match (x) {
- n: f64 => signf64(n),
- n: f32 => signf32(n),
+ match (x) {
+ case n: f64 =>
+ return signf64(n);
+ case n: f32 =>
+ return signf32(n);
};
};
@@ -368,9 +376,11 @@ export fn ispositivef32(x: f32) bool = signf32(x) == 1i32;
// Returns whether or not x is positive.
export fn ispositive(x: types::floating) bool = {
- return match (x) {
- n: f64 => ispositivef64(n),
- n: f32 => ispositivef32(n),
+ match (x) {
+ case n: f64 =>
+ return ispositivef64(n);
+ case n: f32 =>
+ return ispositivef32(n);
};
};
@@ -382,9 +392,11 @@ export fn isnegativef32(x: f32) bool = signf32(x) == -1i32;
// Returns whether or not x is negative.
export fn isnegative(x: types::floating) bool = {
- return match (x) {
- n: f64 => isnegativef64(n),
- n: f32 => isnegativef32(n),
+ match (x) {
+ case n: f64 =>
+ return isnegativef64(n);
+ case n: f32 =>
+ return isnegativef32(n);
};
};
@@ -402,9 +414,11 @@ export fn copysignf32(x: f32, y: f32) f32 = {
// Returns x, but with the sign of y.
export fn copysign(x: types::floating, y: types::floating) f64 = {
- return match (x) {
- n: f64 => copysignf64(n, (y: f64)),
- n: f32 => (copysignf32(n, (y: f32)): f64),
+ match (x) {
+ case n: f64 =>
+ return copysignf64(n, (y: f64));
+ case n: f32 =>
+ return (copysignf32(n, (y: f32)): f64);
};
};
@@ -492,9 +506,11 @@ export fn frexpf32(n: f32) (f64, i64) = {
// Breaks a float down into its mantissa and exponent. The mantissa will be
// between 0.5 and 1.
export fn frexp(n: types::floating) (f64, i64) = {
- return match (n) {
- n: f64 => frexpf64(n),
- n: f32 => frexpf32(n),
+ match (n) {
+ case n: f64 =>
+ return frexpf64(n);
+ case n: f32 =>
+ return frexpf32(n);
};
};
diff --git a/math/ints.ha b/math/ints.ha
@@ -38,11 +38,15 @@ export fn absi64(n: i64) i64 = {
// Returns the absolute value of signed integer n.
export fn absi(n: types::integer) i64 = {
- return match (n) {
- n: i8 => (absi8(n): i64),
- n: i16 => (absi16(n): i64),
- n: i32 => (absi32(n): i64),
- n: i64 => (absi64(n): i64),
+ match (n) {
+ case n: i8 =>
+ return (absi8(n): i64);
+ case n: i16 =>
+ return (absi16(n): i64);
+ case n: i32 =>
+ return (absi32(n): i64);
+ case n: i64 =>
+ return (absi64(n): i64);
};
};
@@ -111,11 +115,15 @@ export fn signi64(n: i64) i64 = {
// Return 1 if n is positive, -1 if it's negative and 0 if it's 0.
export fn signi(n: types::integer) i64 = {
- return match (n) {
- n: i8 => (signi8(n): i64),
- n: i16 => (signi16(n): i64),
- n: i32 => (signi32(n): i64),
- n: i64 => (signi64(n): i64),
+ match (n) {
+ case n: i8 =>
+ return (signi8(n): i64);
+ case n: i16 =>
+ return (signi16(n): i64);
+ case n: i32 =>
+ return (signi32(n): i64);
+ case n: i64 =>
+ return (signi64(n): i64);
};
};
diff --git a/math/math.ha b/math/math.ha
@@ -70,9 +70,11 @@ export fn eqwithinf32(x: f32, y: f32, tol: f32) bool = {
// Returns whether x and y are within tol of each other.
export fn eqwithin(x: types::floating, y: types::floating,
tol: types::floating) bool = {
- return match (x) {
- n: f64 => eqwithinf64(n, y as f64, tol as f64),
- n: f32 => eqwithinf32(n, y as f32, tol as f32),
+ match (x) {
+ case n: f64 =>
+ return eqwithinf64(n, y as f64, tol as f64);
+ case n: f32 =>
+ return eqwithinf32(n, y as f32, tol as f32);
};
};
@@ -88,9 +90,11 @@ export fn isclosef32(x: f32, y: f32) bool = {
// Returns whether x and y are within [[STANDARD_TOL]] of each other.
export fn isclose(x: types::floating, y: types::floating) bool = {
- return match (x) {
- n: f64 => isclosef64(n, y as f64),
- n: f32 => isclosef32(n, y as f32),
+ match (x) {
+ case n: f64 =>
+ return isclosef64(n, y as f64);
+ case n: f32 =>
+ return isclosef32(n, y as f32);
};
};
diff --git a/net/+linux.ha b/net/+linux.ha
@@ -25,8 +25,10 @@ export fn stream_accept(l: *listener) (io::file | error) = {
let sn = rt::sockaddr {...};
const sz = size(rt::sockaddr): u32;
const fd = match (rt::accept(l.fd, &sn, &sz)) {
- err: rt::errno => return errors::errno(err),
- fd: int => fd,
+ case err: rt::errno =>
+ return errors::errno(err);
+ case fd: int =>
+ yield fd;
};
static let namebuf: [32]u8 = [0...];
diff --git a/net/dial/ip.ha b/net/dial/ip.ha
@@ -11,10 +11,12 @@ fn dial_tcp(addr: str, service: str) (io::file | error) = {
for (let i = 0z; i < len(addrs); i += 1) {
const addr = addrs[i];
match (tcp::connect(addr, port)) {
- conn: io::file => return conn,
- err: net::error => if (i + 1 >= len(addrs)) {
+ case conn: io::file =>
+ return conn;
+ case err: net::error =>
+ if (i + 1 >= len(addrs)) {
return err;
- },
+ };
};
};
abort(); // Unreachable
@@ -26,10 +28,12 @@ fn dial_udp(addr: str, service: str) (io::file | error) = {
for (let i = 0z; i < len(addrs); i += 1) {
const addr = addrs[i];
match (udp::connect(addr, port)) {
- sock: io::file => return sock,
- err: net::error => if (i + 1 >= len(addrs)) {
+ case sock: io::file =>
+ return sock;
+ case err: net::error =>
+ if (i + 1 >= len(addrs)) {
return err;
- },
+ };
};
};
abort(); // Unreachable
diff --git a/net/dial/registry.ha b/net/dial/registry.ha
@@ -17,11 +17,15 @@ export type error = !(invalid_address | unknown_service | net::error | dns::erro
// Converts an [[error]] to a human-readable string.
export fn strerror(err: error) const str = {
// TODO: These could be better
- return match (err) {
- invalid_address => "Attempted to dial an invalid address",
- unknown_service => "Unknown service",
- err: net::error => net::strerror(err),
- err: dns::error => dns::strerror(err),
+ match (err) {
+ case invalid_address =>
+ return "Attempted to dial an invalid address";
+ case unknown_service =>
+ return "Unknown service";
+ case err: net::error =>
+ return net::strerror(err);
+ case err: dns::error =>
+ return dns::strerror(err);
};
};
diff --git a/net/dial/resolve.ha b/net/dial/resolve.ha
@@ -16,18 +16,22 @@ export fn resolve(
service: str,
) (([]ip::addr, u16) | error) = {
let port = match (strings::index(addr, ':')) {
- void => match (strconv::stou16(service)) {
- u: u16 => u,
- * => 0u16,
- },
- i: size => {
- const sub = strings::sub(addr, i + 1, strings::end);
- addr = strings::sub(addr, 0, i);
- yield match (strconv::stou16(sub)) {
- u: u16 => u,
- * => return invalid_address,
- };
- },
+ case void =>
+ yield match (strconv::stou16(service)) {
+ case u: u16 =>
+ yield u;
+ case =>
+ yield 0u16;
+ };
+ case i: size =>
+ const sub = strings::sub(addr, i + 1, strings::end);
+ addr = strings::sub(addr, 0, i);
+ yield match (strconv::stou16(sub)) {
+ case u: u16 =>
+ yield u;
+ case =>
+ return invalid_address;
+ };
};
if (service == "unknown" && port == 0) {
return unknown_service;
@@ -35,8 +39,9 @@ export fn resolve(
let addrs = resolve_addr(addr)?;
if (port == 0) match (lookup_service(proto, service)) {
- p: u16 => port = p,
- void => void,
+ case p: u16 =>
+ port = p;
+ case void => void;
};
// TODO:
@@ -55,13 +60,12 @@ export fn resolve(
fn resolve_addr(addr: str) ([]ip::addr | error) = {
match (ip::parse(addr)) {
- addr: ip::addr => {
- // XXX: harec bug prevents just alloc'ing this
- let addrs: []ip::addr = [];
- append(addrs, addr);
- return addrs;
- },
- ip::invalid => void,
+ case addr: ip::addr =>
+ // XXX: harec bug prevents just alloc'ing this
+ let addrs: []ip::addr = [];
+ append(addrs, addr);
+ return addrs;
+ case ip::invalid => void;
};
const addrs = hosts::lookup(addr);
@@ -133,11 +137,12 @@ fn resolve_addr(addr: str) ([]ip::addr | error) = {
fn collect_answers(addrs: *[]ip::addr, answers: *[]dns::rrecord) void = {
for (let i = 0z; i < len(answers); i += 1) {
match (answers[i].rdata) {
- // XXX: harec bug prevents us from casting directly to
- // ip::addr
- addr: dns::aaaa => append(addrs, addr: ip::addr6: ip::addr),
- addr: dns::a => append(addrs, addr: ip::addr4: ip::addr),
- * => void,
+ // XXX: harec bug prevents us from casting directly to ip::addr
+ case addr: dns::aaaa =>
+ append(addrs, addr: ip::addr6: ip::addr);
+ case addr: dns::a =>
+ append(addrs, addr: ip::addr4: ip::addr);
+ case => void;
};
};
};
diff --git a/net/dns/decode.ha b/net/dns/decode.ha
@@ -145,16 +145,19 @@ fn decode_rrecord(dec: *decoder) (rrecord | format) = {
};
fn decode_rdata(dec: *decoder, rtype: rtype, rlen: size) (rdata | format) = {
- return switch (rtype) {
- rtype::A => decode_a(dec),
- rtype::AAAA => decode_aaaa(dec),
- rtype::MX => decode_mx(dec),
- rtype::TXT => decode_txt(dec),
- * => {
- let buf = dec.cur[..rlen];
- dec.cur = dec.cur[rlen..];
- return buf: unknown_rdata;
- },
+ switch (rtype) {
+ case rtype::A =>
+ return decode_a(dec);
+ case rtype::AAAA =>
+ return decode_aaaa(dec);
+ case rtype::MX =>
+ return decode_mx(dec);
+ case rtype::TXT =>
+ return decode_txt(dec);
+ case =>
+ let buf = dec.cur[..rlen];
+ dec.cur = dec.cur[rlen..];
+ return buf: unknown_rdata;
};
};
diff --git a/net/dns/error.ha b/net/dns/error.ha
@@ -30,27 +30,42 @@ export type error = !(format | server_failure | name_error
export fn strerror(err: error) const str = {
static let buf: [64]u8 = [0...];
- return match (err) {
- format => "The DNS message was poorly formatted",
- server_failure => "The name server was unable to process this query due to a problem with the name server",
- name_error => "The domain name referenced in the query does not exist",
- not_implemented => "The name server does not support the requested kind of query",
- refused => "The name server refuses to perform the specified operation for policy reasons",
- ue: unknown_error => fmt::bsprintf(buf, "Unknown DNS error {}", ue: u8),
- errors::overflow => "The encoded message would exceed the buffer size",
- errors::timeout => "The DNS request timed out",
- err: net::error => net::strerror(err),
+ match (err) {
+ case format =>
+ return "The DNS message was poorly formatted";
+ case server_failure =>
+ return "The name server was unable to process this query due to a problem with the name server";
+ case name_error =>
+ return "The domain name referenced in the query does not exist";
+ case not_implemented =>
+ return "The name server does not support the requested kind of query";
+ case refused =>
+ return "The name server refuses to perform the specified operation for policy reasons";
+ case ue: unknown_error =>
+ return fmt::bsprintf(buf, "Unknown DNS error {}", ue: u8);
+ case errors::overflow =>
+ return "The encoded message would exceed the buffer size";
+ case errors::timeout =>
+ return "The DNS request timed out";
+ case err: net::error =>
+ return net::strerror(err);
};
};
fn check_rcode(rcode: rcode) (void | error) = {
- return switch (rcode) {
- rcode::NO_ERROR => void,
- rcode::FMT_ERROR => format,
- rcode::SERVER_FAILURE => server_failure,
- rcode::NAME_ERROR => name_error,
- rcode::NOT_IMPLEMENTED => not_implemented,
- rcode::REFUSED => refused,
- * => rcode: unknown_error,
+ switch (rcode) {
+ case rcode::NO_ERROR => void;
+ case rcode::FMT_ERROR =>
+ return format;
+ case rcode::SERVER_FAILURE =>
+ return server_failure;
+ case rcode::NAME_ERROR =>
+ return name_error;
+ case rcode::NOT_IMPLEMENTED =>
+ return not_implemented;
+ case rcode::REFUSED =>
+ return refused;
+ case =>
+ return rcode: unknown_error;
};
};
diff --git a/net/dns/query.ha b/net/dns/query.ha
@@ -49,12 +49,10 @@ export fn query(query: *message, servers: ip::addr...) (*message | error) = {
// We send requests in parallel to all configured servers and take the
// first one which sends us a reasonable answer.
for (let i = 0z; i < len(servers); i += 1) match (servers[i]) {
- ip::addr4 => {
- udp::sendto(&socket4, sendbuf[..z], servers[i], 53)?;
- },
- ip::addr6 => {
- udp::sendto(&socket6, sendbuf[..z], servers[i], 53)?;
- },
+ case ip::addr4 =>
+ udp::sendto(&socket4, sendbuf[..z], servers[i], 53)?;
+ case ip::addr6 =>
+ udp::sendto(&socket6, sendbuf[..z], servers[i], 53)?;
};
let header = header { ... };
diff --git a/net/dns/types.ha b/net/dns/types.ha
@@ -194,8 +194,10 @@ fn bytes_free(in: [][]u8) void = {
fn rrecord_finish(rr: *rrecord) void = {
strings_free(rr.name);
match (rr.rdata) {
- mx: mx => strings_free(mx.name),
- tx: txt => bytes_free(tx: [][]u8),
- * => void,
+ case mx: mx =>
+ strings_free(mx.name);
+ case tx: txt =>
+ bytes_free(tx: [][]u8);
+ case => void;
};
};
diff --git a/net/errors.ha b/net/errors.ha
@@ -8,9 +8,11 @@ export type error = !(unknownproto | ...errors::error);
// Converts a [[net::error]] into a human-readable string.
export fn strerror(err: error) const str = {
- return match (err) {
- unknownproto => "Unsupported protocol",
- err: errors::error => errors::strerror(err),
+ match (err) {
+ case unknownproto =>
+ return "Unsupported protocol";
+ case err: errors::error =>
+ return errors::strerror(err);
};
};
diff --git a/net/ip/+linux.ha b/net/ip/+linux.ha
@@ -2,35 +2,38 @@ use rt;
use endian;
export fn to_native(a: addr, port: u16) rt::sockaddr = {
- return match (a) {
- v4: addr4 => rt::sockaddr { in = rt::sockaddr_in {
+ match (a) {
+ case v4: addr4 =>
+ return rt::sockaddr { in = rt::sockaddr_in {
sin_family = rt::AF_INET,
sin_port = endian::htonu16(port),
sin_addr = rt::in_addr { s_addr = *(&v4[0]: *void: *u32) },
- } },
- v6: addr6 => rt::sockaddr { in6 = rt::sockaddr_in6 {
+ } };
+ case v6: addr6 =>
+ return rt::sockaddr { in6 = rt::sockaddr_in6 {
sin6_family = rt::AF_INET6,
sin6_port = endian::htonu16(port),
sin6_addr = rt::in6_addr { s6_addr = v6 },
- } },
+ } };
};
};
export fn from_native(a: rt::sockaddr) (addr, u16) = {
let family = a.in.sin_family;
switch (family) {
- rt::AF_INET => {
- let addr = a.in.sin_addr.s_addr;
- return (
- [addr: u8, (addr >> 8): u8, (addr >> 16): u8,
- (addr >> 24): u8]: addr4,
- endian::ntohu16(a.in.sin_port)
- );
- },
- rt::AF_INET6 => return (
+ case rt::AF_INET =>
+ let addr = a.in.sin_addr.s_addr;
+ return (
+ [addr: u8, (addr >> 8): u8, (addr >> 16): u8,
+ (addr >> 24): u8]: addr4,
+ endian::ntohu16(a.in.sin_port)
+ );
+ case rt::AF_INET6 =>
+ return (
a.in6.sin6_addr.s6_addr: addr6,
endian::ntohu16(a.in6.sin6_port)
- ),
- * => abort("Wrong address family!"),
+ );
+ case =>
+ abort("Wrong address family!");
};
};
diff --git a/net/ip/+test.ha b/net/ip/+test.ha
@@ -59,8 +59,10 @@ fn ip_test(s: str, expected: (addr|invalid)) void = {
fn subnet_test_simple(s: str) void = {
let net = match (parsecidr(s)) {
- a: subnet => a,
- * => return,
+ case a: subnet =>
+ yield a;
+ case =>
+ return;
};
let fmted = string(net);
assert(fmted == s);
diff --git a/net/ip/ip.ha b/net/ip/ip.ha
@@ -34,21 +34,19 @@ export type invalid = !void;
// Test if two [[addr]]s are equal.
export fn equal(l: addr, r: addr) bool = {
- return match (l) {
- l: addr4 => {
- if (!(r is addr4)) {
- return false;
- };
- let r = r as addr4;
- yield bytes::equal(l, r);
- },
- l: addr6 => {
- if (!(r is addr6)) {
- return false;
- };
- let r = r as addr6;
- yield bytes::equal(l, r);
- },
+ match (l) {
+ case l: addr4 =>
+ if (!(r is addr4)) {
+ return false;
+ };
+ let r = r as addr4;
+ return bytes::equal(l, r);
+ case l: addr6 =>
+ if (!(r is addr6)) {
+ return false;
+ };
+ let r = r as addr6;
+ return bytes::equal(l, r);
};
};
@@ -62,8 +60,10 @@ fn parsev4(st: str) (addr4 | invalid) = {
return invalid;
};
ret[i] = match (strconv::stou8(s)) {
- term: u8 => term,
- * => return invalid
+ case term: u8 =>
+ yield term;
+ case =>
+ return invalid;
};
};
if (i < 4 || !(strings::next_token(&tok) is void)) {
@@ -89,8 +89,10 @@ fn parsev6(st: str) (addr6 | invalid) = {
let i = 0;
for (i < 16) {
let s = match (strings::next_token(&tok)) {
- s: str => s,
- void => break,
+ case s: str =>
+ yield s;
+ case void =>
+ break;
};
if (s == "") {
if (ells != -1) {
@@ -137,12 +139,14 @@ fn parsev6(st: str) (addr6 | invalid) = {
// Parses an IP address.
export fn parse(s: str) (addr | invalid) = {
match (parsev4(s)) {
- v4: addr4 => return v4,
- invalid => void,
+ case v4: addr4 =>
+ return v4;
+ case invalid => void;
};
match (parsev6(s)) {
- v6: addr6 => return v6,
- invalid => void,
+ case v6: addr6 =>
+ return v6;
+ case invalid => void;
};
return invalid;
};
@@ -214,8 +218,10 @@ fn fillmask(mask: []u8, val: u8) void = {
// Returns an addr representing a netmask
fn cidrmask(addr: addr, val: u8) (addr | invalid) = {
let a_len: u8 = match (addr) {
- addr4 => 4,
- addr6 => 16,
+ case addr4 =>
+ yield 4;
+ case addr6 =>
+ yield 16;
};
if (val > 8 * a_len)
@@ -240,8 +246,10 @@ export fn parsecidr(st: str) (subnet | invalid) = {
let addr = parse(ips)?;
let masks = wanttoken(&tok)?;
let val = match (strconv::stou8(masks)) {
- x: u8 => x,
- * => return invalid,
+ case x: u8 =>
+ yield x;
+ case =>
+ return invalid;
};
if (!(strings::next_token(&tok) is void)) {
return invalid;
@@ -278,19 +286,21 @@ fn masklen(addr: []u8) (void | size) = {
fn fmtmask(s: *io::stream, mask: addr) (io::error | size) = {
let ret = 0z;
let slice = match (mask) {
- v4: addr4 => v4[..],
- v6: addr6 => v6[..],
+ case v4: addr4 =>
+ yield v4[..];
+ case v6: addr6 =>
+ yield v6[..];
};
match (masklen(slice)) {
- // format as hex, if zero runs are not contiguous
+ case void =>
+ // Format as hex, if zero runs are not contiguous
// (like golang does)
- void => {
- for (let i = 0z; i < len(slice); i += 1) {
- ret += fmt::fprintf(s, "{:x}", slice[i])?;
- };
- },
- // standard CIDR integer
- n: size => ret += fmt::fprintf(s, "{}", n)?,
+ for (let i = 0z; i < len(slice); i += 1) {
+ ret += fmt::fprintf(s, "{:x}", slice[i])?;
+ };
+ case n: size =>
+ // Standard CIDR integer
+ ret += fmt::fprintf(s, "{}", n)?;
};
return ret;
};
@@ -305,10 +315,13 @@ fn fmtsubnet(s: *io::stream, subnet: subnet) (io::error | size) = {
// Formats an [[addr]] or [[subnet]] and prints it to a stream.
export fn fmt(s: *io::stream, item: (...addr | subnet)) (io::error | size) = {
- return match (item) {
- v4: addr4 => fmtv4(s, v4)?,
- v6: addr6 => fmtv6(s, v6)?,
- sub: subnet => fmtsubnet(s, sub),
+ match (item) {
+ case v4: addr4 =>
+ return fmtv4(s, v4)?;
+ case v6: addr6 =>
+ return fmtv6(s, v6)?;
+ case sub: subnet =>
+ return fmtsubnet(s, sub);
};
};
@@ -324,8 +337,10 @@ export fn string(item: (...addr | subnet)) str = {
};
fn wanttoken(tok: *strings::tokenizer) (str | invalid) = {
- return match (strings::next_token(tok)) {
- s: str => s,
- void => invalid
+ match (strings::next_token(tok)) {
+ case s: str =>
+ return s;
+ case void =>
+ return invalid;
};
};
diff --git a/net/listener.ha b/net/listener.ha
@@ -4,16 +4,19 @@ use io;
// Accepts the next connection from a listener. Blocks until a new connection is
// available.
export fn accept(l: *listener) (io::file | error) = {
- return match (l.accept) {
- f: *fn(l: *listener) (io::file | error) => f(l),
- null => errors::unsupported,
+ match (l.accept) {
+ case f: *fn(l: *listener) (io::file | error) =>
+ return f(l);
+ case null =>
+ return errors::unsupported;
};
};
// Shuts down a [[listener]] and frees resources associated with it.
export fn shutdown(l: *listener) void = {
match (l.shutdown) {
- f: *fn(l: *listener) void => f(l),
- null => void,
+ case f: *fn(l: *listener) void =>
+ f(l);
+ case null => void;
};
};
diff --git a/net/tcp/+linux.ha b/net/tcp/+linux.ha
@@ -13,12 +13,17 @@ export fn connect(
options: connect_option...
) (io::file | net::error) = {
const sockaddr = ip::to_native(addr, port);
- const sockfd = match (rt::socket(match (addr) {
- ip::addr4 => rt::AF_INET: int,
- ip::addr6 => rt::AF_INET6: int,
- }, rt::SOCK_STREAM, 0)) {
- err: rt::errno => return errors::errno(err),
- fd: int => fd,
+ const family = match (addr) {
+ case ip::addr4 =>
+ yield rt::AF_INET: int;
+ case ip::addr6 =>
+ yield rt::AF_INET6: int;
+ };
+ const sockfd = match (rt::socket(family, rt::SOCK_STREAM, 0)) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case fd: int =>
+ yield fd;
};
let flags = rt::fcntl(sockfd, rt::F_GETFL, 0)!;
rt::fcntl(sockfd, rt::F_SETFL, flags | rt::O_CLOEXEC)!;
@@ -29,8 +34,9 @@ export fn connect(
};
const sz = size(rt::sockaddr): u32;
match (rt::connect(sockfd, &sockaddr, sz)) {
- err: rt::errno => return errors::errno(err),
- int => void,
+ case err: rt::errno =>
+ return errors::errno(err);
+ case int => void;
};
return io::fdopen(sockfd, ip::string(addr),
io::mode::READ | io::mode::WRITE);
@@ -43,12 +49,17 @@ export fn listen(
options: listen_option...
) (*net::listener | net::error) = {
const sockaddr = ip::to_native(addr, port);
- const sockfd = match (rt::socket(match (addr) {
- ip::addr4 => rt::AF_INET: int,
- ip::addr6 => rt::AF_INET6: int,
- }, rt::SOCK_STREAM, 0)) {
- err: rt::errno => return errors::errno(err),
- fd: int => fd,
+ const family = match (addr) {
+ case ip::addr4 =>
+ yield rt::AF_INET: int;
+ case ip::addr6 =>
+ yield rt::AF_INET6: int;
+ };
+ const sockfd = match (rt::socket(family, rt::SOCK_STREAM, 0)) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case fd: int =>
+ yield fd;
};
let flags = rt::fcntl(sockfd, rt::F_GETFL, 0)!;
rt::fcntl(sockfd, rt::F_SETFL, flags | rt::O_CLOEXEC)!;
@@ -56,33 +67,42 @@ export fn listen(
let bk: u32 = 10;
for (let i = 0z; i < len(options); i += 1) {
match (options[i]) {
- reuseaddr => setsockopt(sockfd, rt::SO_REUSEADDR, true)?,
- reuseport => setsockopt(sockfd, rt::SO_REUSEPORT, true)?,
- keepalive => setsockopt(sockfd, rt::SO_KEEPALIVE, true)?,
- b: backlog => bk = b,
- p: portassignment => void,
+ case reuseaddr =>
+ setsockopt(sockfd, rt::SO_REUSEADDR, true)?;
+ case reuseport =>
+ setsockopt(sockfd, rt::SO_REUSEPORT, true)?;
+ case keepalive =>
+ setsockopt(sockfd, rt::SO_KEEPALIVE, true)?;
+ case b: backlog =>
+ bk = b;
+ case p: portassignment => void;
};
};
match (rt::bind(sockfd, &sockaddr, size(rt::sockaddr): u32)) {
- err: rt::errno => return errors::errno(err),
- int => void,
+ case err: rt::errno =>
+ return errors::errno(err);
+ case int => void;
};
- match ((rt::listen(sockfd, bk))) {
- err: rt::errno => return errors::errno(err),
- int => void,
+ match (rt::listen(sockfd, bk)) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case int => void;
};
for (let i = 0z; i < len(options); i += 1) {
let portout = match (options[i]) {
- p: portassignment => p,
- * => continue,
+ case p: portassignment =>
+ yield p;
+ case =>
+ continue;
};
let sn = rt::sockaddr {...};
let al = size(rt::sockaddr): u32;
match (rt::getsockname(sockfd, &sn, &al)) {
- err: rt::errno => return errors::errno(err),
- int => void,
+ case err: rt::errno =>
+ return errors::errno(err);
+ case int => void;
};
const addr = ip::from_native(sn);
*portout = addr.1;
@@ -115,9 +135,10 @@ fn setsockopt(
value: bool,
) (void | net::error) = {
let val: int = if (value) 1 else 0;
- return match (rt::setsockopt(sockfd, rt::SOL_SOCKET, option,
+ match (rt::setsockopt(sockfd, rt::SOL_SOCKET, option,
&val: *void, size(int): u32)) {
- err: rt::errno => errors::errno(err),
- int => void,
+ case err: rt::errno =>
+ return errors::errno(err);
+ case int => void;
};
};
diff --git a/net/udp/+linux.ha b/net/udp/+linux.ha
@@ -10,21 +10,27 @@ export fn connect(
dest: ip::addr,
port: u16,
) (io::file | net::error) = {
- const sockfd = match (rt::socket(match (dest) {
- ip::addr4 => rt::AF_INET: int,
- ip::addr6 => rt::AF_INET6: int,
- }, rt::SOCK_DGRAM, 0)) {
- err: rt::errno => return errors::errno(err),
- fd: int => fd,
+ const family = match (dest) {
+ case ip::addr4 =>
+ yield rt::AF_INET: int;
+ case ip::addr6 =>
+ yield rt::AF_INET6: int;
+ };
+ const sockfd = match (rt::socket(family, rt::SOCK_DGRAM, 0)) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case fd: int =>
+ yield fd;
};
const sockaddr = ip::to_native(dest, port);
const sz = size(rt::sockaddr): u32;
- return match (rt::connect(sockfd, &sockaddr, sz)) {
- int => io::fdopen(sockfd,
- "<udp connection>",
- io::mode::READ | io::mode::WRITE),
- err: rt::errno => errors::errno(err),
+ match (rt::connect(sockfd, &sockaddr, sz)) {
+ case int =>
+ return io::fdopen(sockfd, "<udp connection>",
+ io::mode::READ | io::mode::WRITE);
+ case err: rt::errno =>
+ return errors::errno(err);
};
};
@@ -34,12 +40,17 @@ export fn listen(
port: u16,
options: listen_option...
) (io::file | net::error) = {
- const sockfd = match (rt::socket(match (addr) {
- ip::addr4 => rt::AF_INET: int,
- ip::addr6 => rt::AF_INET6: int,
- }, rt::SOCK_DGRAM, 0)) {
- err: rt::errno => return errors::errno(err),
- fd: int => fd,
+ const family = match (addr) {
+ case ip::addr4 =>
+ yield rt::AF_INET: int;
+ case ip::addr6 =>
+ yield rt::AF_INET6: int;
+ };
+ const sockfd = match (rt::socket(family, rt::SOCK_DGRAM, 0)) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case fd: int =>
+ yield fd;
};
let flags = rt::fcntl(sockfd, rt::F_GETFL, 0)!;
rt::fcntl(sockfd, rt::F_SETFL, flags | rt::O_CLOEXEC)!;
@@ -47,8 +58,9 @@ export fn listen(
const sockaddr = ip::to_native(addr, port);
const sz = size(rt::sockaddr): u32;
match (rt::bind(sockfd, &sockaddr, sz)) {
- int => void,
- err: rt::errno => return errors::errno(err),
+ case int => void;
+ case err: rt::errno =>
+ return errors::errno(err);
};
for (let i = 0z; i < len(options); i += 1) {
@@ -56,8 +68,9 @@ export fn listen(
let sn = rt::sockaddr {...};
let al = size(rt::sockaddr): u32;
match (rt::getsockname(sockfd, &sn, &al)) {
- err: rt::errno => return errors::errno(err),
- int => void,
+ case err: rt::errno =>
+ return errors::errno(err);
+ case int => void;
};
const addr = ip::from_native(sn);
*options[i] = addr.1;
@@ -69,9 +82,11 @@ export fn listen(
// Sends a UDP packet to the destination previously specified by [[connect]].
export fn send(sock: *io::file, buf: []u8) (size | net::error) = {
- return match (rt::send(io::fd(sock), buf: *[*]u8, len(buf), 0)) {
- sz: size => sz,
- err: rt::errno => errors::errno(err),
+ match (rt::send(io::fd(sock), buf: *[*]u8, len(buf), 0)) {
+ case sz: size =>
+ return sz;
+ case err: rt::errno =>
+ return errors::errno(err);
};
};
@@ -84,10 +99,12 @@ export fn sendto(
) (size | net::error) = {
const sockaddr = ip::to_native(dest, port);
const sz = size(rt::sockaddr): u32;
- return match (rt::sendto(io::fd(sock), buf: *[*]u8, len(buf),
+ match (rt::sendto(io::fd(sock), buf: *[*]u8, len(buf),
0, &sockaddr, sz)) {
- sz: size => sz,
- err: rt::errno => errors::errno(err),
+ case sz: size =>
+ return sz;
+ case err: rt::errno =>
+ return errors::errno(err);
};
};
@@ -102,19 +119,23 @@ export fn recvfrom(
const sockaddr = rt::sockaddr { ... };
const sz = match (rt::recvfrom(io::fd(sock), buf: *[*]u8, len(buf),
0, &sockaddr, &addrsz)) {
- sz: size => sz,
- err: rt::errno => return errors::errno(err),
+ case sz: size =>
+ yield sz;
+ case err: rt::errno =>
+ return errors::errno(err);
};
assert(addrsz <= size(rt::sockaddr));
const peer = ip::from_native(sockaddr);
match (src) {
- null => void,
- src: *ip::addr => *src = peer.0,
+ case null => void;
+ case src: *ip::addr =>
+ *src = peer.0;
};
match (port) {
- null => void,
- port: *u16 => *port = peer.1,
+ case null => void;
+ case port: *u16 =>
+ *port = peer.1;
};
return sz;
diff --git a/net/unix/+linux.ha b/net/unix/+linux.ha
@@ -11,20 +11,25 @@ use types;
// established.
export fn connect(addr: addr) (io::file | net::error) = {
let sockaddr = match (to_native(addr)) {
- a: rt::sockaddr => a,
- invalid => return errors::unsupported, // path too long
+ case a: rt::sockaddr =>
+ yield a;
+ case invalid =>
+ return errors::unsupported; // path too long
};
const sockfd = match (rt::socket(rt::AF_UNIX: int, rt::SOCK_STREAM, 0)) {
- err: rt::errno => return errors::errno(err),
- fd: int => fd,
+ case err: rt::errno =>
+ return errors::errno(err);
+ case fd: int =>
+ yield fd;
};
let flags = rt::fcntl(sockfd, rt::F_GETFL, 0)!;
rt::fcntl(sockfd, rt::F_SETFL, flags | rt::O_CLOEXEC)!;
const sz = size(rt::sockaddr_un): u32;
match (rt::connect(sockfd, &sockaddr, sz)) {
- err: rt::errno => return errors::errno(err),
- int => void,
+ case err: rt::errno =>
+ return errors::errno(err);
+ case int => void;
};
static let buf: [rt::UNIX_PATH_MAX + 32]u8 = [0...];
return io::fdopen(sockfd,
@@ -38,12 +43,16 @@ export fn listen(
options: listen_option...
) (*net::listener | net::error) = {
let sockaddr = match (to_native(addr)) {
- a: rt::sockaddr => a,
- invalid => return errors::unsupported, // path too long
+ case a: rt::sockaddr =>
+ yield a;
+ case invalid =>
+ return errors::unsupported; // path too long
};
const sockfd = match (rt::socket(rt::AF_UNIX: int, rt::SOCK_STREAM, 0)) {
- err: rt::errno => return errors::errno(err),
- fd: int => fd,
+ case err: rt::errno =>
+ return errors::errno(err);
+ case fd: int =>
+ yield fd;
};
let flags = rt::fcntl(sockfd, rt::F_GETFL, 0)!;
rt::fcntl(sockfd, rt::F_SETFL, flags | rt::O_CLOEXEC)!;
@@ -55,12 +64,14 @@ export fn listen(
};
match (rt::bind(sockfd, &sockaddr, size(rt::sockaddr_un): u32)) {
- err: rt::errno => return errors::errno(err),
- int => void,
+ case err: rt::errno =>
+ return errors::errno(err);
+ case int => void;
};
- match ((rt::listen(sockfd, bk))) {
- err: rt::errno => return errors::errno(err),
- int => void,
+ match (rt::listen(sockfd, bk)) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case int => void;
};
return alloc(net::stream_listener {
@@ -85,8 +96,9 @@ fn to_native(addr: addr) (rt::sockaddr | invalid) = {
}
};
match ((&addr: *types::string).data) {
- null => void,
- data: *[*]u8 => rt::memcpy(&ret.un.sun_path, data, len(addr)),
+ case null => void;
+ case data: *[*]u8 =>
+ rt::memcpy(&ret.un.sun_path, data, len(addr));
};
ret.un.sun_path[len(addr)] = 0;
return ret;
diff --git a/net/unix/dial.ha b/net/unix/dial.ha
@@ -3,9 +3,11 @@ use net::dial;
use net;
fn dial_unix(addr: str, service: str) (io::file | dial::error) = {
- return match (connect(addr)) {
- conn: io::file => conn,
- err: net::error => err,
+ match (connect(addr)) {
+ case conn: io::file =>
+ return conn;
+ case err: net::error =>
+ return err;
};
};
diff --git a/os/+linux/dirfdfs.ha b/os/+linux/dirfdfs.ha
@@ -111,14 +111,22 @@ export fn dirfdfs_set_getdents_bufsz(fs: *fs::fs, sz: size) void = {
};
fn errno_to_fs(err: rt::errno) fs::error = switch (err) {
- rt::ENOENT => errors::noentry,
- rt::EEXIST => errors::exists,
- rt::EACCES => errors::noaccess,
- rt::EBUSY => errors::busy,
- rt::ENOTDIR => fs::wrongtype,
- rt::EOPNOTSUPP, rt::ENOSYS => errors::unsupported,
- rt::EXDEV => fs::cannotrename,
- * => errors::errno(err),
+case rt::ENOENT =>
+ yield errors::noentry;
+case rt::EEXIST =>
+ yield errors::exists;
+case rt::EACCES =>
+ yield errors::noaccess;
+case rt::EBUSY =>
+ yield errors::busy;
+case rt::ENOTDIR =>
+ yield fs::wrongtype;
+case rt::EOPNOTSUPP, rt::ENOSYS =>
+ yield errors::unsupported;
+case rt::EXDEV =>
+ yield fs::cannotrename;
+case =>
+ yield errors::errno(err);
};
fn _fs_open(
@@ -144,8 +152,10 @@ fn _fs_open(
};
let fd = match (rt::openat2(fs.dirfd, path, oh, size(rt::open_how))) {
- err: rt::errno => return errno_to_fs(err),
- fd: int => fd,
+ case err: rt::errno =>
+ return errno_to_fs(err);
+ case fd: int =>
+ yield fd;
};
return io::fdopen(fd, path, mode);
@@ -240,16 +250,18 @@ fn fs_create(
fn fs_remove(fs: *fs::fs, path: str) (void | fs::error) = {
let fs = fs: *os_filesystem;
match (rt::unlinkat(fs.dirfd, path, 0)) {
- err: rt::errno => return errno_to_fs(err),
- void => void,
+ case err: rt::errno =>
+ return errno_to_fs(err);
+ case void => void;
};
};
fn fs_rename(fs: *fs::fs, oldpath: str, newpath: str) (void | fs::error) = {
let fs = fs: *os_filesystem;
match (rt::renameat(fs.dirfd, oldpath, fs.dirfd, newpath, 0)) {
- err: rt::errno => return errno_to_fs(err),
- void => void,
+ case err: rt::errno =>
+ return errno_to_fs(err);
+ case void => void;
};
};
@@ -257,8 +269,9 @@ fn fs_stat(fs: *fs::fs, path: str) (fs::filestat | fs::error) = {
let fs = fs: *os_filesystem;
let st = rt::st { ... };
match (rt::fstatat(fs.dirfd, path, &st, rt::AT_SYMLINK_NOFOLLOW)) {
- err: rt::errno => return errno_to_fs(err),
- void => void,
+ case err: rt::errno =>
+ return errno_to_fs(err);
+ case void => void;
};
return fs::filestat {
mask = fs::stat_mask::UID
@@ -297,8 +310,10 @@ fn fs_subdir(fs: *fs::fs, path: str) (*fs::fs | fs::error) = {
let fd: int = match (rt::openat2(fs.dirfd, path,
&oh, size(rt::open_how))) {
- err: rt::errno => return errno_to_fs(err),
- n: int => n,
+ case err: rt::errno =>
+ return errno_to_fs(err);
+ case fd: int =>
+ yield fd;
};
return dirfdopen(fd);
@@ -307,32 +322,36 @@ fn fs_subdir(fs: *fs::fs, path: str) (*fs::fs | fs::error) = {
fn fs_rmdir(fs: *fs::fs, path: str) (void | fs::error) = {
let fs = fs: *os_filesystem;
match (rt::unlinkat(fs.dirfd, path, rt::AT_REMOVEDIR)) {
- err: rt::errno => return errno_to_fs(err),
- void => void,
+ case err: rt::errno =>
+ return errno_to_fs(err);
+ case void => void;
};
};
fn fs_mkdir(fs: *fs::fs, path: str) (void | fs::error) = {
let fs = fs: *os_filesystem;
- return match (rt::mkdirat(fs.dirfd, path, 0o755)) {
- err: rt::errno => errno_to_fs(err),
- void => void,
+ match (rt::mkdirat(fs.dirfd, path, 0o755)) {
+ case err: rt::errno =>
+ return errno_to_fs(err);
+ case void => void;
};
};
fn fs_chmod(fs: *fs::fs, path: str, mode: fs::mode) (void | fs::error) = {
let fs = fs: *os_filesystem;
- return match (rt::fchmodat(fs.dirfd, path, mode: uint, 0)) {
- err: rt::errno => return errno_to_fs(err),
- void => void,
+ match (rt::fchmodat(fs.dirfd, path, mode: uint, 0)) {
+ case err: rt::errno =>
+ return errno_to_fs(err);
+ case void => void;
};
};
fn fs_chown(fs: *fs::fs, path: str, uid: uint, gid: uint) (void | fs::error) = {
let fs = fs: *os_filesystem;
- return match (rt::fchownat(fs.dirfd, path, uid, gid, 0)) {
- err: rt::errno => return errno_to_fs(err),
- void => void,
+ match (rt::fchownat(fs.dirfd, path, uid, gid, 0)) {
+ case err: rt::errno =>
+ return errno_to_fs(err);
+ case void => void;
};
};
@@ -353,15 +372,23 @@ fn fs_resolve(fs: *fs::fs, path: str) str = {
let parts: []str = [];
if (!path::abs(path)) {
let iter = path::iter(getcwd());
- for (true) match (path::next(&iter)) {
- void => break,
- p: str => resolve_part(&parts, p),
+ for (true) {
+ match (path::next(&iter)) {
+ case void =>
+ break;
+ case p: str =>
+ resolve_part(&parts, p);
+ };
};
};
let iter = path::iter(path);
- for (true) match (path::next(&iter)) {
- void => break,
- p: str => resolve_part(&parts, p),
+ for (true) {
+ match (path::next(&iter)) {
+ case void =>
+ break;
+ case p: str =>
+ resolve_part(&parts, p);
+ };
};
return path::join(parts...);
};
@@ -390,13 +417,17 @@ fn fs_iter(fs: *fs::fs, path: str) (*fs::iterator | fs::error) = {
};
let fd: int = match (rt::openat2(fs.dirfd, path,
&oh, size(rt::open_how))) {
- err: rt::errno => return errno_to_fs(err),
- n: int => n,
+ case err: rt::errno =>
+ return errno_to_fs(err);
+ case fd: int =>
+ yield fd;
};
let buf = match (rt::malloc(fs.getdents_bufsz)) {
- v: *void => v: *[*]u8,
- null => return errors::nomem,
+ case v: *void =>
+ yield v: *[*]u8;
+ case null =>
+ return errors::nomem;
};
let iter = alloc(os_iterator {
iter = fs::iterator {
@@ -428,15 +459,24 @@ fn iter_next(iter: *fs::iterator) (fs::dirent | void) = {
let name = strings::fromc(&de.d_name: *const char);
let ftype: fs::mode = switch (de.d_type) {
- rt::DT_UNKNOWN => fs::mode::UNKNOWN,
- rt::DT_FIFO => fs::mode::FIFO,
- rt::DT_CHR => fs::mode::CHR,
- rt::DT_DIR => fs::mode::DIR,
- rt::DT_BLK => fs::mode::BLK,
- rt::DT_REG => fs::mode::REG,
- rt::DT_LNK => fs::mode::LINK,
- rt::DT_SOCK => fs::mode::SOCK,
- * => fs::mode::UNKNOWN,
+ case rt::DT_UNKNOWN =>
+ yield fs::mode::UNKNOWN;
+ case rt::DT_FIFO =>
+ yield fs::mode::FIFO;
+ case rt::DT_CHR =>
+ yield fs::mode::CHR;
+ case rt::DT_DIR =>
+ yield fs::mode::DIR;
+ case rt::DT_BLK =>
+ yield fs::mode::BLK;
+ case rt::DT_REG =>
+ yield fs::mode::REG;
+ case rt::DT_LNK =>
+ yield fs::mode::LINK;
+ case rt::DT_SOCK =>
+ yield fs::mode::SOCK;
+ case =>
+ yield fs::mode::UNKNOWN;
};
return fs::dirent {
name = name,
diff --git a/os/+linux/environ.ha b/os/+linux/environ.ha
@@ -38,9 +38,11 @@ export fn getenv(name: const str) (str | void) = {
for (let i = 0z; rt::envp[i] != null; i += 1) {
const item = rt::envp[i]: *[*]u8;
const ln = strings::cstrlen(item: *char);
- const eq: size = match (bytes::index(item[..ln], '=': u32: u8)) {
- void => abort("Environment violates System-V invariants"),
- i: size => i,
+ const eq: size = match (bytes::index(item[..ln], '=': u8)) {
+ case void =>
+ abort("Environment violates System-V invariants");
+ case i: size =>
+ yield i;
};
if (bytes::equal(name_b, item[..eq])) {
const ln = strings::cstrlen(item: *const char);
@@ -52,8 +54,10 @@ export fn getenv(name: const str) (str | void) = {
// Looks up an environment variable and returns its value, or a default value if
// unset.
export fn tryenv(name: const str, default: str) str = match (getenv(name)) {
- s: str => s,
- void => default,
+case s: str =>
+ yield s;
+case void =>
+ yield default;
};
let envp: []str = [];
diff --git a/os/+linux/fs.ha b/os/+linux/fs.ha
@@ -17,19 +17,22 @@ export fn getcwd() str = strings::fromc(rt::getcwd() as *const char);
// Change the current working directory.
export fn chdir(target: (*fs::fs | str)) (void | fs::error) = {
const path: str = match (target) {
- fs: *fs::fs => {
- assert(fs.open == &fs_open);
- let fs = fs: *os_filesystem;
- return match (rt::fchdir(fs.dirfd)) {
- err: rt::errno => errors::errno(err),
- void => void,
- };
- },
- s: str => s,
+ case fs: *fs::fs =>
+ assert(fs.open == &fs_open);
+ let fs = fs: *os_filesystem;
+ match (rt::fchdir(fs.dirfd)) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case void =>
+ return;
+ };
+ case s: str =>
+ yield s;
};
- return match (rt::chdir(path)) {
- err: rt::errno => errors::errno(err),
- void => void,
+ match (rt::chdir(path)) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case void => void;
};
};
@@ -38,18 +41,20 @@ export fn chdir(target: (*fs::fs | str)) (void | fs::error) = {
//
// This function is not appropriate for sandboxing.
export fn chroot(target: str) (void | fs::error) = {
- return match (rt::chroot(target)) {
- err: rt::errno => errors::errno(err),
- void => void,
+ match (rt::chroot(target)) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case void => void;
};
};
// Makes a FIFO node. This function is only available on Unix systems.
export fn mkfifo(path: str, mode: fs::mode) (void | fs::error) = {
- return match (rt::mknodat(rt::AT_FDCWD, path,
+ match (rt::mknodat(rt::AT_FDCWD, path,
mode: rt::mode_t | rt::S_IFIFO, 0)) {
- err: rt::errno => errors::errno(err),
- void => void,
+ case err: rt::errno =>
+ return errors::errno(err);
+ case void => void;
};
};
@@ -60,11 +65,12 @@ export fn mkblk(
major: uint,
minor: uint,
) (void | fs::error) = {
- return match (rt::mknodat(rt::AT_FDCWD, path,
+ match (rt::mknodat(rt::AT_FDCWD, path,
mode: rt::mode_t | rt::S_IFBLK,
rt::mkdev(major: u32, minor: u32))) {
- err: rt::errno => errors::errno(err),
- void => void,
+ case err: rt::errno =>
+ return errors::errno(err);
+ case void => void;
};
};
@@ -75,10 +81,10 @@ export fn mkchr(
major: uint,
minor: uint,
) (void | fs::error) = {
- return match (rt::mknodat(rt::AT_FDCWD, path,
- mode: rt::mode_t | rt::S_IFCHR,
+ match (rt::mknodat(rt::AT_FDCWD, path, mode: rt::mode_t | rt::S_IFCHR,
rt::mkdev(major: u32, minor: u32))) {
- err: rt::errno => errors::errno(err),
- void => void,
+ case err: rt::errno =>
+ return errors::errno(err);
+ case void => void;
};
};
diff --git a/os/exec/cmd.ha b/os/exec/cmd.ha
@@ -14,18 +14,26 @@ use strings;
// let proc = exec::start(&cmd);
// let status = exec::wait(&proc);
// assert(exec::status(status) == 0);
-//
+//
// By default, the new command will inherit the current process's environment.
export fn cmd(name: str, args: str...) (command | error) = {
let env = os::getenvs();
let cmd = command {
platform: platform_cmd =
- if (strings::contains(name, '/')) match (open(name)) {
- p: platform_cmd => p,
- * => return nocmd,
- } else match (lookup(name)) {
- void => return nocmd,
- p: platform_cmd => p,
+ if (strings::contains(name, '/')) {
+ yield match (open(name)) {
+ case p: platform_cmd =>
+ yield p;
+ case =>
+ return nocmd;
+ };
+ } else {
+ yield match (lookup(name)) {
+ case void =>
+ return nocmd;
+ case p: platform_cmd =>
+ yield p;
+ };
},
argv = alloc([], len(args) + 1z),
env = alloc([], len(env)),
@@ -61,9 +69,11 @@ export @noreturn fn exec(cmd: *command) void = {
// Starts a prepared command in a new process.
export fn start(cmd: *command) (error | process) = {
defer finish(cmd);
- return match (platform_start(cmd)) {
- err: errors::opaque => err,
- proc: process => proc,
+ match (platform_start(cmd)) {
+ case err: errors::opaque =>
+ return err;
+ case proc: process =>
+ return proc;
};
};
@@ -80,11 +90,16 @@ export fn clearenv(cmd: *command) void = {
export fn setenv(cmd: *command, key: str, value: str) void = {
let iter = strings::iter(key);
for (let i = 0z; true; i += 1) match (strings::next(&iter)) {
- void => break,
- r: rune => if (i == 0) assert(r == '_' || ascii::isalpha(r),
- "Invalid environment variable")
- else assert(r == '_' || ascii::isalnum(r),
- "Invalid environment variable"),
+ case void =>
+ break;
+ case r: rune =>
+ if (i == 0) {
+ assert(r == '_' || ascii::isalpha(r),
+ "Invalid environment variable");
+ } else {
+ assert(r == '_' || ascii::isalnum(r),
+ "Invalid environment variable");
+ };
};
// XXX: This can be a binary search
@@ -101,20 +116,26 @@ export fn setenv(cmd: *command, key: str, value: str) void = {
fn lookup(name: str) (platform_cmd | void) = {
const path = match (os::getenv("PATH")) {
- void => return,
- s: str => s,
+ case void =>
+ return;
+ case s: str =>
+ yield s;
};
let tok = strings::tokenize(path, ":");
for (true) {
const item = match (strings::next_token(&tok)) {
- void => break,
- s: str => s,
+ case void =>
+ break;
+ case s: str =>
+ yield s;
};
let path = strings::concat(item, "/", name);
defer free(path);
match (open(path)) {
- err: error => continue,
- p: platform_cmd => return p,
+ case err: error =>
+ continue;
+ case p: platform_cmd =>
+ return p;
};
};
};
diff --git a/os/exec/exec+linux.ha b/os/exec/exec+linux.ha
@@ -7,21 +7,31 @@ export type platform_cmd = int;
// Forks the current process, returning the pid of the child (to the parent) and
// void (to the child), or an error.
-export fn fork() (int | void | error) = match (rt::fork()) {
- err: rt::errno => errors::errno(err),
- i: (int | void) => i,
+export fn fork() (int | void | error) = {
+ match (rt::fork()) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case i: (int | void) =>
+ return i;
+ };
};
fn open(path: str) (platform_cmd | error) = {
match (rt::access(path, rt::X_OK)) {
- err: rt::errno => return errors::errno(err),
- b: bool => if (!b) return errors::errno(rt::EACCES),
+ case err: rt::errno =>
+ return errors::errno(err);
+ case b: bool =>
+ if (!b) {
+ return errors::noaccess;
+ };
};
// O_PATH is used because it allows us to use an executable for which we
// have execute permissions, but not read permissions.
- return match (rt::open(path, rt::O_PATH, 0u)) {
- fd: int => fd,
- err: rt::errno => errors::errno(err),
+ match (rt::open(path, rt::O_PATH, 0u)) {
+ case fd: int =>
+ return fd;
+ case err: rt::errno =>
+ return errors::errno(err);
};
};
@@ -54,34 +64,39 @@ fn platform_start(cmd: *command) (process | errors::error) = {
// TODO: Let the user configure clone more to their taste (e.g. SIGCHLD)
let pipe: [2]int = [0...];
match (rt::pipe2(&pipe, rt::O_CLOEXEC)) {
- err: rt::errno => return errors::errno(err),
- void => void,
+ case err: rt::errno =>
+ return errors::errno(err);
+ case void => void;
};
match (rt::clone(null, 0, null, null, 0)) {
- err: rt::errno => return errors::errno(err),
- pid: int => {
- rt::close(pipe[1])!;
- let errno: int = 0;
- return match (rt::read(pipe[0], &errno, size(int))) {
- err: rt::errno => errors::errno(err),
- n: size => switch (n) {
- size(int) => errors::errno(errno),
- * => abort("Unexpected rt::read result"),
- 0 => pid,
- },
- };
- },
- void => {
- rt::close(pipe[0])!;
- let err = platform_exec(cmd);
- if (!(err is errors::opaque)) {
- rt::exit(1);
+ case err: rt::errno =>
+ return errors::errno(err);
+ case pid: int =>
+ rt::close(pipe[1])!;
+ let errno: int = 0;
+ match (rt::read(pipe[0], &errno, size(int))) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case n: size =>
+ switch (n) {
+ case size(int) =>
+ return errors::errno(errno);
+ case 0 =>
+ return pid;
+ case =>
+ abort("Unexpected rt::read result");
};
- let err = err as errors::opaque;
- let err = &err.data: *rt::errno;
- rt::write(pipe[1], &err, size(int))!;
+ };
+ case void =>
+ rt::close(pipe[0])!;
+ let err = platform_exec(cmd);
+ if (!(err is errors::opaque)) {
rt::exit(1);
- },
+ };
+ let err = err as errors::opaque;
+ let err = &err.data: *rt::errno;
+ rt::write(pipe[1], &err, size(int))!;
+ rt::exit(1);
};
};
diff --git a/os/exec/process+linux.ha b/os/exec/process+linux.ha
@@ -38,8 +38,10 @@ export fn wait(proc: *process) (status | error) = {
let ru: rt::rusage = rt::rusage { ... };
let st: status = status { ... };
match (rt::wait4(*proc, &st.status, 0, &ru)) {
- err: rt::errno => return errors::errno(err),
- pid: int => assert(pid == *proc),
+ case err: rt::errno =>
+ return errors::errno(err);
+ case pid: int =>
+ assert(pid == *proc);
};
rusage(&st, &ru);
return st;
@@ -51,11 +53,15 @@ export fn peek(proc: *process) (status | void | error) = {
let ru: rt::rusage = rt::rusage { ... };
let st: status = status { ... };
match (rt::wait4(*proc, &st.status, 0, &ru)) {
- err: rt::errno => return errors::errno(err),
- pid: int => switch (pid) {
- 0 => return void,
- * => assert(pid == *proc),
- },
+ case err: rt::errno =>
+ return errors::errno(err);
+ case pid: int =>
+ switch (pid) {
+ case 0 =>
+ return;
+ case =>
+ assert(pid == *proc);
+ };
};
rusage(&st, &ru);
return st;
@@ -73,13 +79,18 @@ export type exit_status = (exited | signaled);
// Returns a human friendly string describing the exit status.
export fn exitstr(status: exit_status) const str = {
static let buf: [1024]u8 = [0...];
- return match (status) {
- i: exited => switch (i) {
- 0 => "exited normally",
- * => fmt::bsprintf(buf, "exited with status {}", i: int),
- },
+ match (status) {
+ case i: exited =>
+ switch (i) {
+ case 0 =>
+ return "exited normally";
+ case =>
+ return fmt::bsprintf(buf, "exited with status {}",
+ i: int);
+ };
+ case s: signaled =>
// TODO: Add signal name
- s: signaled => fmt::bsprintf(buf, "exited with signal {}", s: int),
+ return fmt::bsprintf(buf, "exited with signal {}", s: int);
};
};
@@ -98,9 +109,11 @@ export fn exit(stat: *status) exit_status = {
// or its status code as an error type if not.
export fn check(stat: *status) (void | !exit_status) = {
if (rt::wifexited(stat.status)) {
- return switch (rt::wexitstatus(stat.status)) {
- 0 => void,
- * => exit(stat),
+ switch (rt::wexitstatus(stat.status)) {
+ case 0 =>
+ return void;
+ case =>
+ return exit(stat);
};
};
return exit(stat);
diff --git a/os/exec/types.ha b/os/exec/types.ha
@@ -15,9 +15,11 @@ export type error = !(nocmd | ...errors::error);
// Returns a human-readable message for the given error.
export fn strerror(err: error) const str = {
- return match (err) {
- nocmd => "Command not found",
- err: errors::opaque => errors::strerror(err),
+ match (err) {
+ case nocmd =>
+ return "Command not found";
+ case err: errors::opaque =>
+ return errors::strerror(err);
};
};
diff --git a/path/iter.ha b/path/iter.ha
@@ -39,9 +39,10 @@ export fn next(iter: *iterator) (str | void) = {
static assert(PATHSEP <= 0x7F);
return strings::fromutf8_unsafe(pathsep);
};
- return match (bytes::next_token(&iter.tok)) {
- b: []u8 => strings::fromutf8_unsafe(b),
- void => void,
+ match (bytes::next_token(&iter.tok)) {
+ case b: []u8 =>
+ return strings::fromutf8_unsafe(b);
+ case void => void;
};
};
diff --git a/path/names.ha b/path/names.ha
@@ -9,8 +9,10 @@ use strings;
export fn dirname(path: str) str = {
let b = strings::toutf8(path);
let i = match (bytes::rindex(b, PATHSEP)) {
- void => return path,
- z: size => z,
+ case void =>
+ return path;
+ case z: size =>
+ yield z;
};
if (i == 0) {
i += 1;
@@ -33,8 +35,10 @@ export fn dirname(path: str) str = {
export fn basename(path: str) str = {
let b = strings::toutf8(path);
let i = match (bytes::rindex(b, PATHSEP)) {
- void => return path,
- z: size => if (z + 1 < len(b)) z + 1z else 0z,
+ case void =>
+ return path;
+ case z: size =>
+ yield if (z + 1 < len(b)) z + 1z else 0z;
};
return strings::fromutf8_unsafe(b[i..]);
};
@@ -62,8 +66,10 @@ export fn extension(p: str) (str, str) = {
return (p, "");
};
let i = match (bytes::index(b, '.': u32: u8)) {
- void => return (p, ""),
- z: size => z,
+ case void =>
+ return (p, "");
+ case z: size =>
+ yield z;
};
let e = b[i..];
let n = b[..i];
diff --git a/rt/+linux/+x86_64.ha b/rt/+linux/+x86_64.ha
@@ -7,17 +7,19 @@ export fn clone(
child_tid: nullable *int,
tls: u64,
) (int | void | errno) = {
- return match (wrap_return(syscall5(SYS_clone,
- flags: u64,
- stack: uintptr: u64,
- parent_tid: uintptr: u64,
- child_tid: uintptr: u64,
- tls))) {
- u: u64 => switch (u) {
- 0 => void,
- * => u: int,
- },
- err: errno => err,
+ match (wrap_return(syscall5(SYS_clone,
+ flags: u64, stack: uintptr: u64,
+ parent_tid: uintptr: u64, child_tid: uintptr: u64,
+ tls))) {
+ case u: u64 =>
+ switch (u) {
+ case 0 =>
+ return;
+ case =>
+ return u: int;
+ };
+ case err: errno =>
+ return err;
};
};
diff --git a/rt/+linux/errno.ha b/rt/+linux/errno.ha
@@ -17,276 +17,540 @@ fn wrap_return(r: u64) (errno | u64) = {
// permitted").
export fn strerror(err: errno) str = {
return switch (err: int) {
- EPERM => "Operation not permitted",
- ENOENT => "No such file or directory",
- ESRCH => "No such process",
- EINTR => "Interrupted system call",
- EIO => "Input/output error",
- ENXIO => "No such device or address",
- E2BIG => "Argument list too long",
- ENOEXEC => "Exec format error",
- EBADF => "Bad file descriptor",
- ECHILD => "No child processes",
- EAGAIN => "Resource temporarily unavailable",
- ENOMEM => "Cannot allocate memory",
- EACCES => "Permission denied",
- EFAULT => "Bad address",
- ENOTBLK => "Block device required",
- EBUSY => "Device or resource busy",
- EEXIST => "File exists",
- EXDEV => "Invalid cross-device link",
- ENODEV => "No such device",
- ENOTDIR => "Not a directory",
- EISDIR => "Is a directory",
- EINVAL => "Invalid argument",
- ENFILE => "Too many open files in system",
- EMFILE => "Too many open files",
- ENOTTY => "Inappropriate ioctl for device",
- ETXTBSY => "Text file busy",
- EFBIG => "File too large",
- ENOSPC => "No space left on device",
- ESPIPE => "Illegal seek",
- EROFS => "Read-only file system",
- EMLINK => "Too many links",
- EPIPE => "Broken pipe",
- EDOM => "Numerical argument out of domain",
- ERANGE => "Numerical result out of range",
- EDEADLK => "Resource deadlock avoided",
- ENAMETOOLONG => "File name too long",
- ENOLCK => "No locks available",
- ENOSYS => "Function not implemented",
- ENOTEMPTY => "Directory not empty",
- ELOOP => "Too many levels of symbolic links",
- ENOMSG => "No message of desired type",
- EIDRM => "Identifier removed",
- ECHRNG => "Channel number out of range",
- EL2NSYNC => "Level 2 not synchronized",
- EL3HLT => "Level 3 halted",
- EL3RST => "Level 3 reset",
- ELNRNG => "Link number out of range",
- EUNATCH => "Protocol driver not attached",
- ENOCSI => "No CSI structure available",
- EL2HLT => "Level 2 halted",
- EBADE => "Invalid exchange",
- EBADR => "Invalid request descriptor",
- EXFULL => "Exchange full",
- ENOANO => "No anode",
- EBADRQC => "Invalid request code",
- EBADSLT => "Invalid slot",
- EBFONT => "Bad font file format",
- ENOSTR => "Device not a stream",
- ENODATA => "No data available",
- ETIME => "Timer expired",
- ENOSR => "Out of streams resources",
- ENONET => "Machine is not on the network",
- ENOPKG => "Package not installed",
- EREMOTE => "Object is remote",
- ENOLINK => "Link has been severed",
- EADV => "Advertise error",
- ESRMNT => "Srmount error",
- ECOMM => "Communication error on send",
- EPROTO => "Protocol error",
- EMULTIHOP => "Multihop attempted",
- EDOTDOT => "RFS specific error",
- EBADMSG => "Bad message",
- EOVERFLOW => "Value too large for defined data type",
- ENOTUNIQ => "Name not unique on network",
- EBADFD => "File descriptor in bad state",
- EREMCHG => "Remote address changed",
- ELIBACC => "Can not access a needed shared library",
- ELIBBAD => "Accessing a corrupted shared library",
- ELIBSCN => ".lib section in a.out corrupted",
- ELIBMAX => "Attempting to link in too many shared libraries",
- ELIBEXEC => "Cannot exec a shared library directly",
- EILSEQ => "Invalid or incomplete multibyte or wide character",
- ERESTART => "Interrupted system call should be restarted",
- ESTRPIPE => "Streams pipe error",
- EUSERS => "Too many users",
- ENOTSOCK => "Socket operation on non-socket",
- EDESTADDRREQ => "Destination address required",
- EMSGSIZE => "Message too long",
- EPROTOTYPE => "Protocol wrong type for socket",
- ENOPROTOOPT => "Protocol not available",
- EPROTONOSUPPORT => "Protocol not supported",
- ESOCKTNOSUPPORT => "Socket type not supported",
- EOPNOTSUPP => "Operation not supported",
- EPFNOSUPPORT => "Protocol family not supported",
- EAFNOSUPPORT => "Address family not supported by protocol",
- EADDRINUSE => "Address already in use",
- EADDRNOTAVAIL => "Cannot assign requested address",
- ENETDOWN => "Network is down",
- ENETUNREACH => "Network is unreachable",
- ENETRESET => "Network dropped connection on reset",
- ECONNABORTED => "Software caused connection abort",
- ECONNRESET => "Connection reset by peer",
- ENOBUFS => "No buffer space available",
- EISCONN => "Transport endpoint is already connected",
- ENOTCONN => "Transport endpoint is not connected",
- ESHUTDOWN => "Cannot send after transport endpoint shutdown",
- ETOOMANYREFS => "Too many references: cannot splice",
- ETIMEDOUT => "Connection timed out",
- ECONNREFUSED => "Connection refused",
- EHOSTDOWN => "Host is down",
- EHOSTUNREACH => "No route to host",
- EALREADY => "Operation already in progress",
- EINPROGRESS => "Operation now in progress",
- ESTALE => "Stale file handle",
- EUCLEAN => "Structure needs cleaning",
- ENOTNAM => "Not a XENIX named type file",
- ENAVAIL => "No XENIX semaphores available",
- EISNAM => "Is a named type file",
- EREMOTEIO => "Remote I/O error",
- EDQUOT => "Disk quota exceeded",
- ENOMEDIUM => "No medium found",
- EMEDIUMTYPE => "Wrong medium type",
- ECANCELED => "Operation canceled",
- ENOKEY => "Required key not available",
- EKEYEXPIRED => "Key has expired",
- EKEYREVOKED => "Key has been revoked",
- EKEYREJECTED => "Key was rejected by service",
- EOWNERDEAD => "Owner died",
- ENOTRECOVERABLE => "State not recoverable",
- ERFKILL => "Operation not possible due to RF-kill",
- EHWPOISON => "Memory page has hardware error",
- * => "Unknown Linux error code", // TODO: snprintf to add errno?
+ case EPERM =>
+ yield "Operation not permitted";
+ case ENOENT =>
+ yield "No such file or directory";
+ case ESRCH =>
+ yield "No such process";
+ case EINTR =>
+ yield "Interrupted system call";
+ case EIO =>
+ yield "Input/output error";
+ case ENXIO =>
+ yield "No such device or address";
+ case E2BIG =>
+ yield "Argument list too long";
+ case ENOEXEC =>
+ yield "Exec format error";
+ case EBADF =>
+ yield "Bad file descriptor";
+ case ECHILD =>
+ yield "No child processes";
+ case EAGAIN =>
+ yield "Resource temporarily unavailable";
+ case ENOMEM =>
+ yield "Cannot allocate memory";
+ case EACCES =>
+ yield "Permission denied";
+ case EFAULT =>
+ yield "Bad address";
+ case ENOTBLK =>
+ yield "Block device required";
+ case EBUSY =>
+ yield "Device or resource busy";
+ case EEXIST =>
+ yield "File exists";
+ case EXDEV =>
+ yield "Invalid cross-device link";
+ case ENODEV =>
+ yield "No such device";
+ case ENOTDIR =>
+ yield "Not a directory";
+ case EISDIR =>
+ yield "Is a directory";
+ case EINVAL =>
+ yield "Invalid argument";
+ case ENFILE =>
+ yield "Too many open files in system";
+ case EMFILE =>
+ yield "Too many open files";
+ case ENOTTY =>
+ yield "Inappropriate ioctl for device";
+ case ETXTBSY =>
+ yield "Text file busy";
+ case EFBIG =>
+ yield "File too large";
+ case ENOSPC =>
+ yield "No space left on device";
+ case ESPIPE =>
+ yield "Illegal seek";
+ case EROFS =>
+ yield "Read-only file system";
+ case EMLINK =>
+ yield "Too many links";
+ case EPIPE =>
+ yield "Broken pipe";
+ case EDOM =>
+ yield "Numerical argument out of domain";
+ case ERANGE =>
+ yield "Numerical result out of range";
+ case EDEADLK =>
+ yield "Resource deadlock avoided";
+ case ENAMETOOLONG =>
+ yield "File name too long";
+ case ENOLCK =>
+ yield "No locks available";
+ case ENOSYS =>
+ yield "Function not implemented";
+ case ENOTEMPTY =>
+ yield "Directory not empty";
+ case ELOOP =>
+ yield "Too many levels of symbolic links";
+ case ENOMSG =>
+ yield "No message of desired type";
+ case EIDRM =>
+ yield "Identifier removed";
+ case ECHRNG =>
+ yield "Channel number out of range";
+ case EL2NSYNC =>
+ yield "Level 2 not synchronized";
+ case EL3HLT =>
+ yield "Level 3 halted";
+ case EL3RST =>
+ yield "Level 3 reset";
+ case ELNRNG =>
+ yield "Link number out of range";
+ case EUNATCH =>
+ yield "Protocol driver not attached";
+ case ENOCSI =>
+ yield "No CSI structure available";
+ case EL2HLT =>
+ yield "Level 2 halted";
+ case EBADE =>
+ yield "Invalid exchange";
+ case EBADR =>
+ yield "Invalid request descriptor";
+ case EXFULL =>
+ yield "Exchange full";
+ case ENOANO =>
+ yield "No anode";
+ case EBADRQC =>
+ yield "Invalid request code";
+ case EBADSLT =>
+ yield "Invalid slot";
+ case EBFONT =>
+ yield "Bad font file format";
+ case ENOSTR =>
+ yield "Device not a stream";
+ case ENODATA =>
+ yield "No data available";
+ case ETIME =>
+ yield "Timer expired";
+ case ENOSR =>
+ yield "Out of streams resources";
+ case ENONET =>
+ yield "Machine is not on the network";
+ case ENOPKG =>
+ yield "Package not installed";
+ case EREMOTE =>
+ yield "Object is remote";
+ case ENOLINK =>
+ yield "Link has been severed";
+ case EADV =>
+ yield "Advertise error";
+ case ESRMNT =>
+ yield "Srmount error";
+ case ECOMM =>
+ yield "Communication error on send";
+ case EPROTO =>
+ yield "Protocol error";
+ case EMULTIHOP =>
+ yield "Multihop attempted";
+ case EDOTDOT =>
+ yield "RFS specific error";
+ case EBADMSG =>
+ yield "Bad message";
+ case EOVERFLOW =>
+ yield "Value too large for defined data type";
+ case ENOTUNIQ =>
+ yield "Name not unique on network";
+ case EBADFD =>
+ yield "File descriptor in bad state";
+ case EREMCHG =>
+ yield "Remote address changed";
+ case ELIBACC =>
+ yield "Can not access a needed shared library";
+ case ELIBBAD =>
+ yield "Accessing a corrupted shared library";
+ case ELIBSCN =>
+ yield ".lib section in a.out corrupted";
+ case ELIBMAX =>
+ yield "Attempting to link in too many shared libraries";
+ case ELIBEXEC =>
+ yield "Cannot exec a shared library directly";
+ case EILSEQ =>
+ yield "Invalid or incomplete multibyte or wide character";
+ case ERESTART =>
+ yield "Interrupted system call should be restarted";
+ case ESTRPIPE =>
+ yield "Streams pipe error";
+ case EUSERS =>
+ yield "Too many users";
+ case ENOTSOCK =>
+ yield "Socket operation on non-socket";
+ case EDESTADDRREQ =>
+ yield "Destination address required";
+ case EMSGSIZE =>
+ yield "Message too long";
+ case EPROTOTYPE =>
+ yield "Protocol wrong type for socket";
+ case ENOPROTOOPT =>
+ yield "Protocol not available";
+ case EPROTONOSUPPORT =>
+ yield "Protocol not supported";
+ case ESOCKTNOSUPPORT =>
+ yield "Socket type not supported";
+ case EOPNOTSUPP =>
+ yield "Operation not supported";
+ case EPFNOSUPPORT =>
+ yield "Protocol family not supported";
+ case EAFNOSUPPORT =>
+ yield "Address family not supported by protocol";
+ case EADDRINUSE =>
+ yield "Address already in use";
+ case EADDRNOTAVAIL =>
+ yield "Cannot assign requested address";
+ case ENETDOWN =>
+ yield "Network is down";
+ case ENETUNREACH =>
+ yield "Network is unreachable";
+ case ENETRESET =>
+ yield "Network dropped connection on reset";
+ case ECONNABORTED =>
+ yield "Software caused connection abort";
+ case ECONNRESET =>
+ yield "Connection reset by peer";
+ case ENOBUFS =>
+ yield "No buffer space available";
+ case EISCONN =>
+ yield "Transport endpoint is already connected";
+ case ENOTCONN =>
+ yield "Transport endpoint is not connected";
+ case ESHUTDOWN =>
+ yield "Cannot send after transport endpoint shutdown";
+ case ETOOMANYREFS =>
+ yield "Too many references: cannot splice";
+ case ETIMEDOUT =>
+ yield "Connection timed out";
+ case ECONNREFUSED =>
+ yield "Connection refused";
+ case EHOSTDOWN =>
+ yield "Host is down";
+ case EHOSTUNREACH =>
+ yield "No route to host";
+ case EALREADY =>
+ yield "Operation already in progress";
+ case EINPROGRESS =>
+ yield "Operation now in progress";
+ case ESTALE =>
+ yield "Stale file handle";
+ case EUCLEAN =>
+ yield "Structure needs cleaning";
+ case ENOTNAM =>
+ yield "Not a XENIX named type file";
+ case ENAVAIL =>
+ yield "No XENIX semaphores available";
+ case EISNAM =>
+ yield "Is a named type file";
+ case EREMOTEIO =>
+ yield "Remote I/O error";
+ case EDQUOT =>
+ yield "Disk quota exceeded";
+ case ENOMEDIUM =>
+ yield "No medium found";
+ case EMEDIUMTYPE =>
+ yield "Wrong medium type";
+ case ECANCELED =>
+ yield "Operation canceled";
+ case ENOKEY =>
+ yield "Required key not available";
+ case EKEYEXPIRED =>
+ yield "Key has expired";
+ case EKEYREVOKED =>
+ yield "Key has been revoked";
+ case EKEYREJECTED =>
+ yield "Key was rejected by service";
+ case EOWNERDEAD =>
+ yield "Owner died";
+ case ENOTRECOVERABLE =>
+ yield "State not recoverable";
+ case ERFKILL =>
+ yield "Operation not possible due to RF-kill";
+ case EHWPOISON =>
+ yield "Memory page has hardware error";
+ case =>
+ yield "Unknown Linux error code"; // TODO: snprintf to add errno?
};
};
// Gets the programmer-friendly name for an [[errno]] (e.g. EPERM).
export fn errname(err: errno) str = {
return switch (err: int) {
- EPERM => "EPERM",
- ENOENT => "ENOENT",
- ESRCH => "ESRCH",
- EINTR => "EINTR",
- EIO => "EIO",
- ENXIO => "ENXIO",
- E2BIG => "E2BIG",
- ENOEXEC => "ENOEXEC",
- EBADF => "EBADF",
- ECHILD => "ECHILD",
- EAGAIN => "EAGAIN",
- ENOMEM => "ENOMEM",
- EACCES => "EACCES",
- EFAULT => "EFAULT",
- ENOTBLK => "ENOTBLK",
- EBUSY => "EBUSY",
- EEXIST => "EEXIST",
- EXDEV => "EXDEV",
- ENODEV => "ENODEV",
- ENOTDIR => "ENOTDIR",
- EISDIR => "EISDIR",
- EINVAL => "EINVAL",
- ENFILE => "ENFILE",
- EMFILE => "EMFILE",
- ENOTTY => "ENOTTY",
- ETXTBSY => "ETXTBSY",
- EFBIG => "EFBIG",
- ENOSPC => "ENOSPC",
- ESPIPE => "ESPIPE",
- EROFS => "EROFS",
- EMLINK => "EMLINK",
- EPIPE => "EPIPE",
- EDOM => "EDOM",
- ERANGE => "ERANGE",
- EDEADLK => "EDEADLK",
- ENAMETOOLONG => "ENAMETOOLONG",
- ENOLCK => "ENOLCK",
- ENOSYS => "ENOSYS",
- ENOTEMPTY => "ENOTEMPTY",
- ELOOP => "ELOOP",
- ENOMSG => "ENOMSG",
- EIDRM => "EIDRM",
- ECHRNG => "ECHRNG",
- EL2NSYNC => "EL2NSYNC",
- EL3HLT => "EL3HLT",
- EL3RST => "EL3RST",
- ELNRNG => "ELNRNG",
- EUNATCH => "EUNATCH",
- ENOCSI => "ENOCSI",
- EL2HLT => "EL2HLT",
- EBADE => "EBADE",
- EBADR => "EBADR",
- EXFULL => "EXFULL",
- ENOANO => "ENOANO",
- EBADRQC => "EBADRQC",
- EBADSLT => "EBADSLT",
- EBFONT => "EBFONT",
- ENOSTR => "ENOSTR",
- ENODATA => "ENODATA",
- ETIME => "ETIME",
- ENOSR => "ENOSR",
- ENONET => "ENONET",
- ENOPKG => "ENOPKG",
- EREMOTE => "EREMOTE",
- ENOLINK => "ENOLINK",
- EADV => "EADV",
- ESRMNT => "ESRMNT",
- ECOMM => "ECOMM",
- EPROTO => "EPROTO",
- EMULTIHOP => "EMULTIHOP",
- EDOTDOT => "EDOTDOT",
- EBADMSG => "EBADMSG",
- EOVERFLOW => "EOVERFLOW",
- ENOTUNIQ => "ENOTUNIQ",
- EBADFD => "EBADFD",
- EREMCHG => "EREMCHG",
- ELIBACC => "ELIBACC",
- ELIBBAD => "ELIBBAD",
- ELIBSCN => "ELIBSCN",
- ELIBMAX => "ELIBMAX",
- ELIBEXEC => "ELIBEXEC",
- EILSEQ => "EILSEQ",
- ERESTART => "ERESTART",
- ESTRPIPE => "ESTRPIPE",
- EUSERS => "EUSERS",
- ENOTSOCK => "ENOTSOCK",
- EDESTADDRREQ => "EDESTADDRREQ",
- EMSGSIZE => "EMSGSIZE",
- EPROTOTYPE => "EPROTOTYPE",
- ENOPROTOOPT => "ENOPROTOOPT",
- EPROTONOSUPPORT => "EPROTONOSUPPORT",
- ESOCKTNOSUPPORT => "ESOCKTNOSUPPORT",
- EOPNOTSUPP => "EOPNOTSUPP",
- EPFNOSUPPORT => "EPFNOSUPPORT",
- EAFNOSUPPORT => "EAFNOSUPPORT",
- EADDRINUSE => "EADDRINUSE",
- EADDRNOTAVAIL => "EADDRNOTAVAIL",
- ENETDOWN => "ENETDOWN",
- ENETUNREACH => "ENETUNREACH",
- ENETRESET => "ENETRESET",
- ECONNABORTED => "ECONNABORTED",
- ECONNRESET => "ECONNRESET",
- ENOBUFS => "ENOBUFS",
- EISCONN => "EISCONN",
- ENOTCONN => "ENOTCONN",
- ESHUTDOWN => "ESHUTDOWN",
- ETOOMANYREFS => "ETOOMANYREFS",
- ETIMEDOUT => "ETIMEDOUT",
- ECONNREFUSED => "ECONNREFUSED",
- EHOSTDOWN => "EHOSTDOWN",
- EHOSTUNREACH => "EHOSTUNREACH",
- EALREADY => "EALREADY",
- EINPROGRESS => "EINPROGRESS",
- ESTALE => "ESTALE",
- EUCLEAN => "EUCLEAN",
- ENOTNAM => "ENOTNAM",
- ENAVAIL => "ENAVAIL",
- EISNAM => "EISNAM",
- EREMOTEIO => "EREMOTEIO",
- EDQUOT => "EDQUOT",
- ENOMEDIUM => "ENOMEDIUM",
- EMEDIUMTYPE => "EMEDIUMTYPE",
- ECANCELED => "ECANCELED",
- ENOKEY => "ENOKEY",
- EKEYEXPIRED => "EKEYEXPIRED",
- EKEYREVOKED => "EKEYREVOKED",
- EKEYREJECTED => "EKEYREJECTED",
- EOWNERDEAD => "EOWNERDEAD",
- ENOTRECOVERABLE => "ENOTRECOVERABLE",
- ERFKILL => "ERFKILL",
- EHWPOISON => "EHWPOISON",
- * => "[unknown errno]", // TODO: snprintf to add errno?
+ case EPERM =>
+ yield "EPERM";
+ case ENOENT =>
+ yield "ENOENT";
+ case ESRCH =>
+ yield "ESRCH";
+ case EINTR =>
+ yield "EINTR";
+ case EIO =>
+ yield "EIO";
+ case ENXIO =>
+ yield "ENXIO";
+ case E2BIG =>
+ yield "E2BIG";
+ case ENOEXEC =>
+ yield "ENOEXEC";
+ case EBADF =>
+ yield "EBADF";
+ case ECHILD =>
+ yield "ECHILD";
+ case EAGAIN =>
+ yield "EAGAIN";
+ case ENOMEM =>
+ yield "ENOMEM";
+ case EACCES =>
+ yield "EACCES";
+ case EFAULT =>
+ yield "EFAULT";
+ case ENOTBLK =>
+ yield "ENOTBLK";
+ case EBUSY =>
+ yield "EBUSY";
+ case EEXIST =>
+ yield "EEXIST";
+ case EXDEV =>
+ yield "EXDEV";
+ case ENODEV =>
+ yield "ENODEV";
+ case ENOTDIR =>
+ yield "ENOTDIR";
+ case EISDIR =>
+ yield "EISDIR";
+ case EINVAL =>
+ yield "EINVAL";
+ case ENFILE =>
+ yield "ENFILE";
+ case EMFILE =>
+ yield "EMFILE";
+ case ENOTTY =>
+ yield "ENOTTY";
+ case ETXTBSY =>
+ yield "ETXTBSY";
+ case EFBIG =>
+ yield "EFBIG";
+ case ENOSPC =>
+ yield "ENOSPC";
+ case ESPIPE =>
+ yield "ESPIPE";
+ case EROFS =>
+ yield "EROFS";
+ case EMLINK =>
+ yield "EMLINK";
+ case EPIPE =>
+ yield "EPIPE";
+ case EDOM =>
+ yield "EDOM";
+ case ERANGE =>
+ yield "ERANGE";
+ case EDEADLK =>
+ yield "EDEADLK";
+ case ENAMETOOLONG =>
+ yield "ENAMETOOLONG";
+ case ENOLCK =>
+ yield "ENOLCK";
+ case ENOSYS =>
+ yield "ENOSYS";
+ case ENOTEMPTY =>
+ yield "ENOTEMPTY";
+ case ELOOP =>
+ yield "ELOOP";
+ case ENOMSG =>
+ yield "ENOMSG";
+ case EIDRM =>
+ yield "EIDRM";
+ case ECHRNG =>
+ yield "ECHRNG";
+ case EL2NSYNC =>
+ yield "EL2NSYNC";
+ case EL3HLT =>
+ yield "EL3HLT";
+ case EL3RST =>
+ yield "EL3RST";
+ case ELNRNG =>
+ yield "ELNRNG";
+ case EUNATCH =>
+ yield "EUNATCH";
+ case ENOCSI =>
+ yield "ENOCSI";
+ case EL2HLT =>
+ yield "EL2HLT";
+ case EBADE =>
+ yield "EBADE";
+ case EBADR =>
+ yield "EBADR";
+ case EXFULL =>
+ yield "EXFULL";
+ case ENOANO =>
+ yield "ENOANO";
+ case EBADRQC =>
+ yield "EBADRQC";
+ case EBADSLT =>
+ yield "EBADSLT";
+ case EBFONT =>
+ yield "EBFONT";
+ case ENOSTR =>
+ yield "ENOSTR";
+ case ENODATA =>
+ yield "ENODATA";
+ case ETIME =>
+ yield "ETIME";
+ case ENOSR =>
+ yield "ENOSR";
+ case ENONET =>
+ yield "ENONET";
+ case ENOPKG =>
+ yield "ENOPKG";
+ case EREMOTE =>
+ yield "EREMOTE";
+ case ENOLINK =>
+ yield "ENOLINK";
+ case EADV =>
+ yield "EADV";
+ case ESRMNT =>
+ yield "ESRMNT";
+ case ECOMM =>
+ yield "ECOMM";
+ case EPROTO =>
+ yield "EPROTO";
+ case EMULTIHOP =>
+ yield "EMULTIHOP";
+ case EDOTDOT =>
+ yield "EDOTDOT";
+ case EBADMSG =>
+ yield "EBADMSG";
+ case EOVERFLOW =>
+ yield "EOVERFLOW";
+ case ENOTUNIQ =>
+ yield "ENOTUNIQ";
+ case EBADFD =>
+ yield "EBADFD";
+ case EREMCHG =>
+ yield "EREMCHG";
+ case ELIBACC =>
+ yield "ELIBACC";
+ case ELIBBAD =>
+ yield "ELIBBAD";
+ case ELIBSCN =>
+ yield "ELIBSCN";
+ case ELIBMAX =>
+ yield "ELIBMAX";
+ case ELIBEXEC =>
+ yield "ELIBEXEC";
+ case EILSEQ =>
+ yield "EILSEQ";
+ case ERESTART =>
+ yield "ERESTART";
+ case ESTRPIPE =>
+ yield "ESTRPIPE";
+ case EUSERS =>
+ yield "EUSERS";
+ case ENOTSOCK =>
+ yield "ENOTSOCK";
+ case EDESTADDRREQ =>
+ yield "EDESTADDRREQ";
+ case EMSGSIZE =>
+ yield "EMSGSIZE";
+ case EPROTOTYPE =>
+ yield "EPROTOTYPE";
+ case ENOPROTOOPT =>
+ yield "ENOPROTOOPT";
+ case EPROTONOSUPPORT =>
+ yield "EPROTONOSUPPORT";
+ case ESOCKTNOSUPPORT =>
+ yield "ESOCKTNOSUPPORT";
+ case EOPNOTSUPP =>
+ yield "EOPNOTSUPP";
+ case EPFNOSUPPORT =>
+ yield "EPFNOSUPPORT";
+ case EAFNOSUPPORT =>
+ yield "EAFNOSUPPORT";
+ case EADDRINUSE =>
+ yield "EADDRINUSE";
+ case EADDRNOTAVAIL =>
+ yield "EADDRNOTAVAIL";
+ case ENETDOWN =>
+ yield "ENETDOWN";
+ case ENETUNREACH =>
+ yield "ENETUNREACH";
+ case ENETRESET =>
+ yield "ENETRESET";
+ case ECONNABORTED =>
+ yield "ECONNABORTED";
+ case ECONNRESET =>
+ yield "ECONNRESET";
+ case ENOBUFS =>
+ yield "ENOBUFS";
+ case EISCONN =>
+ yield "EISCONN";
+ case ENOTCONN =>
+ yield "ENOTCONN";
+ case ESHUTDOWN =>
+ yield "ESHUTDOWN";
+ case ETOOMANYREFS =>
+ yield "ETOOMANYREFS";
+ case ETIMEDOUT =>
+ yield "ETIMEDOUT";
+ case ECONNREFUSED =>
+ yield "ECONNREFUSED";
+ case EHOSTDOWN =>
+ yield "EHOSTDOWN";
+ case EHOSTUNREACH =>
+ yield "EHOSTUNREACH";
+ case EALREADY =>
+ yield "EALREADY";
+ case EINPROGRESS =>
+ yield "EINPROGRESS";
+ case ESTALE =>
+ yield "ESTALE";
+ case EUCLEAN =>
+ yield "EUCLEAN";
+ case ENOTNAM =>
+ yield "ENOTNAM";
+ case ENAVAIL =>
+ yield "ENAVAIL";
+ case EISNAM =>
+ yield "EISNAM";
+ case EREMOTEIO =>
+ yield "EREMOTEIO";
+ case EDQUOT =>
+ yield "EDQUOT";
+ case ENOMEDIUM =>
+ yield "ENOMEDIUM";
+ case EMEDIUMTYPE =>
+ yield "EMEDIUMTYPE";
+ case ECANCELED =>
+ yield "ECANCELED";
+ case ENOKEY =>
+ yield "ENOKEY";
+ case EKEYEXPIRED =>
+ yield "EKEYEXPIRED";
+ case EKEYREVOKED =>
+ yield "EKEYREVOKED";
+ case EKEYREJECTED =>
+ yield "EKEYREJECTED";
+ case EOWNERDEAD =>
+ yield "EOWNERDEAD";
+ case ENOTRECOVERABLE =>
+ yield "ENOTRECOVERABLE";
+ case ERFKILL =>
+ yield "ERFKILL";
+ case EHWPOISON =>
+ yield "EHWPOISON";
+ case =>
+ yield "[unknown errno]"; // TODO: snprintf to add errno?
};
};
diff --git a/rt/+linux/segmalloc.ha b/rt/+linux/segmalloc.ha
@@ -1,21 +1,21 @@
// Allocates a segment.
fn segmalloc(n: size) nullable *void = {
- return match (mmap(null, n,
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANON, -1, 0)) {
- err: errno => {
- assert(err == ENOMEM: errno);
- yield null;
- },
- p: *void => p,
+ return match (mmap(null, n, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON, -1, 0)) {
+ case err: errno =>
+ assert(err == ENOMEM: errno);
+ yield null;
+ case p: *void =>
+ yield p;
};
};
// Frees a segment allocated with segmalloc.
fn segfree(p: *void, s: size) void = {
match (munmap(p, s)) {
- err: errno => abort("munmap failed"),
- void => void,
+ case err: errno =>
+ abort("munmap failed");
+ case void => void;
};
};
diff --git a/rt/+linux/syscalls.ha b/rt/+linux/syscalls.ha
@@ -12,16 +12,17 @@ let pathbuf: [PATH_MAX + 1]u8 = [0...];
fn copy_kpath(path: path, buf: []u8) (*const char | errno) = {
let path = match (path) {
- c: *const char => return c,
- s: str => {
- let ptr = &s: *struct {
- buf: *[*]u8,
- length: size,
- capacity: size,
- };
- yield ptr.buf[..ptr.length];
- },
- b: []u8 => b,
+ case c: *const char =>
+ return c;
+ case s: str =>
+ let ptr = &s: *struct {
+ buf: *[*]u8,
+ length: size,
+ capacity: size,
+ };
+ yield ptr.buf[..ptr.length];
+ case b: []u8 =>
+ yield b;
};
if (len(path) + 1 >= len(pathbuf)) {
return ENAMETOOLONG;
@@ -186,10 +187,12 @@ export fn execveat(dirfd: int, path: path, argv: *[*]nullable *const char,
envp: *[*]nullable *const char, flags: int) errno = {
let path = kpath(path)?;
return match (wrap_return(syscall5(SYS_execveat, dirfd: u64,
- path: uintptr: u64, argv: uintptr: u64,
- envp: uintptr: u64, flags: u64))) {
- err: errno => err,
- u64 => abort("unreachable"),
+ path: uintptr: u64, argv: uintptr: u64,
+ envp: uintptr: u64, flags: u64))) {
+ case err: errno =>
+ yield err;
+ case u64 =>
+ abort("unreachable");
};
};
@@ -241,17 +244,17 @@ export fn mmap(
let r = syscall6(SYS_mmap, addr: uintptr: u64,
length: u64, prot: u64, flags: u64, fd: u64, offs: u64);
return match (wrap_return(r)) {
- err: errno => {
- // XXX: Type promotion would simplify this
- return if (r: int == -EPERM
- && addr: uintptr == null: uintptr
- && (flags & MAP_ANON) > 0
- && (flags & MAP_FIXED) == 0) {
- // Fix up incorrect EPERM from kernel:
- yield wrap_errno(ENOMEM);
- } else err;
- },
- n: u64 => n: uintptr: *void,
+ case err: errno =>
+ // XXX: Type promotion would simplify this
+ return if (r: int == -EPERM
+ && addr: uintptr == null: uintptr
+ && (flags & MAP_ANON) > 0
+ && (flags & MAP_FIXED) == 0) {
+ // Fix up incorrect EPERM from kernel:
+ yield wrap_errno(ENOMEM);
+ } else err;
+ case n: u64 =>
+ yield n: uintptr: *void;
};
};
@@ -276,15 +279,17 @@ export fn lseek(fd: int, off: i64, whence: uint) (i64 | errno) = {
fn faccessat1(dirfd: int, path: *const char, mode: int) (bool | errno) = {
return match (wrap_return(syscall3(SYS_faccessat, dirfd: u64,
- path: uintptr: u64, mode: u64))) {
- err: errno => switch (err) {
- EACCES => false,
- * => err,
- },
- n: u64 => {
- assert(n == 0);
- yield true;
- },
+ path: uintptr: u64, mode: u64))) {
+ case err: errno =>
+ yield switch (err) {
+ case EACCES =>
+ yield false;
+ case =>
+ yield err;
+ };
+ case n: u64 =>
+ assert(n == 0);
+ yield true;
};
};
@@ -298,19 +303,24 @@ export fn faccessat(
flags: int,
) (bool | errno) = {
let path = kpath(path)?;
- return match (wrap_return(syscall4(SYS_faccessat2, dirfd: u64,
+ match (wrap_return(syscall4(SYS_faccessat2, dirfd: u64,
path: uintptr: u64, mode: u64, flags: u64))) {
- err: errno => switch (err) {
- EACCES => false,
- ENOSYS =>
- if (flags == 0) faccessat1(dirfd, path, mode)
- else err,
- * => err,
- },
- n: u64 => {
- assert(n == 0);
- yield true;
- },
+ case err: errno =>
+ switch (err) {
+ case EACCES =>
+ return false;
+ case ENOSYS =>
+ if (flags == 0) {
+ return faccessat1(dirfd, path, mode);
+ } else {
+ return err;
+ };
+ case =>
+ return err;
+ };
+ case n: u64 =>
+ assert(n == 0);
+ return true;
};
};
@@ -330,11 +340,16 @@ export type fcntl_arg = (void | int | *st_flock | *f_owner_ex | *u64);
export fn fcntl(fd: int, cmd: int, arg: fcntl_arg) (int | errno) = {
let _fd = fd: u64, _cmd = cmd: u64;
return wrap_return(match (arg) {
- void => syscall2(SYS_fcntl, _fd, _cmd),
- i: int => syscall3(SYS_fcntl, _fd, _cmd, i: u64),
- l: *st_flock => syscall3(SYS_fcntl, _fd, _cmd, l: uintptr: u64),
- o: *f_owner_ex => syscall3(SYS_fcntl, _fd, _cmd, o: uintptr: u64),
- u: *u64 => syscall3(SYS_fcntl, _fd, _cmd, u: uintptr: u64),
+ case void =>
+ yield syscall2(SYS_fcntl, _fd, _cmd);
+ case i: int =>
+ yield syscall3(SYS_fcntl, _fd, _cmd, i: u64);
+ case l: *st_flock =>
+ yield syscall3(SYS_fcntl, _fd, _cmd, l: uintptr: u64);
+ case o: *f_owner_ex =>
+ yield syscall3(SYS_fcntl, _fd, _cmd, o: uintptr: u64);
+ case u: *u64 =>
+ yield syscall3(SYS_fcntl, _fd, _cmd, u: uintptr: u64);
})?: int;
};
diff --git a/rt/+x86_64/backtrace.ha b/rt/+x86_64/backtrace.ha
@@ -13,8 +13,10 @@ export fn backtrace() frame = frame {
// Returns the frame above the current frame, if any.
export fn nextframe(sframe: frame) (frame | void) = {
let addr = sframe.addr: *nullable *void;
- return match (*addr) {
- null => void,
- a: *void => frame { addr = a }
+ match (*addr) {
+ case a: *void =>
+ return frame { addr = a };
+ case null =>
+ return;
};
};
diff --git a/scripts/gen-stdlib b/scripts/gen-stdlib
@@ -800,12 +800,6 @@ types() {
gen_ssa types
}
-unicode() {
- gen_srcs unicode \
- properties.ha
- gen_ssa unicode
-}
-
unix() {
# XXX: getuid and setuid are probably platform-specific too
gen_srcs unix \
@@ -922,7 +916,6 @@ strio
temp
time
types
-unicode
unix
unix::hosts
unix::passwd
diff --git a/sort/+test.ha b/sort/+test.ha
@@ -8,8 +8,10 @@ fn ncmp(a: const *void, b: const *void) int = {
for (let i = 0z; i < len(nums); i += 1) {
const key = nums[i];
match (search(nums[..], size(int), &key, &ncmp): nullable *int) {
- null => abort(),
- p: *int => assert(p == &nums[i] && *p == nums[i]),
+ case null =>
+ abort();
+ case p: *int =>
+ assert(p == &nums[i] && *p == nums[i]);
};
};
const key = 1337;
diff --git a/stdlib.mk b/stdlib.mk
@@ -154,6 +154,10 @@ hare_stdlib_deps+=$(stdlib_errors)
stdlib_fmt=$(HARECACHE)/fmt/fmt.o
hare_stdlib_deps+=$(stdlib_fmt)
+# gen_lib fnmatch
+stdlib_fnmatch=$(HARECACHE)/fnmatch/fnmatch.o
+hare_stdlib_deps+=$(stdlib_fnmatch)
+
# gen_lib format::elf
stdlib_format_elf=$(HARECACHE)/format/elf/format_elf.o
hare_stdlib_deps+=$(stdlib_format_elf)
@@ -162,10 +166,6 @@ hare_stdlib_deps+=$(stdlib_format_elf)
stdlib_format_xml=$(HARECACHE)/format/xml/format_xml.o
hare_stdlib_deps+=$(stdlib_format_xml)
-# gen_lib fnmatch
-stdlib_fnmatch=$(HARECACHE)/fnmatch/fnmatch.o
-hare_stdlib_deps+=$(stdlib_fnmatch)
-
# gen_lib fs
stdlib_fs=$(HARECACHE)/fs/fs.o
hare_stdlib_deps+=$(stdlib_fs)
@@ -330,10 +330,6 @@ hare_stdlib_deps+=$(stdlib_time)
stdlib_types=$(HARECACHE)/types/types.o
hare_stdlib_deps+=$(stdlib_types)
-# gen_lib unicode
-stdlib_unicode=$(HARECACHE)/unicode/unicode.o
-hare_stdlib_deps+=$(stdlib_unicode)
-
# gen_lib unix
stdlib_unix=$(HARECACHE)/unix/unix.o
hare_stdlib_deps+=$(stdlib_unix)
@@ -571,6 +567,16 @@ $(HARECACHE)/fmt/fmt.ssa: $(stdlib_fmt_srcs) $(stdlib_rt) $(stdlib_bufio) $(stdl
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nfmt \
-t$(HARECACHE)/fmt/fmt.td $(stdlib_fmt_srcs)
+# fnmatch
+stdlib_fnmatch_srcs= \
+ $(STDLIB)/fnmatch/fnmatch.ha
+
+$(HARECACHE)/fnmatch/fnmatch.ssa: $(stdlib_fnmatch_srcs) $(stdlib_rt) $(stdlib_strings) $(stdlib_bytes) $(stdlib_sort) $(stdlib_ascii) $(stdlib_io) $(stdlib_fmt)
+ @printf 'HAREC \t$@\n'
+ @mkdir -p $(HARECACHE)/fnmatch
+ @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nfnmatch \
+ -t$(HARECACHE)/fnmatch/fnmatch.td $(stdlib_fnmatch_srcs)
+
# format::elf
stdlib_format_elf_srcs= \
$(STDLIB)/format/elf/$(ARCH).ha \
@@ -595,16 +601,6 @@ $(HARECACHE)/format/xml/format_xml.ssa: $(stdlib_format_xml_srcs) $(stdlib_rt) $
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nformat::xml \
-t$(HARECACHE)/format/xml/format_xml.td $(stdlib_format_xml_srcs)
-# fnmatch
-stdlib_fnmatch_srcs= \
- $(STDLIB)/fnmatch/fnmatch.ha
-
-$(HARECACHE)/fnmatch/fnmatch.ssa: $(stdlib_fnmatch_srcs) $(stdlib_rt) $(stdlib_strings) $(stdlib_bytes) $(stdlib_sort) $(stdlib_ascii) $(stdlib_io) $(stdlib_fmt)
- @printf 'HAREC \t$@\n'
- @mkdir -p $(HARECACHE)/fnmatch
- @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nfnmatch \
- -t$(HARECACHE)/fnmatch/fnmatch.td $(stdlib_fnmatch_srcs)
-
# fs
stdlib_fs_srcs= \
$(STDLIB)/fs/types.ha \
@@ -1136,16 +1132,6 @@ $(HARECACHE)/types/types.ssa: $(stdlib_types_srcs) $(stdlib_rt)
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Ntypes \
-t$(HARECACHE)/types/types.td $(stdlib_types_srcs)
-# unicode
-stdlib_unicode_srcs= \
- $(STDLIB)/unicode/properties.ha
-
-$(HARECACHE)/unicode/unicode.ssa: $(stdlib_unicode_srcs) $(stdlib_rt)
- @printf 'HAREC \t$@\n'
- @mkdir -p $(HARECACHE)/unicode
- @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nunicode \
- -t$(HARECACHE)/unicode/unicode.td $(stdlib_unicode_srcs)
-
# unix
stdlib_unix_srcs= \
$(STDLIB)/unix/$(PLATFORM)/nice.ha \
@@ -1381,6 +1367,10 @@ hare_testlib_deps+=$(testlib_errors)
testlib_fmt=$(TESTCACHE)/fmt/fmt.o
hare_testlib_deps+=$(testlib_fmt)
+# gen_lib fnmatch
+testlib_fnmatch=$(TESTCACHE)/fnmatch/fnmatch.o
+hare_testlib_deps+=$(testlib_fnmatch)
+
# gen_lib format::elf
testlib_format_elf=$(TESTCACHE)/format/elf/format_elf.o
hare_testlib_deps+=$(testlib_format_elf)
@@ -1389,10 +1379,6 @@ hare_testlib_deps+=$(testlib_format_elf)
testlib_format_xml=$(TESTCACHE)/format/xml/format_xml.o
hare_testlib_deps+=$(testlib_format_xml)
-# gen_lib fnmatch
-testlib_fnmatch=$(TESTCACHE)/fnmatch/fnmatch.o
-hare_testlib_deps+=$(testlib_fnmatch)
-
# gen_lib fs
testlib_fs=$(TESTCACHE)/fs/fs.o
hare_testlib_deps+=$(testlib_fs)
@@ -1557,10 +1543,6 @@ hare_testlib_deps+=$(testlib_time)
testlib_types=$(TESTCACHE)/types/types.o
hare_testlib_deps+=$(testlib_types)
-# gen_lib unicode
-testlib_unicode=$(TESTCACHE)/unicode/unicode.o
-hare_testlib_deps+=$(testlib_unicode)
-
# gen_lib unix
testlib_unix=$(TESTCACHE)/unix/unix.o
hare_testlib_deps+=$(testlib_unix)
@@ -1805,6 +1787,17 @@ $(TESTCACHE)/fmt/fmt.ssa: $(testlib_fmt_srcs) $(testlib_rt) $(testlib_bufio) $(t
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nfmt \
-t$(TESTCACHE)/fmt/fmt.td $(testlib_fmt_srcs)
+# fnmatch
+testlib_fnmatch_srcs= \
+ $(STDLIB)/fnmatch/fnmatch.ha \
+ $(STDLIB)/fnmatch/+test.ha
+
+$(TESTCACHE)/fnmatch/fnmatch.ssa: $(testlib_fnmatch_srcs) $(testlib_rt) $(testlib_strings) $(testlib_bytes) $(testlib_sort) $(testlib_ascii) $(testlib_io) $(testlib_fmt)
+ @printf 'HAREC \t$@\n'
+ @mkdir -p $(TESTCACHE)/fnmatch
+ @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nfnmatch \
+ -t$(TESTCACHE)/fnmatch/fnmatch.td $(testlib_fnmatch_srcs)
+
# format::elf
testlib_format_elf_srcs= \
$(STDLIB)/format/elf/$(ARCH).ha \
@@ -1830,17 +1823,6 @@ $(TESTCACHE)/format/xml/format_xml.ssa: $(testlib_format_xml_srcs) $(testlib_rt)
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nformat::xml \
-t$(TESTCACHE)/format/xml/format_xml.td $(testlib_format_xml_srcs)
-# fnmatch
-testlib_fnmatch_srcs= \
- $(STDLIB)/fnmatch/fnmatch.ha \
- $(STDLIB)/fnmatch/+test.ha
-
-$(TESTCACHE)/fnmatch/fnmatch.ssa: $(testlib_fnmatch_srcs) $(testlib_rt) $(testlib_strings) $(testlib_bytes) $(testlib_sort) $(testlib_ascii) $(testlib_io) $(testlib_fmt)
- @printf 'HAREC \t$@\n'
- @mkdir -p $(TESTCACHE)/fnmatch
- @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nfnmatch \
- -t$(TESTCACHE)/fnmatch/fnmatch.td $(testlib_fnmatch_srcs)
-
# fs
testlib_fs_srcs= \
$(STDLIB)/fs/types.ha \
@@ -2389,16 +2371,6 @@ $(TESTCACHE)/types/types.ssa: $(testlib_types_srcs) $(testlib_rt)
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Ntypes \
-t$(TESTCACHE)/types/types.td $(testlib_types_srcs)
-# unicode
-testlib_unicode_srcs= \
- $(STDLIB)/unicode/properties.ha
-
-$(TESTCACHE)/unicode/unicode.ssa: $(testlib_unicode_srcs) $(testlib_rt)
- @printf 'HAREC \t$@\n'
- @mkdir -p $(TESTCACHE)/unicode
- @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nunicode \
- -t$(TESTCACHE)/unicode/unicode.td $(testlib_unicode_srcs)
-
# unix
testlib_unix_srcs= \
$(STDLIB)/unix/$(PLATFORM)/nice.ha \
diff --git a/strconv/numeric.ha b/strconv/numeric.ha
@@ -4,12 +4,17 @@ use types;
// statically allocated and will be overwritten on subsequent calls; see
// [[strings::dup]] to duplicate the result.
export fn signedtosb(n: types::signed, b: base) const str = {
- return match (n) {
- i: int => itosb(i, b),
- i: i8 => i8tosb(i, b),
- i: i16 => i16tosb(i, b),
- i: i32 => i32tosb(i, b),
- i: i64 => i64tosb(i, b),
+ match (n) {
+ case i: int =>
+ return itosb(i, b);
+ case i: i8 =>
+ return i8tosb(i, b);
+ case i: i16 =>
+ return i16tosb(i, b);
+ case i: i32 =>
+ return i32tosb(i, b);
+ case i: i64 =>
+ return i64tosb(i, b);
};
};
@@ -22,13 +27,19 @@ export fn signedtos(n: types::signed) const str = signedtosb(n, base::DEC);
// is statically allocated and will be overwritten on subsequent calls; see
// [[strings::dup]] to duplicate the result.
export fn unsignedtosb(n: types::unsigned, b: base) const str = {
- return match (n) {
- u: size => ztosb(u, b),
- u: uint => utosb(u, b),
- u: u8 => u8tosb(u, b),
- u: u16 => u16tosb(u, b),
- u: u32 => u32tosb(u, b),
- u: u64 => u64tosb(u, b),
+ match (n) {
+ case u: size =>
+ return ztosb(u, b);
+ case u: uint =>
+ return utosb(u, b);
+ case u: u8 =>
+ return u8tosb(u, b);
+ case u: u16 =>
+ return u16tosb(u, b);
+ case u: u32 =>
+ return u32tosb(u, b);
+ case u: u64 =>
+ return u64tosb(u, b);
};
};
@@ -41,9 +52,11 @@ export fn unsignedtos(n: types::unsigned) const str = unsignedtosb(n, base::DEC)
// 8, 10, or 16. The return value is statically allocated and will be
// overwritten on subsequent calls; see [[strings::dup]] to duplicate the result.
export fn integertosb(n: types::integer, b: base) const str = {
- return match (n) {
- s: types::signed => signedtosb(s, b),
- u: types::unsigned => unsignedtosb(u, b),
+ match (n) {
+ case s: types::signed =>
+ return signedtosb(s, b);
+ case u: types::unsigned =>
+ return unsignedtosb(u, b);
};
};
@@ -57,9 +70,11 @@ export fn integertos(n: types::integer) const str = integertosb(n, base::DEC);
// [[strings::dup]] to duplicate the result.
export fn floatingtosb(n: types::floating, b: base) const str = {
assert(b == base::DEC);
- return match (n) {
- f: f32 => abort(), // TODO
- f: f64 => f64tos(f),
+ match (n) {
+ case f: f32 =>
+ abort(); // TODO
+ case f: f64 =>
+ return f64tos(f);
};
};
@@ -72,9 +87,11 @@ export fn floatingtos(n: types::floating) const str = floatingtosb(n, base::DEC)
// is statically allocated and will be overwritten on subsequent calls; see
// [[strings::dup]] to duplicate the result.
export fn numerictosb(n: types::numeric, b: base) const str = {
- return match (n) {
- i: types::integer => integertosb(i, b),
- f: types::floating => floatingtosb(f, b),
+ match (n) {
+ case i: types::integer =>
+ return integertosb(i, b);
+ case f: types::floating =>
+ return floatingtosb(f, b);
};
};
diff --git a/strconv/stou.ha b/strconv/stou.ha
@@ -27,16 +27,22 @@ export fn stou64b(s: str, base: uint) (u64 | invalid | overflow) = {
let iter = strings::iter(s);
for (true) {
let r: rune = match (strings::next(&iter)) {
- void => break,
- r: rune => r,
+ case r: rune =>
+ yield r;
+ case void =>
+ break;
};
let digit = match (rune_to_integer(r)) {
- void => return (iter.dec.offs - 1): invalid,
- d: u64 => d,
+ case void =>
+ return (iter.dec.offs - 1): invalid;
+ case d: u64 =>
+ yield d;
};
- if (digit >= base: u64) return (iter.dec.offs - 1): invalid;
+ if (digit >= base: u64) {
+ return (iter.dec.offs - 1): invalid;
+ };
let old = n;
@@ -103,12 +109,20 @@ export fn stoub(s: str, base: uint) (uint | invalid | overflow) = {
// returned. Supported bases are 2, 8, 10 and 16.
export fn stozb(s: str, base: uint) (size | invalid | overflow) = {
static assert(size(size) == size(u32) || size(size) == size(u64));
- return if (size(size) == size(u32)) match (stou32b(s, base)) {
- v: (invalid | overflow) => v,
- n: u32 => n: size,
- } else match (stou64b(s, base)) {
- v: (invalid | overflow) => v,
- n: u64 => n: size,
+ if (size(size) == size(u32)) {
+ match (stou32b(s, base)) {
+ case v: (invalid | overflow) =>
+ return v;
+ case n: u32 =>
+ return n: size;
+ };
+ } else {
+ match (stou64b(s, base)) {
+ case v: (invalid | overflow) =>
+ return v;
+ case n: u64 =>
+ return n: size;
+ };
};
};
diff --git a/strings/contains.ha b/strings/contains.ha
@@ -3,8 +3,10 @@ use encoding::utf8;
// Returns true if a string contains a rune or a sub-string.
export fn contains(haystack: str, needle: (str | rune)) bool = match (needle) {
- s: str => bytes::contains(toutf8(haystack), toutf8(s)),
- r: rune => bytes::contains(toutf8(haystack), utf8::encoderune(r)),
+case s: str =>
+ yield bytes::contains(toutf8(haystack), toutf8(s));
+case r: rune =>
+ yield bytes::contains(toutf8(haystack), utf8::encoderune(r));
};
@test fn contains() void = {
diff --git a/strings/cstrings.ha b/strings/cstrings.ha
@@ -22,8 +22,8 @@ export fn cstrlen(cstr: *const char) size = {
export fn fromc_unsafe(cstr: *const char) const str = {
const l = cstrlen(cstr);
const s = types::string {
- data = cstr: *[*]u8,
- length = l,
+ data = cstr: *[*]u8,
+ length = l,
capacity = l,
};
return *(&s: *const str);
@@ -42,12 +42,15 @@ export fn fromc(cstr: *const char) const str = {
export fn to_c(s: const str) *char = {
let ptr = rt::malloc(len(s) + 1): nullable *[*]u8;
let ptr = match (ptr) {
- null => abort("Out of memory"),
- p: *[*]u8 => p,
+ case null =>
+ abort("Out of memory");
+ case p: *[*]u8 =>
+ yield p;
};
match ((&s: *types::string).data) {
- null => void,
- data: *[*]u8 => rt::memcpy(ptr, data, len(s)),
+ case null => void;
+ case data: *[*]u8 =>
+ yield rt::memcpy(ptr, data, len(s));
};
ptr[len(s)] = 0;
return ptr: *char;
diff --git a/strings/dup.ha b/strings/dup.ha
@@ -6,12 +6,16 @@ use types;
export fn dup(s: const str) str = {
const in = &s: *types::string;
const id = match (in.data) {
- null => return "", // Empty string
- b: *[*]u8 => b,
+ case null =>
+ return ""; // Empty string
+ case b: *[*]u8 =>
+ yield b;
};
let buf: *[*]u8 = match (rt::malloc(in.length + 1)) {
- null => abort("Out of memory"),
- v: *void => v,
+ case null =>
+ abort("Out of memory");
+ case v: *void =>
+ yield v;
};
bytes::copy(buf[..in.length + 1z], id[..in.length + 1]);
let out = types::string {
diff --git a/strings/index.ha b/strings/index.ha
@@ -4,17 +4,25 @@ use bytes;
// void if not present. The index returned is the rune-wise index, not the
// byte-wise index.
export fn index(haystack: str, needle: (str | rune)) (size | void) = {
- return match (needle) {
- r: rune => index_rune(haystack, r),
- s: str => abort(), // TODO
+ match (needle) {
+ case r: rune =>
+ return index_rune(haystack, r);
+ case s: str =>
+ abort(); // TODO
};
};
fn index_rune(s: str, r: rune) (size | void) = {
let iter = iter(s);
- for (let i = 0z; true; i += 1) match (next(&iter)) {
- n: rune => if (r == n) return i,
- void => break,
+ for (let i = 0z; true; i += 1) {
+ match (next(&iter)) {
+ case n: rune =>
+ if (r == n) {
+ return i;
+ };
+ case void =>
+ break;
+ };
};
};
diff --git a/strings/iter.ha b/strings/iter.ha
@@ -31,17 +31,17 @@ export fn riter(src: str) iterator = {
// [[unicode::graphiter]] instead.
export fn next(iter: *iterator) (rune | void) = {
match (iter.push) {
- r: rune => {
- iter.push = void;
- return r;
- },
- void => void,
+ case r: rune =>
+ iter.push = void;
+ return r;
+ case void => void;
};
return match (utf8::next(&iter.dec)) {
- r: rune => r,
- void => void,
- (utf8::more | utf8::invalid) =>
- abort("Invalid UTF-8 string (this should not happen)"),
+ case void => void;
+ case (utf8::more | utf8::invalid) =>
+ abort("Invalid UTF-8 string (this should not happen)");
+ case r: rune =>
+ yield r;
};
};
@@ -50,10 +50,12 @@ export fn next(iter: *iterator) (rune | void) = {
export fn prev(iter: *iterator) (rune | void) = {
assert(iter.push is void);
return match (utf8::prev(&iter.dec)) {
- r: rune => r,
- void => void,
- (utf8::more | utf8::invalid) =>
- abort("Invalid UTF-8 string (this should not happen)"),
+ case void =>
+ yield void;
+ case (utf8::more | utf8::invalid) =>
+ abort("Invalid UTF-8 string (this should not happen)");
+ case r: rune =>
+ yield r;
};
};
@@ -79,8 +81,10 @@ export fn iter_str(iter: *iterator) str = {
const expected1 = ['こ', 'ん'];
for (let i = 0z; i < len(expected1); i += 1) {
match (next(&s)) {
- r: rune => assert(r == expected1[i]),
- void => abort(),
+ case r: rune =>
+ assert(r == expected1[i]);
+ case void =>
+ abort();
};
};
assert(iter_str(&s) == "にちは");
@@ -88,8 +92,10 @@ export fn iter_str(iter: *iterator) str = {
const expected2 = ['ん', 'に', 'ち', 'は'];
for (let i = 0z; i < len(expected2); i += 1) {
match (next(&s)) {
- r: rune => assert(r == expected2[i]),
- void => abort(),
+ case r: rune =>
+ assert(r == expected2[i]);
+ case void =>
+ abort();
};
};
assert(next(&s) is void);
@@ -102,8 +108,10 @@ export fn iter_str(iter: *iterator) str = {
const expected3 = ['は', 'ち', 'に'];
for (let i = 0z; i< len(expected3); i += 1) {
match (prev(&s)) {
- r: rune => assert(r == expected3[i]),
- void => abort(),
+ case r: rune =>
+ assert(r == expected3[i]);
+ case void =>
+ abort();
};
};
assert(prev(&s) is void);
diff --git a/strings/sub.ha b/strings/sub.ha
@@ -5,9 +5,11 @@ export type end = void;
fn utf8_byte_len_bounded(iter: *iterator, end: size) size = {
let pos = 0z;
for (let i = 0z; i < end; i += 1) {
- let r: rune = match (strings::next(iter)) {
- void => break,
- r: rune => r,
+ let r = match (strings::next(iter)) {
+ case r: rune =>
+ yield r;
+ case void =>
+ break;
};
pos += utf8::runesz(r);
@@ -18,9 +20,11 @@ fn utf8_byte_len_bounded(iter: *iterator, end: size) size = {
fn utf8_byte_len_unbounded(iter: *iterator) size = {
let pos = 0z;
for (true) {
- let r: rune = match (strings::next(iter)) {
- void => break,
- r: rune => r,
+ let r = match (strings::next(iter)) {
+ case r: rune =>
+ yield r;
+ case void =>
+ break;
};
pos += utf8::runesz(r);
@@ -40,8 +44,10 @@ export fn sub(s: str, start: size, end: (size | end)) str = {
let iter = iter(s);
let starti = utf8_byte_len_bounded(&iter, start);
let endi = match (end) {
- sz: size => starti + utf8_byte_len_bounded(&iter, sz - start),
- end => starti + utf8_byte_len_unbounded(&iter),
+ case sz: size =>
+ yield starti + utf8_byte_len_bounded(&iter, sz - start);
+ case end =>
+ yield starti + utf8_byte_len_unbounded(&iter);
};
let bytes = toutf8(s);
return fromutf8_unsafe(bytes[starti..endi]);
diff --git a/strings/tokenize.ha b/strings/tokenize.ha
@@ -18,16 +18,18 @@ export fn tokenize(s: str, delim: str) tokenizer =
// void if there are no tokens left.
export fn next_token(s: *tokenizer) (str | void) = {
return match (bytes::next_token(s)) {
- b: []u8 => fromutf8(b),
- void => void,
+ case b: []u8 =>
+ yield fromutf8(b);
+ case void => void;
};
};
// Same as next_token(), but does not advance the cursor
export fn peek_token(s: *tokenizer) (str | void) = {
return match (bytes::peek_token(s)) {
- b: []u8 => fromutf8(b),
- void => void,
+ case b: []u8 =>
+ yield fromutf8(b);
+ case void => void;
};
};
@@ -40,24 +42,32 @@ export fn remaining_tokens(s: *tokenizer) str = {
@test fn tokenize() void = {
let tok = tokenize("Hello, my name is drew", " ");
match (next_token(&tok)) {
- s: str => assert(s == "Hello,"),
- void => abort(),
+ case s: str =>
+ assert(s == "Hello,");
+ case void =>
+ abort();
};
match (next_token(&tok)) {
- s: str => assert(s == "my"),
- void => abort(),
+ case s: str =>
+ assert(s == "my");
+ case void =>
+ abort();
};
match (peek_token(&tok)) {
- s: str => assert(s == "name"),
- void => abort(),
+ case s: str =>
+ assert(s == "name");
+ case void =>
+ abort();
};
match (next_token(&tok)) {
- s: str => assert(s == "name"),
- void => abort(),
+ case s: str =>
+ assert(s == "name");
+ case void =>
+ abort();
};
assert(remaining_tokens(&tok) == "is drew");
@@ -89,8 +99,10 @@ export fn splitN(in: str, delim: str, n: size) []str = {
let tok = tokenize(in, delim);
for (let i = 0z; i < n - 1z; i += 1) {
match (next_token(&tok)) {
- s: str => append(toks, s),
- void => return toks,
+ case s: str =>
+ append(toks, s);
+ case void =>
+ return toks;
};
};
append(toks, remaining_tokens(&tok));
diff --git a/strings/trim.ha b/strings/trim.ha
@@ -12,8 +12,10 @@ export fn ltrim(input: str, trim: rune...) str = {
let it = iter(input);
for (true) {
const r = match (next(&it)) {
- r: rune => r,
- void => break,
+ case r: rune =>
+ yield r;
+ case void =>
+ break;
};
let found = false;
for (let i = 0z; i < len(trim); i += 1) {
@@ -40,8 +42,10 @@ export fn rtrim(input: str, trim: rune...) str = {
let it = riter(input);
for (true) {
const r = match (prev(&it)) {
- r: rune => r,
- void => break,
+ case r: rune =>
+ yield r;
+ case void =>
+ break;
};
let found = false;
for (let i = 0z; i < len(trim); i += 1) {
diff --git a/temp/+linux.ha b/temp/+linux.ha
@@ -32,11 +32,12 @@ export fn file(
} else {
oflags |= fs::flags::WRONLY;
};
- return match (os::create(get_tmpdir(), fmode, oflags)) {
- // TODO: Add a custom "close" function which removes the named
- // file
- err: fs::error => named(os::cwd, get_tmpdir(), iomode, mode...),
- f: io::file => f,
+ // TODO: Add a custom "close" function which removes the named file
+ match (os::create(get_tmpdir(), fmode, oflags)) {
+ case err: fs::error =>
+ return named(os::cwd, get_tmpdir(), iomode, mode...);
+ case f: io::file =>
+ return f;
};
};
@@ -74,9 +75,12 @@ export fn named(
const id = *(&rand[0]: *u64);
const fpath = fmt::bsprintf(pathbuf, "{}/temp.{}", path, id);
match (fs::create_file(fs, fpath, fmode, oflags)) {
- errors::exists => continue,
- err: fs::error => return err,
- f: io::file => return f,
+ case errors::exists =>
+ continue;
+ case err: fs::error =>
+ return err;
+ case f: io::file =>
+ return f;
};
};
abort(); // Unreachable
@@ -99,8 +103,8 @@ export fn dir() str = {
let path = path::join(get_tmpdir(), name);
match (os::mkdir(path)) {
- err: fs::error => abort("Could not create temp directory"),
- void => void,
+ case err: fs::error => abort("Could not create temp directory");
+ case void => void;
};
return path;
};
diff --git a/time/+linux/functions.ha b/time/+linux/functions.ha
@@ -31,13 +31,15 @@ export fn sleep(n: duration) void = {
for (true) {
let res = rt::timespec { ... };
match (rt::nanosleep(req, &res)) {
- void => return,
- err: rt::errno => switch (err) {
- rt::EINTR => {
- req = &res;
- },
- * => abort("Unexpected error from nanosleep"),
- },
+ case void =>
+ return;
+ case err: rt::errno =>
+ switch (err) {
+ case rt::EINTR =>
+ req = &res;
+ case =>
+ abort("Unexpected error from nanosleep");
+ };
};
};
};
@@ -80,8 +82,10 @@ fn cgt_vdso() nullable *fn(_: int, _: *rt::timespec) int = {
fn now_vdso(clock: clock, tp: *rt::timespec) (void | rt::errno) = {
const vfn = match (cgt_vdso()) {
- null => return rt::wrap_errno(rt::ENOSYS),
- vfn: *fn(_: int, _: *rt::timespec) int => vfn,
+ case null =>
+ return rt::wrap_errno(rt::ENOSYS);
+ case vfn: *fn(_: int, _: *rt::timespec) int =>
+ yield vfn;
};
const ret = vfn(clock, tp);
if (ret == 0) {
@@ -94,14 +98,18 @@ fn now_vdso(clock: clock, tp: *rt::timespec) (void | rt::errno) = {
export fn now(clock: clock) instant = {
let tp = rt::timespec { ... };
let err = match (now_vdso(clock, &tp)) {
- void => return timespec_to_instant(tp),
- err: rt::errno => err
+ case void =>
+ return timespec_to_instant(tp);
+ case err: rt::errno =>
+ yield err;
};
if (err != rt::wrap_errno(rt::ENOSYS)) {
abort("Unexpected error from clock_gettime");
};
- return match (rt::clock_gettime(clock, &tp)) {
- void => timespec_to_instant(tp),
- err: rt::errno => abort("Unexpected error from clock_gettime"),
+ match (rt::clock_gettime(clock, &tp)) {
+ case void =>
+ return timespec_to_instant(tp);
+ case err: rt::errno =>
+ abort("Unexpected error from clock_gettime");
};
};
diff --git a/unicode/README b/unicode/README
@@ -1,30 +0,0 @@
-This module provides Unicode support for Hare programs.
-
-Programs which deal with basic text manipulation are likely to be served
-sufficiently by the [[encoding::utf8]], [[strings]], [[ascii]], and so on. For
-example, the question of "is this character uppercase?" is often sufficiently
-answered with [[ascii::isupper]], and matters such as Unicode string equivalence
-are often fraught with error potential - for example, a vulnerability was once
-found in a web login form which used a Unicode equivalence comparison on
-usernames, allowing a malicious actor to register a username which was bytewise
-distinct but uniwise equal to a victim, and then use it to log into their
-account. This module also contains a copy of the Unicode Character Database,
-which is rather large, and linking to it will increase the size of your
-binaries.
-
-The purpose of this module is not to handle every day string manipulation, but
-instead to provide support code for software which is explicitly aware of
-internationalization concerns and seeking out functions which specifically
-address those concerns.
-
-This module makes little attempt to be useful without a broader understanding of
-Unicode. The module is close to a 1:1 implementation of the Unicode standard,
-and it is recommended that any reading of this module's API or source code is
-accompanied by a reading of the Unicode standard. The documentation for each
-type and function makes an effort to direct the reader to the appropriate part
-of the Unicode standard.
-
-See the [[i18n]] module for a high-level internationalization API.
-
-The present implementation of this module conforms to Unicode 13.0.0, which was
-released on March 11th, 2020.
diff --git a/unicode/properties.ha b/unicode/properties.ha
@@ -1,1130 +0,0 @@
-// Unicode character blocks. See Blocks.txt in the UCD.
-export type blk = enum {
- ADLAM,
- AEGEAN_NUMBERS,
- AHOM,
- ALCHEMICAL,
- ALPHABETIC_PF,
- ANATOLIAN_HIEROGLYPHS,
- ANCIENT_GREEK_MUSIC,
- ANCIENT_GREEK_NUMBERS,
- ANCIENT_SYMBOLS,
- ARABIC,
- ARABIC_EXT_A,
- ARABIC_MATH,
- ARABIC_PF_A,
- ARABIC_PF_B,
- ARABIC_SUP,
- ARMENIAN,
- ARROWS,
- ASCII,
- AVESTAN,
- BALINESE,
- BAMUM,
- BAMUM_SUP,
- BASSA_VAH,
- BATAK,
- BENGALI,
- BHAIKSUKI,
- BLOCK_ELEMENTS,
- BOPOMOFO,
- BOPOMOFO_EXT,
- BOX_DRAWING,
- BRAHMI,
- BRAILLE,
- BUGINESE,
- BUHID,
- BYZANTINE_MUSIC,
- CARIAN,
- CAUCASIAN_ALBANIAN,
- CHAKMA,
- CHAM,
- CHEROKEE,
- CHEROKEE_SUP,
- CHESS_SYMBOLS,
- CHORASMIAN,
- CJK,
- CJK_COMPAT,
- CJK_COMPAT_FORMS,
- CJK_COMPAT_IDEOGRAPHS,
- CJK_COMPAT_IDEOGRAPHS_SUP,
- CJK_EXT_A,
- CJK_EXT_B,
- CJK_EXT_C,
- CJK_EXT_D,
- CJK_EXT_E,
- CJK_EXT_F,
- CJK_EXT_G,
- CJK_RADICALS_SUP,
- CJK_STROKES,
- CJK_SYMBOLS,
- COMPAT_JAMO,
- CONTROL_PICTURES,
- COPTIC,
- COPTIC_EPACT_NUMBERS,
- COUNTING_ROD,
- CUNEIFORM,
- CUNEIFORM_NUMBERS,
- CURRENCY_SYMBOLS,
- CYPRIOT_SYLLABARY,
- CYRILLIC,
- CYRILLIC_EXT_A,
- CYRILLIC_EXT_B,
- CYRILLIC_EXT_C,
- CYRILLIC_SUP,
- DESERET,
- DEVANAGARI,
- DEVANAGARI_EXT,
- DIACRITICALS,
- DIACRITICALS_FOR_SYMBOLS,
- DIACRITICALS_SUP,
- DIACRITICALS_EXT,
- DINGBATS,
- DIVES_AKURU,
- DOGRA,
- DOMINO,
- DUPLOYAN,
- EARLY_DYNASTIC_CUNEIFORM,
- EGYPTIAN_HIEROGLYPHS,
- EGYPTIAN_HIEROGLYPH_FORMAT_CONTROLS,
- ELBASAN,
- ELYMAIC,
- EMOTICONS,
- ENCLOSED_ALPHANUM,
- ENCLOSED_ALPHANUM_SUP,
- ENCLOSED_CJK,
- ENCLOSED_IDEOGRAPHIC_SUP,
- ETHIOPIC,
- ETHIOPIC_EXT,
- ETHIOPIC_EXT_A,
- ETHIOPIC_SUP,
- GEOMETRIC_SHAPES,
- GEOMETRIC_SHAPES_EXT,
- GEORGIAN,
- GEORGIAN_EXT,
- GEORGIAN_SUP,
- GLAGOLITIC,
- GLAGOLITIC_SUP,
- GOTHIC,
- GRANTHA,
- GREEK,
- GREEK_EXT,
- GUJARATI,
- GUNJALA_GONDI,
- GURMUKHI,
- HALF_AND_FULL_FORMS,
- HALF_MARKS,
- HANGUL,
- HANIFI_ROHINGYA,
- HANUNOO,
- HATRAN,
- HEBREW,
- HIGH_PU_SURROGATES,
- HIGH_SURROGATES,
- HIRAGANA,
- IDC,
- IDEOGRAPHIC_SYMBOLS,
- IMPERIAL_ARAMAIC,
- INDIC_NUMBER_FORMS,
- INDIC_SIYAQ_NUMBERS,
- INSCRIPTIONAL_PAHLAVI,
- INSCRIPTIONAL_PARTHIAN,
- IPA_EXT,
- JAMO,
- JAMO_EXT_A,
- JAMO_EXT_B,
- JAVANESE,
- KAITHI,
- KANA_EXT_A,
- KANA_SUP,
- KANBUN,
- KANGXI,
- KANNADA,
- KATAKANA,
- KATAKANA_EXT,
- KAYAH_LI,
- KHAROSHTHI,
- KHITAN_SMALL_SCRIPT,
- KHMER,
- KHMER_SYMBOLS,
- KHOJKI,
- KHUDAWADI,
- LAO,
- LATIN_1_SUP,
- LATIN_EXT_A,
- LATIN_EXT_ADDITIONAL,
- LATIN_EXT_B,
- LATIN_EXT_C,
- LATIN_EXT_D,
- LATIN_EXT_E,
- LEPCHA,
- LETTERLIKE_SYMBOLS,
- LIMBU,
- LINEAR_A,
- LINEAR_B_IDEOGRAMS,
- LINEAR_B_SYLLABARY,
- LISU,
- LISU_SUP,
- LOW_SURROGATES,
- LYCIAN,
- LYDIAN,
- MAHAJANI,
- MAHJONG,
- MAKASAR,
- MALAYALAM,
- MANDAIC,
- MANICHAEAN,
- MARCHEN,
- MASARAM_GONDI,
- MATH_ALPHANUM,
- MATH_OPERATORS,
- MAYAN_NUMERALS,
- MEDEFAIDRIN,
- MEETEI_MAYEK,
- MEETEI_MAYEK_EXT,
- MENDE_KIKAKUI,
- MEROITIC_CURSIVE,
- MEROITIC_HIEROGLYPHS,
- MIAO,
- MISC_ARROWS,
- MISC_MATH_SYMBOLS_A,
- MISC_MATH_SYMBOLS_B,
- MISC_PICTOGRAPHS,
- MISC_SYMBOLS,
- MISC_TECHNICAL,
- MODI,
- MODIFIER_LETTERS,
- MODIFIER_TONE_LETTERS,
- MONGOLIAN,
- MONGOLIAN_SUP,
- MRO,
- MUSIC,
- MULTANI,
- MYANMAR,
- MYANMAR_EXT_A,
- MYANMAR_EXT_B,
- NABATAEAN,
- NANDINAGARI,
- NB,
- NEW_TAI_LUE,
- NEWA,
- NKO,
- NUMBER_FORMS,
- NUSHU,
- NYIAKENG_PUACHUE_HMONG,
- OCR,
- OGHAM,
- OL_CHIKI,
- OLD_HUNGARIAN,
- OLD_ITALIC,
- OLD_NORTH_ARABIAN,
- OLD_PERMIC,
- OLD_PERSIAN,
- OLD_SOGDIAN,
- OLD_SOUTH_ARABIAN,
- OLD_TURKIC,
- ORIYA,
- ORNAMENTAL_DINGBATS,
- OSAGE,
- OSMANYA,
- OTTOMAN_SIYAQ_NUMBERS,
- PAHAWH_HMONG,
- PALMYRENE,
- PAU_CIN_HAU,
- PHAGS_PA,
- PHAISTOS,
- PHOENICIAN,
- PHONETIC_EXT,
- PHONETIC_EXT_SUP,
- PLAYING_CARDS,
- PSALTER_PAHLAVI,
- PUA,
- PUNCTUATION,
- REJANG,
- RUMI,
- RUNIC,
- SAMARITAN,
- SAURASHTRA,
- SHARADA,
- SHAVIAN,
- SHORTHAND_FORMAT_CONTROLS,
- SIDDHAM,
- SINHALA,
- SINHALA_ARCHAIC_NUMBERS,
- SMALL_FORMS,
- SMALL_KANA_EXT,
- SOGDIAN,
- SORA_SOMPENG,
- SOYOMBO,
- SPECIALS,
- SUNDANESE,
- SUNDANESE_SUP,
- SUP_ARROWS_A,
- SUP_ARROWS_B,
- SUP_ARROWS_C,
- SUP_MATH_OPERATORS,
- SUP_PUA_A,
- SUP_PUA_B,
- SUP_PUNCTUATION,
- SUP_SYMBOLS_AND_PICTOGRAPHS,
- SUPER_AND_SUB,
- SUTTON_SIGNWRITING,
- SYLOTI_NAGRI,
- SYMBOLS_AND_PICTOGRAPHS_EXT_A,
- SYMBOLS_FOR_LEGACY_COMPUTING,
- SYRIAC,
- SYRIAC_SUP,
- TAGALOG,
- TAGBANWA,
- TAGS,
- TAI_LE,
- TAI_THAM,
- TAI_VIET,
- TAI_XUAN_JING,
- TAKRI,
- TAMIL,
- TAMIL_SUP,
- TANGUT,
- TANGUT_COMPONENTS,
- TANGUT_SUP,
- TELUGU,
- THAANA,
- THAI,
- TIBETAN,
- TIFINAGH,
- TIRHUTA,
- TRANSPORT_AND_MAP,
- UCAS,
- UCAS_EXT,
- UGARITIC,
- VAI,
- VEDIC_EXT,
- VERTICAL_FORMS,
- VS,
- VS_SUP,
- WANCHO,
- WARANG_CITI,
- YEZIDI,
- YI_RADICALS,
- YI_SYLLABLES,
- YIJING,
- ZANABAZAR_SQUARE,
-};
-
-// Unicode general character categories. See Unicode section 4.5.
-export type gc = enum {
- // Letter, uppercase
- LU,
- // Letter, lowercase
- LL,
- // Letter, titlecase
- LT,
- // Letter, modifier
- LM,
- // Letter, other
- LO,
- // Mark, nonspacing
- MN,
- // Mark, spacing combining
- MC,
- // Mark, enclosing
- ME,
- // Number, decimal digit
- ND,
- // Number, letter
- NL,
- // Number, other
- NO,
- // Punctuation, connector
- PC,
- // Punctuation, dash
- PD,
- // Punctuation, open
- PS,
- // Punctuation, close
- PE,
- // Punctuation, initial quote
- PI,
- // Punctuation, final quote
- PF,
- // Punctuation, other
- PO,
- // Symbol, math
- SM,
- // Symbol, currency
- SC,
- // Symbol, modifier
- SK,
- // Symbol, other
- SO,
- // Separator, space
- ZS,
- // Separator, line
- ZL,
- // Separator, paragraph
- ZP,
- // Other, control
- CC,
- // Other, format
- CF,
- // Other, surrogate
- CS,
- // Other, private use
- CO,
- // Other, not assigned (including noncharacters)
- CN,
-};
-
-// Bidirectional class. See UAX #9.
-export type bc = enum {
- // Right-to-left (Arabic)
- AL,
- // Arabic number
- AN,
- // Paragraph separator
- B,
- // Boundary neutral
- BN,
- // Common number separator
- CS,
- // European number
- EN,
- // European number separator
- ES,
- // Euromean number terminator
- ET,
- // First strong isolate
- FSI,
- // Left-to-right
- L,
- // Left-to-right embedding
- LRE,
- // Right-to-left isolate
- LRI,
- // Left-to-right override
- LRO,
- // Nonspacing mark
- NSM,
- // Other neutrals
- ON,
- // Pop directional format
- PDF,
- // Pop directional isolate
- PDI,
- // Right-to-left
- R,
- // Right-to-left embedding
- RLE,
- // Right-to-left isolate
- RLI,
- // Right-to-left override
- RLO,
- // Segment separator
- S,
- // Whitespace
- WS,
-};
-
-// Bidi paired bracket type. See BidiBrackets.txt in the UCD.
-export type bpt = enum {
- // Open
- O,
- // Closed
- C,
- // None
- N,
-};
-
-// Decomposition type. See UAX #44, section 5.7.3.
-export type dt = enum {
- // Canonical mapping
- CAN,
- // Otherwise unspecified compatibility character
- COM,
- // Encircled form
- ENC,
- // Final presentation form (Arabic)
- FIN,
- // Font variant (for example, a blackletter form)
- FONT,
- // Vulgar fraction form
- FRA,
- // Initial presentation form (Arabic)
- INIT,
- // Isolated presentation form (Arabic)
- ISO,
- // Medial presentation form (Arabic)
- MED,
- // Narrow (or hankaku) compatibility character
- NAR,
- // No-break version of a space or hyphen
- NB,
- // Small variant form (CNS compatibility)
- SML,
- // CJK squared font variant
- SQR,
- // Subscript form
- SUB,
- // Superscript form
- SUP,
- // Vertical layout presentation form
- VERT,
- // Wide (or zenkaku) compatibility character
- WIDE,
- // None
- NONE,
-};
-
-// Normalization quick-check properties. See UAX #44, section 5.7.5.
-export type quickcheck = enum uint {
- NO = 0b00,
- MAYBE = 0b01,
- YES = 0b11,
-};
-
-// Numeric type. See Unicode section 4.6.
-export type nt = enum {
- // Non-numeric
- NONE,
- // Decimal
- DE,
- // Digit
- DI,
- // Numeric
- NU,
-};
-
-// Character joining class. See Unicode section 9.2.
-export type jt = enum {
- // Non-joining
- U,
- // Join causing
- C,
- // Transparent
- T,
- // Dual joining
- D,
- // Left joining
- L,
- // Right joining
- R,
-};
-
-// Character joining group. See Unicode section 9.2.
-export type jg = enum {
- AFRICAN_FEH,
- AFRICAN_NOON,
- AFRICAN_QAF,
- AIN,
- ALAPH,
- ALEF,
- ALEF_MAQSURAH,
- BEH,
- BETH,
- BURUSHASKI_YEH_BARREE,
- DAL,
- DALATH_RISH,
- E,
- FARSI_YEH,
- FE,
- FEH,
- FINAL_SEMKATH,
- GAF,
- GAMAL,
- HAH,
- HAMZA_ON_HEH_GOAL,
- HE,
- HEH,
- HEH_GOAL,
- HETH,
- HANIFI_ROHINGYA_KINNA_YA,
- HANIFI_ROHINGYA_PA,
- KAF,
- KAPH,
- KHAPH,
- KNOTTED_HEH,
- LAM,
- LAMADH,
- MALAYALAM_NGA,
- MALAYALAM_JA,
- MALAYALAM_NYA,
- MALAYALAM_TTA,
- MALAYALAM_NNA,
- MALAYALAM_NNNA,
- MALAYALAM_BHA,
- MALAYALAM_RA,
- MALAYALAM_LLA,
- MALAYALAM_LLLA,
- MALAYALAM_SSA,
- MANICHAEAN_ALEPH,
- MANICHAEAN_AYIN,
- MANICHAEAN_BETH,
- MANICHAEAN_DALETH,
- MANICHAEAN_DHAMEDH,
- MANICHAEAN_FIVE,
- MANICHAEAN_GIMEL,
- MANICHAEAN_HETH,
- MANICHAEAN_HUNDRED,
- MANICHAEAN_KAPH,
- MANICHAEAN_LAMEDH,
- MANICHAEAN_MEM,
- MANICHAEAN_NUN,
- MANICHAEAN_ONE,
- MANICHAEAN_PE,
- MANICHAEAN_QOPH,
- MANICHAEAN_RESH,
- MANICHAEAN_SADHE,
- MANICHAEAN_SAMEKH,
- MANICHAEAN_TAW,
- MANICHAEAN_TEN,
- MANICHAEAN_TETH,
- MANICHAEAN_THAMEDH,
- MANICHAEAN_TWENTY,
- MANICHAEAN_WAW,
- MANICHAEAN_YODH,
- MANICHAEAN_ZAYIN,
- MEEM,
- MIM,
- NO_JOINING_GROUP,
- NOON,
- NUN,
- NYA,
- PE,
- QAF,
- QAPH,
- REH,
- REVERSED_PE,
- ROHINGYA_YEH,
- SAD,
- SADHE,
- SEEN,
- SEMKATH,
- SHIN,
- STRAIGHT_WAW,
- SWASH_KAF,
- SYRIAC_WAW,
- TAH,
- TAW,
- TEH_MARBUTA,
- TEH_MARBUTA_GOAL,
- TETH,
- WAW,
- YEH,
- YEH_BARREE,
- YEH_WITH_TAIL,
- YUDH,
- YUDH_HE,
- ZAIN,
- ZHAIN,
-};
-
-// Line breaking properties. See UAX #14.
-export type lb = enum {
- // Ambiguous
- AI,
- // Alphabetic
- AL,
- // Break opportunity before and after
- B2,
- // Break after
- BA,
- // Break before
- BB,
- // Mandatory break
- BK,
- // Contingent break opportunity
- CB,
- // Conditional Japanese starter
- CJ,
- // Close punctuation
- CL,
- // Combining mark
- CM,
- // Close parenthesis
- CP,
- // Carriage return
- CR,
- // Emoji base
- EB,
- // Emoji modifier
- EM,
- // Exclamation/interrogation
- EX,
- // Non-breaking ("glue")
- GL,
- // Hangul LV syllable
- H2,
- // Hangul LVT syllable
- H3,
- // Hebrew letter
- HL,
- // Hyphen
- HY,
- // Ideographic
- ID,
- // Inseparable
- IN,
- // Infix numeric separator
- IS,
- // Hangul L Jamo
- JL,
- // Hangul T Jamo
- JT,
- // Hangul V Jamo
- JV,
- // Line feed
- LF,
- // Next line
- NL,
- // Nonstarter
- NS,
- // Numeric
- NU,
- // Open punctuation
- OP,
- // Postfix numeric
- PO,
- // Prefix numeric
- PR,
- // Quotation
- QU,
- // Regional indicator
- RI,
- // Complex context dependent (South East Asian)
- SA,
- // Surrogate
- SG,
- // Space
- SP,
- // Symbols allowing break after
- SY,
- // Word joiner
- WJ,
- // Unknown
- XX,
- // Zero width space
- ZW,
- // Zero width joiner
- ZWJ,
-};
-
-// East-asian width. See UAX #11.
-export type ea = enum {
- // Ambiguous
- A,
- // Fullwidth
- F,
- // Halfwidth
- H,
- // Neutral
- N,
- // Narrow
- NA,
- // Wide
- W,
-};
-
-// Case property. See Unicode section 4.2.
-export type case = enum uint {
- UPPER = 1 << 0,
- LOWER = 1 << 1,
- OTHER_UPPER = 1 << 2,
- OTHER_LOWER = 1 << 3,
-};
-
-// Casing attributes. See Unicode section 4.2.
-export type case_attrs = enum uint {
- // Case ignorable
- CI = 1 << 0,
- // Cased
- CASED = 1 << 1,
- // Changes when casefolded
- CWCF = 1 << 2,
- // Changes when casemapped
- CWCM = 1 << 3,
- // Changes when lowercased
- CWL = 1 << 4,
- // Changes when NFKC casefolded
- CWKCF = 1 << 5,
- // Changes when titlecased
- CWT = 1 << 6,
- // Changes when uppercased
- CWU = 1 << 7,
- // NFKC casefold
- NFKC_CF = 1 << 8,
-};
-
-// Script property. See UAX #24.
-export type script = enum {
- ADLM,
- AGHB,
- AHOM,
- ARAB,
- ARMI,
- ARMN,
- AVST,
- BALI,
- BAMU,
- BASS,
- BATK,
- BENG,
- BHKS,
- BOPO,
- BRAH,
- BRAI,
- BUGI,
- BUHD,
- CAKM,
- CANS,
- CARI,
- CHAM,
- CHER,
- CHRS,
- COPT,
- CPRT,
- CYRL,
- DEVA,
- DIAK,
- DOGR,
- DSRT,
- DUPL,
- ELBA,
- ELYM,
- EGYP,
- ETHI,
- GEOR,
- GLAG,
- GONG,
- GONM,
- GOTH,
- GRAN,
- GREK,
- GUJR,
- GURU,
- HANG,
- HANI,
- HANO,
- HATR,
- HEBR,
- HIRA,
- HLUW,
- HMNG,
- HMNP,
- HRKT,
- HUNG,
- ITAL,
- JAVA,
- KALI,
- KANA,
- KHAR,
- KHMR,
- KHOJ,
- KITS,
- KNDA,
- KTHI,
- LANA,
- LAOO,
- LATN,
- LEPC,
- LIMB,
- LINA,
- LINB,
- LISU,
- LYCI,
- LYDI,
- MAHJ,
- MAKA,
- MAND,
- MANI,
- MARC,
- MEDF,
- MEND,
- MERC,
- MERO,
- MLYM,
- MODI,
- MONG,
- MROO,
- MTEI,
- MULT,
- MYMR,
- NAND,
- NARB,
- NBAT,
- NEWA,
- NKOO,
- NSHU,
- OGAM,
- OLCK,
- ORKH,
- ORYA,
- OSGE,
- OSMA,
- PALM,
- PAUC,
- PERM,
- PHAG,
- PHLI,
- PHLP,
- PHNX,
- PLRD,
- PRTI,
- QAAI,
- ROHG,
- RJNG,
- RUNR,
- SAMR,
- SARB,
- SAUR,
- SGNW,
- SHAW,
- SHRD,
- SIDD,
- SIND,
- SINH,
- SOGD,
- SOGO,
- SORA,
- SOYO,
- SUND,
- SYLO,
- SYRC,
- TAGB,
- TAKR,
- TALE,
- TALU,
- TAML,
- TANG,
- TAVT,
- TELU,
- TFNG,
- TGLG,
- THAA,
- THAI,
- TIBT,
- TIRH,
- UGAR,
- VAII,
- WARA,
- WCHO,
- XPEO,
- XSUX,
- YEZI,
- YIII,
- ZANB,
- ZINH,
- ZYYY,
- ZZZZ,
-};
-
-// Hangul syllable type. See Unicode section 3.12 and 18.6.
-export type hst = enum {
- // Leading consonant
- L,
- // LV syllable
- LV,
- // LVT syllable
- LVT,
- // Trailing consonant
- T,
- // Vowel
- V,
- // Non-applicable
- NA,
-};
-
-// Indic syllabic category. See IndicSyllabicCategory.txt in the UCD.
-export type insc = enum {
- AVAGRAHA,
- BINDU,
- BRAHMI_JOINING_NUMBER,
- CANTILLATION_MARK,
- CONSONANT,
- CONSONANT_DEAD,
- CONSONANT_FINAL,
- CONSONANT_HEAD_LETTER,
- CONSONANT_INITIAL_POSTFIXED,
- CONSONANT_KILLER,
- CONSONANT_MEDIAL,
- CONSONANT_PLACEHOLDER,
- CONSONANT_PRECEDING_REPHA,
- CONSONANT_PREFIXED,
- CONSONANT_REPHA,
- CONSONANT_SUBJOINED,
- CONSONANT_SUCCEEDING_REPHA,
- CONSONANT_WITH_STACKER,
- GEMINATION_MARK,
- INVISIBLE_STACKER,
- JOINER,
- MODIFYING_LETTER,
- NON_JOINER,
- NUKTA,
- NUMBER,
- NUMBER_JOINER,
- OTHER,
- PURE_KILLER,
- REGISTER_SHIFTER,
- SYLLABLE_MODIFIER,
- TONE_LETTER,
- TONE_MARK,
- VIRAMA,
- VISARGA,
- VOWEL,
- VOWEL_DEPENDENT,
- VOWEL_INDEPENDENT,
-};
-
-// Indic positional category. See IndicPositionalCategory.txt in the UCD.
-export type inpc = enum {
- BOTTOM,
- BOTTOM_AND_LEFT,
- BOTTOM_AND_RIGHT,
- LEFT,
- LEFT_AND_RIGHT,
- NA,
- OVERSTRUCK,
- RIGHT,
- TOP,
- TOP_AND_BOTTOM,
- TOP_AND_BOTTOM_AND_LEFT,
- TOP_AND_BOTTOM_AND_RIGHT,
- TOP_AND_LEFT,
- TOP_AND_LEFT_AND_RIGHT,
- TOP_AND_RIGHT,
- VISUAL_ORDER_LEFT,
-};
-
-// Identifier and pattern properties. See UAX #31.
-export type id = enum uint {
- IDS = 1 << 0,
- IDC = 1 << 1,
- OIDS = 1 << 2,
- OIDC = 1 << 2,
- XIDS = 1 << 3,
- XIDC = 1 << 4,
- SYN = 1 << 5,
- WS = 1 << 6,
-};
-
-// Properties related to function and graphics characteristics. This is a
-// synethetic type based on mulitple Unicode properties listed in UAX #42
-// section 4.4.10.
-export type fgc = enum uint {
- DASH = 1 << 0,
- HYPHEN = 1 << 1,
- QUOTATION_MARK = 1 << 2,
- TERMINAL_PUNCTUATION = 1 << 3,
- SENTENCE_TERMINAL = 1 << 4,
- DIACRITIC = 1 << 5,
- EXTENDER = 1 << 6,
- SOFT_DOTTED = 1 << 7,
- ALPHABETIC = 1 << 8,
- OTHER_ALPHABETIC = 1 << 9,
- MATH = 1 << 10,
- OTHER_MATH = 1 << 11,
- HEX_DIGIT = 1 << 12,
- ASCII_HEX_DIGIT = 1 << 13,
- DEFAULT_IGNORABLE_CODE_POINT = 1 << 14,
- OTHER_DEFAULT_IGNORABLE_CODE_POINT = 1 << 15,
- LOGICAL_ORDER_EXCEPTION = 1 << 16,
- PREPENDED_CONCATENATION_MARK = 1 << 17,
- WHITE_SPACE = 1 << 18,
- VERTICAL_ORIENTATION = 1 << 19,
- REGIONAL_INDICATOR = 1 << 20,
-};
-
-// Properties related to boundaries. This is a synethetic type based on mulitple
-// Unicode properties listed in UAX #42 section 4.4.20.
-export type gr = enum uint {
- GR_BASE = 1 << 0,
- GR_EXT = 1 << 1,
-};
-
-// Grapheme cluster break. See UAX #29.
-export type gcb = enum {
- XX,
- CN,
- CR,
- EX,
- L,
- LF,
- LV,
- LVT,
- PP,
- RI,
- SM,
- T,
- V,
- ZWJ,
-};
-
-// Word break. See UAX #29.
-export type wb = enum {
- XX,
- CR,
- DQ,
- EX,
- EXTEND,
- FO,
- HL,
- KA,
- LE,
- LF,
- MB,
- ML,
- MN,
- NL,
- NU,
- RI,
- SQ,
- WSEGSPACE,
- ZWJ,
-};
-
-// Sentence break. See UAX #29.
-export type sb = enum {
- XX,
- AT,
- CL,
- CR,
- EX,
- FO,
- LE,
- LF,
- LO,
- NU,
- SC,
- SE,
- SP,
- ST,
- UP,
-};
-
-// Properties related to ideographs. This is a synethetic type based on mulitple
-// Unicode properties listed in UAX #42 section 4.4.21.
-export type ideo = enum uint {
- IDEO = 1 << 1,
- UIDEO = 1 << 2,
- IDSB = 1 << 3,
- IDST = 1 << 4,
- RADICAL = 1 << 5,
-};
-
-// Miscellaneous properties. This is a synethetic type based on mulitple Unicode
-// properties listed in UAX #42 section 4.4.22.
-export type misc = enum uint {
- DEP = 1 << 0,
- VS = 1 << 1,
- NCHAR = 1 << 2,
-};
-
-// Properties related to Emoji. This is a synethetic type based on mulitple
-// Unicode properties listed in UAX #42 section 4.4.26.
-export type emoji = enum uint {
- EMOJI = 1 << 0,
- EPRES = 1 << 1,
- EMOD = 1 << 2,
- EBASE = 1 << 3,
- ECOMP = 1 << 4,
- EXTPICT = 1 << 5,
-};
diff --git a/unix/+linux/nice.ha b/unix/+linux/nice.ha
@@ -16,8 +16,9 @@ export fn nice(inc: int) (void | errors::error) = {
if (prio < -20) {
prio = -20;
};
- return match (rt::setpriority(rt::PRIO_PROCESS, 0, prio)) {
- void => void,
- err: rt::errno => errors::errno(err),
+ match (rt::setpriority(rt::PRIO_PROCESS, 0, prio)) {
+ case void => void;
+ case err: rt::errno =>
+ return errors::errno(err);
};
};
diff --git a/unix/+linux/umask.ha b/unix/+linux/umask.ha
@@ -5,8 +5,10 @@ use rt;
// Sets the file mode creation mask for the current process and return the
// previous value of the mask.
export fn umask(mode: fs::mode) (fs::mode | errors::error) = {
- return match (rt::umask(mode)) {
- mode: rt::mode_t => mode: fs::mode,
- err: rt::errno => errors::errno(err),
+ match (rt::umask(mode)) {
+ case mode: rt::mode_t =>
+ return mode: fs::mode;
+ case err: rt::errno =>
+ return errors::errno(err);
};
};
diff --git a/unix/hosts/lookup.ha b/unix/hosts/lookup.ha
@@ -18,8 +18,10 @@ export fn lookup(name: str) []ip::addr = {
let addrs: []ip::addr = [];
for (true) {
const line = match (bufio::scanline(&file)) {
- io::EOF => break,
- line: []u8 => line,
+ case io::EOF =>
+ break;
+ case line: []u8 =>
+ yield line;
};
defer free(line);
if (len(line) == 0 || line[0] == '#': u32: u8) {
@@ -30,16 +32,20 @@ export fn lookup(name: str) []ip::addr = {
defer io::close(scanner);
const tok = match (bufio::scantok(scanner, ' ', '\t')!) {
- io::EOF => break,
- tok: []u8 => tok,
+ case io::EOF =>
+ break;
+ case tok: []u8 =>
+ yield tok;
};
defer free(tok);
const addr = ip::parse(strings::fromutf8(tok))!;
for (true) {
const tok = match (bufio::scantok(scanner, ' ', '\t')!) {
- io::EOF => break,
- tok: []u8 => tok,
+ case io::EOF =>
+ break;
+ case tok: []u8 =>
+ yield tok;
};
defer free(tok);
diff --git a/unix/passwd/group.ha b/unix/passwd/group.ha
@@ -20,12 +20,16 @@ export type grent = struct {
// using [[grent_finish]].
export fn nextgr(stream: *io::stream) (grent | io::EOF | io::error | invalid) = {
let line = match (bufio::scanline(stream)?) {
- ln: []u8 => ln,
- io::EOF => return io::EOF,
+ case ln: []u8 =>
+ yield ln;
+ case io::EOF =>
+ return io::EOF;
};
let line = match (strings::try_fromutf8(line)) {
- s: str => s,
- * => return invalid,
+ case s: str =>
+ yield s;
+ case =>
+ return invalid;
};
let fields = strings::split(line, ":");
@@ -36,8 +40,10 @@ export fn nextgr(stream: *io::stream) (grent | io::EOF | io::error | invalid) =
};
let gid = match (strconv::stou(fields[2])) {
- u: uint => u,
- * => return invalid,
+ case u: uint =>
+ yield u;
+ case =>
+ return invalid;
};
return grent {
@@ -61,16 +67,21 @@ export fn grent_finish(ent: grent) void = {
// See [[nextgr]] for low-level parsing API.
export fn getgroup(name: str) (grent | void) = {
let file = match (os::open("/etc/group")) {
- f: io::file => f,
- * => abort("Unable to open /etc/group"),
+ case f: io::file =>
+ yield f;
+ case =>
+ abort("Unable to open /etc/group");
};
defer io::close(&file);
for (true) {
let ent = match (nextgr(&file)) {
- e: grent => e,
- io::EOF => break,
- * => abort("Invalid entry in /etc/group"),
+ case e: grent =>
+ yield e;
+ case io::EOF =>
+ break;
+ case =>
+ abort("Invalid entry in /etc/group");
};
if (ent.name == name) {
diff --git a/unix/passwd/passwd.ha b/unix/passwd/passwd.ha
@@ -26,12 +26,16 @@ export type pwent = struct {
// result using [[pwent_finish]].
export fn nextpw(stream: *io::stream) (pwent | io::EOF | io::error | invalid) = {
let line = match (bufio::scanline(stream)?) {
- io::EOF => return io::EOF,
- ln: []u8 => ln,
+ case io::EOF =>
+ return io::EOF;
+ case ln: []u8 =>
+ yield ln;
};
let line = match (strings::try_fromutf8(line)) {
- s: str => s,
- * => return invalid,
+ case s: str =>
+ yield s;
+ case =>
+ return invalid;
};
let fields = strings::split(line, ":");
@@ -42,13 +46,17 @@ export fn nextpw(stream: *io::stream) (pwent | io::EOF | io::error | invalid) =
};
let uid = match (strconv::stou(fields[2])) {
- u: uint => u,
- * => return invalid,
+ case u: uint =>
+ yield u;
+ case =>
+ return invalid;
};
let gid = match (strconv::stou(fields[3])) {
- u: uint => u,
- * => return invalid,
+ case u: uint =>
+ yield u;
+ case =>
+ return invalid;
};
return pwent {
@@ -78,16 +86,21 @@ export fn pwent_finish(ent: pwent) void = {
// See [[nextpw]] for low-level parsing API.
export fn getuser(username: str) (pwent | void) = {
let file = match (os::open("/etc/passwd")) {
- f: io::file => f,
- * => abort("Can't open /etc/passwd"),
+ case f: io::file =>
+ yield f;
+ case =>
+ abort("Can't open /etc/passwd");
};
defer io::close(&file);
for (true) {
let ent = match (nextpw(&file)) {
- e: pwent => e,
- io::EOF => break,
- * => abort("Invalid entry in /etc/passwd"),
+ case e: pwent =>
+ yield e;
+ case io::EOF =>
+ break;
+ case =>
+ abort("Invalid entry in /etc/passwd");
};
if (ent.username == username) {
diff --git a/unix/poll/+linux.ha b/unix/poll/+linux.ha
@@ -38,8 +38,10 @@ export fn poll(
) (uint | errors::error) = {
let ts = rt::timespec { ... };
time::duration_to_timespec(timeout, &ts);
- return match (rt::ppoll(fds: *[*]pollfd, len(fds), &ts, null)) {
- err: rt::errno => errors::errno(err),
- n: int => n: uint,
+ match (rt::ppoll(fds: *[*]pollfd, len(fds), &ts, null)) {
+ case err: rt::errno =>
+ return errors::errno(err);
+ case n: int =>
+ return n: uint;
};
};
diff --git a/unix/resolvconf/load.ha b/unix/resolvconf/load.ha
@@ -27,8 +27,10 @@ export fn load() []ip::addr = {
for (true) {
const line = match (bufio::scanline(&file)) {
- io::EOF => break,
- line: []u8 => line,
+ case io::EOF =>
+ break;
+ case line: []u8 =>
+ yield line;
};
defer free(line);
if (len(line) == 0 || line[0] == '#': u32: u8) {
@@ -39,8 +41,10 @@ export fn load() []ip::addr = {
defer io::close(scanner);
const tok = match (bufio::scantok(scanner, ' ', '\t')!) {
- io::EOF => break,
- tok: []u8 => tok,
+ case io::EOF =>
+ break;
+ case tok: []u8 =>
+ yield tok;
};
defer free(tok);
if (strings::fromutf8(tok) != "nameserver") {
@@ -48,8 +52,10 @@ export fn load() []ip::addr = {
};
const tok = match (bufio::scantok(scanner, ' ')!) {
- io::EOF => break,
- tok: []u8 => tok,
+ case io::EOF =>
+ break;
+ case tok: []u8 =>
+ yield tok;
};
defer free(tok);
append(cache, ip::parse(strings::fromutf8(tok))!);
diff --git a/unix/tty/+linux/isatty.ha b/unix/tty/+linux/isatty.ha
@@ -5,12 +5,16 @@ use os;
// Returns whether the given stream is connected to a terminal.
export fn isatty(stream: *io::stream) bool = {
let fd = match (io::unwrapfd(stream)) {
- void => return false,
- fd: int => fd,
+ case void =>
+ return false;
+ case fd: int =>
+ yield fd;
};
let wsz = rt::winsize { ... };
- return match (rt::ioctl(fd, rt::TIOCGWINSZ, &wsz: *void)) {
- e: rt::errno => false,
- r: int => if (r == 0) true else false,
+ match (rt::ioctl(fd, rt::TIOCGWINSZ, &wsz: *void)) {
+ case e: rt::errno =>
+ return false;
+ case r: int =>
+ return r == 0;
};
};
diff --git a/unix/tty/+linux/open.ha b/unix/tty/+linux/open.ha
@@ -6,9 +6,10 @@ use os;
// Returns a stream connected to the TTY of the current process. The caller must
// close it using [[io::close]].
export fn open() (io::file | error) = {
- return match (os::open("/dev/tty", fs::flags::RDWR,
- fs::flags::CLOEXEC)) {
- f: io::file => f,
- fs::error => errors::noentry,
+ match (os::open("/dev/tty", fs::flags::RDWR, fs::flags::CLOEXEC)) {
+ case f: io::file =>
+ return f;
+ case fs::error =>
+ return errors::noentry;
};
};
diff --git a/unix/tty/+linux/winsize.ha b/unix/tty/+linux/winsize.ha
@@ -6,19 +6,26 @@ use rt;
// Returns the dimensions of underlying terminal of the stream.
export fn winsize(tty: *io::stream) (ttysize | error) = {
let fd = match (io::unwrapfd(tty)) {
- void => return errors::unsupported,
- fd: int => fd,
+ case void =>
+ return errors::unsupported;
+ case fd: int =>
+ yield fd;
};
let wsz = rt::winsize { ... };
- return match (rt::ioctl(fd, rt::TIOCGWINSZ, &wsz: *void)) {
- e: rt::errno => switch (e: int) {
- rt::EBADFD => errors::invalid,
- rt::ENOTTY => errors::unsupported,
- * => abort("unreachable"),
- },
- int => ttysize {
+ match (rt::ioctl(fd, rt::TIOCGWINSZ, &wsz: *void)) {
+ case e: rt::errno =>
+ switch (e: int) {
+ case rt::EBADFD =>
+ return errors::invalid;
+ case rt::ENOTTY =>
+ return errors::unsupported;
+ case =>
+ abort("Unexpected error from ioctl");
+ };
+ case int =>
+ return ttysize {
rows = wsz.ws_row,
columns = wsz.ws_col,
- },
+ };
};
};
diff --git a/uuid/uuid.ha b/uuid/uuid.ha
@@ -111,23 +111,30 @@ export fn decode(in: *io::stream) (uuid | invalid | io::error) = {
for (let i = 0z; i < len(u); i += 1) {
let buf: [2]u8 = [0...];
match (io::read(in, buf)?) {
- io::EOF => return invalid,
- z: size => assert(z == len(buf)),
+ case io::EOF =>
+ return invalid;
+ case z: size =>
+ assert(z == len(buf));
};
u[i] = match (strconv::stou8b(
strings::fromutf8_unsafe(buf),
strconv::base::HEX)) {
- strconv::overflow => abort(),
- strconv::invalid => return invalid,
- u: u8 => u,
+ case strconv::overflow =>
+ abort();
+ case strconv::invalid =>
+ return invalid;
+ case u: u8 =>
+ yield u;
};
if (i + 1 == TIME_MID
|| i + 1 == TIME_HI_AND_VERSION
|| i + 1 == CLOCK_SEQ_HI_AND_RESERVED
|| i + 1 == NODE) {
match (io::read(in, buf[..1])?) {
- io::EOF => return invalid,
- z: size => assert(z == 1),
+ case io::EOF =>
+ return invalid;
+ case z: size =>
+ assert(z == 1);
};
if (buf[0] != '-': u32: u8) {
return invalid;
@@ -141,18 +148,23 @@ export fn decode(in: *io::stream) (uuid | invalid | io::error) = {
export fn decodestr(in: str) (uuid | invalid) = {
let buf = bufio::fixed(strings::toutf8(in), io::mode::READ);
defer io::close(buf);
- return match (decode(buf)) {
- err: io::error => abort(),
- invalid => invalid,
- u: uuid => u,
+ match (decode(buf)) {
+ case err: io::error =>
+ abort();
+ case invalid =>
+ return invalid;
+ case u: uuid =>
+ return u;
};
};
@test fn decode() void = {
let in = "3ded910c-8080-4bc8-af39-b6cccee36741";
let id = match (decodestr(in)) {
- invalid => abort(),
- u: uuid => u,
+ case invalid =>
+ abort();
+ case u: uuid =>
+ yield u;
};
assert(compare(id, [
0x3d, 0xed, 0x91, 0x0c, 0x80, 0x80, 0x4b, 0xc8,