hare

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

commit c97b946439ed6024d4a1381d70e4fd2cdd426db7
parent 904ef3090352080cee6f7a0898cbf32066d3f536
Author: Drew DeVault <sir@cmpwn.com>
Date:   Sat,  4 Sep 2021 11:03:07 +0200

all: return io::file from os::open

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

Diffstat:
Mcmd/harec/errors.ha | 8++++----
Mcmd/harec/main.ha | 6+++---
Mcmd/haredoc/hare.ha | 6+++---
Mcmd/haredoc/html.ha | 6+++---
Mcmd/haredoc/main.ha | 20++++++++++----------
Mcmd/haredoc/tty.ha | 6+++---
Mfs/fs.ha | 4++--
Mfs/types.ha | 4++--
Mhare/module/manifest.ha | 24++++++++++++------------
Mio/+linux/file.ha | 15++++++++++-----
Mos/+linux/dirfdfs.ha | 14++++++++------
Mos/fs.ha | 6+++---
Mtemp/+linux.ha | 10+++++-----
Munix/hosts/lookup.ha | 4++--
Munix/passwd/group.ha | 6+++---
Munix/passwd/passwd.ha | 6+++---
Munix/resolvconf/load.ha | 4++--
Munix/tty/+linux/open.ha | 4++--
18 files changed, 80 insertions(+), 73 deletions(-)

diff --git a/cmd/harec/errors.ha b/cmd/harec/errors.ha @@ -16,18 +16,18 @@ fn printerr(err: parse::error) void = { fn printerr_syntax(err: lex::syntax) void = { let location = err.0, details = err.1; - let file = os::open(location.path) as *io::stream; - defer io::close(file); + let file = os::open(location.path)!; + defer io::close(&file); let line = 1u; for (line < location.line) { - let r = bufio::scanrune(file) as rune; + let r = bufio::scanrune(&file) as rune; if (r == '\n') { line += 1u; }; }; - let line = bufio::scanline(file) as []u8; + let line = bufio::scanline(&file) as []u8; defer free(line); let line = strings::fromutf8(line); fmt::errorfln("{}:{},{}: Syntax error: {}", diff --git a/cmd/harec/main.ha b/cmd/harec/main.ha @@ -51,13 +51,13 @@ export fn main() void = { for (let i = 0z; i < len(cmd.args); i += 1) { let input = match (os::open(cmd.args[i])) { - f: *io::stream => f, + f: io::file => f, err: io::error => fmt::fatal("Error opening {}: {}", cmd.args[i], io::strerror(err)), }; - defer io::close(input); + defer io::close(&input); static let buf: [os::BUFSIZ]u8 = [0...]; - let bufin = bufio::buffered(input, buf, []); + let bufin = bufio::buffered(&input, buf, []); defer io::close(bufin); let lexer = lex::init(bufin, cmd.args[i]); diff --git a/cmd/haredoc/hare.ha b/cmd/haredoc/hare.ha @@ -14,9 +14,9 @@ fn emit_hare(ctx: *context) (void | error) = { let first = true; match (ctx.readme) { - readme: *io::stream => { + readme: io::file => { first = false; - for (true) match (bufio::scanline(readme)?) { + for (true) match (bufio::scanline(&readme)?) { b: []u8 => { fmt::printfln("// {}", strings::fromutf8(b))?; free(b); @@ -24,7 +24,7 @@ fn emit_hare(ctx: *context) (void | error) = { io::EOF => break, }; }, - null => void, + void => void, }; // XXX: Should we emit the dependencies, too? diff --git a/cmd/haredoc/html.ha b/cmd/haredoc/html.ha @@ -71,10 +71,10 @@ fn emit_html(ctx: *context) (void | error) = { fmt::println("</span></h2>")?; match (ctx.readme) { - null => void, - f: *io::stream => { + void => void, + f: io::file => { fmt::println("<div class='readme'>")?; - markup_html(ctx, f)?; + markup_html(ctx, &f)?; fmt::println("</div>")?; }, }; diff --git a/cmd/haredoc/main.ha b/cmd/haredoc/main.ha @@ -27,7 +27,7 @@ type context = struct { format: format, template: bool, show_undocumented: bool, - readme: nullable *io::stream, + readme: (io::file | void), }; export fn main() void = { @@ -110,15 +110,15 @@ export fn main() void = { const rpath = path::join(version.basedir, "README"); defer free(rpath); - const readme: nullable *io::stream = if (decl == "") { + const readme: (io::file | void) = if (decl == "") { yield match (os::open(rpath)) { - err: fs::error => null, - f: *io::stream => f, + err: fs::error => void, + f: io::file => f, }; - } else null; + } else void; defer match (readme) { - null => void, - f: *io::stream => io::close(f), + void => void, + f: io::file => io::close(&f), }; if (decl != "") { @@ -176,12 +176,12 @@ fn has_decl(decl: ast::decl, name: str) bool = { fn scan(path: str) (ast::subunit | error) = { const input = match (os::open(path)) { - s: *io::stream => s, + f: io::file => f, err: fs::error => fmt::fatal("Error reading {}: {}", path, fs::strerror(err)), }; - defer io::close(input); - const lexer = lex::init(input, path, lex::flags::COMMENTS); + defer io::close(&input); + const lexer = lex::init(&input, path, lex::flags::COMMENTS); return parse::subunit(&lexer)?; }; diff --git a/cmd/haredoc/tty.ha b/cmd/haredoc/tty.ha @@ -16,8 +16,8 @@ fn emit_tty(ctx: *context) (void | error) = { const summary = ctx.summary; match (ctx.readme) { - readme: *io::stream => { - for (true) match (bufio::scanline(readme)?) { + readme: io::file => { + for (true) match (bufio::scanline(&readme)?) { b: []u8 => { firstline = false; fmt::printfln( @@ -28,7 +28,7 @@ fn emit_tty(ctx: *context) (void | error) = { io::EOF => break, }; }, - null => void, + void => void, }; // XXX: Should we emit the dependencies, too? diff --git a/fs/fs.ha b/fs/fs.ha @@ -24,7 +24,7 @@ export fn open(fs: *fs, path: str, flags: flags...) (*io::stream | error) = { // filesystem implementations (such cases will return [[io::unsupported]]). // // 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) = { +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...), @@ -56,7 +56,7 @@ export fn create_file( path: str, mode: mode, flags: flags... -) (*io::file | error) = { +) (io::file | error) = { return match (fs.createfile) { null => errors::unsupported, f: *createfilefunc => f(fs, path, mode, flags...), diff --git a/fs/types.ha b/fs/types.ha @@ -187,7 +187,7 @@ export type openfilefunc = fn( fs: *fs, path: str, flags: flags... -) (*io::file | error); +) (io::file | error); export type createfunc = fn( fs: *fs, @@ -201,7 +201,7 @@ export type createfilefunc = fn( path: str, mode: mode, flags: flags... -) (*io::file | error); +) (io::file | error); // An abstract implementation of a filesystem, which provides common filesystem // operations such as file creation and deletion, but which may be backed by any diff --git a/hare/module/manifest.ha b/hare/module/manifest.ha @@ -233,18 +233,18 @@ export fn manifest_write(ctx: *context, manifest: *manifest) (void | error) = { let mpath = path::join(cachedir, "manifest"); defer free(mpath); - let fd = temp::named(ctx.fs, cachedir, io::mode::WRITE, 0o644)?; + let file = temp::named(ctx.fs, cachedir, io::mode::WRITE, 0o644)?; defer { - fs::remove(ctx.fs, fd.name): void; - io::close(fd); + fs::remove(ctx.fs, file.name): void; + io::close(&file); }; let ident = unparse::identstr(manifest.ident); defer free(ident); - fmt::fprintfln(fd, "# {}", ident)?; - fmt::fprintln(fd, "# This file is an internal Hare implementation detail.")?; - fmt::fprintln(fd, "# The format is not stable.")?; - fmt::fprintfln(fd, "version {}", VERSION)?; + fmt::fprintfln(&file, "# {}", ident)?; + fmt::fprintln(&file, "# This file is an internal Hare implementation detail.")?; + fmt::fprintln(&file, "# The format is not stable.")?; + fmt::fprintfln(&file, "version {}", VERSION)?; for (let i = 0z; i < len(manifest.inputs); i += 1) { const input = manifest.inputs[i]; let hash = hex::encodestr(input.hash); @@ -252,7 +252,7 @@ export fn manifest_write(ctx: *context, manifest: *manifest) (void | error) = { const want = fs::stat_mask::INODE | fs::stat_mask::MTIME; assert(input.stat.mask & want == want); - fmt::fprintfln(fd, "input {} {} {} {}", + fmt::fprintfln(&file, "input {} {} {} {}", hash, input.path, input.stat.inode, time::unix(input.stat.mtime))?; }; @@ -262,19 +262,19 @@ export fn manifest_write(ctx: *context, manifest: *manifest) (void | error) = { let hash = hex::encodestr(ver.hash); defer free(hash); - fmt::fprintf(fd, "module {}", hash)?; + fmt::fprintf(&file, "module {}", hash)?; for (let j = 0z; j < len(ver.inputs); j += 1) { let hash = hex::encodestr(ver.inputs[i].hash); defer free(hash); - fmt::fprintf(fd, " {}", hash)?; + fmt::fprintf(&file, " {}", hash)?; }; - fmt::fprintln(fd)?; + fmt::fprintln(&file)?; }; - fs::move(ctx.fs, fd.name, mpath)?; + fs::move(ctx.fs, file.name, mpath)?; }; fn input_finish(in: *input) void = { diff --git a/io/+linux/file.ha b/io/+linux/file.ha @@ -33,14 +33,19 @@ export fn fdopen(fd: int, name: str, mode: mode) file = { return stream; }; +// Duplicates a [[file]] onto the heap, as if it were opened with [[fdalloc]]. +export fn filedup(f: *file) *file = { + let new = alloc(*f); + new.closer = &fd_close; + return new; +}; + // Similar to [[fdopen]], but heap-allocates the file. Closing the stream will // free the associated resources. -export fn fdalloc(fd: int, name: str, mode: mode) *file = { - let file = alloc(fdopen(fd, strings::dup(name), mode)); - file.closer = &fd_close; - return file; -}; +export fn fdalloc(fd: int, name: str, mode: mode) *file = + filedup(&fdopen(fd, strings::dup(name), mode)); +// Returns true if a [[stream]] is a file. export fn is_file(s: *stream) bool = { return s.reader == &fd_read || s.writer == &fd_write diff --git a/os/+linux/dirfdfs.ha b/os/+linux/dirfdfs.ha @@ -126,7 +126,7 @@ fn _fs_open( path: str, mode: io::mode, oh: *rt::open_how, -) (*io::file | fs::error) = { +) (io::file | fs::error) = { let fs = fs: *os_filesystem; oh.resolve = 0u64; @@ -148,14 +148,14 @@ fn _fs_open( fd: int => fd, }; - return io::fdalloc(fd, path, mode); + return io::fdopen(fd, path, mode); }; fn fs_open_file( fs: *fs::fs, path: str, flags: fs::flags... -) (*io::file | fs::error) = { +) (io::file | fs::error) = { let oflags = 0; let iomode = io::mode::NONE; if (len(flags) == 0z) { @@ -192,14 +192,14 @@ fn fs_open( fs: *fs::fs, path: str, flags: fs::flags... -) (*io::stream | fs::error) = fs_open_file(fs, path, flags...)?; +) (*io::stream | fs::error) = io::filedup(&fs_open_file(fs, path, flags...)?); fn fs_create_file( fs: *fs::fs, path: str, mode: fs::mode, flags: fs::flags... -) (*io::file | fs::error) = { +) (io::file | fs::error) = { let oflags = 0; let iomode = io::mode::NONE; if (len(flags) == 0z) { @@ -233,7 +233,9 @@ fn fs_create( path: str, mode: fs::mode, flags: fs::flags... -) (*io::stream | fs::error) = fs_create_file(fs, path, mode, flags...)?; +) (*io::stream | fs::error) = { + return io::filedup(&fs_create_file(fs, path, mode, flags...)?); +}; fn fs_remove(fs: *fs::fs, path: str) (void | fs::error) = { let fs = fs: *os_filesystem; diff --git a/os/fs.ha b/os/fs.ha @@ -66,8 +66,8 @@ export fn resolve(path: str) str = fs::resolve(cwd, path); // [[fs::flags::CLOEXEC]] are used when opening the file. If you pass your own // flags, it is recommended that you add the latter two unless you know that you // do not want them. -export fn open(path: str, flags: fs::flags...) (*io::stream | fs::error) = - fs::open(cwd, path, flags...); +export fn open(path: str, flags: fs::flags...) (io::file | fs::error) = + fs::open_file(cwd, path, flags...); // Creates a new file and opens it for writing. // @@ -82,4 +82,4 @@ export fn create( path: str, mode: fs::mode, flags: fs::flags... -) (*io::stream | fs::error) = fs::create(cwd, path, mode, flags...); +) (io::file | fs::error) = fs::create_file(cwd, path, mode, flags...); diff --git a/temp/+linux.ha b/temp/+linux.ha @@ -22,7 +22,7 @@ fn get_tmpdir() str = os::tryenv("TMPDIR", "/tmp"); export fn file( iomode: io::mode, mode: fs::mode... -) (*io::stream | fs::error) = { +) (io::file | fs::error) = { assert(iomode == io::mode::WRITE || iomode == io::mode::RDWR); assert(len(mode) == 0 || len(mode) == 1); let fmode = if (len(mode) != 0) mode[0] else 0o644: fs::mode; @@ -36,7 +36,7 @@ export fn file( // TODO: Add a custom "close" function which removes the named // file err: fs::error => named(os::cwd, get_tmpdir(), iomode, mode...), - s: *io::stream => s, + f: io::file => f, }; }; @@ -54,7 +54,7 @@ export fn named( path: str, iomode: io::mode, mode: fs::mode... -) (*io::stream | fs::error) = { +) (io::file | fs::error) = { assert(iomode == io::mode::WRITE || iomode == io::mode::RDWR); assert(len(mode) == 0 || len(mode) == 1); @@ -73,10 +73,10 @@ export fn named( random::buffer(rand); const id = *(&rand[0]: *u64); const fpath = fmt::bsprintf(pathbuf, "{}/temp.{}", path, id); - match (fs::create(fs, fpath, fmode, oflags)) { + match (fs::create_file(fs, fpath, fmode, oflags)) { errors::exists => continue, err: fs::error => return err, - s: *io::stream => return s, + f: io::file => return f, }; }; abort(); // Unreachable diff --git a/unix/hosts/lookup.ha b/unix/hosts/lookup.ha @@ -13,11 +13,11 @@ export fn lookup(name: str) []ip::addr = { // XXX: Would be cool if we could do this without allocating anything // XXX: Would be cool to have meaningful error handling(?) const file = os::open(path)!; - defer io::close(file); + defer io::close(&file); let addrs: []ip::addr = []; for (true) { - const line = match (bufio::scanline(file)) { + const line = match (bufio::scanline(&file)) { io::EOF => break, line: []u8 => line, }; diff --git a/unix/passwd/group.ha b/unix/passwd/group.ha @@ -61,13 +61,13 @@ 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")) { - s: *io::stream => s, + f: io::file => f, * => abort("Unable to open /etc/group"), }; - defer io::close(file); + defer io::close(&file); for (true) { - let ent = match (nextgr(file)) { + let ent = match (nextgr(&file)) { e: grent => e, io::EOF => break, * => abort("Invalid entry in /etc/group"), diff --git a/unix/passwd/passwd.ha b/unix/passwd/passwd.ha @@ -78,13 +78,13 @@ 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")) { - s: *io::stream => s, + f: io::file => f, * => abort("Can't open /etc/passwd"), }; - defer io::close(file); + defer io::close(&file); for (true) { - let ent = match (nextpw(file)) { + let ent = match (nextpw(&file)) { e: pwent => e, io::EOF => break, * => abort("Invalid entry in /etc/passwd"), diff --git a/unix/resolvconf/load.ha b/unix/resolvconf/load.ha @@ -23,10 +23,10 @@ export fn load() []ip::addr = { }; const file = os::open(path)!; - defer io::close(file); + defer io::close(&file); for (true) { - const line = match (bufio::scanline(file)) { + const line = match (bufio::scanline(&file)) { io::EOF => break, line: []u8 => line, }; diff --git a/unix/tty/+linux/open.ha b/unix/tty/+linux/open.ha @@ -5,10 +5,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::stream | error) = { +export fn open() (io::file | error) = { return match (os::open("/dev/tty", fs::flags::RDWR, fs::flags::CLOEXEC)) { - s: *io::stream => s, + f: io::file => f, fs::error => errors::noentry, }; };