diff --git a/src/comp/syntax/fold.rs b/src/comp/syntax/fold.rs index 4c35dd821705d..158935a261d79 100644 --- a/src/comp/syntax/fold.rs +++ b/src/comp/syntax/fold.rs @@ -13,6 +13,7 @@ export make_fold; export dummy_out; export noop_fold_crate; export noop_fold_item; +export noop_fold_expr; type ast_fold = @mutable a_f; diff --git a/src/comp/syntax/print/pprust.rs b/src/comp/syntax/print/pprust.rs index 021c5b26b3c1a..0543b01128eb7 100644 --- a/src/comp/syntax/print/pprust.rs +++ b/src/comp/syntax/print/pprust.rs @@ -404,6 +404,7 @@ fn print_item(&ps s, &@ast::item item) { case (ast::item_native_mod(?nmod)) { head(s, "native"); alt (nmod.abi) { + case (ast::native_abi_llvm) { word_nbsp(s, "\"llvm\""); } case (ast::native_abi_rust) { word_nbsp(s, "\"rust\""); } case (ast::native_abi_cdecl) { word_nbsp(s, "\"cdecl\""); } case (ast::native_abi_rust_intrinsic) { diff --git a/src/fuzzer/ast_match.rs b/src/fuzzer/ast_match.rs new file mode 100644 index 0000000000000..001172a356ebd --- /dev/null +++ b/src/fuzzer/ast_match.rs @@ -0,0 +1,32 @@ +use std; +import std::ivec; + +fn ivec_equal[T](&T[] v, &T[] u, fn (&T, &T) -> bool element_equality_test) -> bool { + auto Lv = ivec::len(v); + if (Lv != ivec::len(u)) { + ret false; + } + auto i = 0u; + while (i < Lv) { + if (!element_equality_test(v.(i), u.(i))) { + ret false; + } + i += 1u; + } + ret true; +} + +fn builtin_equal[T](&T a, &T b) -> bool { + ret a == b; +} + +fn main() { + assert builtin_equal(5, 5); + assert !builtin_equal(5, 4); + assert !ivec_equal(~[5, 5], ~[5], builtin_equal); + assert !ivec_equal(~[5, 5], ~[5, 4], builtin_equal); + assert !ivec_equal(~[5, 5], ~[4, 5], builtin_equal); + assert ivec_equal(~[5, 5], ~[5, 5], builtin_equal); + + log_err "Pass"; +} diff --git a/src/fuzzer/fuzzer.rs b/src/fuzzer/fuzzer.rs index 2de291eac5b4c..2c7b8ff58698c 100644 --- a/src/fuzzer/fuzzer.rs +++ b/src/fuzzer/fuzzer.rs @@ -1,60 +1,161 @@ +use std; +use rustc; + import std::fs; import std::getopts; import std::getopts::optopt; import std::getopts::opt_present; import std::getopts::opt_str; import std::io; +import std::io::stdout; import std::vec; +import std::ivec; +import std::str; +import std::uint; -type src_gen = iter() -> str; +import rustc::syntax::ast; +import rustc::syntax::fold; +import rustc::syntax::walk; +import rustc::syntax::codemap; +import rustc::syntax::print::pprust; -iter dir_src_gen(str dir) -> str { -} +import driver = rustc::driver::rustc; // see https://github.com/graydon/rust/issues/624 +import rustc::back::link; +import rustc::driver::rustc::time; +import rustc::driver::session; -fn usage(str binary) { - io::stdout().write_line("usage"); -} +/* +// Imports for "the rest of driver::compile_input" +import rustc::metadata::creader; +import rustc::metadata::cstore; +import rustc::syntax::parse::parser; +import rustc::syntax::parse::token; +import rustc::front; +import rustc::front::attr; +import rustc::middle; +import rustc::middle::trans; +import rustc::middle::resolve; +import rustc::middle::ty; +import rustc::middle::typeck; +import rustc::middle::tstate::ck; +import rustc::syntax::print::pp; +import rustc::util::ppaux; +import rustc::lib::llvm; +*/ -type session = rec(str srcdir); - -fn make_session(vec[str] args) -> session { - // Directory of rust source files to use as input - auto opt_src = "src"; +fn file_contains(&str filename, &str needle) -> bool { + auto r = io::file_reader(filename); + auto contents = str::unsafe_from_bytes(r.read_whole_stream()); + ret str::find(contents, needle) != -1; +} - auto binary = vec::shift[str](args); - auto opts = [optopt(opt_src)]; - auto match; - alt (getopts::getopts(args, opts)) { - case (getopts::failure(?f)) { - log_err #fmt("error: %s", getopts::fail_str(f)); - fail; +fn find_rust_files(&mutable str[] files, str path) { + if (str::ends_with(path, ".rs")) { + if (file_contains(path, "xfail-stage1")) { + //log_err "Skipping " + path + " because it is marked as xfail-stage1"; + } else if ( + !str::ends_with(path, "constrained-type.rs") && // https://github.com/graydon/rust/issues/653 + str::find(path, "utf8") != -1 && // https://github.com/graydon/rust/issues/654 + true) { + //log_err "Skipping " + path + " because of a known bug"; + } else { + files += ~[path]; } - case (getopts::success(?m)) { - match = m; + } else if (fs::file_is_dir(path) && str::find(path, "compile-fail") == -1) { + for (str p in fs::list_dir(path)) { + find_rust_files(files, p); } - }; - - if (!opt_present(match, opt_src)) { - usage(binary); - fail; } +} - auto srcdir = opt_str(match, opt_src); +fn steal_exprs(&ast::crate crate) -> ast::expr[] { + let @mutable ast::expr[] exprs = @mutable ~[]; + // "Stash" cannot be type-parameterized because of https://github.com/graydon/rust/issues/375 + fn stash_expr(@mutable ast::expr[] es, &@ast::expr e) { *es += ~[*e]; } + auto v = rec(visit_expr_pre = bind stash_expr(exprs, _) with walk::default_visitor()); + walk::walk_crate(v, crate); + *exprs +} - ret rec(srcdir = srcdir); +// https://github.com/graydon/rust/issues/652 +fn safe_to_replace(ast::expr_ e) -> bool { + alt (e) { + case (ast::expr_if(_, _, _)) { false } + case (ast::expr_block(_)) { false } + case (_) { true } + } } -fn log_session(session sess) { - log #fmt("srcdir: %s", sess.srcdir); +// Replace the |i|th expr (in fold order) of |crate| with |newexpr|. +fn replace_expr_in_crate(&ast::crate crate, uint i, ast::expr_ newexpr) -> ast::crate { + let @mutable uint j = @mutable 0u; + fn fold_expr_rep(@mutable uint j_, uint i_, &ast::expr_ newexpr_, &ast::expr_ original, fold::ast_fold fld) -> ast::expr_ { + *j_ += 1u; + if (i_ + 1u == *j_ && safe_to_replace(original)) { + newexpr_ + } else { + fold::noop_fold_expr(original, fld) + } + } + auto afp = rec(fold_expr = bind fold_expr_rep(j, i, newexpr, _, _) with *fold::default_ast_fold()); + auto af = fold::make_fold(afp); + let @ast::crate crate2 = @af.fold_crate(crate); + fold::dummy_out(af); // work around a leak (https://github.com/graydon/rust/issues/651) + *crate2 } -fn run_session(session sess) { +iter under(uint n) -> uint { let uint i = 0u; while (i < n) { put i; i += 1u; } } + +fn devnull() -> io::writer { std::io::string_writer().get_writer() } + +fn pp_variants(&ast::crate crate, &session::session sess, &str filename) { + auto exprs = steal_exprs(crate); + auto exprsL = ivec::len(exprs); + if (exprsL < 100u) { + for each (uint i in under(uint::min(exprsL, 20u))) { + log_err "Replacing... " + pprust::expr_to_str(@exprs.(i)); + for each (uint j in under(uint::min(exprsL, 5u))) { + log_err "With... " + pprust::expr_to_str(@exprs.(j)); + auto crate2 = @replace_expr_in_crate(crate, i, exprs.(j).node); + pprust::print_crate(sess.get_codemap(), crate2, filename, devnull(), pprust::no_ann()); + } + } + } } fn main(vec[str] args) { - auto sess = make_session(args); - log_session(sess); - run_session(sess); + auto files = ~[]; + auto root = "/Users/jruderman/code/rust/src/"; // XXX + find_rust_files(files, root); // not using time here because that currently screws with passing-a-mutable-array + log_err uint::str(ivec::len(files)) + " files"; + + auto binary = vec::shift[str](args); + auto binary_dir = fs::dirname(binary); + + let @session::options sopts = + @rec(library=false, + static=false, + optimize=0u, + debuginfo=false, + verify=true, + run_typestate=true, + save_temps=false, + stats=false, + time_passes=false, + time_llvm_passes=false, + output_type=link::output_type_bitcode, + library_search_paths=[binary_dir + "/lib"], + sysroot=driver::get_default_sysroot(binary), + cfg=~[], + test=false); + + for (str file in files) { + log_err "=== " + file + " ==="; + let session::session sess = driver::build_session(sopts); + let @ast::crate crate = time(true, "parsing " + file, bind driver::parse_input(sess, ~[], file)); + pprust::print_crate(sess.get_codemap(), crate, file, devnull(), pprust::no_ann()); + pp_variants(*crate, sess, file); + } } // Local Variables: diff --git a/src/fuzzer/ivec_fuzz.rs b/src/fuzzer/ivec_fuzz.rs new file mode 100644 index 0000000000000..4d52e73e56b7f --- /dev/null +++ b/src/fuzzer/ivec_fuzz.rs @@ -0,0 +1,98 @@ +/* + +Idea: provide functions for 'exhaustive' and 'random' modification of vecs. + + two functions, "return all edits" and "return a random edit" <-- leaning toward this model + or + two functions, "return the number of possible edits" and "return edit #n" + +It would be nice if this could be data-driven, so the two functions could share information: + type vec_modifier = rec(fn (&T[] v, uint i) -> T[] fun, uint lo, uint di); + const vec_modifier[] vec_modifiers = ~[rec(fun=vec_omit, 0u, 1u), ...]; +But that gives me "error: internal compiler error unimplemented consts that's not a plain literal". +https://github.com/graydon/rust/issues/570 + +vec_edits is not an iter because iters might go away and: +https://github.com/graydon/rust/issues/639 + +vec_omit and friends are not type-parameterized because: +https://github.com/graydon/rust/issues/640 + +*/ + +use std; +import std::ivec; +import std::ivec::slice; +import std::ivec::len; +import std::int; + +//fn vec_reverse(&T[] v) -> T[] { ... } + +fn vec_omit [T] (&T[] v, uint i) -> T[] { slice(v, 0u, i) + slice(v, i+1u, len(v)) } +fn vec_dup [T] (&T[] v, uint i) -> T[] { slice(v, 0u, i) + ~[v.(i)] + slice(v, i, len(v)) } +fn vec_swadj [T] (&T[] v, uint i) -> T[] { slice(v, 0u, i) + ~[v.(i+1u), v.(i)] + slice(v, i+2u, len(v)) } +fn vec_prefix [T] (&T[] v, uint i) -> T[] { slice(v, 0u, i) } +fn vec_suffix [T] (&T[] v, uint i) -> T[] { slice(v, i, len(v)) } + +fn vec_poke [T] (&T[] v, uint i, &T x) -> T[] { slice(v, 0u, i) + ~[x] + slice(v, i+1u, len(v)) } +fn vec_insert [T] (&T[] v, uint i, &T x) -> T[] { slice(v, 0u, i) + ~[x] + slice(v, i, len(v)) } + +// Iterates over 0...length, skipping the specified number on each side. +iter ix(uint skip_low, uint skip_high, uint length) -> uint { let uint i = skip_low; while (i + skip_high <= length) { put i; i += 1u; } } + +// Returns a bunch of modified versions of v, some of which introduce new elements (borrowed from xs). +fn vec_edits[T](&T[] v, &T[] xs) -> T[][] { + let T[][] edits = ~[]; + let uint Lv = len(v); + + if (Lv != 1u) { edits += ~[~[]]; } // When Lv == 1u, this is redundant with omit + //if (Lv >= 3u) { edits += ~[vec_reverse(v)]; } + + for each (uint i in ix(0u, 1u, Lv)) { edits += ~[vec_omit (v, i)]; } + for each (uint i in ix(0u, 1u, Lv)) { edits += ~[vec_dup (v, i)]; } + for each (uint i in ix(0u, 2u, Lv)) { edits += ~[vec_swadj (v, i)]; } + for each (uint i in ix(1u, 2u, Lv)) { edits += ~[vec_prefix(v, i)]; } + for each (uint i in ix(2u, 1u, Lv)) { edits += ~[vec_suffix(v, i)]; } + + for each (uint j in ix(0u, 1u, len(xs))) { + for each (uint i in ix(0u, 1u, Lv)) { edits += ~[vec_poke (v, i, xs.(j))]; } + for each (uint i in ix(0u, 0u, Lv)) { edits += ~[vec_insert(v, i, xs.(j))]; } + } + + edits +} + +// Would be nice if this were built in: https://github.com/graydon/rust/issues/424 +fn vec_to_str(&int[] v) -> str { + auto i = 0u; + auto s = "["; + while (i < len(v)) { + s += int::str(v.(i)); + if (i + 1u < len(v)) { + s += ", " + } + i += 1u; + } + ret s + "]"; +} + +fn show_edits(&int[] a, &int[] xs) { + log_err "=== Edits of " + vec_to_str(a) + " ==="; + auto b = vec_edits(a, xs); + for each (uint i in ix(0u, 1u, len(b))) { + log_err vec_to_str(b.(i)); + } +} + +fn demo_edits() { + auto xs = ~[7, 8]; + show_edits(~[], xs); + show_edits(~[1], xs); + show_edits(~[1,2], xs); + show_edits(~[1,2,3], xs); + show_edits(~[1,2,3,4], xs); +} + +fn main() { + demo_edits(); +} diff --git a/src/lib/uint.rs b/src/lib/uint.rs index 6908aa6342a62..2b3c2875c935c 100644 --- a/src/lib/uint.rs +++ b/src/lib/uint.rs @@ -24,6 +24,8 @@ pred gt(uint x, uint y) -> bool { ret x > y; } fn max(uint x, uint y) -> uint { if (x > y) { ret x; } ret y; } +fn min(uint x, uint y) -> uint { if (x > y) { ret y; } ret x; } + iter range(uint lo, uint hi) -> uint { auto lo_ = lo; while (lo_ < hi) { put lo_; lo_ += 1u; }