stdlib: Make io failures recoverable by returning a result

This commit is contained in:
Brian Anderson 2011-10-28 21:19:59 -07:00
parent 2b62a80202
commit 2cebef095e
11 changed files with 123 additions and 37 deletions

View File

@ -11,7 +11,7 @@ import syntax::print::{pp, pprust};
import util::{ppaux, common, filesearch};
import back::link;
import lib::llvm;
import std::{fs, option, str, vec, int, io, run, getopts};
import std::{fs, option, str, vec, int, io, run, getopts, result};
import std::map::mk_hashmap;
import std::option::{some, none};
import std::getopts::{optopt, optmulti, optflag, optflagopt, opt_present};
@ -77,10 +77,16 @@ fn parse_input(sess: session::session, cfg: ast::crate_cfg, input: str) ->
fn parse_input_src(sess: session::session, cfg: ast::crate_cfg, infile: str)
-> {crate: @ast::crate, src: str} {
let srcbytes =
if infile != "-" {
io::file_reader(infile)
} else { io::stdin() }.read_whole_stream();
let srcbytes = if infile != "-" {
alt io::file_reader(infile) {
result::ok(reader) { reader }
result::err(e) {
sess.fatal(e)
}
}
} else {
io::stdin()
}.read_whole_stream();
let src = str::unsafe_from_bytes(srcbytes);
let crate =
parser::parse_crate_from_source_str(infile, src, cfg,

View File

@ -1,4 +1,4 @@
import std::{vec, uint, str, term, io, option};
import std::{vec, uint, str, term, io, option, result};
import std::option::{some, none};
type filename = str;
@ -154,7 +154,13 @@ fn maybe_highlight_lines(sp: option::t<span>, cm: codemap,
// FIXME: reading in the entire file is the worst possible way to
// get access to the necessary lines.
let file = io::read_whole_file_str(lines.name);
let file = alt io::read_whole_file_str(lines.name) {
result::ok(file) { file }
result::err(e) {
emit_error(none, e, cm);
fail;
}
};
let fm = get_filemap(cm, lines.name);
// arbitrarily only print up to six lines of the error

View File

@ -1,5 +1,5 @@
import std::{io, vec, str, option, either};
import std::{io, vec, str, option, either, result};
import std::option::{some, none};
import std::either::{left, right};
import std::map::{hashmap, new_str_hash};
@ -53,7 +53,16 @@ type parser =
fn new_parser_from_file(sess: parse_sess, cfg: ast::crate_cfg, path: str,
chpos: uint, byte_pos: uint, ftype: file_type) ->
parser {
let src = io::read_whole_file_str(path);
let src = alt io::read_whole_file_str(path) {
result::ok(src) {
// FIXME: This copy is unfortunate
src
}
result::err(e) {
codemap::emit_error(none, e, sess.cm);
fail;
}
};
let filemap = codemap::new_filemap(path, chpos, byte_pos);
sess.cm.files += [filemap];
let itr = @interner::mk(str::hash, str::eq);

View File

@ -63,7 +63,7 @@ fn is_test_ignored(config: config, testfile: str) -> bool {
}
fn iter_header(testfile: str, it: block(str)) {
let rdr = io::file_reader(testfile);
let rdr = std::result::get(io::file_reader(testfile));
while !rdr.eof() {
let ln = rdr.read_line();

View File

@ -5,6 +5,7 @@ import std::fs;
import std::os;
import std::vec;
import std::test;
import std::result;
import common::mode_run_pass;
import common::mode_run_fail;
@ -92,7 +93,7 @@ fn run_pretty_test(cx: cx, props: test_props, testfile: str) {
let rounds =
alt props.pp_exact { option::some(_) { 1 } option::none. { 2 } };
let srcs = [io::read_whole_file_str(testfile)];
let srcs = [result::get(io::read_whole_file_str(testfile))];
let round = 0;
while round < rounds {
@ -112,7 +113,7 @@ fn run_pretty_test(cx: cx, props: test_props, testfile: str) {
alt props.pp_exact {
option::some(file) {
let filepath = fs::connect(fs::dirname(testfile), file);
io::read_whole_file_str(filepath)
result::get(io::read_whole_file_str(filepath))
}
option::none. { srcs[vec::len(srcs) - 2u] }
};
@ -339,7 +340,8 @@ fn dump_output(config: config, testfile: str, out: str, err: str) {
#[cfg(target_os = "linux")]
fn dump_output_file(config: config, testfile: str, out: str, extension: str) {
let outfile = make_out_name(config, testfile, extension);
let writer = io::file_writer(outfile, [io::create, io::truncate]);
let writer = result::get(
io::file_writer(outfile, [io::create, io::truncate]));
writer.write_str(out);
}

View File

@ -1,7 +1,7 @@
use std;
use rustc;
import std::{fs, io, getopts, math, vec, str, int, uint, option};
import std::{fs, io, getopts, math, vec, str, int, uint, option, result};
import std::getopts::{optopt, opt_present, opt_str};
import std::io::stdout;
@ -13,7 +13,9 @@ tag test_mode { tm_converge; tm_run; }
type context = { mode: test_mode }; // + rng
fn write_file(filename: str, content: str) {
io::file_writer(filename, [io::create, io::truncate]).write_str(content);
result::get(
io::file_writer(filename, [io::create, io::truncate]))
.write_str(content);
// Work around https://github.com/graydon/rust/issues/726
std::run::run_program("chmod", ["644", filename]);
}
@ -517,7 +519,7 @@ fn check_convergence(files: [str]) {
log_err #fmt["pp convergence tests: %u files", vec::len(files)];
for file in files {
if !file_might_not_converge(file) {
let s = io::read_whole_file_str(file);
let s = result::get(io::read_whole_file_str(file));
if !content_might_not_converge(s) {
log_err #fmt["pp converge: %s", file];
// Change from 7u to 2u once https://github.com/graydon/rust/issues/850 is fixed
@ -533,7 +535,7 @@ fn check_variants(files: [str], cx: context) {
cont;
}
let s = io::read_whole_file_str(file);
let s = result::get(io::read_whole_file_str(file));
if contains(s, "#") {
cont; // Macros are confusing
}

View File

@ -173,14 +173,16 @@ fn stdin() -> reader {
ret new_reader(FILE_buf_reader(rustrt::rust_get_stdin(), option::none));
}
fn file_reader(path: str) -> reader {
fn file_reader(path: str) -> result::t<reader, str> {
let f = str::as_buf(path, {|pathbuf|
str::as_buf("r", {|modebuf|
os::libc::fopen(pathbuf, modebuf)
})
});
if f as uint == 0u { log_err "error opening " + path; fail; }
ret new_reader(FILE_buf_reader(f, option::some(@FILE_res(f))));
ret if f as uint == 0u { result::err("error opening " + path) }
else {
result::ok(new_reader(FILE_buf_reader(f, option::some(@FILE_res(f)))))
}
}
@ -278,7 +280,8 @@ obj fd_buf_writer(fd: int, res: option::t<@fd_res>) {
}
}
fn file_buf_writer(path: str, flags: [fileflag]) -> buf_writer {
fn file_buf_writer(path: str,
flags: [fileflag]) -> result::t<buf_writer, str> {
let fflags: int =
os::libc_constants::O_WRONLY() | os::libc_constants::O_BINARY();
for f: fileflag in flags {
@ -296,12 +299,12 @@ fn file_buf_writer(path: str, flags: [fileflag]) -> buf_writer {
os::libc_constants::S_IRUSR() |
os::libc_constants::S_IWUSR())
});
if fd < 0 {
log_err "error opening file for writing";
ret if fd < 0 {
log_err sys::last_os_error();
fail;
result::err("error opening " + path)
} else {
result::ok(fd_buf_writer(fd, option::some(@fd_res(fd))))
}
ret fd_buf_writer(fd, option::some(@fd_res(fd)));
}
type writer =
@ -359,13 +362,15 @@ obj new_writer(out: buf_writer) {
}
}
fn file_writer(path: str, flags: [fileflag]) -> writer {
ret new_writer(file_buf_writer(path, flags));
fn file_writer(path: str, flags: [fileflag]) -> result::t<writer, str> {
result::chain(file_buf_writer(path, flags), { |w|
result::ok(new_writer(w))
})
}
// FIXME: fileflags
fn buffered_file_buf_writer(path: str) -> buf_writer {
fn buffered_file_buf_writer(path: str) -> result::t<buf_writer, str> {
let f =
str::as_buf(path,
{|pathbuf|
@ -374,8 +379,8 @@ fn buffered_file_buf_writer(path: str) -> buf_writer {
os::libc::fopen(pathbuf, modebuf)
})
});
if f as uint == 0u { log_err "error opening " + path; fail; }
ret FILE_writer(f, option::some(@FILE_res(f)));
ret if f as uint == 0u { result::err("error opening " + path) }
else { result::ok(FILE_writer(f, option::some(@FILE_res(f)))) }
}
@ -452,14 +457,18 @@ fn seek_in_buf(offset: int, pos: uint, len: uint, whence: seek_style) ->
ret bpos as uint;
}
fn read_whole_file_str(file: str) -> str {
str::unsafe_from_bytes(read_whole_file(file))
fn read_whole_file_str(file: str) -> result::t<str, str> {
result::chain(read_whole_file(file), { |bytes|
result::ok(str::unsafe_from_bytes(bytes))
})
}
fn read_whole_file(file: str) -> [u8] {
fn read_whole_file(file: str) -> result::t<[u8], str> {
// FIXME: There's a lot of copying here
file_reader(file).read_whole_stream()
result::chain(file_reader(file), { |rdr|
result::ok(rdr.read_whole_stream())
})
}

View File

@ -41,6 +41,8 @@ fn get<T, U>(res: t<T, U>) -> T {
alt res {
ok(t) { t }
err(_) {
// FIXME: Serialize the error value
// and include it in the fail message
fail "get called on error result";
}
}

View File

@ -20,6 +20,7 @@ import std::io;
import std::time;
import std::u64;
import std::result;
import std::task;
import std::task::joinable_task;
@ -30,7 +31,7 @@ import std::comm::recv;
import std::comm::send;
fn map(filename: str, emit: map_reduce::putter) {
let f = io::file_reader(filename);
let f = result::get(io::file_reader(filename));
while true {

View File

@ -0,0 +1,3 @@
// error-pattern:error opening
mod doesnotexist;

View File

@ -2,6 +2,7 @@
use std;
import std::io;
import std::str;
import std::result;
#[cfg(target_os = "linux")]
#[cfg(target_os = "win32")]
@ -13,10 +14,10 @@ fn test_simple() {
log frood;
{
let out: io::writer =
io::file_writer(tmpfile, [io::create, io::truncate]);
result::get(io::file_writer(tmpfile, [io::create, io::truncate]));
out.write_str(frood);
}
let inp: io::reader = io::file_reader(tmpfile);
let inp: io::reader = result::get(io::file_reader(tmpfile));
let frood2: str = inp.read_c_str();
log frood2;
assert (str::eq(frood, frood2));
@ -28,3 +29,48 @@ fn test_simple() {
#[ignore]
fn test_simple() { }
#[test]
fn file_reader_not_exist() {
alt io::file_reader("not a file") {
result::err(e) {
assert e == "error opening not a file";
}
result::ok(_) { fail; }
}
}
#[cfg(target_os = "linux")]
#[cfg(target_os = "win32")]
#[test]
fn file_buf_writer_bad_name() {
alt io::file_buf_writer("/?", []) {
result::err(e) {
assert e == "error opening /?";
}
result::ok(_) { fail; }
}
}
// FIXME (726)
#[cfg(target_os = "macos")]
#[test]
#[ignore]
fn file_buf_writer_bad_name() { }
#[cfg(target_os = "linux")]
#[cfg(target_os = "win32")]
#[test]
fn buffered_file_buf_writer_bad_name() {
alt io::buffered_file_buf_writer("/?") {
result::err(e) {
assert e == "error opening /?";
}
result::ok(_) { fail; }
}
}
// FIXME (726)
#[cfg(target_os = "macos")]
#[test]
#[ignore]
fn buffered_file_buf_writer_bad_name() { }