stdlib: Make io failures recoverable by returning a result
This commit is contained in:
parent
2b62a80202
commit
2cebef095e
11 changed files with 123 additions and 37 deletions
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
3
src/test/compile-fail/missingmod.rc
Normal file
3
src/test/compile-fail/missingmod.rc
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
// error-pattern:error opening
|
||||||
|
|
||||||
|
mod doesnotexist;
|
|
@ -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() { }
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue