1
Fork 0

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 util::{ppaux, common, filesearch};
import back::link; import back::link;
import lib::llvm; 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::map::mk_hashmap;
import std::option::{some, none}; import std::option::{some, none};
import std::getopts::{optopt, optmulti, optflag, optflagopt, opt_present}; 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) fn parse_input_src(sess: session::session, cfg: ast::crate_cfg, infile: str)
-> {crate: @ast::crate, src: str} { -> {crate: @ast::crate, src: str} {
let srcbytes = let srcbytes = if infile != "-" {
if infile != "-" { alt io::file_reader(infile) {
io::file_reader(infile) result::ok(reader) { reader }
} else { io::stdin() }.read_whole_stream(); result::err(e) {
sess.fatal(e)
}
}
} else {
io::stdin()
}.read_whole_stream();
let src = str::unsafe_from_bytes(srcbytes); let src = str::unsafe_from_bytes(srcbytes);
let crate = let crate =
parser::parse_crate_from_source_str(infile, src, cfg, 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}; import std::option::{some, none};
type filename = str; 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 // FIXME: reading in the entire file is the worst possible way to
// get access to the necessary lines. // 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); let fm = get_filemap(cm, lines.name);
// arbitrarily only print up to six lines of the error // 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::option::{some, none};
import std::either::{left, right}; import std::either::{left, right};
import std::map::{hashmap, new_str_hash}; 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, fn new_parser_from_file(sess: parse_sess, cfg: ast::crate_cfg, path: str,
chpos: uint, byte_pos: uint, ftype: file_type) -> chpos: uint, byte_pos: uint, ftype: file_type) ->
parser { 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); let filemap = codemap::new_filemap(path, chpos, byte_pos);
sess.cm.files += [filemap]; sess.cm.files += [filemap];
let itr = @interner::mk(str::hash, str::eq); 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)) { 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() { while !rdr.eof() {
let ln = rdr.read_line(); let ln = rdr.read_line();

View file

@ -5,6 +5,7 @@ import std::fs;
import std::os; import std::os;
import std::vec; import std::vec;
import std::test; import std::test;
import std::result;
import common::mode_run_pass; import common::mode_run_pass;
import common::mode_run_fail; import common::mode_run_fail;
@ -92,7 +93,7 @@ fn run_pretty_test(cx: cx, props: test_props, testfile: str) {
let rounds = let rounds =
alt props.pp_exact { option::some(_) { 1 } option::none. { 2 } }; 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; let round = 0;
while round < rounds { while round < rounds {
@ -112,7 +113,7 @@ fn run_pretty_test(cx: cx, props: test_props, testfile: str) {
alt props.pp_exact { alt props.pp_exact {
option::some(file) { option::some(file) {
let filepath = fs::connect(fs::dirname(testfile), 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] } 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")] #[cfg(target_os = "linux")]
fn dump_output_file(config: config, testfile: str, out: str, extension: str) { fn dump_output_file(config: config, testfile: str, out: str, extension: str) {
let outfile = make_out_name(config, testfile, extension); 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); writer.write_str(out);
} }

View file

@ -1,7 +1,7 @@
use std; use std;
use rustc; 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::getopts::{optopt, opt_present, opt_str};
import std::io::stdout; import std::io::stdout;
@ -13,7 +13,9 @@ tag test_mode { tm_converge; tm_run; }
type context = { mode: test_mode }; // + rng type context = { mode: test_mode }; // + rng
fn write_file(filename: str, content: str) { 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 // Work around https://github.com/graydon/rust/issues/726
std::run::run_program("chmod", ["644", filename]); 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)]; log_err #fmt["pp convergence tests: %u files", vec::len(files)];
for file in files { for file in files {
if !file_might_not_converge(file) { 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) { if !content_might_not_converge(s) {
log_err #fmt["pp converge: %s", file]; log_err #fmt["pp converge: %s", file];
// Change from 7u to 2u once https://github.com/graydon/rust/issues/850 is fixed // 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; cont;
} }
let s = io::read_whole_file_str(file); let s = result::get(io::read_whole_file_str(file));
if contains(s, "#") { if contains(s, "#") {
cont; // Macros are confusing 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)); 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| let f = str::as_buf(path, {|pathbuf|
str::as_buf("r", {|modebuf| str::as_buf("r", {|modebuf|
os::libc::fopen(pathbuf, modebuf) os::libc::fopen(pathbuf, modebuf)
}) })
}); });
if f as uint == 0u { log_err "error opening " + path; fail; } ret if f as uint == 0u { result::err("error opening " + path) }
ret new_reader(FILE_buf_reader(f, option::some(@FILE_res(f)))); 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 = let fflags: int =
os::libc_constants::O_WRONLY() | os::libc_constants::O_BINARY(); os::libc_constants::O_WRONLY() | os::libc_constants::O_BINARY();
for f: fileflag in flags { 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_IRUSR() |
os::libc_constants::S_IWUSR()) os::libc_constants::S_IWUSR())
}); });
if fd < 0 { ret if fd < 0 {
log_err "error opening file for writing";
log_err sys::last_os_error(); 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 = type writer =
@ -359,13 +362,15 @@ obj new_writer(out: buf_writer) {
} }
} }
fn file_writer(path: str, flags: [fileflag]) -> writer { fn file_writer(path: str, flags: [fileflag]) -> result::t<writer, str> {
ret new_writer(file_buf_writer(path, flags)); result::chain(file_buf_writer(path, flags), { |w|
result::ok(new_writer(w))
})
} }
// FIXME: fileflags // 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 = let f =
str::as_buf(path, str::as_buf(path,
{|pathbuf| {|pathbuf|
@ -374,8 +379,8 @@ fn buffered_file_buf_writer(path: str) -> buf_writer {
os::libc::fopen(pathbuf, modebuf) os::libc::fopen(pathbuf, modebuf)
}) })
}); });
if f as uint == 0u { log_err "error opening " + path; fail; } ret if f as uint == 0u { result::err("error opening " + path) }
ret FILE_writer(f, option::some(@FILE_res(f))); 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; ret bpos as uint;
} }
fn read_whole_file_str(file: str) -> str { fn read_whole_file_str(file: str) -> result::t<str, str> {
str::unsafe_from_bytes(read_whole_file(file)) 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 // 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 { alt res {
ok(t) { t } ok(t) { t }
err(_) { err(_) {
// FIXME: Serialize the error value
// and include it in the fail message
fail "get called on error result"; fail "get called on error result";
} }
} }

View file

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

View file

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

View file

@ -2,6 +2,7 @@
use std; use std;
import std::io; import std::io;
import std::str; import std::str;
import std::result;
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
#[cfg(target_os = "win32")] #[cfg(target_os = "win32")]
@ -13,10 +14,10 @@ fn test_simple() {
log frood; log frood;
{ {
let out: io::writer = 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); 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(); let frood2: str = inp.read_c_str();
log frood2; log frood2;
assert (str::eq(frood, frood2)); assert (str::eq(frood, frood2));
@ -28,3 +29,48 @@ fn test_simple() {
#[ignore] #[ignore]
fn test_simple() { } 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() { }