Remove the crate language
This commit is contained in:
parent
81a79603c0
commit
be6613e048
@ -26,6 +26,198 @@ mod common;
|
||||
#[legacy_exports]
|
||||
mod errors;
|
||||
|
||||
use std::getopts;
|
||||
use std::test;
|
||||
|
||||
use core::result;
|
||||
use result::{Ok, Err};
|
||||
|
||||
use common::config;
|
||||
use common::mode_run_pass;
|
||||
use common::mode_run_fail;
|
||||
use common::mode_compile_fail;
|
||||
use common::mode_pretty;
|
||||
use common::mode;
|
||||
use util::logv;
|
||||
|
||||
fn main() {
|
||||
let args = os::args();
|
||||
let config = parse_config(args);
|
||||
log_config(config);
|
||||
run_tests(config);
|
||||
}
|
||||
|
||||
fn parse_config(args: ~[~str]) -> config {
|
||||
let opts =
|
||||
~[getopts::reqopt(~"compile-lib-path"),
|
||||
getopts::reqopt(~"run-lib-path"),
|
||||
getopts::reqopt(~"rustc-path"), getopts::reqopt(~"src-base"),
|
||||
getopts::reqopt(~"build-base"), getopts::reqopt(~"aux-base"),
|
||||
getopts::reqopt(~"stage-id"),
|
||||
getopts::reqopt(~"mode"), getopts::optflag(~"ignored"),
|
||||
getopts::optopt(~"runtool"), getopts::optopt(~"rustcflags"),
|
||||
getopts::optflag(~"verbose"),
|
||||
getopts::optopt(~"logfile"),
|
||||
getopts::optflag(~"jit")];
|
||||
|
||||
assert (vec::is_not_empty(args));
|
||||
let args_ = vec::tail(args);
|
||||
let matches =
|
||||
match getopts::getopts(args_, opts) {
|
||||
Ok(m) => m,
|
||||
Err(f) => fail getopts::fail_str(f)
|
||||
};
|
||||
|
||||
fn opt_path(m: getopts::Matches, nm: ~str) -> Path {
|
||||
Path(getopts::opt_str(m, nm))
|
||||
}
|
||||
|
||||
return {compile_lib_path: getopts::opt_str(matches, ~"compile-lib-path"),
|
||||
run_lib_path: getopts::opt_str(matches, ~"run-lib-path"),
|
||||
rustc_path: opt_path(matches, ~"rustc-path"),
|
||||
src_base: opt_path(matches, ~"src-base"),
|
||||
build_base: opt_path(matches, ~"build-base"),
|
||||
aux_base: opt_path(matches, ~"aux-base"),
|
||||
stage_id: getopts::opt_str(matches, ~"stage-id"),
|
||||
mode: str_mode(getopts::opt_str(matches, ~"mode")),
|
||||
run_ignored: getopts::opt_present(matches, ~"ignored"),
|
||||
filter:
|
||||
if vec::len(matches.free) > 0u {
|
||||
option::Some(matches.free[0])
|
||||
} else { option::None },
|
||||
logfile: option::map(&getopts::opt_maybe_str(matches,
|
||||
~"logfile"),
|
||||
|s| Path(*s)),
|
||||
runtool: getopts::opt_maybe_str(matches, ~"runtool"),
|
||||
rustcflags: getopts::opt_maybe_str(matches, ~"rustcflags"),
|
||||
jit: getopts::opt_present(matches, ~"jit"),
|
||||
verbose: getopts::opt_present(matches, ~"verbose")};
|
||||
}
|
||||
|
||||
fn log_config(config: config) {
|
||||
let c = config;
|
||||
logv(c, fmt!("configuration:"));
|
||||
logv(c, fmt!("compile_lib_path: %s", config.compile_lib_path));
|
||||
logv(c, fmt!("run_lib_path: %s", config.run_lib_path));
|
||||
logv(c, fmt!("rustc_path: %s", config.rustc_path.to_str()));
|
||||
logv(c, fmt!("src_base: %s", config.src_base.to_str()));
|
||||
logv(c, fmt!("build_base: %s", config.build_base.to_str()));
|
||||
logv(c, fmt!("stage_id: %s", config.stage_id));
|
||||
logv(c, fmt!("mode: %s", mode_str(config.mode)));
|
||||
logv(c, fmt!("run_ignored: %b", config.run_ignored));
|
||||
logv(c, fmt!("filter: %s", opt_str(config.filter)));
|
||||
logv(c, fmt!("runtool: %s", opt_str(config.runtool)));
|
||||
logv(c, fmt!("rustcflags: %s", opt_str(config.rustcflags)));
|
||||
logv(c, fmt!("jit: %b", config.jit));
|
||||
logv(c, fmt!("verbose: %b", config.verbose));
|
||||
logv(c, fmt!("\n"));
|
||||
}
|
||||
|
||||
fn opt_str(maybestr: Option<~str>) -> ~str {
|
||||
match maybestr { option::Some(s) => s, option::None => ~"(none)" }
|
||||
}
|
||||
|
||||
fn str_opt(maybestr: ~str) -> Option<~str> {
|
||||
if maybestr != ~"(none)" { option::Some(maybestr) } else { option::None }
|
||||
}
|
||||
|
||||
fn str_mode(s: ~str) -> mode {
|
||||
match s {
|
||||
~"compile-fail" => mode_compile_fail,
|
||||
~"run-fail" => mode_run_fail,
|
||||
~"run-pass" => mode_run_pass,
|
||||
~"pretty" => mode_pretty,
|
||||
_ => fail ~"invalid mode"
|
||||
}
|
||||
}
|
||||
|
||||
fn mode_str(mode: mode) -> ~str {
|
||||
match mode {
|
||||
mode_compile_fail => ~"compile-fail",
|
||||
mode_run_fail => ~"run-fail",
|
||||
mode_run_pass => ~"run-pass",
|
||||
mode_pretty => ~"pretty"
|
||||
}
|
||||
}
|
||||
|
||||
fn run_tests(config: config) {
|
||||
let opts = test_opts(config);
|
||||
let tests = make_tests(config);
|
||||
let res = test::run_tests_console(&opts, tests);
|
||||
if !res { fail ~"Some tests failed"; }
|
||||
}
|
||||
|
||||
fn test_opts(config: config) -> test::TestOpts {
|
||||
{filter:
|
||||
match config.filter {
|
||||
option::Some(s) => option::Some(s),
|
||||
option::None => option::None
|
||||
},
|
||||
run_ignored: config.run_ignored,
|
||||
logfile:
|
||||
match config.logfile {
|
||||
option::Some(s) => option::Some(s.to_str()),
|
||||
option::None => option::None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn make_tests(config: config) -> ~[test::TestDesc] {
|
||||
debug!("making tests from %s",
|
||||
config.src_base.to_str());
|
||||
let mut tests = ~[];
|
||||
for os::list_dir_path(&config.src_base).each |file| {
|
||||
let file = copy *file;
|
||||
debug!("inspecting file %s", file.to_str());
|
||||
if is_test(config, file) {
|
||||
tests.push(make_test(config, file))
|
||||
}
|
||||
}
|
||||
move tests
|
||||
}
|
||||
|
||||
fn is_test(config: config, testfile: &Path) -> bool {
|
||||
// Pretty-printer does not work with .rc files yet
|
||||
let valid_extensions =
|
||||
match config.mode {
|
||||
mode_pretty => ~[~".rs"],
|
||||
_ => ~[~".rc", ~".rs"]
|
||||
};
|
||||
let invalid_prefixes = ~[~".", ~"#", ~"~"];
|
||||
let name = testfile.filename().get();
|
||||
|
||||
let mut valid = false;
|
||||
|
||||
for valid_extensions.each |ext| {
|
||||
if str::ends_with(name, *ext) { valid = true; }
|
||||
}
|
||||
|
||||
for invalid_prefixes.each |pre| {
|
||||
if str::starts_with(name, *pre) { valid = false; }
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
fn make_test(config: config, testfile: &Path) ->
|
||||
test::TestDesc {
|
||||
{
|
||||
name: make_test_name(config, testfile),
|
||||
testfn: make_test_closure(config, testfile),
|
||||
ignore: header::is_test_ignored(config, testfile),
|
||||
should_fail: false
|
||||
}
|
||||
}
|
||||
|
||||
fn make_test_name(config: config, testfile: &Path) -> ~str {
|
||||
fmt!("[%s] %s", mode_str(config.mode), testfile.to_str())
|
||||
}
|
||||
|
||||
fn make_test_closure(config: config, testfile: &Path) -> test::TestFn {
|
||||
let testfile = testfile.to_str();
|
||||
fn~() { runtest::run(config, testfile) }
|
||||
}
|
||||
|
||||
// Local Variables:
|
||||
// fill-column: 78;
|
||||
// indent-tabs-mode: nil
|
||||
|
@ -1,198 +0,0 @@
|
||||
use std::getopts;
|
||||
use std::test;
|
||||
|
||||
use core::result;
|
||||
use result::{Ok, Err};
|
||||
|
||||
use common::config;
|
||||
use common::mode_run_pass;
|
||||
use common::mode_run_fail;
|
||||
use common::mode_compile_fail;
|
||||
use common::mode_pretty;
|
||||
use common::mode;
|
||||
use util::logv;
|
||||
|
||||
fn main() {
|
||||
let args = os::args();
|
||||
let config = parse_config(args);
|
||||
log_config(config);
|
||||
run_tests(config);
|
||||
}
|
||||
|
||||
fn parse_config(args: ~[~str]) -> config {
|
||||
let opts =
|
||||
~[getopts::reqopt(~"compile-lib-path"),
|
||||
getopts::reqopt(~"run-lib-path"),
|
||||
getopts::reqopt(~"rustc-path"), getopts::reqopt(~"src-base"),
|
||||
getopts::reqopt(~"build-base"), getopts::reqopt(~"aux-base"),
|
||||
getopts::reqopt(~"stage-id"),
|
||||
getopts::reqopt(~"mode"), getopts::optflag(~"ignored"),
|
||||
getopts::optopt(~"runtool"), getopts::optopt(~"rustcflags"),
|
||||
getopts::optflag(~"verbose"),
|
||||
getopts::optopt(~"logfile"),
|
||||
getopts::optflag(~"jit")];
|
||||
|
||||
assert (vec::is_not_empty(args));
|
||||
let args_ = vec::tail(args);
|
||||
let matches =
|
||||
match getopts::getopts(args_, opts) {
|
||||
Ok(m) => m,
|
||||
Err(f) => fail getopts::fail_str(f)
|
||||
};
|
||||
|
||||
fn opt_path(m: getopts::Matches, nm: ~str) -> Path {
|
||||
Path(getopts::opt_str(m, nm))
|
||||
}
|
||||
|
||||
return {compile_lib_path: getopts::opt_str(matches, ~"compile-lib-path"),
|
||||
run_lib_path: getopts::opt_str(matches, ~"run-lib-path"),
|
||||
rustc_path: opt_path(matches, ~"rustc-path"),
|
||||
src_base: opt_path(matches, ~"src-base"),
|
||||
build_base: opt_path(matches, ~"build-base"),
|
||||
aux_base: opt_path(matches, ~"aux-base"),
|
||||
stage_id: getopts::opt_str(matches, ~"stage-id"),
|
||||
mode: str_mode(getopts::opt_str(matches, ~"mode")),
|
||||
run_ignored: getopts::opt_present(matches, ~"ignored"),
|
||||
filter:
|
||||
if vec::len(matches.free) > 0u {
|
||||
option::Some(matches.free[0])
|
||||
} else { option::None },
|
||||
logfile: option::map(&getopts::opt_maybe_str(matches,
|
||||
~"logfile"),
|
||||
|s| Path(*s)),
|
||||
runtool: getopts::opt_maybe_str(matches, ~"runtool"),
|
||||
rustcflags: getopts::opt_maybe_str(matches, ~"rustcflags"),
|
||||
jit: getopts::opt_present(matches, ~"jit"),
|
||||
verbose: getopts::opt_present(matches, ~"verbose")};
|
||||
}
|
||||
|
||||
fn log_config(config: config) {
|
||||
let c = config;
|
||||
logv(c, fmt!("configuration:"));
|
||||
logv(c, fmt!("compile_lib_path: %s", config.compile_lib_path));
|
||||
logv(c, fmt!("run_lib_path: %s", config.run_lib_path));
|
||||
logv(c, fmt!("rustc_path: %s", config.rustc_path.to_str()));
|
||||
logv(c, fmt!("src_base: %s", config.src_base.to_str()));
|
||||
logv(c, fmt!("build_base: %s", config.build_base.to_str()));
|
||||
logv(c, fmt!("stage_id: %s", config.stage_id));
|
||||
logv(c, fmt!("mode: %s", mode_str(config.mode)));
|
||||
logv(c, fmt!("run_ignored: %b", config.run_ignored));
|
||||
logv(c, fmt!("filter: %s", opt_str(config.filter)));
|
||||
logv(c, fmt!("runtool: %s", opt_str(config.runtool)));
|
||||
logv(c, fmt!("rustcflags: %s", opt_str(config.rustcflags)));
|
||||
logv(c, fmt!("jit: %b", config.jit));
|
||||
logv(c, fmt!("verbose: %b", config.verbose));
|
||||
logv(c, fmt!("\n"));
|
||||
}
|
||||
|
||||
fn opt_str(maybestr: Option<~str>) -> ~str {
|
||||
match maybestr { option::Some(s) => s, option::None => ~"(none)" }
|
||||
}
|
||||
|
||||
fn str_opt(maybestr: ~str) -> Option<~str> {
|
||||
if maybestr != ~"(none)" { option::Some(maybestr) } else { option::None }
|
||||
}
|
||||
|
||||
fn str_mode(s: ~str) -> mode {
|
||||
match s {
|
||||
~"compile-fail" => mode_compile_fail,
|
||||
~"run-fail" => mode_run_fail,
|
||||
~"run-pass" => mode_run_pass,
|
||||
~"pretty" => mode_pretty,
|
||||
_ => fail ~"invalid mode"
|
||||
}
|
||||
}
|
||||
|
||||
fn mode_str(mode: mode) -> ~str {
|
||||
match mode {
|
||||
mode_compile_fail => ~"compile-fail",
|
||||
mode_run_fail => ~"run-fail",
|
||||
mode_run_pass => ~"run-pass",
|
||||
mode_pretty => ~"pretty"
|
||||
}
|
||||
}
|
||||
|
||||
fn run_tests(config: config) {
|
||||
let opts = test_opts(config);
|
||||
let tests = make_tests(config);
|
||||
let res = test::run_tests_console(&opts, tests);
|
||||
if !res { fail ~"Some tests failed"; }
|
||||
}
|
||||
|
||||
fn test_opts(config: config) -> test::TestOpts {
|
||||
{filter:
|
||||
match config.filter {
|
||||
option::Some(s) => option::Some(s),
|
||||
option::None => option::None
|
||||
},
|
||||
run_ignored: config.run_ignored,
|
||||
logfile:
|
||||
match config.logfile {
|
||||
option::Some(s) => option::Some(s.to_str()),
|
||||
option::None => option::None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn make_tests(config: config) -> ~[test::TestDesc] {
|
||||
debug!("making tests from %s",
|
||||
config.src_base.to_str());
|
||||
let mut tests = ~[];
|
||||
for os::list_dir_path(&config.src_base).each |file| {
|
||||
let file = copy *file;
|
||||
debug!("inspecting file %s", file.to_str());
|
||||
if is_test(config, file) {
|
||||
tests.push(make_test(config, file))
|
||||
}
|
||||
}
|
||||
move tests
|
||||
}
|
||||
|
||||
fn is_test(config: config, testfile: &Path) -> bool {
|
||||
// Pretty-printer does not work with .rc files yet
|
||||
let valid_extensions =
|
||||
match config.mode {
|
||||
mode_pretty => ~[~".rs"],
|
||||
_ => ~[~".rc", ~".rs"]
|
||||
};
|
||||
let invalid_prefixes = ~[~".", ~"#", ~"~"];
|
||||
let name = testfile.filename().get();
|
||||
|
||||
let mut valid = false;
|
||||
|
||||
for valid_extensions.each |ext| {
|
||||
if str::ends_with(name, *ext) { valid = true; }
|
||||
}
|
||||
|
||||
for invalid_prefixes.each |pre| {
|
||||
if str::starts_with(name, *pre) { valid = false; }
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
fn make_test(config: config, testfile: &Path) ->
|
||||
test::TestDesc {
|
||||
{
|
||||
name: make_test_name(config, testfile),
|
||||
testfn: make_test_closure(config, testfile),
|
||||
ignore: header::is_test_ignored(config, testfile),
|
||||
should_fail: false
|
||||
}
|
||||
}
|
||||
|
||||
fn make_test_name(config: config, testfile: &Path) -> ~str {
|
||||
fmt!("[%s] %s", mode_str(config.mode), testfile.to_str())
|
||||
}
|
||||
|
||||
fn make_test_closure(config: config, testfile: &Path) -> test::TestFn {
|
||||
let testfile = testfile.to_str();
|
||||
fn~() { runtest::run(config, testfile) }
|
||||
}
|
||||
|
||||
// Local Variables:
|
||||
// fill-column: 78;
|
||||
// indent-tabs-mode: nil
|
||||
// c-basic-offset: 4
|
||||
// buffer-file-coding-system: utf-8-unix
|
||||
// End:
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
273
src/libcore/alternate_crate.rc
Normal file
273
src/libcore/alternate_crate.rc
Normal file
@ -0,0 +1,273 @@
|
||||
/*!
|
||||
|
||||
The Rust core library.
|
||||
|
||||
The Rust core library provides runtime features required by the language,
|
||||
including the task scheduler and memory allocators, as well as library
|
||||
support for Rust built-in types, platform abstractions, and other commonly
|
||||
used features.
|
||||
|
||||
`core` includes modules corresponding to each of the integer types, each of
|
||||
the floating point types, the `bool` type, tuples, characters, strings,
|
||||
vectors (`vec`), shared boxes (`box`), and unsafe and borrowed pointers
|
||||
(`ptr`). Additionally, `core` provides task management and creation (`task`),
|
||||
communication primitives (`comm` and `pipes`), an efficient vector builder
|
||||
(`dvec`), platform abstractions (`os` and `path`), basic I/O abstractions
|
||||
(`io`), common traits (`cmp`, `num`, `to_str`), and complete bindings
|
||||
to the C standard library (`libc`).
|
||||
|
||||
`core` is linked to all crates by default and its contents imported.
|
||||
Implicitly, all crates behave as if they included the following prologue:
|
||||
|
||||
extern mod core;
|
||||
use core::*;
|
||||
|
||||
*/
|
||||
|
||||
#[link(name = "core",
|
||||
vers = "0.5",
|
||||
uuid = "c70c24a7-5551-4f73-8e37-380b11d80be8",
|
||||
url = "https://github.com/mozilla/rust/tree/master/src/libcore")];
|
||||
|
||||
#[comment = "The Rust core library"];
|
||||
#[license = "MIT"];
|
||||
#[crate_type = "lib"];
|
||||
|
||||
// Don't link to core. We are core.
|
||||
#[no_core];
|
||||
|
||||
#[warn(deprecated_mode)];
|
||||
#[warn(deprecated_pattern)];
|
||||
|
||||
#[warn(vecs_implicitly_copyable)];
|
||||
#[deny(non_camel_case_types)];
|
||||
|
||||
// Built-in-type support modules
|
||||
|
||||
/// Operations and constants for `int`
|
||||
#[path = "int-template.rs"]
|
||||
#[merge = "int-template/intb.rs"]
|
||||
pub mod int;
|
||||
|
||||
/// Operations and constants for `i8`
|
||||
#[path = "int-template.rs"]
|
||||
#[merge = "int-template/i8b.rs"]
|
||||
pub mod i8;
|
||||
|
||||
/// Operations and constants for `i16`
|
||||
#[path = "int-template.rs"]
|
||||
#[merge = "int-template/i16b.rs"]
|
||||
pub mod i16;
|
||||
|
||||
/// Operations and constants for `i32`
|
||||
#[path = "int-template.rs"]
|
||||
#[merge = "int-template/i32b.rs"]
|
||||
pub mod i32;
|
||||
|
||||
/// Operations and constants for `i64`
|
||||
#[path = "int-template.rs"]
|
||||
#[merge = "int-template/i64b.rs"]
|
||||
pub mod i64;
|
||||
|
||||
/// Operations and constants for `uint`
|
||||
#[path = "uint-template.rs"]
|
||||
#[merge = "uint-template/uintb.rs"]
|
||||
pub mod uint;
|
||||
|
||||
/// Operations and constants for `u8`
|
||||
#[path = "uint-template.rs"]
|
||||
#[merge = "uint-template/u8b.rs"]
|
||||
pub mod u8;
|
||||
|
||||
/// Operations and constants for `u16`
|
||||
#[path = "uint-template.rs"]
|
||||
#[merge = "uint-template/u16b.rs"]
|
||||
pub mod u16;
|
||||
|
||||
/// Operations and constants for `u32`
|
||||
#[path = "uint-template.rs"]
|
||||
#[merge = "uint-template/u32b.rs"]
|
||||
pub mod u32;
|
||||
|
||||
/// Operations and constants for `u64`
|
||||
#[path = "uint-template.rs"]
|
||||
#[merge = "uint-template/u64b.rs"]
|
||||
pub mod u64;
|
||||
|
||||
|
||||
pub mod box;
|
||||
pub mod char;
|
||||
pub mod float;
|
||||
pub mod f32;
|
||||
pub mod f64;
|
||||
pub mod str;
|
||||
pub mod ptr;
|
||||
pub mod vec;
|
||||
pub mod at_vec;
|
||||
pub mod bool;
|
||||
pub mod tuple;
|
||||
pub mod unit;
|
||||
pub mod owned;
|
||||
|
||||
// Ubiquitous-utility-type modules
|
||||
|
||||
#[cfg(notest)]
|
||||
pub mod ops;
|
||||
pub mod cmp;
|
||||
pub mod num;
|
||||
pub mod hash;
|
||||
pub mod either;
|
||||
pub mod iter;
|
||||
pub mod logging;
|
||||
pub mod option;
|
||||
#[path="iter-trait.rs"]
|
||||
#[merge = "iter-trait/optionb.rs"]
|
||||
pub mod option_iter;
|
||||
pub mod result;
|
||||
pub mod to_str;
|
||||
pub mod to_bytes;
|
||||
pub mod from_str;
|
||||
pub mod util;
|
||||
|
||||
// Data structure modules
|
||||
|
||||
pub mod dvec;
|
||||
#[path="iter-trait.rs"]
|
||||
#[merge = "iter-trait/dvecb.rs"]
|
||||
pub mod dvec_iter;
|
||||
pub mod dlist;
|
||||
#[path="iter-trait.rs"]
|
||||
#[merge = "iter-trait/dlistb.rs"]
|
||||
pub mod dlist_iter;
|
||||
pub mod send_map;
|
||||
|
||||
// Concurrency
|
||||
pub mod comm;
|
||||
#[merge = "task/mod.rs"]
|
||||
pub mod task;
|
||||
pub mod pipes;
|
||||
|
||||
// Runtime and language-primitive support
|
||||
|
||||
pub mod gc;
|
||||
pub mod io;
|
||||
pub mod libc;
|
||||
pub mod os;
|
||||
pub mod path;
|
||||
pub mod rand;
|
||||
pub mod run;
|
||||
pub mod sys;
|
||||
pub mod cast;
|
||||
pub mod mutable;
|
||||
pub mod flate;
|
||||
pub mod repr;
|
||||
pub mod cleanup;
|
||||
pub mod reflect;
|
||||
pub mod condition;
|
||||
|
||||
// Modules supporting compiler-generated code
|
||||
// Exported but not part of the public interface
|
||||
|
||||
pub mod extfmt;
|
||||
// The test harness links against core, so don't include runtime in tests.
|
||||
#[cfg(notest)]
|
||||
#[legacy_exports]
|
||||
pub mod rt;
|
||||
|
||||
// Ideally not exported, but currently is.
|
||||
pub mod private;
|
||||
|
||||
// For internal use, not exported.
|
||||
mod unicode;
|
||||
mod cmath;
|
||||
mod stackwalk;
|
||||
|
||||
// Top-level, visible-everywhere definitions.
|
||||
|
||||
// Export various ubiquitous types, constructors, methods.
|
||||
|
||||
pub use option::{Some, None};
|
||||
pub use Option = option::Option;
|
||||
pub use result::{Result, Ok, Err};
|
||||
|
||||
pub use Path = path::Path;
|
||||
pub use GenericPath = path::GenericPath;
|
||||
pub use WindowsPath = path::WindowsPath;
|
||||
pub use PosixPath = path::PosixPath;
|
||||
|
||||
pub use tuple::{CopyableTuple, ImmutableTuple, ExtendedTupleOps};
|
||||
pub use str::{StrSlice, Trimmable};
|
||||
pub use vec::{ConstVector, CopyableVector, ImmutableVector};
|
||||
pub use vec::{ImmutableEqVector, ImmutableCopyableVector};
|
||||
pub use vec::{MutableVector, MutableCopyableVector};
|
||||
pub use iter::{BaseIter, ExtendedIter, EqIter, CopyableIter};
|
||||
pub use iter::{CopyableOrderedIter, CopyableNonstrictIter, Times};
|
||||
pub use num::Num;
|
||||
pub use ptr::Ptr;
|
||||
pub use to_str::ToStr;
|
||||
|
||||
// The following exports are the core operators and kinds
|
||||
// The compiler has special knowlege of these so we must not duplicate them
|
||||
// when compiling for testing
|
||||
#[cfg(notest)]
|
||||
pub use ops::{Const, Copy, Send, Owned};
|
||||
#[cfg(notest)]
|
||||
pub use ops::{Drop};
|
||||
#[cfg(notest)]
|
||||
pub use ops::{Add, Sub, Mul, Div, Modulo, Neg, BitAnd, BitOr, BitXor};
|
||||
#[cfg(notest)]
|
||||
pub use ops::{Shl, Shr, Index};
|
||||
|
||||
#[cfg(test)]
|
||||
extern mod coreops(name = "core", vers = "0.5");
|
||||
|
||||
#[cfg(test)]
|
||||
pub use coreops::ops::{Const, Copy, Send, Owned};
|
||||
#[cfg(test)]
|
||||
pub use coreops::ops::{Drop};
|
||||
#[cfg(test)]
|
||||
pub use coreops::ops::{Add, Sub, Mul, Div, Modulo, Neg, BitAnd, BitOr};
|
||||
#[cfg(test)]
|
||||
pub use coreops::ops::{BitXor};
|
||||
#[cfg(test)]
|
||||
pub use coreops::ops::{Shl, Shr, Index};
|
||||
|
||||
|
||||
// Export the log levels as global constants. Higher levels mean
|
||||
// more-verbosity. Error is the bottom level, default logging level is
|
||||
// warn-and-below.
|
||||
|
||||
/// The error log level
|
||||
pub const error : u32 = 1_u32;
|
||||
/// The warning log level
|
||||
pub const warn : u32 = 2_u32;
|
||||
/// The info log level
|
||||
pub const info : u32 = 3_u32;
|
||||
/// The debug log level
|
||||
pub const debug : u32 = 4_u32;
|
||||
|
||||
// A curious inner-module that's not exported that contains the binding
|
||||
// 'core' so that macro-expanded references to core::error and such
|
||||
// can be resolved within libcore.
|
||||
#[doc(hidden)] // FIXME #3538
|
||||
mod core {
|
||||
pub const error : u32 = 1_u32;
|
||||
pub const warn : u32 = 2_u32;
|
||||
pub const info : u32 = 3_u32;
|
||||
pub const debug : u32 = 4_u32;
|
||||
}
|
||||
|
||||
// Similar to above. Some magic to make core testable.
|
||||
#[cfg(test)]
|
||||
mod std {
|
||||
extern mod std(vers = "0.5");
|
||||
pub use std::test;
|
||||
}
|
||||
|
||||
// Local Variables:
|
||||
// mode: rust;
|
||||
// fill-column: 78;
|
||||
// indent-tabs-mode: nil
|
||||
// c-basic-offset: 4
|
||||
// buffer-file-coding-system: utf-8-unix
|
||||
// End:
|
@ -1,3 +1,5 @@
|
||||
// DIVERT
|
||||
|
||||
/*!
|
||||
|
||||
The Rust core library.
|
||||
|
4
src/libcore/int-template/i16b.rs
Normal file
4
src/libcore/int-template/i16b.rs
Normal file
@ -0,0 +1,4 @@
|
||||
mod inst {
|
||||
pub type T = i16;
|
||||
pub const bits: uint = u16::bits;
|
||||
}
|
4
src/libcore/int-template/i32b.rs
Normal file
4
src/libcore/int-template/i32b.rs
Normal file
@ -0,0 +1,4 @@
|
||||
mod inst {
|
||||
pub type T = i32;
|
||||
pub const bits: uint = u32::bits;
|
||||
}
|
4
src/libcore/int-template/i64b.rs
Normal file
4
src/libcore/int-template/i64b.rs
Normal file
@ -0,0 +1,4 @@
|
||||
mod inst {
|
||||
pub type T = i64;
|
||||
pub const bits: uint = u64::bits;
|
||||
}
|
4
src/libcore/int-template/i8b.rs
Normal file
4
src/libcore/int-template/i8b.rs
Normal file
@ -0,0 +1,4 @@
|
||||
mod inst {
|
||||
pub type T = i8;
|
||||
pub const bits: uint = u8::bits;
|
||||
}
|
45
src/libcore/int-template/intb.rs
Normal file
45
src/libcore/int-template/intb.rs
Normal file
@ -0,0 +1,45 @@
|
||||
pub use inst::pow;
|
||||
|
||||
mod inst {
|
||||
pub type T = int;
|
||||
pub const bits: uint = uint::bits;
|
||||
|
||||
/// Returns `base` raised to the power of `exponent`
|
||||
pub fn pow(base: int, exponent: uint) -> int {
|
||||
if exponent == 0u {
|
||||
//Not mathemtically true if ~[base == 0]
|
||||
return 1;
|
||||
}
|
||||
if base == 0 { return 0; }
|
||||
let mut my_pow = exponent;
|
||||
let mut acc = 1;
|
||||
let mut multiplier = base;
|
||||
while(my_pow > 0u) {
|
||||
if my_pow % 2u == 1u {
|
||||
acc *= multiplier;
|
||||
}
|
||||
my_pow /= 2u;
|
||||
multiplier *= multiplier;
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pow() {
|
||||
assert (pow(0, 0u) == 1);
|
||||
assert (pow(0, 1u) == 0);
|
||||
assert (pow(0, 2u) == 0);
|
||||
assert (pow(-1, 0u) == 1);
|
||||
assert (pow(1, 0u) == 1);
|
||||
assert (pow(-3, 2u) == 9);
|
||||
assert (pow(-3, 3u) == -27);
|
||||
assert (pow(4, 9u) == 262144);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_overflows() {
|
||||
assert (max_value > 0);
|
||||
assert (min_value <= 0);
|
||||
assert (min_value + max_value + 1 == 0);
|
||||
}
|
||||
}
|
38
src/libcore/iter-trait/dlistb.rs
Normal file
38
src/libcore/iter-trait/dlistb.rs
Normal file
@ -0,0 +1,38 @@
|
||||
mod inst {
|
||||
#[allow(non_camel_case_types)]
|
||||
pub type IMPL_T<A> = dlist::DList<A>;
|
||||
|
||||
/**
|
||||
* Iterates through the current contents.
|
||||
*
|
||||
* Attempts to access this dlist during iteration are allowed (to
|
||||
* allow for e.g. breadth-first search with in-place enqueues), but
|
||||
* removing the current node is forbidden.
|
||||
*/
|
||||
pub pure fn EACH<A>(self: &IMPL_T<A>, f: fn(v: &A) -> bool) {
|
||||
let mut link = self.peek_n();
|
||||
while option::is_some(&link) {
|
||||
let nobe = option::get(link);
|
||||
assert nobe.linked;
|
||||
if !f(&nobe.data) { break; }
|
||||
// Check (weakly) that the user didn't do a remove.
|
||||
if self.size == 0 {
|
||||
fail ~"The dlist became empty during iteration??"
|
||||
}
|
||||
if !nobe.linked ||
|
||||
(!((nobe.prev.is_some()
|
||||
|| box::ptr_eq(*self.hd.expect(~"headless dlist?"),
|
||||
*nobe))
|
||||
&& (nobe.next.is_some()
|
||||
|| box::ptr_eq(*self.tl.expect(~"tailless dlist?"),
|
||||
*nobe)))) {
|
||||
fail ~"Removing a dlist node during iteration is forbidden!"
|
||||
}
|
||||
link = nobe.next_link();
|
||||
}
|
||||
}
|
||||
|
||||
pub pure fn SIZE_HINT<A>(self: &IMPL_T<A>) -> Option<uint> {
|
||||
Some(self.len())
|
||||
}
|
||||
}
|
22
src/libcore/iter-trait/dvecb.rs
Normal file
22
src/libcore/iter-trait/dvecb.rs
Normal file
@ -0,0 +1,22 @@
|
||||
mod inst {
|
||||
#[allow(non_camel_case_types)]
|
||||
pub type IMPL_T<A> = dvec::DVec<A>;
|
||||
|
||||
/**
|
||||
* Iterates through the current contents.
|
||||
*
|
||||
* Attempts to access this dvec during iteration will fail.
|
||||
*/
|
||||
pub pure fn EACH<A>(self: &IMPL_T<A>, f: fn(v: &A) -> bool) {
|
||||
unsafe {
|
||||
do self.swap |v| {
|
||||
v.each(f);
|
||||
move v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub pure fn SIZE_HINT<A>(self: &IMPL_T<A>) -> Option<uint> {
|
||||
Some(self.len())
|
||||
}
|
||||
}
|
18
src/libcore/iter-trait/optionb.rs
Normal file
18
src/libcore/iter-trait/optionb.rs
Normal file
@ -0,0 +1,18 @@
|
||||
mod inst {
|
||||
#[allow(non_camel_case_types)]
|
||||
pub type IMPL_T<A> = Option<A>;
|
||||
|
||||
pub pure fn EACH<A>(self: &IMPL_T<A>, f: fn(v: &A) -> bool) {
|
||||
match *self {
|
||||
None => (),
|
||||
Some(ref a) => { f(a); }
|
||||
}
|
||||
}
|
||||
|
||||
pub pure fn SIZE_HINT<A>(self: &IMPL_T<A>) -> Option<uint> {
|
||||
match *self {
|
||||
None => Some(0),
|
||||
Some(_) => Some(1)
|
||||
}
|
||||
}
|
||||
}
|
8
src/libcore/task/mod.rs
Normal file
8
src/libcore/task/mod.rs
Normal file
@ -0,0 +1,8 @@
|
||||
|
||||
mod local_data_priv;
|
||||
|
||||
pub mod local_data;
|
||||
|
||||
pub mod rt;
|
||||
|
||||
pub mod spawn;
|
4
src/libcore/uint-template/u16b.rs
Normal file
4
src/libcore/uint-template/u16b.rs
Normal file
@ -0,0 +1,4 @@
|
||||
mod inst {
|
||||
pub type T = u16;
|
||||
pub const bits: uint = 16;
|
||||
}
|
4
src/libcore/uint-template/u32b.rs
Normal file
4
src/libcore/uint-template/u32b.rs
Normal file
@ -0,0 +1,4 @@
|
||||
mod inst {
|
||||
pub type T = u32;
|
||||
pub const bits: uint = 32;
|
||||
}
|
4
src/libcore/uint-template/u64b.rs
Normal file
4
src/libcore/uint-template/u64b.rs
Normal file
@ -0,0 +1,4 @@
|
||||
mod inst {
|
||||
pub type T = u64;
|
||||
pub const bits: uint = 64;
|
||||
}
|
11
src/libcore/uint-template/u8b.rs
Normal file
11
src/libcore/uint-template/u8b.rs
Normal file
@ -0,0 +1,11 @@
|
||||
pub use inst::is_ascii;
|
||||
|
||||
mod inst {
|
||||
pub type T = u8;
|
||||
pub const bits: uint = 8;
|
||||
|
||||
// Type-specific functions here. These must be reexported by the
|
||||
// parent module so that they appear in core::u8 and not core::u8::u8;
|
||||
|
||||
pub pure fn is_ascii(x: T) -> bool { return 0 as T == x & 128 as T; }
|
||||
}
|
160
src/libcore/uint-template/uintb.rs
Normal file
160
src/libcore/uint-template/uintb.rs
Normal file
@ -0,0 +1,160 @@
|
||||
pub use inst::{
|
||||
div_ceil, div_round, div_floor, iterate,
|
||||
next_power_of_two
|
||||
};
|
||||
|
||||
mod inst {
|
||||
pub type T = uint;
|
||||
|
||||
#[cfg(target_arch = "x86")]
|
||||
#[cfg(target_arch = "arm")]
|
||||
pub const bits: uint = 32;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub const bits: uint = 64;
|
||||
|
||||
/**
|
||||
* Divide two numbers, return the result, rounded up.
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * x - an integer
|
||||
* * y - an integer distinct from 0u
|
||||
*
|
||||
* # Return value
|
||||
*
|
||||
* The smallest integer `q` such that `x/y <= q`.
|
||||
*/
|
||||
pub pure fn div_ceil(x: uint, y: uint) -> uint {
|
||||
let div = x / y;
|
||||
if x % y == 0u { div }
|
||||
else { div + 1u }
|
||||
}
|
||||
|
||||
/**
|
||||
* Divide two numbers, return the result, rounded to the closest integer.
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * x - an integer
|
||||
* * y - an integer distinct from 0u
|
||||
*
|
||||
* # Return value
|
||||
*
|
||||
* The integer `q` closest to `x/y`.
|
||||
*/
|
||||
pub pure fn div_round(x: uint, y: uint) -> uint {
|
||||
let div = x / y;
|
||||
if x % y * 2u < y { div }
|
||||
else { div + 1u }
|
||||
}
|
||||
|
||||
/**
|
||||
* Divide two numbers, return the result, rounded down.
|
||||
*
|
||||
* Note: This is the same function as `div`.
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * x - an integer
|
||||
* * y - an integer distinct from 0u
|
||||
*
|
||||
* # Return value
|
||||
*
|
||||
* The smallest integer `q` such that `x/y <= q`. This
|
||||
* is either `x/y` or `x/y + 1`.
|
||||
*/
|
||||
pub pure fn div_floor(x: uint, y: uint) -> uint { return x / y; }
|
||||
|
||||
/**
|
||||
* Iterate over the range [`lo`..`hi`), or stop when requested
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * lo - The integer at which to start the loop (included)
|
||||
* * hi - The integer at which to stop the loop (excluded)
|
||||
* * it - A block to execute with each consecutive integer of the range.
|
||||
* Return `true` to continue, `false` to stop.
|
||||
*
|
||||
* # Return value
|
||||
*
|
||||
* `true` If execution proceeded correctly, `false` if it was interrupted,
|
||||
* that is if `it` returned `false` at any point.
|
||||
*/
|
||||
pub pure fn iterate(lo: uint, hi: uint, it: fn(uint) -> bool) -> bool {
|
||||
let mut i = lo;
|
||||
while i < hi {
|
||||
if (!it(i)) { return false; }
|
||||
i += 1u;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Returns the smallest power of 2 greater than or equal to `n`
|
||||
#[inline(always)]
|
||||
pub fn next_power_of_two(n: uint) -> uint {
|
||||
let halfbits: uint = sys::size_of::<uint>() * 4u;
|
||||
let mut tmp: uint = n - 1u;
|
||||
let mut shift: uint = 1u;
|
||||
while shift <= halfbits { tmp |= tmp >> shift; shift <<= 1u; }
|
||||
return tmp + 1u;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_next_power_of_two() {
|
||||
assert (uint::next_power_of_two(0u) == 0u);
|
||||
assert (uint::next_power_of_two(1u) == 1u);
|
||||
assert (uint::next_power_of_two(2u) == 2u);
|
||||
assert (uint::next_power_of_two(3u) == 4u);
|
||||
assert (uint::next_power_of_two(4u) == 4u);
|
||||
assert (uint::next_power_of_two(5u) == 8u);
|
||||
assert (uint::next_power_of_two(6u) == 8u);
|
||||
assert (uint::next_power_of_two(7u) == 8u);
|
||||
assert (uint::next_power_of_two(8u) == 8u);
|
||||
assert (uint::next_power_of_two(9u) == 16u);
|
||||
assert (uint::next_power_of_two(10u) == 16u);
|
||||
assert (uint::next_power_of_two(11u) == 16u);
|
||||
assert (uint::next_power_of_two(12u) == 16u);
|
||||
assert (uint::next_power_of_two(13u) == 16u);
|
||||
assert (uint::next_power_of_two(14u) == 16u);
|
||||
assert (uint::next_power_of_two(15u) == 16u);
|
||||
assert (uint::next_power_of_two(16u) == 16u);
|
||||
assert (uint::next_power_of_two(17u) == 32u);
|
||||
assert (uint::next_power_of_two(18u) == 32u);
|
||||
assert (uint::next_power_of_two(19u) == 32u);
|
||||
assert (uint::next_power_of_two(20u) == 32u);
|
||||
assert (uint::next_power_of_two(21u) == 32u);
|
||||
assert (uint::next_power_of_two(22u) == 32u);
|
||||
assert (uint::next_power_of_two(23u) == 32u);
|
||||
assert (uint::next_power_of_two(24u) == 32u);
|
||||
assert (uint::next_power_of_two(25u) == 32u);
|
||||
assert (uint::next_power_of_two(26u) == 32u);
|
||||
assert (uint::next_power_of_two(27u) == 32u);
|
||||
assert (uint::next_power_of_two(28u) == 32u);
|
||||
assert (uint::next_power_of_two(29u) == 32u);
|
||||
assert (uint::next_power_of_two(30u) == 32u);
|
||||
assert (uint::next_power_of_two(31u) == 32u);
|
||||
assert (uint::next_power_of_two(32u) == 32u);
|
||||
assert (uint::next_power_of_two(33u) == 64u);
|
||||
assert (uint::next_power_of_two(34u) == 64u);
|
||||
assert (uint::next_power_of_two(35u) == 64u);
|
||||
assert (uint::next_power_of_two(36u) == 64u);
|
||||
assert (uint::next_power_of_two(37u) == 64u);
|
||||
assert (uint::next_power_of_two(38u) == 64u);
|
||||
assert (uint::next_power_of_two(39u) == 64u);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_overflows() {
|
||||
assert (uint::max_value > 0u);
|
||||
assert (uint::min_value <= 0u);
|
||||
assert (uint::min_value + uint::max_value + 1u == 0u);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_div() {
|
||||
assert(uint::div_floor(3u, 4u) == 0u);
|
||||
assert(uint::div_ceil(3u, 4u) == 1u);
|
||||
assert(uint::div_round(3u, 4u) == 1u);
|
||||
}
|
||||
}
|
@ -24,6 +24,635 @@ extern mod syntax(vers = "0.5");
|
||||
|
||||
use core::*;
|
||||
|
||||
use io::WriterUtil;
|
||||
|
||||
use syntax::{ast, ast_util, fold, visit, codemap};
|
||||
use syntax::parse;
|
||||
use syntax::print::pprust;
|
||||
use syntax::diagnostic;
|
||||
|
||||
enum test_mode { tm_converge, tm_run, }
|
||||
type context = { mode: test_mode }; // + rng
|
||||
|
||||
#[cfg(stage0)]
|
||||
impl test_mode : cmp::Eq {
|
||||
pure fn eq(other: &test_mode) -> bool {
|
||||
(self as uint) == ((*other) as uint)
|
||||
}
|
||||
pure fn ne(other: &test_mode) -> bool { !self.eq(other) }
|
||||
}
|
||||
|
||||
#[cfg(stage1)]
|
||||
#[cfg(stage2)]
|
||||
impl test_mode : cmp::Eq {
|
||||
pure fn eq(&self, other: &test_mode) -> bool {
|
||||
((*self) as uint) == ((*other) as uint)
|
||||
}
|
||||
pure fn ne(&self, other: &test_mode) -> bool { !(*self).eq(other) }
|
||||
}
|
||||
|
||||
fn write_file(filename: &Path, content: ~str) {
|
||||
result::get(
|
||||
&io::file_writer(filename, ~[io::Create, io::Truncate]))
|
||||
.write_str(content);
|
||||
}
|
||||
|
||||
fn contains(haystack: ~str, needle: ~str) -> bool {
|
||||
str::contains(haystack, needle)
|
||||
}
|
||||
|
||||
fn find_rust_files(files: &mut ~[Path], path: &Path) {
|
||||
if path.filetype() == Some(~".rs") && !contains(path.to_str(), ~"utf8") {
|
||||
// ignoring "utf8" tests because something is broken
|
||||
files.push(*path);
|
||||
} else if os::path_is_dir(path)
|
||||
&& !contains(path.to_str(), ~"compile-fail")
|
||||
&& !contains(path.to_str(), ~"build") {
|
||||
for os::list_dir_path(path).each |p| {
|
||||
find_rust_files(files, *p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn common_exprs() -> ~[ast::expr] {
|
||||
fn dse(e: ast::expr_) -> ast::expr {
|
||||
{ id: 0, callee_id: -1, node: e, span: ast_util::dummy_sp() }
|
||||
}
|
||||
|
||||
fn dsl(l: ast::lit_) -> ast::lit {
|
||||
{ node: l, span: ast_util::dummy_sp() }
|
||||
}
|
||||
|
||||
~[dse(ast::expr_break(option::None)),
|
||||
dse(ast::expr_again(option::None)),
|
||||
dse(ast::expr_fail(option::None)),
|
||||
dse(ast::expr_fail(option::Some(
|
||||
@dse(ast::expr_lit(@dsl(ast::lit_str(@~"boo"))))))),
|
||||
dse(ast::expr_ret(option::None)),
|
||||
dse(ast::expr_lit(@dsl(ast::lit_nil))),
|
||||
dse(ast::expr_lit(@dsl(ast::lit_bool(false)))),
|
||||
dse(ast::expr_lit(@dsl(ast::lit_bool(true)))),
|
||||
dse(ast::expr_unary(ast::box(ast::m_imm),
|
||||
@dse(ast::expr_lit(@dsl(ast::lit_bool(true)))))),
|
||||
dse(ast::expr_unary(ast::uniq(ast::m_imm),
|
||||
@dse(ast::expr_lit(@dsl(ast::lit_bool(true))))))
|
||||
]
|
||||
}
|
||||
|
||||
pure fn safe_to_steal_expr(e: @ast::expr, tm: test_mode) -> bool {
|
||||
safe_to_use_expr(*e, tm)
|
||||
}
|
||||
|
||||
pure fn safe_to_use_expr(e: ast::expr, tm: test_mode) -> bool {
|
||||
match tm {
|
||||
tm_converge => {
|
||||
match e.node {
|
||||
// If the fuzzer moves a block-ending-in-semicolon into callee
|
||||
// position, the pretty-printer can't preserve this even by
|
||||
// parenthesizing!! See email to marijn.
|
||||
ast::expr_if(*) | ast::expr_block(*)
|
||||
| ast::expr_match(*) | ast::expr_while(*) => { false }
|
||||
|
||||
// https://github.com/mozilla/rust/issues/929
|
||||
ast::expr_cast(*) | ast::expr_assert(*) |
|
||||
ast::expr_binary(*) | ast::expr_assign(*) |
|
||||
ast::expr_assign_op(*) => { false }
|
||||
|
||||
ast::expr_fail(option::None) |
|
||||
ast::expr_ret(option::None) => { false }
|
||||
|
||||
// https://github.com/mozilla/rust/issues/953
|
||||
ast::expr_fail(option::Some(_)) => { false }
|
||||
|
||||
// https://github.com/mozilla/rust/issues/928
|
||||
//ast::expr_cast(_, _) { false }
|
||||
|
||||
// https://github.com/mozilla/rust/issues/1458
|
||||
ast::expr_call(_, _, _) => { false }
|
||||
|
||||
_ => { true }
|
||||
}
|
||||
}
|
||||
tm_run => { true }
|
||||
}
|
||||
}
|
||||
|
||||
fn safe_to_steal_ty(t: @ast::Ty, tm: test_mode) -> bool {
|
||||
// Restrictions happen to be the same.
|
||||
safe_to_replace_ty(t.node, tm)
|
||||
}
|
||||
|
||||
// Not type-parameterized: https://github.com/mozilla/rust/issues/898 (FIXED)
|
||||
fn stash_expr_if(c: fn@(@ast::expr, test_mode)->bool,
|
||||
es: @mut ~[ast::expr],
|
||||
e: @ast::expr,
|
||||
tm: test_mode) {
|
||||
if c(e, tm) {
|
||||
*es += ~[*e];
|
||||
} else {/* now my indices are wrong :( */ }
|
||||
}
|
||||
|
||||
fn stash_ty_if(c: fn@(@ast::Ty, test_mode)->bool,
|
||||
es: @mut ~[ast::Ty],
|
||||
e: @ast::Ty,
|
||||
tm: test_mode) {
|
||||
if c(e, tm) {
|
||||
es.push(*e);
|
||||
} else {/* now my indices are wrong :( */ }
|
||||
}
|
||||
|
||||
type stolen_stuff = {exprs: ~[ast::expr], tys: ~[ast::Ty]};
|
||||
|
||||
fn steal(crate: ast::crate, tm: test_mode) -> stolen_stuff {
|
||||
let exprs = @mut ~[];
|
||||
let tys = @mut ~[];
|
||||
let v = visit::mk_simple_visitor(@{
|
||||
visit_expr: |a| stash_expr_if(safe_to_steal_expr, exprs, a, tm),
|
||||
visit_ty: |a| stash_ty_if(safe_to_steal_ty, tys, a, tm),
|
||||
.. *visit::default_simple_visitor()
|
||||
});
|
||||
visit::visit_crate(crate, (), v);
|
||||
{exprs: *exprs, tys: *tys}
|
||||
}
|
||||
|
||||
|
||||
fn safe_to_replace_expr(e: ast::expr_, _tm: test_mode) -> bool {
|
||||
match e {
|
||||
// https://github.com/mozilla/rust/issues/652
|
||||
ast::expr_if(*) => { false }
|
||||
ast::expr_block(_) => { false }
|
||||
|
||||
// expr_call is also missing a constraint
|
||||
ast::expr_fn_block(*) => { false }
|
||||
|
||||
_ => { true }
|
||||
}
|
||||
}
|
||||
|
||||
fn safe_to_replace_ty(t: ast::ty_, _tm: test_mode) -> bool {
|
||||
match t {
|
||||
ast::ty_infer => { false } // always implicit, always top level
|
||||
ast::ty_bot => { false } // in source, can only appear
|
||||
// as the out type of a function
|
||||
ast::ty_mac(_) => { false }
|
||||
_ => { true }
|
||||
}
|
||||
}
|
||||
|
||||
// Replace the |i|th expr (in fold order) of |crate| with |newexpr|.
|
||||
fn replace_expr_in_crate(crate: ast::crate, i: uint,
|
||||
newexpr: ast::expr, tm: test_mode) ->
|
||||
ast::crate {
|
||||
let j: @mut uint = @mut 0u;
|
||||
fn fold_expr_rep(j_: @mut uint, i_: uint, newexpr_: ast::expr_,
|
||||
original: ast::expr_, fld: fold::ast_fold,
|
||||
tm_: test_mode) ->
|
||||
ast::expr_ {
|
||||
*j_ += 1u;
|
||||
if i_ + 1u == *j_ && safe_to_replace_expr(original, tm_) {
|
||||
newexpr_
|
||||
} else {
|
||||
fold::noop_fold_expr(original, fld)
|
||||
}
|
||||
}
|
||||
let afp = @{
|
||||
fold_expr: fold::wrap(|a,b| {
|
||||
fold_expr_rep(j, i, newexpr.node, a, b, tm)
|
||||
}),
|
||||
.. *fold::default_ast_fold()
|
||||
};
|
||||
let af = fold::make_fold(afp);
|
||||
let crate2: @ast::crate = @af.fold_crate(crate);
|
||||
*crate2
|
||||
}
|
||||
|
||||
|
||||
// Replace the |i|th ty (in fold order) of |crate| with |newty|.
|
||||
fn replace_ty_in_crate(crate: ast::crate, i: uint, newty: ast::Ty,
|
||||
tm: test_mode) -> ast::crate {
|
||||
let j: @mut uint = @mut 0u;
|
||||
fn fold_ty_rep(j_: @mut uint, i_: uint, newty_: ast::ty_,
|
||||
original: ast::ty_, fld: fold::ast_fold,
|
||||
tm_: test_mode) ->
|
||||
ast::ty_ {
|
||||
*j_ += 1u;
|
||||
if i_ + 1u == *j_ && safe_to_replace_ty(original, tm_) {
|
||||
newty_
|
||||
} else { fold::noop_fold_ty(original, fld) }
|
||||
}
|
||||
let afp = @{
|
||||
fold_ty: fold::wrap(|a,b| fold_ty_rep(j, i, newty.node, a, b, tm) ),
|
||||
.. *fold::default_ast_fold()
|
||||
};
|
||||
let af = fold::make_fold(afp);
|
||||
let crate2: @ast::crate = @af.fold_crate(crate);
|
||||
*crate2
|
||||
}
|
||||
|
||||
fn under(n: uint, it: fn(uint)) {
|
||||
let mut i: uint = 0u;
|
||||
while i < n { it(i); i += 1u; }
|
||||
}
|
||||
|
||||
fn as_str(f: fn@(+x: io::Writer)) -> ~str {
|
||||
io::with_str_writer(f)
|
||||
}
|
||||
|
||||
fn check_variants_of_ast(crate: ast::crate, codemap: @codemap::CodeMap,
|
||||
filename: &Path, cx: context) {
|
||||
let stolen = steal(crate, cx.mode);
|
||||
let extra_exprs = vec::filter(common_exprs(),
|
||||
|a| safe_to_use_expr(*a, cx.mode) );
|
||||
check_variants_T(crate, codemap, filename, ~"expr",
|
||||
extra_exprs + stolen.exprs, pprust::expr_to_str,
|
||||
replace_expr_in_crate, cx);
|
||||
check_variants_T(crate, codemap, filename, ~"ty", stolen.tys,
|
||||
pprust::ty_to_str, replace_ty_in_crate, cx);
|
||||
}
|
||||
|
||||
fn check_variants_T<T: Copy>(
|
||||
crate: ast::crate,
|
||||
codemap: @codemap::CodeMap,
|
||||
filename: &Path,
|
||||
thing_label: ~str,
|
||||
things: ~[T],
|
||||
stringifier: fn@(@T, @syntax::parse::token::ident_interner) -> ~str,
|
||||
replacer: fn@(ast::crate, uint, T, test_mode) -> ast::crate,
|
||||
cx: context
|
||||
) {
|
||||
error!("%s contains %u %s objects", filename.to_str(),
|
||||
things.len(), thing_label);
|
||||
|
||||
// Assuming we're not generating any token_trees
|
||||
let intr = syntax::parse::token::mk_fake_ident_interner();
|
||||
|
||||
let L = things.len();
|
||||
|
||||
if L < 100 {
|
||||
do under(uint::min(L, 20)) |i| {
|
||||
log(error, ~"Replacing... #" + uint::str(i));
|
||||
let fname = str::from_slice(filename.to_str());
|
||||
do under(uint::min(L, 30)) |j| {
|
||||
log(error, ~"With... " + stringifier(@things[j], intr));
|
||||
let crate2 = @replacer(crate, i, things[j], cx.mode);
|
||||
// It would be best to test the *crate* for stability, but
|
||||
// testing the string for stability is easier and ok for now.
|
||||
let handler = diagnostic::mk_handler(None);
|
||||
let str3 = do io::with_str_reader("") |rdr| {
|
||||
@as_str(|a|pprust::print_crate(
|
||||
codemap,
|
||||
intr,
|
||||
diagnostic::mk_span_handler(handler, codemap),
|
||||
crate2,
|
||||
fname,
|
||||
rdr, a,
|
||||
pprust::no_ann(),
|
||||
false))
|
||||
};
|
||||
match cx.mode {
|
||||
tm_converge => {
|
||||
check_roundtrip_convergence(str3, 1u);
|
||||
}
|
||||
tm_run => {
|
||||
let file_label = fmt!("rusttmp/%s_%s_%u_%u",
|
||||
last_part(filename.to_str()),
|
||||
thing_label, i, j);
|
||||
let safe_to_run = !(content_is_dangerous_to_run(*str3)
|
||||
|| has_raw_pointers(*crate2));
|
||||
check_whole_compiler(*str3, &Path(file_label),
|
||||
safe_to_run);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn last_part(filename: ~str) -> ~str {
|
||||
let ix = option::get(str::rfind_char(filename, '/'));
|
||||
str::slice(filename, ix + 1u, str::len(filename) - 3u)
|
||||
}
|
||||
|
||||
enum happiness {
|
||||
passed,
|
||||
cleanly_rejected(~str),
|
||||
known_bug(~str),
|
||||
failed(~str),
|
||||
}
|
||||
|
||||
// We'd find more bugs if we could take an AST here, but
|
||||
// - that would find many "false positives" or unimportant bugs
|
||||
// - that would be tricky, requiring use of tasks or serialization
|
||||
// or randomness.
|
||||
// This seems to find plenty of bugs as it is :)
|
||||
fn check_whole_compiler(code: ~str, suggested_filename_prefix: &Path,
|
||||
allow_running: bool) {
|
||||
let filename = &suggested_filename_prefix.with_filetype("rs");
|
||||
write_file(filename, code);
|
||||
|
||||
let compile_result = check_compiling(filename);
|
||||
|
||||
let run_result = match (compile_result, allow_running) {
|
||||
(passed, true) => { check_running(suggested_filename_prefix) }
|
||||
(h, _) => { h }
|
||||
};
|
||||
|
||||
match run_result {
|
||||
passed | cleanly_rejected(_) | known_bug(_) => {
|
||||
removeIfExists(suggested_filename_prefix);
|
||||
removeIfExists(&suggested_filename_prefix.with_filetype("rs"));
|
||||
removeDirIfExists(&suggested_filename_prefix.with_filetype("dSYM"));
|
||||
}
|
||||
failed(s) => {
|
||||
log(error, ~"check_whole_compiler failure: " + s);
|
||||
log(error, ~"Saved as: " + filename.to_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn removeIfExists(filename: &Path) {
|
||||
// So sketchy!
|
||||
assert !contains(filename.to_str(), ~" ");
|
||||
run::program_output(~"bash", ~[~"-c", ~"rm " + filename.to_str()]);
|
||||
}
|
||||
|
||||
fn removeDirIfExists(filename: &Path) {
|
||||
// So sketchy!
|
||||
assert !contains(filename.to_str(), ~" ");
|
||||
run::program_output(~"bash", ~[~"-c", ~"rm -r " + filename.to_str()]);
|
||||
}
|
||||
|
||||
fn check_running(exe_filename: &Path) -> happiness {
|
||||
let p = run::program_output(
|
||||
~"/Users/jruderman/scripts/timed_run_rust_program.py",
|
||||
~[exe_filename.to_str()]);
|
||||
let comb = p.out + ~"\n" + p.err;
|
||||
if str::len(comb) > 1u {
|
||||
log(error, ~"comb comb comb: " + comb);
|
||||
}
|
||||
|
||||
if contains(comb, ~"Assertion failed:") {
|
||||
failed(~"C++ assertion failure")
|
||||
} else if contains(comb, ~"leaked memory in rust main loop") {
|
||||
// might also use exit code 134
|
||||
//failed("Leaked")
|
||||
known_bug(~"https://github.com/mozilla/rust/issues/910")
|
||||
} else if contains(comb, ~"src/rt/") {
|
||||
failed(~"Mentioned src/rt/")
|
||||
} else if contains(comb, ~"malloc") {
|
||||
failed(~"Mentioned malloc")
|
||||
} else {
|
||||
match p.status {
|
||||
0 => { passed }
|
||||
100 => { cleanly_rejected(~"running: explicit fail") }
|
||||
101 | 247 => { cleanly_rejected(~"running: timed out") }
|
||||
245 | 246 | 138 | 252 => {
|
||||
known_bug(~"https://github.com/mozilla/rust/issues/1466")
|
||||
}
|
||||
136 | 248 => {
|
||||
known_bug(
|
||||
~"SIGFPE - https://github.com/mozilla/rust/issues/944")
|
||||
}
|
||||
rc => {
|
||||
failed(~"Rust program ran but exited with status " +
|
||||
int::str(rc))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_compiling(filename: &Path) -> happiness {
|
||||
let p = run::program_output(
|
||||
~"/Users/jruderman/code/rust/build/x86_64-apple-darwin/\
|
||||
stage1/bin/rustc",
|
||||
~[filename.to_str()]);
|
||||
|
||||
//error!("Status: %d", p.status);
|
||||
if p.status == 0 {
|
||||
passed
|
||||
} else if p.err != ~"" {
|
||||
if contains(p.err, ~"error:") {
|
||||
cleanly_rejected(~"rejected with span_error")
|
||||
} else {
|
||||
log(error, ~"Stderr: " + p.err);
|
||||
failed(~"Unfamiliar error message")
|
||||
}
|
||||
} else if contains(p.out, ~"Assertion") && contains(p.out, ~"failed") {
|
||||
log(error, ~"Stdout: " + p.out);
|
||||
failed(~"Looks like an llvm assertion failure")
|
||||
} else if contains(p.out, ~"internal compiler error unimplemented") {
|
||||
known_bug(~"Something unimplemented")
|
||||
} else if contains(p.out, ~"internal compiler error") {
|
||||
log(error, ~"Stdout: " + p.out);
|
||||
failed(~"internal compiler error")
|
||||
|
||||
} else {
|
||||
log(error, p.status);
|
||||
log(error, ~"!Stdout: " + p.out);
|
||||
failed(~"What happened?")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn parse_and_print(code: @~str) -> ~str {
|
||||
let filename = Path("tmp.rs");
|
||||
let sess = parse::new_parse_sess(option::None);
|
||||
write_file(&filename, *code);
|
||||
let crate = parse::parse_crate_from_source_str(
|
||||
filename.to_str(), code, ~[], sess);
|
||||
do io::with_str_reader(*code) |rdr| {
|
||||
as_str(|a|
|
||||
pprust::print_crate(
|
||||
sess.cm,
|
||||
// Assuming there are no token_trees
|
||||
syntax::parse::token::mk_fake_ident_interner(),
|
||||
sess.span_diagnostic,
|
||||
crate,
|
||||
filename.to_str(),
|
||||
rdr, a,
|
||||
pprust::no_ann(),
|
||||
false) )
|
||||
}
|
||||
}
|
||||
|
||||
fn has_raw_pointers(c: ast::crate) -> bool {
|
||||
let has_rp = @mut false;
|
||||
fn visit_ty(flag: @mut bool, t: @ast::Ty) {
|
||||
match t.node {
|
||||
ast::ty_ptr(_) => { *flag = true; }
|
||||
_ => { }
|
||||
}
|
||||
}
|
||||
let v =
|
||||
visit::mk_simple_visitor(@{visit_ty: |a| visit_ty(has_rp, a),
|
||||
.. *visit::default_simple_visitor()});
|
||||
visit::visit_crate(c, (), v);
|
||||
return *has_rp;
|
||||
}
|
||||
|
||||
fn content_is_dangerous_to_run(code: ~str) -> bool {
|
||||
let dangerous_patterns =
|
||||
~[~"xfail-test",
|
||||
~"import", // espeically fs, run
|
||||
~"extern",
|
||||
~"unsafe",
|
||||
~"log"]; // python --> rust pipe deadlock?
|
||||
|
||||
for dangerous_patterns.each |p| { if contains(code, *p) { return true; } }
|
||||
return false;
|
||||
}
|
||||
|
||||
fn content_is_dangerous_to_compile(code: ~str) -> bool {
|
||||
let dangerous_patterns =
|
||||
~[~"xfail-test"];
|
||||
|
||||
for dangerous_patterns.each |p| { if contains(code, *p) { return true; } }
|
||||
return false;
|
||||
}
|
||||
|
||||
fn content_might_not_converge(code: ~str) -> bool {
|
||||
let confusing_patterns =
|
||||
~[~"xfail-test",
|
||||
~"xfail-pretty",
|
||||
~"self", // crazy rules enforced by parser not typechecker?
|
||||
~"spawn", // precedence issues?
|
||||
~"bind", // precedence issues?
|
||||
~" be ", // don't want to replace its child with a non-call:
|
||||
// "Non-call expression in tail call"
|
||||
~"\n\n\n\n\n" // https://github.com/mozilla/rust/issues/850
|
||||
];
|
||||
|
||||
for confusing_patterns.each |p| { if contains(code, *p) { return true; } }
|
||||
return false;
|
||||
}
|
||||
|
||||
fn file_might_not_converge(filename: &Path) -> bool {
|
||||
let confusing_files = ~[
|
||||
~"expr-alt.rs", // pretty-printing "(a = b) = c"
|
||||
// vs "a = b = c" and wrapping
|
||||
~"block-arg-in-ternary.rs", // wrapping
|
||||
~"move-3-unique.rs", // 0 becomes (0), but both seem reasonable. wtf?
|
||||
~"move-3.rs" // 0 becomes (0), but both seem reasonable. wtf?
|
||||
];
|
||||
|
||||
|
||||
for confusing_files.each |f| {
|
||||
if contains(filename.to_str(), *f) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
fn check_roundtrip_convergence(code: @~str, maxIters: uint) {
|
||||
|
||||
let mut i = 0u;
|
||||
let mut newv = code;
|
||||
let mut oldv = code;
|
||||
|
||||
while i < maxIters {
|
||||
oldv = newv;
|
||||
if content_might_not_converge(*oldv) { return; }
|
||||
newv = @parse_and_print(oldv);
|
||||
if oldv == newv { break; }
|
||||
i += 1u;
|
||||
}
|
||||
|
||||
if oldv == newv {
|
||||
error!("Converged after %u iterations", i);
|
||||
} else {
|
||||
error!("Did not converge after %u iterations!", i);
|
||||
write_file(&Path("round-trip-a.rs"), *oldv);
|
||||
write_file(&Path("round-trip-b.rs"), *newv);
|
||||
run::run_program(~"diff",
|
||||
~[~"-w", ~"-u", ~"round-trip-a.rs",
|
||||
~"round-trip-b.rs"]);
|
||||
fail ~"Mismatch";
|
||||
}
|
||||
}
|
||||
|
||||
fn check_convergence(files: &[Path]) {
|
||||
error!("pp convergence tests: %u files", vec::len(files));
|
||||
for files.each |file| {
|
||||
if !file_might_not_converge(file) {
|
||||
let s = @result::get(&io::read_whole_file_str(file));
|
||||
if !content_might_not_converge(*s) {
|
||||
error!("pp converge: %s", file.to_str());
|
||||
// Change from 7u to 2u once
|
||||
// https://github.com/mozilla/rust/issues/850 is fixed
|
||||
check_roundtrip_convergence(s, 7u);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_variants(files: &[Path], cx: context) {
|
||||
for files.each |file| {
|
||||
if cx.mode == tm_converge &&
|
||||
file_might_not_converge(file) {
|
||||
error!("Skipping convergence test based on\
|
||||
file_might_not_converge");
|
||||
loop;
|
||||
}
|
||||
|
||||
let s = @result::get(&io::read_whole_file_str(file));
|
||||
if contains(*s, ~"#") {
|
||||
loop; // Macros are confusing
|
||||
}
|
||||
if cx.mode == tm_converge && content_might_not_converge(*s) {
|
||||
loop;
|
||||
}
|
||||
if cx.mode == tm_run && content_is_dangerous_to_compile(*s) {
|
||||
loop;
|
||||
}
|
||||
|
||||
let file_str = file.to_str();
|
||||
|
||||
log(error, ~"check_variants: " + file_str);
|
||||
let sess = parse::new_parse_sess(option::None);
|
||||
let crate =
|
||||
parse::parse_crate_from_source_str(
|
||||
file_str,
|
||||
s, ~[], sess);
|
||||
io::with_str_reader(*s, |rdr| {
|
||||
error!("%s",
|
||||
as_str(|a| pprust::print_crate(
|
||||
sess.cm,
|
||||
// Assuming no token_trees
|
||||
syntax::parse::token::mk_fake_ident_interner(),
|
||||
sess.span_diagnostic,
|
||||
crate,
|
||||
file_str,
|
||||
rdr, a,
|
||||
pprust::no_ann(),
|
||||
false)))
|
||||
});
|
||||
check_variants_of_ast(*crate, sess.cm, file, cx);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args = os::args();
|
||||
if vec::len(args) != 2u {
|
||||
error!("usage: %s <testdir>", args[0]);
|
||||
return;
|
||||
}
|
||||
let mut files = ~[];
|
||||
let root = Path(args[1]);
|
||||
|
||||
find_rust_files(&mut files, &root);
|
||||
error!("== check_convergence ==");
|
||||
check_convergence(files);
|
||||
error!("== check_variants: converge ==");
|
||||
check_variants(files, { mode: tm_converge });
|
||||
error!("== check_variants: run ==");
|
||||
check_variants(files, { mode: tm_run });
|
||||
|
||||
error!("Fuzzer done");
|
||||
}
|
||||
|
||||
// Local Variables:
|
||||
// fill-column: 78;
|
||||
// indent-tabs-mode: nil
|
||||
|
@ -1,638 +0,0 @@
|
||||
#[legacy_exports];
|
||||
|
||||
use io::WriterUtil;
|
||||
|
||||
use syntax::{ast, ast_util, fold, visit, codemap};
|
||||
use syntax::parse;
|
||||
use syntax::print::pprust;
|
||||
use syntax::diagnostic;
|
||||
|
||||
enum test_mode { tm_converge, tm_run, }
|
||||
type context = { mode: test_mode }; // + rng
|
||||
|
||||
#[cfg(stage0)]
|
||||
impl test_mode : cmp::Eq {
|
||||
pure fn eq(other: &test_mode) -> bool {
|
||||
(self as uint) == ((*other) as uint)
|
||||
}
|
||||
pure fn ne(other: &test_mode) -> bool { !self.eq(other) }
|
||||
}
|
||||
|
||||
#[cfg(stage1)]
|
||||
#[cfg(stage2)]
|
||||
impl test_mode : cmp::Eq {
|
||||
pure fn eq(&self, other: &test_mode) -> bool {
|
||||
((*self) as uint) == ((*other) as uint)
|
||||
}
|
||||
pure fn ne(&self, other: &test_mode) -> bool { !(*self).eq(other) }
|
||||
}
|
||||
|
||||
fn write_file(filename: &Path, content: ~str) {
|
||||
result::get(
|
||||
&io::file_writer(filename, ~[io::Create, io::Truncate]))
|
||||
.write_str(content);
|
||||
}
|
||||
|
||||
fn contains(haystack: ~str, needle: ~str) -> bool {
|
||||
str::contains(haystack, needle)
|
||||
}
|
||||
|
||||
fn find_rust_files(files: &mut ~[Path], path: &Path) {
|
||||
if path.filetype() == Some(~".rs") && !contains(path.to_str(), ~"utf8") {
|
||||
// ignoring "utf8" tests because something is broken
|
||||
files.push(*path);
|
||||
} else if os::path_is_dir(path)
|
||||
&& !contains(path.to_str(), ~"compile-fail")
|
||||
&& !contains(path.to_str(), ~"build") {
|
||||
for os::list_dir_path(path).each |p| {
|
||||
find_rust_files(files, *p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn common_exprs() -> ~[ast::expr] {
|
||||
fn dse(e: ast::expr_) -> ast::expr {
|
||||
{ id: 0, callee_id: -1, node: e, span: ast_util::dummy_sp() }
|
||||
}
|
||||
|
||||
fn dsl(l: ast::lit_) -> ast::lit {
|
||||
{ node: l, span: ast_util::dummy_sp() }
|
||||
}
|
||||
|
||||
~[dse(ast::expr_break(option::None)),
|
||||
dse(ast::expr_again(option::None)),
|
||||
dse(ast::expr_fail(option::None)),
|
||||
dse(ast::expr_fail(option::Some(
|
||||
@dse(ast::expr_lit(@dsl(ast::lit_str(@~"boo"))))))),
|
||||
dse(ast::expr_ret(option::None)),
|
||||
dse(ast::expr_lit(@dsl(ast::lit_nil))),
|
||||
dse(ast::expr_lit(@dsl(ast::lit_bool(false)))),
|
||||
dse(ast::expr_lit(@dsl(ast::lit_bool(true)))),
|
||||
dse(ast::expr_unary(ast::box(ast::m_imm),
|
||||
@dse(ast::expr_lit(@dsl(ast::lit_bool(true)))))),
|
||||
dse(ast::expr_unary(ast::uniq(ast::m_imm),
|
||||
@dse(ast::expr_lit(@dsl(ast::lit_bool(true))))))
|
||||
]
|
||||
}
|
||||
|
||||
pure fn safe_to_steal_expr(e: @ast::expr, tm: test_mode) -> bool {
|
||||
safe_to_use_expr(*e, tm)
|
||||
}
|
||||
|
||||
pure fn safe_to_use_expr(e: ast::expr, tm: test_mode) -> bool {
|
||||
match tm {
|
||||
tm_converge => {
|
||||
match e.node {
|
||||
// If the fuzzer moves a block-ending-in-semicolon into callee
|
||||
// position, the pretty-printer can't preserve this even by
|
||||
// parenthesizing!! See email to marijn.
|
||||
ast::expr_if(*) | ast::expr_block(*)
|
||||
| ast::expr_match(*) | ast::expr_while(*) => { false }
|
||||
|
||||
// https://github.com/mozilla/rust/issues/929
|
||||
ast::expr_cast(*) | ast::expr_assert(*) |
|
||||
ast::expr_binary(*) | ast::expr_assign(*) |
|
||||
ast::expr_assign_op(*) => { false }
|
||||
|
||||
ast::expr_fail(option::None) |
|
||||
ast::expr_ret(option::None) => { false }
|
||||
|
||||
// https://github.com/mozilla/rust/issues/953
|
||||
ast::expr_fail(option::Some(_)) => { false }
|
||||
|
||||
// https://github.com/mozilla/rust/issues/928
|
||||
//ast::expr_cast(_, _) { false }
|
||||
|
||||
// https://github.com/mozilla/rust/issues/1458
|
||||
ast::expr_call(_, _, _) => { false }
|
||||
|
||||
_ => { true }
|
||||
}
|
||||
}
|
||||
tm_run => { true }
|
||||
}
|
||||
}
|
||||
|
||||
fn safe_to_steal_ty(t: @ast::Ty, tm: test_mode) -> bool {
|
||||
// Restrictions happen to be the same.
|
||||
safe_to_replace_ty(t.node, tm)
|
||||
}
|
||||
|
||||
// Not type-parameterized: https://github.com/mozilla/rust/issues/898 (FIXED)
|
||||
fn stash_expr_if(c: fn@(@ast::expr, test_mode)->bool,
|
||||
es: @mut ~[ast::expr],
|
||||
e: @ast::expr,
|
||||
tm: test_mode) {
|
||||
if c(e, tm) {
|
||||
*es += ~[*e];
|
||||
} else {/* now my indices are wrong :( */ }
|
||||
}
|
||||
|
||||
fn stash_ty_if(c: fn@(@ast::Ty, test_mode)->bool,
|
||||
es: @mut ~[ast::Ty],
|
||||
e: @ast::Ty,
|
||||
tm: test_mode) {
|
||||
if c(e, tm) {
|
||||
es.push(*e);
|
||||
} else {/* now my indices are wrong :( */ }
|
||||
}
|
||||
|
||||
type stolen_stuff = {exprs: ~[ast::expr], tys: ~[ast::Ty]};
|
||||
|
||||
fn steal(crate: ast::crate, tm: test_mode) -> stolen_stuff {
|
||||
let exprs = @mut ~[];
|
||||
let tys = @mut ~[];
|
||||
let v = visit::mk_simple_visitor(@{
|
||||
visit_expr: |a| stash_expr_if(safe_to_steal_expr, exprs, a, tm),
|
||||
visit_ty: |a| stash_ty_if(safe_to_steal_ty, tys, a, tm),
|
||||
.. *visit::default_simple_visitor()
|
||||
});
|
||||
visit::visit_crate(crate, (), v);
|
||||
{exprs: *exprs, tys: *tys}
|
||||
}
|
||||
|
||||
|
||||
fn safe_to_replace_expr(e: ast::expr_, _tm: test_mode) -> bool {
|
||||
match e {
|
||||
// https://github.com/mozilla/rust/issues/652
|
||||
ast::expr_if(*) => { false }
|
||||
ast::expr_block(_) => { false }
|
||||
|
||||
// expr_call is also missing a constraint
|
||||
ast::expr_fn_block(*) => { false }
|
||||
|
||||
_ => { true }
|
||||
}
|
||||
}
|
||||
|
||||
fn safe_to_replace_ty(t: ast::ty_, _tm: test_mode) -> bool {
|
||||
match t {
|
||||
ast::ty_infer => { false } // always implicit, always top level
|
||||
ast::ty_bot => { false } // in source, can only appear
|
||||
// as the out type of a function
|
||||
ast::ty_mac(_) => { false }
|
||||
_ => { true }
|
||||
}
|
||||
}
|
||||
|
||||
// Replace the |i|th expr (in fold order) of |crate| with |newexpr|.
|
||||
fn replace_expr_in_crate(crate: ast::crate, i: uint,
|
||||
newexpr: ast::expr, tm: test_mode) ->
|
||||
ast::crate {
|
||||
let j: @mut uint = @mut 0u;
|
||||
fn fold_expr_rep(j_: @mut uint, i_: uint, newexpr_: ast::expr_,
|
||||
original: ast::expr_, fld: fold::ast_fold,
|
||||
tm_: test_mode) ->
|
||||
ast::expr_ {
|
||||
*j_ += 1u;
|
||||
if i_ + 1u == *j_ && safe_to_replace_expr(original, tm_) {
|
||||
newexpr_
|
||||
} else {
|
||||
fold::noop_fold_expr(original, fld)
|
||||
}
|
||||
}
|
||||
let afp = @{
|
||||
fold_expr: fold::wrap(|a,b| {
|
||||
fold_expr_rep(j, i, newexpr.node, a, b, tm)
|
||||
}),
|
||||
.. *fold::default_ast_fold()
|
||||
};
|
||||
let af = fold::make_fold(afp);
|
||||
let crate2: @ast::crate = @af.fold_crate(crate);
|
||||
*crate2
|
||||
}
|
||||
|
||||
|
||||
// Replace the |i|th ty (in fold order) of |crate| with |newty|.
|
||||
fn replace_ty_in_crate(crate: ast::crate, i: uint, newty: ast::Ty,
|
||||
tm: test_mode) -> ast::crate {
|
||||
let j: @mut uint = @mut 0u;
|
||||
fn fold_ty_rep(j_: @mut uint, i_: uint, newty_: ast::ty_,
|
||||
original: ast::ty_, fld: fold::ast_fold,
|
||||
tm_: test_mode) ->
|
||||
ast::ty_ {
|
||||
*j_ += 1u;
|
||||
if i_ + 1u == *j_ && safe_to_replace_ty(original, tm_) {
|
||||
newty_
|
||||
} else { fold::noop_fold_ty(original, fld) }
|
||||
}
|
||||
let afp = @{
|
||||
fold_ty: fold::wrap(|a,b| fold_ty_rep(j, i, newty.node, a, b, tm) ),
|
||||
.. *fold::default_ast_fold()
|
||||
};
|
||||
let af = fold::make_fold(afp);
|
||||
let crate2: @ast::crate = @af.fold_crate(crate);
|
||||
*crate2
|
||||
}
|
||||
|
||||
fn under(n: uint, it: fn(uint)) {
|
||||
let mut i: uint = 0u;
|
||||
while i < n { it(i); i += 1u; }
|
||||
}
|
||||
|
||||
fn as_str(f: fn@(+x: io::Writer)) -> ~str {
|
||||
io::with_str_writer(f)
|
||||
}
|
||||
|
||||
fn check_variants_of_ast(crate: ast::crate, codemap: @codemap::CodeMap,
|
||||
filename: &Path, cx: context) {
|
||||
let stolen = steal(crate, cx.mode);
|
||||
let extra_exprs = vec::filter(common_exprs(),
|
||||
|a| safe_to_use_expr(*a, cx.mode) );
|
||||
check_variants_T(crate, codemap, filename, ~"expr",
|
||||
extra_exprs + stolen.exprs, pprust::expr_to_str,
|
||||
replace_expr_in_crate, cx);
|
||||
check_variants_T(crate, codemap, filename, ~"ty", stolen.tys,
|
||||
pprust::ty_to_str, replace_ty_in_crate, cx);
|
||||
}
|
||||
|
||||
fn check_variants_T<T: Copy>(
|
||||
crate: ast::crate,
|
||||
codemap: @codemap::CodeMap,
|
||||
filename: &Path,
|
||||
thing_label: ~str,
|
||||
things: ~[T],
|
||||
stringifier: fn@(@T, @syntax::parse::token::ident_interner) -> ~str,
|
||||
replacer: fn@(ast::crate, uint, T, test_mode) -> ast::crate,
|
||||
cx: context
|
||||
) {
|
||||
error!("%s contains %u %s objects", filename.to_str(),
|
||||
things.len(), thing_label);
|
||||
|
||||
// Assuming we're not generating any token_trees
|
||||
let intr = syntax::parse::token::mk_fake_ident_interner();
|
||||
|
||||
let L = things.len();
|
||||
|
||||
if L < 100 {
|
||||
do under(uint::min(L, 20)) |i| {
|
||||
log(error, ~"Replacing... #" + uint::str(i));
|
||||
let fname = str::from_slice(filename.to_str());
|
||||
do under(uint::min(L, 30)) |j| {
|
||||
log(error, ~"With... " + stringifier(@things[j], intr));
|
||||
let crate2 = @replacer(crate, i, things[j], cx.mode);
|
||||
// It would be best to test the *crate* for stability, but
|
||||
// testing the string for stability is easier and ok for now.
|
||||
let handler = diagnostic::mk_handler(None);
|
||||
let str3 = do io::with_str_reader("") |rdr| {
|
||||
@as_str(|a|pprust::print_crate(
|
||||
codemap,
|
||||
intr,
|
||||
diagnostic::mk_span_handler(handler, codemap),
|
||||
crate2,
|
||||
fname,
|
||||
rdr, a,
|
||||
pprust::no_ann(),
|
||||
false))
|
||||
};
|
||||
match cx.mode {
|
||||
tm_converge => {
|
||||
check_roundtrip_convergence(str3, 1u);
|
||||
}
|
||||
tm_run => {
|
||||
let file_label = fmt!("rusttmp/%s_%s_%u_%u",
|
||||
last_part(filename.to_str()),
|
||||
thing_label, i, j);
|
||||
let safe_to_run = !(content_is_dangerous_to_run(*str3)
|
||||
|| has_raw_pointers(*crate2));
|
||||
check_whole_compiler(*str3, &Path(file_label),
|
||||
safe_to_run);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn last_part(filename: ~str) -> ~str {
|
||||
let ix = option::get(str::rfind_char(filename, '/'));
|
||||
str::slice(filename, ix + 1u, str::len(filename) - 3u)
|
||||
}
|
||||
|
||||
enum happiness {
|
||||
passed,
|
||||
cleanly_rejected(~str),
|
||||
known_bug(~str),
|
||||
failed(~str),
|
||||
}
|
||||
|
||||
// We'd find more bugs if we could take an AST here, but
|
||||
// - that would find many "false positives" or unimportant bugs
|
||||
// - that would be tricky, requiring use of tasks or serialization
|
||||
// or randomness.
|
||||
// This seems to find plenty of bugs as it is :)
|
||||
fn check_whole_compiler(code: ~str, suggested_filename_prefix: &Path,
|
||||
allow_running: bool) {
|
||||
let filename = &suggested_filename_prefix.with_filetype("rs");
|
||||
write_file(filename, code);
|
||||
|
||||
let compile_result = check_compiling(filename);
|
||||
|
||||
let run_result = match (compile_result, allow_running) {
|
||||
(passed, true) => { check_running(suggested_filename_prefix) }
|
||||
(h, _) => { h }
|
||||
};
|
||||
|
||||
match run_result {
|
||||
passed | cleanly_rejected(_) | known_bug(_) => {
|
||||
removeIfExists(suggested_filename_prefix);
|
||||
removeIfExists(&suggested_filename_prefix.with_filetype("rs"));
|
||||
removeDirIfExists(&suggested_filename_prefix.with_filetype("dSYM"));
|
||||
}
|
||||
failed(s) => {
|
||||
log(error, ~"check_whole_compiler failure: " + s);
|
||||
log(error, ~"Saved as: " + filename.to_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn removeIfExists(filename: &Path) {
|
||||
// So sketchy!
|
||||
assert !contains(filename.to_str(), ~" ");
|
||||
run::program_output(~"bash", ~[~"-c", ~"rm " + filename.to_str()]);
|
||||
}
|
||||
|
||||
fn removeDirIfExists(filename: &Path) {
|
||||
// So sketchy!
|
||||
assert !contains(filename.to_str(), ~" ");
|
||||
run::program_output(~"bash", ~[~"-c", ~"rm -r " + filename.to_str()]);
|
||||
}
|
||||
|
||||
fn check_running(exe_filename: &Path) -> happiness {
|
||||
let p = run::program_output(
|
||||
~"/Users/jruderman/scripts/timed_run_rust_program.py",
|
||||
~[exe_filename.to_str()]);
|
||||
let comb = p.out + ~"\n" + p.err;
|
||||
if str::len(comb) > 1u {
|
||||
log(error, ~"comb comb comb: " + comb);
|
||||
}
|
||||
|
||||
if contains(comb, ~"Assertion failed:") {
|
||||
failed(~"C++ assertion failure")
|
||||
} else if contains(comb, ~"leaked memory in rust main loop") {
|
||||
// might also use exit code 134
|
||||
//failed("Leaked")
|
||||
known_bug(~"https://github.com/mozilla/rust/issues/910")
|
||||
} else if contains(comb, ~"src/rt/") {
|
||||
failed(~"Mentioned src/rt/")
|
||||
} else if contains(comb, ~"malloc") {
|
||||
failed(~"Mentioned malloc")
|
||||
} else {
|
||||
match p.status {
|
||||
0 => { passed }
|
||||
100 => { cleanly_rejected(~"running: explicit fail") }
|
||||
101 | 247 => { cleanly_rejected(~"running: timed out") }
|
||||
245 | 246 | 138 | 252 => {
|
||||
known_bug(~"https://github.com/mozilla/rust/issues/1466")
|
||||
}
|
||||
136 | 248 => {
|
||||
known_bug(
|
||||
~"SIGFPE - https://github.com/mozilla/rust/issues/944")
|
||||
}
|
||||
rc => {
|
||||
failed(~"Rust program ran but exited with status " +
|
||||
int::str(rc))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_compiling(filename: &Path) -> happiness {
|
||||
let p = run::program_output(
|
||||
~"/Users/jruderman/code/rust/build/x86_64-apple-darwin/\
|
||||
stage1/bin/rustc",
|
||||
~[filename.to_str()]);
|
||||
|
||||
//error!("Status: %d", p.status);
|
||||
if p.status == 0 {
|
||||
passed
|
||||
} else if p.err != ~"" {
|
||||
if contains(p.err, ~"error:") {
|
||||
cleanly_rejected(~"rejected with span_error")
|
||||
} else {
|
||||
log(error, ~"Stderr: " + p.err);
|
||||
failed(~"Unfamiliar error message")
|
||||
}
|
||||
} else if contains(p.out, ~"Assertion") && contains(p.out, ~"failed") {
|
||||
log(error, ~"Stdout: " + p.out);
|
||||
failed(~"Looks like an llvm assertion failure")
|
||||
} else if contains(p.out, ~"internal compiler error unimplemented") {
|
||||
known_bug(~"Something unimplemented")
|
||||
} else if contains(p.out, ~"internal compiler error") {
|
||||
log(error, ~"Stdout: " + p.out);
|
||||
failed(~"internal compiler error")
|
||||
|
||||
} else {
|
||||
log(error, p.status);
|
||||
log(error, ~"!Stdout: " + p.out);
|
||||
failed(~"What happened?")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn parse_and_print(code: @~str) -> ~str {
|
||||
let filename = Path("tmp.rs");
|
||||
let sess = parse::new_parse_sess(option::None);
|
||||
write_file(&filename, *code);
|
||||
let crate = parse::parse_crate_from_source_str(
|
||||
filename.to_str(), code, ~[], sess);
|
||||
do io::with_str_reader(*code) |rdr| {
|
||||
as_str(|a|
|
||||
pprust::print_crate(
|
||||
sess.cm,
|
||||
// Assuming there are no token_trees
|
||||
syntax::parse::token::mk_fake_ident_interner(),
|
||||
sess.span_diagnostic,
|
||||
crate,
|
||||
filename.to_str(),
|
||||
rdr, a,
|
||||
pprust::no_ann(),
|
||||
false) )
|
||||
}
|
||||
}
|
||||
|
||||
fn has_raw_pointers(c: ast::crate) -> bool {
|
||||
let has_rp = @mut false;
|
||||
fn visit_ty(flag: @mut bool, t: @ast::Ty) {
|
||||
match t.node {
|
||||
ast::ty_ptr(_) => { *flag = true; }
|
||||
_ => { }
|
||||
}
|
||||
}
|
||||
let v =
|
||||
visit::mk_simple_visitor(@{visit_ty: |a| visit_ty(has_rp, a),
|
||||
.. *visit::default_simple_visitor()});
|
||||
visit::visit_crate(c, (), v);
|
||||
return *has_rp;
|
||||
}
|
||||
|
||||
fn content_is_dangerous_to_run(code: ~str) -> bool {
|
||||
let dangerous_patterns =
|
||||
~[~"xfail-test",
|
||||
~"import", // espeically fs, run
|
||||
~"extern",
|
||||
~"unsafe",
|
||||
~"log"]; // python --> rust pipe deadlock?
|
||||
|
||||
for dangerous_patterns.each |p| { if contains(code, *p) { return true; } }
|
||||
return false;
|
||||
}
|
||||
|
||||
fn content_is_dangerous_to_compile(code: ~str) -> bool {
|
||||
let dangerous_patterns =
|
||||
~[~"xfail-test"];
|
||||
|
||||
for dangerous_patterns.each |p| { if contains(code, *p) { return true; } }
|
||||
return false;
|
||||
}
|
||||
|
||||
fn content_might_not_converge(code: ~str) -> bool {
|
||||
let confusing_patterns =
|
||||
~[~"xfail-test",
|
||||
~"xfail-pretty",
|
||||
~"self", // crazy rules enforced by parser not typechecker?
|
||||
~"spawn", // precedence issues?
|
||||
~"bind", // precedence issues?
|
||||
~" be ", // don't want to replace its child with a non-call:
|
||||
// "Non-call expression in tail call"
|
||||
~"\n\n\n\n\n" // https://github.com/mozilla/rust/issues/850
|
||||
];
|
||||
|
||||
for confusing_patterns.each |p| { if contains(code, *p) { return true; } }
|
||||
return false;
|
||||
}
|
||||
|
||||
fn file_might_not_converge(filename: &Path) -> bool {
|
||||
let confusing_files = ~[
|
||||
~"expr-alt.rs", // pretty-printing "(a = b) = c"
|
||||
// vs "a = b = c" and wrapping
|
||||
~"block-arg-in-ternary.rs", // wrapping
|
||||
~"move-3-unique.rs", // 0 becomes (0), but both seem reasonable. wtf?
|
||||
~"move-3.rs" // 0 becomes (0), but both seem reasonable. wtf?
|
||||
];
|
||||
|
||||
|
||||
for confusing_files.each |f| {
|
||||
if contains(filename.to_str(), *f) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
fn check_roundtrip_convergence(code: @~str, maxIters: uint) {
|
||||
|
||||
let mut i = 0u;
|
||||
let mut newv = code;
|
||||
let mut oldv = code;
|
||||
|
||||
while i < maxIters {
|
||||
oldv = newv;
|
||||
if content_might_not_converge(*oldv) { return; }
|
||||
newv = @parse_and_print(oldv);
|
||||
if oldv == newv { break; }
|
||||
i += 1u;
|
||||
}
|
||||
|
||||
if oldv == newv {
|
||||
error!("Converged after %u iterations", i);
|
||||
} else {
|
||||
error!("Did not converge after %u iterations!", i);
|
||||
write_file(&Path("round-trip-a.rs"), *oldv);
|
||||
write_file(&Path("round-trip-b.rs"), *newv);
|
||||
run::run_program(~"diff",
|
||||
~[~"-w", ~"-u", ~"round-trip-a.rs",
|
||||
~"round-trip-b.rs"]);
|
||||
fail ~"Mismatch";
|
||||
}
|
||||
}
|
||||
|
||||
fn check_convergence(files: &[Path]) {
|
||||
error!("pp convergence tests: %u files", vec::len(files));
|
||||
for files.each |file| {
|
||||
if !file_might_not_converge(file) {
|
||||
let s = @result::get(&io::read_whole_file_str(file));
|
||||
if !content_might_not_converge(*s) {
|
||||
error!("pp converge: %s", file.to_str());
|
||||
// Change from 7u to 2u once
|
||||
// https://github.com/mozilla/rust/issues/850 is fixed
|
||||
check_roundtrip_convergence(s, 7u);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_variants(files: &[Path], cx: context) {
|
||||
for files.each |file| {
|
||||
if cx.mode == tm_converge &&
|
||||
file_might_not_converge(file) {
|
||||
error!("Skipping convergence test based on\
|
||||
file_might_not_converge");
|
||||
loop;
|
||||
}
|
||||
|
||||
let s = @result::get(&io::read_whole_file_str(file));
|
||||
if contains(*s, ~"#") {
|
||||
loop; // Macros are confusing
|
||||
}
|
||||
if cx.mode == tm_converge && content_might_not_converge(*s) {
|
||||
loop;
|
||||
}
|
||||
if cx.mode == tm_run && content_is_dangerous_to_compile(*s) {
|
||||
loop;
|
||||
}
|
||||
|
||||
let file_str = file.to_str();
|
||||
|
||||
log(error, ~"check_variants: " + file_str);
|
||||
let sess = parse::new_parse_sess(option::None);
|
||||
let crate =
|
||||
parse::parse_crate_from_source_str(
|
||||
file_str,
|
||||
s, ~[], sess);
|
||||
io::with_str_reader(*s, |rdr| {
|
||||
error!("%s",
|
||||
as_str(|a| pprust::print_crate(
|
||||
sess.cm,
|
||||
// Assuming no token_trees
|
||||
syntax::parse::token::mk_fake_ident_interner(),
|
||||
sess.span_diagnostic,
|
||||
crate,
|
||||
file_str,
|
||||
rdr, a,
|
||||
pprust::no_ann(),
|
||||
false)))
|
||||
});
|
||||
check_variants_of_ast(*crate, sess.cm, file, cx);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args = os::args();
|
||||
if vec::len(args) != 2u {
|
||||
error!("usage: %s <testdir>", args[0]);
|
||||
return;
|
||||
}
|
||||
let mut files = ~[];
|
||||
let root = Path(args[1]);
|
||||
|
||||
find_rust_files(&mut files, &root);
|
||||
error!("== check_convergence ==");
|
||||
check_convergence(files);
|
||||
error!("== check_variants: converge ==");
|
||||
check_variants(files, { mode: tm_converge });
|
||||
error!("== check_variants: run ==");
|
||||
check_variants(files, { mode: tm_run });
|
||||
|
||||
error!("Fuzzer done");
|
||||
}
|
||||
|
||||
// Local Variables:
|
||||
// mode: rust;
|
||||
// fill-column: 78;
|
||||
// indent-tabs-mode: nil
|
||||
// c-basic-offset: 4
|
||||
// buffer-file-coding-system: utf-8-unix
|
||||
// End:
|
501
src/librustc/alternate_crate.rc
Normal file
501
src/librustc/alternate_crate.rc
Normal file
@ -0,0 +1,501 @@
|
||||
// -*- rust -*-
|
||||
|
||||
#[link(name = "rustc",
|
||||
vers = "0.5",
|
||||
uuid = "0ce89b41-2f92-459e-bbc1-8f5fe32f16cf",
|
||||
url = "https://github.com/mozilla/rust/tree/master/src/rustc")];
|
||||
|
||||
#[comment = "The Rust compiler"];
|
||||
#[license = "MIT"];
|
||||
#[crate_type = "lib"];
|
||||
|
||||
#[no_core];
|
||||
|
||||
#[legacy_modes];
|
||||
#[legacy_exports];
|
||||
|
||||
#[allow(vecs_implicitly_copyable)];
|
||||
#[allow(non_camel_case_types)];
|
||||
#[allow(deprecated_mode)];
|
||||
#[allow(deprecated_pattern)];
|
||||
|
||||
extern mod core(vers = "0.5");
|
||||
extern mod std(vers = "0.5");
|
||||
extern mod syntax(vers = "0.5");
|
||||
|
||||
use core::*;
|
||||
|
||||
/*
|
||||
Alternate names for some modules.
|
||||
|
||||
I am using this to help extract metadata into its own crate. In metadata.rs
|
||||
it redefines all these modules in order to gate access from metadata to the
|
||||
rest of the compiler, then uses these to access the original implementation.
|
||||
*/
|
||||
use util_ = util;
|
||||
use lib_ = lib;
|
||||
use driver_ = driver;
|
||||
use middle_ = middle;
|
||||
use back_ = back;
|
||||
|
||||
mod middle {
|
||||
#[legacy_exports];
|
||||
mod trans {
|
||||
#[legacy_exports];
|
||||
#[legacy_exports]
|
||||
#[path = "middle/trans/inline.rs"]
|
||||
mod inline;
|
||||
#[legacy_exports]
|
||||
#[path = "middle/trans/monomorphize.rs"]
|
||||
mod monomorphize;
|
||||
#[legacy_exports]
|
||||
#[path = "middle/trans/controlflow.rs"]
|
||||
mod controlflow;
|
||||
#[legacy_exports]
|
||||
#[path = "middle/trans/glue.rs"]
|
||||
mod glue;
|
||||
#[legacy_exports]
|
||||
#[path = "middle/trans/datum.rs"]
|
||||
mod datum;
|
||||
#[legacy_exports]
|
||||
#[path = "middle/trans/callee.rs"]
|
||||
mod callee;
|
||||
#[legacy_exports]
|
||||
#[path = "middle/trans/expr.rs"]
|
||||
mod expr;
|
||||
#[legacy_exports]
|
||||
#[path = "middle/trans/common.rs"]
|
||||
mod common;
|
||||
#[legacy_exports]
|
||||
#[path = "middle/trans/consts.rs"]
|
||||
mod consts;
|
||||
#[legacy_exports]
|
||||
#[path = "middle/trans/type_of.rs"]
|
||||
mod type_of;
|
||||
#[legacy_exports]
|
||||
#[path = "middle/trans/build.rs"]
|
||||
mod build;
|
||||
#[legacy_exports]
|
||||
#[path = "middle/trans/base.rs"]
|
||||
mod base;
|
||||
#[legacy_exports]
|
||||
#[path = "middle/trans/alt.rs"]
|
||||
mod alt;
|
||||
#[legacy_exports]
|
||||
#[path = "middle/trans/uniq.rs"]
|
||||
mod uniq;
|
||||
#[legacy_exports]
|
||||
#[path = "middle/trans/closure.rs"]
|
||||
mod closure;
|
||||
#[legacy_exports]
|
||||
#[path = "middle/trans/tvec.rs"]
|
||||
mod tvec;
|
||||
#[legacy_exports]
|
||||
#[path = "middle/trans/meth.rs"]
|
||||
mod meth;
|
||||
#[legacy_exports]
|
||||
#[path = "middle/trans/foreign.rs"]
|
||||
mod foreign;
|
||||
#[legacy_exports]
|
||||
#[path = "middle/trans/reflect.rs"]
|
||||
mod reflect;
|
||||
#[legacy_exports]
|
||||
#[path = "middle/trans/shape.rs"]
|
||||
mod shape;
|
||||
#[legacy_exports]
|
||||
#[path = "middle/trans/debuginfo.rs"]
|
||||
mod debuginfo;
|
||||
#[legacy_exports]
|
||||
#[path = "middle/trans/type_use.rs"]
|
||||
mod type_use;
|
||||
#[legacy_exports]
|
||||
#[path = "middle/trans/reachable.rs"]
|
||||
mod reachable;
|
||||
#[path = "middle/trans/machine.rs"]
|
||||
mod machine;
|
||||
#[path = "middle/trans/deriving.rs"]
|
||||
mod deriving;
|
||||
}
|
||||
#[legacy_exports]
|
||||
#[path = "middle/ty.rs"]
|
||||
mod ty;
|
||||
#[legacy_exports]
|
||||
#[path = "middle/resolve.rs"]
|
||||
mod resolve;
|
||||
#[path = "middle/typeck.rs"]
|
||||
#[merge = "middle/typeck/mod.rs"]
|
||||
pub mod typeck;
|
||||
#[legacy_exports]
|
||||
#[path = "middle/check_loop.rs"]
|
||||
mod check_loop;
|
||||
#[legacy_exports]
|
||||
#[path = "middle/check_alt.rs"]
|
||||
mod check_alt;
|
||||
#[legacy_exports]
|
||||
#[path = "middle/check_const.rs"]
|
||||
mod check_const;
|
||||
#[legacy_exports]
|
||||
#[path = "middle/lint.rs"]
|
||||
mod lint;
|
||||
#[path = "middle/borrowck.rs"]
|
||||
#[merge = "middle/borrowck/mod.rs"]
|
||||
mod borrowck;
|
||||
#[legacy_exports]
|
||||
#[path = "middle/mem_categorization.rs"]
|
||||
mod mem_categorization;
|
||||
#[legacy_exports]
|
||||
#[path = "middle/liveness.rs"]
|
||||
mod liveness;
|
||||
#[legacy_exports]
|
||||
#[path = "middle/kind.rs"]
|
||||
mod kind;
|
||||
#[legacy_exports]
|
||||
#[path = "middle/freevars.rs"]
|
||||
mod freevars;
|
||||
#[legacy_exports]
|
||||
#[path = "middle/capture.rs"]
|
||||
mod capture;
|
||||
#[legacy_exports]
|
||||
#[path = "middle/pat_util.rs"]
|
||||
mod pat_util;
|
||||
#[legacy_exports]
|
||||
#[path = "middle/region.rs"]
|
||||
mod region;
|
||||
#[legacy_exports]
|
||||
#[path = "middle/const_eval.rs"]
|
||||
mod const_eval;
|
||||
#[legacy_exports]
|
||||
#[path = "middle/astencode.rs"]
|
||||
mod astencode;
|
||||
#[legacy_exports]
|
||||
#[path = "middle/lang_items.rs"]
|
||||
mod lang_items;
|
||||
#[legacy_exports]
|
||||
#[path = "middle/privacy.rs"]
|
||||
mod privacy;
|
||||
}
|
||||
|
||||
mod front {
|
||||
#[legacy_exports];
|
||||
#[legacy_exports]
|
||||
#[path = "front/config.rs"]
|
||||
mod config;
|
||||
#[legacy_exports]
|
||||
#[path = "front/test.rs"]
|
||||
mod test;
|
||||
#[legacy_exports]
|
||||
#[path = "front/core_inject.rs"]
|
||||
mod core_inject;
|
||||
#[legacy_exports]
|
||||
#[path = "front/intrinsic_inject.rs"]
|
||||
mod intrinsic_inject;
|
||||
}
|
||||
|
||||
mod back {
|
||||
#[legacy_exports];
|
||||
#[legacy_exports]
|
||||
#[path = "back/link.rs"]
|
||||
mod link;
|
||||
#[legacy_exports]
|
||||
#[path = "back/abi.rs"]
|
||||
mod abi;
|
||||
#[legacy_exports]
|
||||
#[path = "back/upcall.rs"]
|
||||
mod upcall;
|
||||
#[legacy_exports]
|
||||
#[path = "back/x86.rs"]
|
||||
mod x86;
|
||||
#[legacy_exports]
|
||||
#[path = "back/x86_64.rs"]
|
||||
mod x86_64;
|
||||
#[legacy_exports]
|
||||
#[path = "back/rpath.rs"]
|
||||
mod rpath;
|
||||
#[legacy_exports]
|
||||
#[path = "back/target_strs.rs"]
|
||||
mod target_strs;
|
||||
}
|
||||
|
||||
#[merge = "metadata/mod.rs"]
|
||||
mod metadata;
|
||||
|
||||
#[merge = "driver/mod.rs"]
|
||||
mod driver;
|
||||
|
||||
mod util {
|
||||
#[legacy_exports];
|
||||
#[legacy_exports]
|
||||
#[path = "util/common.rs"]
|
||||
mod common;
|
||||
#[legacy_exports]
|
||||
#[path = "util/ppaux.rs"]
|
||||
mod ppaux;
|
||||
}
|
||||
|
||||
mod lib {
|
||||
#[legacy_exports];
|
||||
#[legacy_exports]
|
||||
#[path = "lib/llvm.rs"]
|
||||
mod llvm;
|
||||
}
|
||||
|
||||
use result::{Ok, Err};
|
||||
use io::ReaderUtil;
|
||||
use std::getopts;
|
||||
use std::map::HashMap;
|
||||
use getopts::{opt_present};
|
||||
use getopts::groups;
|
||||
use syntax::codemap;
|
||||
use syntax::diagnostic;
|
||||
use driver::driver::{host_triple, optgroups, early_error,
|
||||
str_input, file_input, build_session_options,
|
||||
build_session, build_configuration, parse_pretty,
|
||||
pp_mode, pretty_print_input, list_metadata,
|
||||
compile_input};
|
||||
use driver::session;
|
||||
use middle::lint;
|
||||
|
||||
fn version(argv0: &str) {
|
||||
let mut vers = ~"unknown version";
|
||||
let env_vers = env!("CFG_VERSION");
|
||||
if env_vers.len() != 0 { vers = env_vers; }
|
||||
io::println(fmt!("%s %s", argv0, vers));
|
||||
io::println(fmt!("host: %s", host_triple()));
|
||||
}
|
||||
|
||||
fn usage(argv0: &str) {
|
||||
let message = fmt!("Usage: %s [OPTIONS] INPUT", argv0);
|
||||
io::println(groups::usage(message, optgroups()) +
|
||||
~"Additional help:
|
||||
-W help Print 'lint' options and default settings
|
||||
-Z help Print internal options for debugging rustc
|
||||
");
|
||||
}
|
||||
|
||||
fn describe_warnings() {
|
||||
io::println(fmt!("
|
||||
Available lint options:
|
||||
-W <foo> Warn about <foo>
|
||||
-A <foo> Allow <foo>
|
||||
-D <foo> Deny <foo>
|
||||
-F <foo> Forbid <foo> (deny, and deny all overrides)
|
||||
"));
|
||||
|
||||
let lint_dict = lint::get_lint_dict();
|
||||
let mut max_key = 0;
|
||||
for lint_dict.each_key |k| { max_key = uint::max(k.len(), max_key); }
|
||||
fn padded(max: uint, s: &str) -> ~str {
|
||||
str::from_bytes(vec::from_elem(max - s.len(), ' ' as u8)) + s
|
||||
}
|
||||
io::println(fmt!("\nAvailable lint checks:\n"));
|
||||
io::println(fmt!(" %s %7.7s %s",
|
||||
padded(max_key, ~"name"), ~"default", ~"meaning"));
|
||||
io::println(fmt!(" %s %7.7s %s\n",
|
||||
padded(max_key, ~"----"), ~"-------", ~"-------"));
|
||||
for lint_dict.each |k, v| {
|
||||
let k = str::replace(k, ~"_", ~"-");
|
||||
io::println(fmt!(" %s %7.7s %s",
|
||||
padded(max_key, k),
|
||||
match v.default {
|
||||
lint::allow => ~"allow",
|
||||
lint::warn => ~"warn",
|
||||
lint::deny => ~"deny",
|
||||
lint::forbid => ~"forbid"
|
||||
},
|
||||
v.desc));
|
||||
}
|
||||
io::println(~"");
|
||||
}
|
||||
|
||||
fn describe_debug_flags() {
|
||||
io::println(fmt!("\nAvailable debug options:\n"));
|
||||
for session::debugging_opts_map().each |pair| {
|
||||
let (name, desc, _) = *pair;
|
||||
io::println(fmt!(" -Z %-20s -- %s", name, desc));
|
||||
}
|
||||
}
|
||||
|
||||
fn run_compiler(args: &~[~str], demitter: diagnostic::emitter) {
|
||||
// Don't display log spew by default. Can override with RUST_LOG.
|
||||
logging::console_off();
|
||||
|
||||
let mut args = *args;
|
||||
let binary = args.shift();
|
||||
|
||||
if args.is_empty() { usage(binary); return; }
|
||||
|
||||
let matches =
|
||||
match getopts::groups::getopts(args, optgroups()) {
|
||||
Ok(m) => m,
|
||||
Err(f) => {
|
||||
early_error(demitter, getopts::fail_str(f))
|
||||
}
|
||||
};
|
||||
|
||||
if opt_present(matches, ~"h") || opt_present(matches, ~"help") {
|
||||
usage(binary);
|
||||
return;
|
||||
}
|
||||
|
||||
let lint_flags = vec::append(getopts::opt_strs(matches, ~"W"),
|
||||
getopts::opt_strs(matches, ~"warn"));
|
||||
if lint_flags.contains(&~"help") {
|
||||
describe_warnings();
|
||||
return;
|
||||
}
|
||||
|
||||
if getopts::opt_strs(matches, ~"Z").contains(&~"help") {
|
||||
describe_debug_flags();
|
||||
return;
|
||||
}
|
||||
|
||||
if opt_present(matches, ~"v") || opt_present(matches, ~"version") {
|
||||
version(binary);
|
||||
return;
|
||||
}
|
||||
let input = match vec::len(matches.free) {
|
||||
0u => early_error(demitter, ~"no input filename given"),
|
||||
1u => {
|
||||
let ifile = matches.free[0];
|
||||
if ifile == ~"-" {
|
||||
let src = str::from_bytes(io::stdin().read_whole_stream());
|
||||
str_input(src)
|
||||
} else {
|
||||
file_input(Path(ifile))
|
||||
}
|
||||
}
|
||||
_ => early_error(demitter, ~"multiple input filenames provided")
|
||||
};
|
||||
|
||||
let sopts = build_session_options(binary, matches, demitter);
|
||||
let sess = build_session(sopts, demitter);
|
||||
let odir = getopts::opt_maybe_str(matches, ~"out-dir");
|
||||
let odir = odir.map(|o| Path(*o));
|
||||
let ofile = getopts::opt_maybe_str(matches, ~"o");
|
||||
let ofile = ofile.map(|o| Path(*o));
|
||||
let cfg = build_configuration(sess, binary, input);
|
||||
let pretty =
|
||||
option::map(&getopts::opt_default(matches, ~"pretty",
|
||||
~"normal"),
|
||||
|a| parse_pretty(sess, *a) );
|
||||
match pretty {
|
||||
Some::<pp_mode>(ppm) => {
|
||||
pretty_print_input(sess, cfg, input, ppm);
|
||||
return;
|
||||
}
|
||||
None::<pp_mode> => {/* continue */ }
|
||||
}
|
||||
let ls = opt_present(matches, ~"ls");
|
||||
if ls {
|
||||
match input {
|
||||
file_input(ifile) => {
|
||||
list_metadata(sess, &ifile, io::stdout());
|
||||
}
|
||||
str_input(_) => {
|
||||
early_error(demitter, ~"can not list metadata for stdin");
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
compile_input(sess, cfg, input, &odir, &ofile);
|
||||
}
|
||||
|
||||
enum monitor_msg {
|
||||
fatal,
|
||||
done,
|
||||
}
|
||||
|
||||
impl monitor_msg : cmp::Eq {
|
||||
#[cfg(stage0)]
|
||||
pure fn eq(other: &monitor_msg) -> bool {
|
||||
(self as uint) == ((*other) as uint)
|
||||
}
|
||||
#[cfg(stage1)]
|
||||
#[cfg(stage2)]
|
||||
pure fn eq(&self, other: &monitor_msg) -> bool {
|
||||
((*self) as uint) == ((*other) as uint)
|
||||
}
|
||||
#[cfg(stage0)]
|
||||
pure fn ne(other: &monitor_msg) -> bool { !self.eq(other) }
|
||||
#[cfg(stage1)]
|
||||
#[cfg(stage2)]
|
||||
pure fn ne(&self, other: &monitor_msg) -> bool { !(*self).eq(other) }
|
||||
}
|
||||
|
||||
/*
|
||||
This is a sanity check that any failure of the compiler is performed
|
||||
through the diagnostic module and reported properly - we shouldn't be calling
|
||||
plain-old-fail on any execution path that might be taken. Since we have
|
||||
console logging off by default, hitting a plain fail statement would make the
|
||||
compiler silently exit, which would be terrible.
|
||||
|
||||
This method wraps the compiler in a subtask and injects a function into the
|
||||
diagnostic emitter which records when we hit a fatal error. If the task
|
||||
fails without recording a fatal error then we've encountered a compiler
|
||||
bug and need to present an error.
|
||||
*/
|
||||
fn monitor(+f: fn~(diagnostic::emitter)) {
|
||||
let p = comm::Port();
|
||||
let ch = comm::Chan(&p);
|
||||
|
||||
match do task::try |move f| {
|
||||
|
||||
// The 'diagnostics emitter'. Every error, warning, etc. should
|
||||
// go through this function.
|
||||
let demitter = fn@(cmsp: Option<(@codemap::CodeMap, codemap::span)>,
|
||||
msg: &str, lvl: diagnostic::level) {
|
||||
if lvl == diagnostic::fatal {
|
||||
comm::send(ch, fatal);
|
||||
}
|
||||
diagnostic::emit(cmsp, msg, lvl);
|
||||
};
|
||||
|
||||
struct finally {
|
||||
ch: comm::Chan<monitor_msg>,
|
||||
drop { comm::send(self.ch, done); }
|
||||
}
|
||||
|
||||
let _finally = finally { ch: ch };
|
||||
|
||||
f(demitter)
|
||||
} {
|
||||
result::Ok(_) => { /* fallthrough */ }
|
||||
result::Err(_) => {
|
||||
// Task failed without emitting a fatal diagnostic
|
||||
if comm::recv(p) == done {
|
||||
diagnostic::emit(
|
||||
None,
|
||||
diagnostic::ice_msg(~"unexpected failure"),
|
||||
diagnostic::error);
|
||||
|
||||
for [
|
||||
~"the compiler hit an unexpected failure path. \
|
||||
this is a bug",
|
||||
~"try running with RUST_LOG=rustc=1,::rt::backtrace \
|
||||
to get further details and report the results \
|
||||
to github.com/mozilla/rust/issues"
|
||||
].each |note| {
|
||||
diagnostic::emit(None, *note, diagnostic::note)
|
||||
}
|
||||
}
|
||||
// Fail so the process returns a failure code
|
||||
fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut args = os::args();
|
||||
do monitor |move args, demitter| {
|
||||
run_compiler(&args, demitter);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Local Variables:
|
||||
// fill-column: 78;
|
||||
// indent-tabs-mode: nil
|
||||
// c-basic-offset: 4
|
||||
// buffer-file-coding-system: utf-8-unix
|
||||
// End:
|
5
src/librustc/driver/mod.rs
Normal file
5
src/librustc/driver/mod.rs
Normal file
@ -0,0 +1,5 @@
|
||||
#[legacy_exports];
|
||||
#[legacy_exports]
|
||||
mod driver;
|
||||
#[legacy_exports]
|
||||
mod session;
|
@ -357,7 +357,6 @@ mod test {
|
||||
if with_bin { attrs += ~[make_crate_type_attr(~"bin")]; }
|
||||
if with_lib { attrs += ~[make_crate_type_attr(~"lib")]; }
|
||||
@ast_util::respan(ast_util::dummy_sp(), {
|
||||
directives: ~[],
|
||||
module: {view_items: ~[], items: ~[]},
|
||||
attrs: attrs,
|
||||
config: ~[]
|
||||
|
32
src/librustc/metadata/mod.rs
Normal file
32
src/librustc/metadata/mod.rs
Normal file
@ -0,0 +1,32 @@
|
||||
#[legacy_exports];
|
||||
export encoder;
|
||||
export creader;
|
||||
export cstore;
|
||||
export csearch;
|
||||
export common;
|
||||
export decoder;
|
||||
export tyencode;
|
||||
export tydecode;
|
||||
export loader;
|
||||
export filesearch;
|
||||
|
||||
#[legacy_exports]
|
||||
mod common;
|
||||
#[legacy_exports]
|
||||
mod tyencode;
|
||||
#[legacy_exports]
|
||||
mod tydecode;
|
||||
#[legacy_exports]
|
||||
mod encoder;
|
||||
#[legacy_exports]
|
||||
mod decoder;
|
||||
#[legacy_exports]
|
||||
mod creader;
|
||||
#[legacy_exports]
|
||||
mod cstore;
|
||||
#[legacy_exports]
|
||||
mod csearch;
|
||||
#[legacy_exports]
|
||||
mod loader;
|
||||
#[legacy_exports]
|
||||
mod filesearch;
|
9
src/librustc/middle/borrowck/mod.rs
Normal file
9
src/librustc/middle/borrowck/mod.rs
Normal file
@ -0,0 +1,9 @@
|
||||
#[legacy_exports];
|
||||
#[legacy_exports]
|
||||
mod check_loans;
|
||||
#[legacy_exports]
|
||||
mod gather_loans;
|
||||
#[legacy_exports]
|
||||
mod loan;
|
||||
#[legacy_exports]
|
||||
mod preserve;
|
14
src/librustc/middle/typeck/check/mod.rs
Normal file
14
src/librustc/middle/typeck/check/mod.rs
Normal file
@ -0,0 +1,14 @@
|
||||
#[legacy_exports]
|
||||
mod alt;
|
||||
#[legacy_exports]
|
||||
mod vtable;
|
||||
#[legacy_exports]
|
||||
mod writeback;
|
||||
#[legacy_exports]
|
||||
mod regionmanip;
|
||||
#[legacy_exports]
|
||||
mod regionck;
|
||||
#[legacy_exports]
|
||||
mod demand;
|
||||
#[legacy_exports]
|
||||
pub mod method;
|
24
src/librustc/middle/typeck/infer/mod.rs
Normal file
24
src/librustc/middle/typeck/infer/mod.rs
Normal file
@ -0,0 +1,24 @@
|
||||
#[legacy_exports];
|
||||
#[legacy_exports]
|
||||
mod assignment;
|
||||
#[legacy_exports]
|
||||
mod combine;
|
||||
#[legacy_exports]
|
||||
mod glb;
|
||||
#[legacy_exports]
|
||||
mod integral;
|
||||
mod floating;
|
||||
#[legacy_exports]
|
||||
mod lattice;
|
||||
#[legacy_exports]
|
||||
mod lub;
|
||||
#[legacy_exports]
|
||||
mod region_inference;
|
||||
#[legacy_exports]
|
||||
mod resolve;
|
||||
#[legacy_exports]
|
||||
mod sub;
|
||||
#[legacy_exports]
|
||||
mod to_str;
|
||||
#[legacy_exports]
|
||||
mod unify;
|
16
src/librustc/middle/typeck/mod.rs
Normal file
16
src/librustc/middle/typeck/mod.rs
Normal file
@ -0,0 +1,16 @@
|
||||
#[legacy_exports];
|
||||
|
||||
#[legacy_exports]
|
||||
#[merge = "check/mod.rs"]
|
||||
pub mod check;
|
||||
#[legacy_exports]
|
||||
mod rscope;
|
||||
#[legacy_exports]
|
||||
mod astconv;
|
||||
#[merge = "infer/mod.rs"]
|
||||
mod infer;
|
||||
#[legacy_exports]
|
||||
mod collect;
|
||||
#[legacy_exports]
|
||||
mod coherence;
|
||||
mod deriving;
|
@ -1,3 +1,5 @@
|
||||
// DIVERT
|
||||
|
||||
// -*- rust -*-
|
||||
|
||||
#[link(name = "rustc",
|
||||
|
@ -52,3 +52,95 @@ mod page_pass;
|
||||
mod sectionalize_pass;
|
||||
mod escape_pass;
|
||||
mod prune_private_pass;
|
||||
|
||||
use doc::ItemUtils;
|
||||
use doc::Item;
|
||||
use pass::Pass;
|
||||
use config::Config;
|
||||
|
||||
fn main() {
|
||||
let args = os::args();
|
||||
|
||||
if args.contains(&~"-h") || args.contains(&~"--help") {
|
||||
config::usage();
|
||||
return;
|
||||
}
|
||||
|
||||
let config = match config::parse_config(args) {
|
||||
Ok(config) => config,
|
||||
Err(err) => {
|
||||
io::println(fmt!("error: %s", err));
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
run(config);
|
||||
}
|
||||
|
||||
/// Runs rustdoc over the given file
|
||||
fn run(config: Config) {
|
||||
|
||||
let source_file = config.input_crate;
|
||||
|
||||
// Create an AST service from the source code
|
||||
do astsrv::from_file(source_file.to_str()) |srv| {
|
||||
|
||||
// Just time how long it takes for the AST to become available
|
||||
do time(~"wait_ast") {
|
||||
do astsrv::exec(srv) |_ctxt| { }
|
||||
};
|
||||
|
||||
// Extract the initial doc tree from the AST. This contains
|
||||
// just names and node ids.
|
||||
let doc = time(~"extract", || {
|
||||
let default_name = source_file;
|
||||
extract::from_srv(srv, default_name.to_str())
|
||||
});
|
||||
|
||||
// Refine and publish the document
|
||||
pass::run_passes(srv, doc, ~[
|
||||
// Generate type and signature strings
|
||||
tystr_pass::mk_pass(),
|
||||
// Record the full paths to various nodes
|
||||
path_pass::mk_pass(),
|
||||
// Extract the docs attributes and attach them to doc nodes
|
||||
attr_pass::mk_pass(),
|
||||
// Perform various text escaping
|
||||
escape_pass::mk_pass(),
|
||||
// Remove things marked doc(hidden)
|
||||
prune_hidden_pass::mk_pass(),
|
||||
// Remove things that are private
|
||||
// XXX enable this after 'export' is removed in favor of 'pub'
|
||||
// prune_private_pass::mk_pass(),
|
||||
// Extract brief documentation from the full descriptions
|
||||
desc_to_brief_pass::mk_pass(),
|
||||
// Massage the text to remove extra indentation
|
||||
unindent_pass::mk_pass(),
|
||||
// Split text into multiple sections according to headers
|
||||
sectionalize_pass::mk_pass(),
|
||||
// Trim extra spaces from text
|
||||
trim_pass::mk_pass(),
|
||||
// Sort items by name
|
||||
sort_item_name_pass::mk_pass(),
|
||||
// Sort items again by kind
|
||||
sort_item_type_pass::mk_pass(),
|
||||
// Create indexes appropriate for markdown
|
||||
markdown_index_pass::mk_pass(config),
|
||||
// Break the document into pages if required by the
|
||||
// output format
|
||||
page_pass::mk_pass(config.output_style),
|
||||
// Render
|
||||
markdown_pass::mk_pass(
|
||||
markdown_writer::make_writer_factory(config)
|
||||
)
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
fn time<T>(what: ~str, f: fn() -> T) -> T {
|
||||
let start = std::time::precise_time_s();
|
||||
let rv = f();
|
||||
let end = std::time::precise_time_s();
|
||||
info!("time: %3.3f s %s", end - start, what);
|
||||
move rv
|
||||
}
|
||||
|
@ -1,91 +0,0 @@
|
||||
use doc::ItemUtils;
|
||||
use doc::Item;
|
||||
use pass::Pass;
|
||||
use config::Config;
|
||||
|
||||
fn main() {
|
||||
let args = os::args();
|
||||
|
||||
if args.contains(&~"-h") || args.contains(&~"--help") {
|
||||
config::usage();
|
||||
return;
|
||||
}
|
||||
|
||||
let config = match config::parse_config(args) {
|
||||
Ok(config) => config,
|
||||
Err(err) => {
|
||||
io::println(fmt!("error: %s", err));
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
run(config);
|
||||
}
|
||||
|
||||
/// Runs rustdoc over the given file
|
||||
fn run(config: Config) {
|
||||
|
||||
let source_file = config.input_crate;
|
||||
|
||||
// Create an AST service from the source code
|
||||
do astsrv::from_file(source_file.to_str()) |srv| {
|
||||
|
||||
// Just time how long it takes for the AST to become available
|
||||
do time(~"wait_ast") {
|
||||
do astsrv::exec(srv) |_ctxt| { }
|
||||
};
|
||||
|
||||
// Extract the initial doc tree from the AST. This contains
|
||||
// just names and node ids.
|
||||
let doc = time(~"extract", || {
|
||||
let default_name = source_file;
|
||||
extract::from_srv(srv, default_name.to_str())
|
||||
});
|
||||
|
||||
// Refine and publish the document
|
||||
pass::run_passes(srv, doc, ~[
|
||||
// Generate type and signature strings
|
||||
tystr_pass::mk_pass(),
|
||||
// Record the full paths to various nodes
|
||||
path_pass::mk_pass(),
|
||||
// Extract the docs attributes and attach them to doc nodes
|
||||
attr_pass::mk_pass(),
|
||||
// Perform various text escaping
|
||||
escape_pass::mk_pass(),
|
||||
// Remove things marked doc(hidden)
|
||||
prune_hidden_pass::mk_pass(),
|
||||
// Remove things that are private
|
||||
// XXX enable this after 'export' is removed in favor of 'pub'
|
||||
// prune_private_pass::mk_pass(),
|
||||
// Extract brief documentation from the full descriptions
|
||||
desc_to_brief_pass::mk_pass(),
|
||||
// Massage the text to remove extra indentation
|
||||
unindent_pass::mk_pass(),
|
||||
// Split text into multiple sections according to headers
|
||||
sectionalize_pass::mk_pass(),
|
||||
// Trim extra spaces from text
|
||||
trim_pass::mk_pass(),
|
||||
// Sort items by name
|
||||
sort_item_name_pass::mk_pass(),
|
||||
// Sort items again by kind
|
||||
sort_item_type_pass::mk_pass(),
|
||||
// Create indexes appropriate for markdown
|
||||
markdown_index_pass::mk_pass(config),
|
||||
// Break the document into pages if required by the
|
||||
// output format
|
||||
page_pass::mk_pass(config.output_style),
|
||||
// Render
|
||||
markdown_pass::mk_pass(
|
||||
markdown_writer::make_writer_factory(config)
|
||||
)
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
fn time<T>(what: ~str, f: fn() -> T) -> T {
|
||||
let start = std::time::precise_time_s();
|
||||
let rv = f();
|
||||
let end = std::time::precise_time_s();
|
||||
info!("time: %3.3f s %s", end - start, what);
|
||||
move rv
|
||||
}
|
@ -31,3 +31,385 @@ use syntax::ast_util::*;
|
||||
use parse::token;
|
||||
use print::{pp, pprust};
|
||||
use std::rl;
|
||||
|
||||
/**
|
||||
* A structure shared across REPL instances for storing history
|
||||
* such as statements and view items. I wish the AST was sendable.
|
||||
*/
|
||||
struct Repl {
|
||||
prompt: ~str,
|
||||
binary: ~str,
|
||||
running: bool,
|
||||
view_items: ~str,
|
||||
stmts: ~str
|
||||
}
|
||||
|
||||
// Action to do after reading a :command
|
||||
enum CmdAction {
|
||||
action_none,
|
||||
action_run_line(~str),
|
||||
}
|
||||
|
||||
/// A utility function that hands off a pretty printer to a callback.
|
||||
fn with_pp(intr: @token::ident_interner,
|
||||
cb: fn(pprust::ps, io::Writer)) -> ~str {
|
||||
do io::with_str_writer |writer| {
|
||||
let pp = pprust::rust_printer(writer, intr);
|
||||
|
||||
cb(pp, writer);
|
||||
pp::eof(pp.s);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The AST (or the rest of rustc) are not sendable yet,
|
||||
* so recorded things are printed to strings. A terrible hack that
|
||||
* needs changes to rustc in order to be outed. This is unfortunately
|
||||
* going to cause the REPL to regress in parser performance,
|
||||
* because it has to parse the statements and view_items on each
|
||||
* input.
|
||||
*/
|
||||
fn record(repl: Repl, blk: @ast::blk, intr: @token::ident_interner) -> Repl {
|
||||
let view_items = if blk.node.view_items.len() > 0 {
|
||||
let new_view_items = do with_pp(intr) |pp, writer| {
|
||||
for blk.node.view_items.each |view_item| {
|
||||
pprust::print_view_item(pp, *view_item);
|
||||
writer.write_line(~"");
|
||||
}
|
||||
};
|
||||
|
||||
debug!("new view items %s", new_view_items);
|
||||
|
||||
repl.view_items + "\n" + new_view_items
|
||||
} else { repl.view_items };
|
||||
let stmts = if blk.node.stmts.len() > 0 {
|
||||
let new_stmts = do with_pp(intr) |pp, writer| {
|
||||
for blk.node.stmts.each |stmt| {
|
||||
match stmt.node {
|
||||
ast::stmt_decl(*) => {
|
||||
pprust::print_stmt(pp, **stmt);
|
||||
writer.write_line(~"");
|
||||
}
|
||||
ast::stmt_expr(expr, _) | ast::stmt_semi(expr, _) => {
|
||||
match expr.node {
|
||||
ast::expr_assign(*) |
|
||||
ast::expr_assign_op(*) |
|
||||
ast::expr_swap(*) => {
|
||||
pprust::print_stmt(pp, **stmt);
|
||||
writer.write_line(~"");
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
debug!("new stmts %s", new_stmts);
|
||||
|
||||
repl.stmts + "\n" + new_stmts
|
||||
} else { repl.stmts };
|
||||
|
||||
Repl{
|
||||
view_items: view_items,
|
||||
stmts: stmts,
|
||||
.. repl
|
||||
}
|
||||
}
|
||||
|
||||
/// Run an input string in a Repl, returning the new Repl.
|
||||
fn run(repl: Repl, input: ~str) -> Repl {
|
||||
let options: @session::options = @{
|
||||
crate_type: session::unknown_crate,
|
||||
binary: repl.binary,
|
||||
addl_lib_search_paths: ~[os::getcwd()],
|
||||
.. *session::basic_options()
|
||||
};
|
||||
|
||||
debug!("building driver input");
|
||||
let head = include_str!("wrapper.rs");
|
||||
let foot = fmt!("%s\nfn main() {\n%s\n\nprint({\n%s\n})\n}",
|
||||
repl.view_items, repl.stmts, input);
|
||||
let wrapped = driver::str_input(head + foot);
|
||||
|
||||
debug!("inputting %s", head + foot);
|
||||
|
||||
debug!("building a driver session");
|
||||
let sess = driver::build_session(options, diagnostic::emit);
|
||||
|
||||
debug!("building driver configuration");
|
||||
let cfg = driver::build_configuration(sess,
|
||||
repl.binary,
|
||||
wrapped);
|
||||
|
||||
debug!("parsing");
|
||||
let mut crate = driver::parse_input(sess, cfg, wrapped);
|
||||
let mut opt = None;
|
||||
|
||||
for crate.node.module.items.each |item| {
|
||||
match item.node {
|
||||
ast::item_fn(_, _, _, blk) => {
|
||||
if item.ident == sess.ident_of(~"main") {
|
||||
opt = blk.node.expr;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
let blk = match opt.get().node {
|
||||
ast::expr_call(_, exprs, _) => {
|
||||
match exprs[0].node {
|
||||
ast::expr_block(blk) => @blk,
|
||||
_ => fail
|
||||
}
|
||||
}
|
||||
_ => fail
|
||||
};
|
||||
|
||||
debug!("configuration");
|
||||
crate = front::config::strip_unconfigured_items(crate);
|
||||
|
||||
debug!("maybe building test harness");
|
||||
crate = front::test::modify_for_testing(sess, crate);
|
||||
|
||||
debug!("expansion");
|
||||
crate = syntax::ext::expand::expand_crate(sess.parse_sess,
|
||||
sess.opts.cfg,
|
||||
crate);
|
||||
|
||||
debug!("intrinsic injection");
|
||||
crate = front::intrinsic_inject::inject_intrinsic(sess, crate);
|
||||
|
||||
debug!("core injection");
|
||||
crate = front::core_inject::maybe_inject_libcore_ref(sess, crate);
|
||||
|
||||
debug!("building lint settings table");
|
||||
lint::build_settings_crate(sess, crate);
|
||||
|
||||
debug!("ast indexing");
|
||||
let ast_map = syntax::ast_map::map_crate(sess.diagnostic(), *crate);
|
||||
|
||||
debug!("external crate/lib resolution");
|
||||
creader::read_crates(sess.diagnostic(), *crate, sess.cstore,
|
||||
sess.filesearch,
|
||||
session::sess_os_to_meta_os(sess.targ_cfg.os),
|
||||
sess.opts.static, sess.parse_sess.interner);
|
||||
|
||||
debug!("language item collection");
|
||||
let lang_items = middle::lang_items::collect_language_items(crate, sess);
|
||||
|
||||
debug!("resolution");
|
||||
let {def_map: def_map,
|
||||
exp_map2: exp_map2,
|
||||
trait_map: trait_map} = middle::resolve::resolve_crate(sess,
|
||||
lang_items,
|
||||
crate);
|
||||
|
||||
debug!("freevar finding");
|
||||
let freevars = freevars::annotate_freevars(def_map, crate);
|
||||
|
||||
debug!("region_resolution");
|
||||
let region_map = middle::region::resolve_crate(sess, def_map, crate);
|
||||
|
||||
debug!("region paramaterization inference");
|
||||
let rp_set = middle::region::determine_rp_in_crate(sess, ast_map,
|
||||
def_map, crate);
|
||||
|
||||
debug!("typechecking");
|
||||
let ty_cx = ty::mk_ctxt(sess, def_map, ast_map, freevars,
|
||||
region_map, rp_set, move lang_items, crate);
|
||||
let (method_map, vtable_map) = typeck::check_crate(ty_cx, trait_map,
|
||||
crate);
|
||||
|
||||
debug!("const marking");
|
||||
middle::const_eval::process_crate(crate, def_map, ty_cx);
|
||||
|
||||
debug!("const checking");
|
||||
middle::check_const::check_crate(sess, crate, ast_map, def_map,
|
||||
method_map, ty_cx);
|
||||
|
||||
debug!("privacy checking");
|
||||
middle::privacy::check_crate(ty_cx, &method_map, crate);
|
||||
|
||||
debug!("loop checking");
|
||||
middle::check_loop::check_crate(ty_cx, crate);
|
||||
|
||||
debug!("alt checking");
|
||||
middle::check_alt::check_crate(ty_cx, crate);
|
||||
|
||||
debug!("liveness checking");
|
||||
let last_use_map = middle::liveness::check_crate(ty_cx,
|
||||
method_map, crate);
|
||||
|
||||
debug!("borrow checking");
|
||||
let (root_map, mutbl_map) = middle::borrowck::check_crate(ty_cx,
|
||||
method_map,
|
||||
last_use_map,
|
||||
crate);
|
||||
|
||||
debug!("kind checking");
|
||||
kind::check_crate(ty_cx, method_map, last_use_map, crate);
|
||||
|
||||
debug!("lint checking");
|
||||
lint::check_crate(ty_cx, crate);
|
||||
|
||||
let maps = {mutbl_map: mutbl_map,
|
||||
root_map: root_map,
|
||||
last_use_map: last_use_map,
|
||||
method_map: method_map,
|
||||
vtable_map: vtable_map};
|
||||
|
||||
debug!("translation");
|
||||
let (llmod, _) = trans::base::trans_crate(sess, crate, ty_cx,
|
||||
~path::from_str("<repl>"),
|
||||
exp_map2, maps);
|
||||
let pm = llvm::LLVMCreatePassManager();
|
||||
|
||||
debug!("executing jit");
|
||||
back::link::jit::exec(sess, pm, llmod, 0, false);
|
||||
llvm::LLVMDisposePassManager(pm);
|
||||
|
||||
debug!("recording input into repl history");
|
||||
record(repl, blk, sess.parse_sess.interner)
|
||||
}
|
||||
|
||||
/// Tries to get a line from rl after outputting a prompt. Returns
|
||||
/// None if no input was read (e.g. EOF was reached).
|
||||
fn get_line(prompt: ~str) -> Option<~str> {
|
||||
let result = unsafe { rl::read(prompt) };
|
||||
|
||||
if result.is_none() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let line = result.get();
|
||||
|
||||
unsafe { rl::add_history(line) };
|
||||
|
||||
return Some(line);
|
||||
}
|
||||
|
||||
/// Run a command, e.g. :clear, :exit, etc.
|
||||
fn run_cmd(repl: &mut Repl, _in: io::Reader, _out: io::Writer,
|
||||
cmd: ~str, _args: ~[~str]) -> CmdAction {
|
||||
let mut action = action_none;
|
||||
match cmd {
|
||||
~"exit" => repl.running = false,
|
||||
~"clear" => {
|
||||
repl.view_items = ~"";
|
||||
repl.stmts = ~"";
|
||||
|
||||
// XXX: Win32 version of linenoise can't do this
|
||||
//rl::clear();
|
||||
}
|
||||
~"help" => {
|
||||
io::println(
|
||||
~":{\\n ..lines.. \\n:}\\n - execute multiline command\n" +
|
||||
~":clear - clear the screen\n" +
|
||||
~":exit - exit from the repl\n" +
|
||||
~":help - show this message");
|
||||
}
|
||||
~"{" => {
|
||||
let mut multiline_cmd = ~"";
|
||||
let mut end_multiline = false;
|
||||
while (!end_multiline) {
|
||||
match get_line(~"rusti| ") {
|
||||
None => fail ~"unterminated multiline command :{ .. :}",
|
||||
Some(line) => {
|
||||
if str::trim(line) == ~":}" {
|
||||
end_multiline = true;
|
||||
} else {
|
||||
multiline_cmd += line + ~"\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
action = action_run_line(multiline_cmd);
|
||||
}
|
||||
_ => io::println(~"unknown cmd: " + cmd)
|
||||
}
|
||||
return action;
|
||||
}
|
||||
|
||||
/// Executes a line of input, which may either be rust code or a
|
||||
/// :command. Returns a new Repl if it has changed.
|
||||
fn run_line(repl: &mut Repl, in: io::Reader, out: io::Writer, line: ~str)
|
||||
-> Option<Repl> {
|
||||
if line.starts_with(~":") {
|
||||
let full = line.substr(1, line.len() - 1);
|
||||
let split = str::words(full);
|
||||
let len = split.len();
|
||||
|
||||
if len > 0 {
|
||||
let cmd = split[0];
|
||||
|
||||
if !cmd.is_empty() {
|
||||
let args = if len > 1 {
|
||||
do vec::view(split, 1, len - 1).map |arg| {
|
||||
*arg
|
||||
}
|
||||
} else { ~[] };
|
||||
|
||||
match run_cmd(repl, in, out, cmd, args) {
|
||||
action_none => { }
|
||||
action_run_line(multiline_cmd) => {
|
||||
if !multiline_cmd.is_empty() {
|
||||
return run_line(repl, in, out, multiline_cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let r = *repl;
|
||||
let result = do task::try |copy r| {
|
||||
run(r, line)
|
||||
};
|
||||
|
||||
if result.is_ok() {
|
||||
return Some(result.get());
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let args = os::args();
|
||||
let in = io::stdin();
|
||||
let out = io::stdout();
|
||||
let mut repl = Repl {
|
||||
prompt: ~"rusti> ",
|
||||
binary: args[0],
|
||||
running: true,
|
||||
view_items: ~"",
|
||||
stmts: ~""
|
||||
};
|
||||
|
||||
unsafe {
|
||||
do rl::complete |line, suggest| {
|
||||
if line.starts_with(":") {
|
||||
suggest(~":clear");
|
||||
suggest(~":exit");
|
||||
suggest(~":help");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while repl.running {
|
||||
match get_line(repl.prompt) {
|
||||
None => break,
|
||||
Some(line) => {
|
||||
if line.is_empty() {
|
||||
io::println(~"()");
|
||||
loop;
|
||||
}
|
||||
match run_line(&mut repl, in, out, line) {
|
||||
Some(new_repl) => repl = new_repl,
|
||||
None => { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,381 +0,0 @@
|
||||
/**
|
||||
* A structure shared across REPL instances for storing history
|
||||
* such as statements and view items. I wish the AST was sendable.
|
||||
*/
|
||||
struct Repl {
|
||||
prompt: ~str,
|
||||
binary: ~str,
|
||||
running: bool,
|
||||
view_items: ~str,
|
||||
stmts: ~str
|
||||
}
|
||||
|
||||
// Action to do after reading a :command
|
||||
enum CmdAction {
|
||||
action_none,
|
||||
action_run_line(~str),
|
||||
}
|
||||
|
||||
/// A utility function that hands off a pretty printer to a callback.
|
||||
fn with_pp(intr: @token::ident_interner,
|
||||
cb: fn(pprust::ps, io::Writer)) -> ~str {
|
||||
do io::with_str_writer |writer| {
|
||||
let pp = pprust::rust_printer(writer, intr);
|
||||
|
||||
cb(pp, writer);
|
||||
pp::eof(pp.s);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The AST (or the rest of rustc) are not sendable yet,
|
||||
* so recorded things are printed to strings. A terrible hack that
|
||||
* needs changes to rustc in order to be outed. This is unfortunately
|
||||
* going to cause the REPL to regress in parser performance,
|
||||
* because it has to parse the statements and view_items on each
|
||||
* input.
|
||||
*/
|
||||
fn record(repl: Repl, blk: @ast::blk, intr: @token::ident_interner) -> Repl {
|
||||
let view_items = if blk.node.view_items.len() > 0 {
|
||||
let new_view_items = do with_pp(intr) |pp, writer| {
|
||||
for blk.node.view_items.each |view_item| {
|
||||
pprust::print_view_item(pp, *view_item);
|
||||
writer.write_line(~"");
|
||||
}
|
||||
};
|
||||
|
||||
debug!("new view items %s", new_view_items);
|
||||
|
||||
repl.view_items + "\n" + new_view_items
|
||||
} else { repl.view_items };
|
||||
let stmts = if blk.node.stmts.len() > 0 {
|
||||
let new_stmts = do with_pp(intr) |pp, writer| {
|
||||
for blk.node.stmts.each |stmt| {
|
||||
match stmt.node {
|
||||
ast::stmt_decl(*) => {
|
||||
pprust::print_stmt(pp, **stmt);
|
||||
writer.write_line(~"");
|
||||
}
|
||||
ast::stmt_expr(expr, _) | ast::stmt_semi(expr, _) => {
|
||||
match expr.node {
|
||||
ast::expr_assign(*) |
|
||||
ast::expr_assign_op(*) |
|
||||
ast::expr_swap(*) => {
|
||||
pprust::print_stmt(pp, **stmt);
|
||||
writer.write_line(~"");
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
debug!("new stmts %s", new_stmts);
|
||||
|
||||
repl.stmts + "\n" + new_stmts
|
||||
} else { repl.stmts };
|
||||
|
||||
Repl{
|
||||
view_items: view_items,
|
||||
stmts: stmts,
|
||||
.. repl
|
||||
}
|
||||
}
|
||||
|
||||
/// Run an input string in a Repl, returning the new Repl.
|
||||
fn run(repl: Repl, input: ~str) -> Repl {
|
||||
let options: @session::options = @{
|
||||
crate_type: session::unknown_crate,
|
||||
binary: repl.binary,
|
||||
addl_lib_search_paths: ~[os::getcwd()],
|
||||
.. *session::basic_options()
|
||||
};
|
||||
|
||||
debug!("building driver input");
|
||||
let head = include_str!("wrapper.rs");
|
||||
let foot = fmt!("%s\nfn main() {\n%s\n\nprint({\n%s\n})\n}",
|
||||
repl.view_items, repl.stmts, input);
|
||||
let wrapped = driver::str_input(head + foot);
|
||||
|
||||
debug!("inputting %s", head + foot);
|
||||
|
||||
debug!("building a driver session");
|
||||
let sess = driver::build_session(options, diagnostic::emit);
|
||||
|
||||
debug!("building driver configuration");
|
||||
let cfg = driver::build_configuration(sess,
|
||||
repl.binary,
|
||||
wrapped);
|
||||
|
||||
debug!("parsing");
|
||||
let mut crate = driver::parse_input(sess, cfg, wrapped);
|
||||
let mut opt = None;
|
||||
|
||||
for crate.node.module.items.each |item| {
|
||||
match item.node {
|
||||
ast::item_fn(_, _, _, blk) => {
|
||||
if item.ident == sess.ident_of(~"main") {
|
||||
opt = blk.node.expr;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
let blk = match opt.get().node {
|
||||
ast::expr_call(_, exprs, _) => {
|
||||
match exprs[0].node {
|
||||
ast::expr_block(blk) => @blk,
|
||||
_ => fail
|
||||
}
|
||||
}
|
||||
_ => fail
|
||||
};
|
||||
|
||||
debug!("configuration");
|
||||
crate = front::config::strip_unconfigured_items(crate);
|
||||
|
||||
debug!("maybe building test harness");
|
||||
crate = front::test::modify_for_testing(sess, crate);
|
||||
|
||||
debug!("expansion");
|
||||
crate = syntax::ext::expand::expand_crate(sess.parse_sess,
|
||||
sess.opts.cfg,
|
||||
crate);
|
||||
|
||||
debug!("intrinsic injection");
|
||||
crate = front::intrinsic_inject::inject_intrinsic(sess, crate);
|
||||
|
||||
debug!("core injection");
|
||||
crate = front::core_inject::maybe_inject_libcore_ref(sess, crate);
|
||||
|
||||
debug!("building lint settings table");
|
||||
lint::build_settings_crate(sess, crate);
|
||||
|
||||
debug!("ast indexing");
|
||||
let ast_map = syntax::ast_map::map_crate(sess.diagnostic(), *crate);
|
||||
|
||||
debug!("external crate/lib resolution");
|
||||
creader::read_crates(sess.diagnostic(), *crate, sess.cstore,
|
||||
sess.filesearch,
|
||||
session::sess_os_to_meta_os(sess.targ_cfg.os),
|
||||
sess.opts.static, sess.parse_sess.interner);
|
||||
|
||||
debug!("language item collection");
|
||||
let lang_items = middle::lang_items::collect_language_items(crate, sess);
|
||||
|
||||
debug!("resolution");
|
||||
let {def_map: def_map,
|
||||
exp_map2: exp_map2,
|
||||
trait_map: trait_map} = middle::resolve::resolve_crate(sess,
|
||||
lang_items,
|
||||
crate);
|
||||
|
||||
debug!("freevar finding");
|
||||
let freevars = freevars::annotate_freevars(def_map, crate);
|
||||
|
||||
debug!("region_resolution");
|
||||
let region_map = middle::region::resolve_crate(sess, def_map, crate);
|
||||
|
||||
debug!("region paramaterization inference");
|
||||
let rp_set = middle::region::determine_rp_in_crate(sess, ast_map,
|
||||
def_map, crate);
|
||||
|
||||
debug!("typechecking");
|
||||
let ty_cx = ty::mk_ctxt(sess, def_map, ast_map, freevars,
|
||||
region_map, rp_set, move lang_items, crate);
|
||||
let (method_map, vtable_map) = typeck::check_crate(ty_cx, trait_map,
|
||||
crate);
|
||||
|
||||
debug!("const marking");
|
||||
middle::const_eval::process_crate(crate, def_map, ty_cx);
|
||||
|
||||
debug!("const checking");
|
||||
middle::check_const::check_crate(sess, crate, ast_map, def_map,
|
||||
method_map, ty_cx);
|
||||
|
||||
debug!("privacy checking");
|
||||
middle::privacy::check_crate(ty_cx, &method_map, crate);
|
||||
|
||||
debug!("loop checking");
|
||||
middle::check_loop::check_crate(ty_cx, crate);
|
||||
|
||||
debug!("alt checking");
|
||||
middle::check_alt::check_crate(ty_cx, crate);
|
||||
|
||||
debug!("liveness checking");
|
||||
let last_use_map = middle::liveness::check_crate(ty_cx,
|
||||
method_map, crate);
|
||||
|
||||
debug!("borrow checking");
|
||||
let (root_map, mutbl_map) = middle::borrowck::check_crate(ty_cx,
|
||||
method_map,
|
||||
last_use_map,
|
||||
crate);
|
||||
|
||||
debug!("kind checking");
|
||||
kind::check_crate(ty_cx, method_map, last_use_map, crate);
|
||||
|
||||
debug!("lint checking");
|
||||
lint::check_crate(ty_cx, crate);
|
||||
|
||||
let maps = {mutbl_map: mutbl_map,
|
||||
root_map: root_map,
|
||||
last_use_map: last_use_map,
|
||||
method_map: method_map,
|
||||
vtable_map: vtable_map};
|
||||
|
||||
debug!("translation");
|
||||
let (llmod, _) = trans::base::trans_crate(sess, crate, ty_cx,
|
||||
~path::from_str("<repl>"),
|
||||
exp_map2, maps);
|
||||
let pm = llvm::LLVMCreatePassManager();
|
||||
|
||||
debug!("executing jit");
|
||||
back::link::jit::exec(sess, pm, llmod, 0, false);
|
||||
llvm::LLVMDisposePassManager(pm);
|
||||
|
||||
debug!("recording input into repl history");
|
||||
record(repl, blk, sess.parse_sess.interner)
|
||||
}
|
||||
|
||||
/// Tries to get a line from rl after outputting a prompt. Returns
|
||||
/// None if no input was read (e.g. EOF was reached).
|
||||
fn get_line(prompt: ~str) -> Option<~str> {
|
||||
let result = unsafe { rl::read(prompt) };
|
||||
|
||||
if result.is_none() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let line = result.get();
|
||||
|
||||
unsafe { rl::add_history(line) };
|
||||
|
||||
return Some(line);
|
||||
}
|
||||
|
||||
/// Run a command, e.g. :clear, :exit, etc.
|
||||
fn run_cmd(repl: &mut Repl, _in: io::Reader, _out: io::Writer,
|
||||
cmd: ~str, _args: ~[~str]) -> CmdAction {
|
||||
let mut action = action_none;
|
||||
match cmd {
|
||||
~"exit" => repl.running = false,
|
||||
~"clear" => {
|
||||
repl.view_items = ~"";
|
||||
repl.stmts = ~"";
|
||||
|
||||
// XXX: Win32 version of linenoise can't do this
|
||||
//rl::clear();
|
||||
}
|
||||
~"help" => {
|
||||
io::println(
|
||||
~":{\\n ..lines.. \\n:}\\n - execute multiline command\n" +
|
||||
~":clear - clear the screen\n" +
|
||||
~":exit - exit from the repl\n" +
|
||||
~":help - show this message");
|
||||
}
|
||||
~"{" => {
|
||||
let mut multiline_cmd = ~"";
|
||||
let mut end_multiline = false;
|
||||
while (!end_multiline) {
|
||||
match get_line(~"rusti| ") {
|
||||
None => fail ~"unterminated multiline command :{ .. :}",
|
||||
Some(line) => {
|
||||
if str::trim(line) == ~":}" {
|
||||
end_multiline = true;
|
||||
} else {
|
||||
multiline_cmd += line + ~"\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
action = action_run_line(multiline_cmd);
|
||||
}
|
||||
_ => io::println(~"unknown cmd: " + cmd)
|
||||
}
|
||||
return action;
|
||||
}
|
||||
|
||||
/// Executes a line of input, which may either be rust code or a
|
||||
/// :command. Returns a new Repl if it has changed.
|
||||
fn run_line(repl: &mut Repl, in: io::Reader, out: io::Writer, line: ~str)
|
||||
-> Option<Repl> {
|
||||
if line.starts_with(~":") {
|
||||
let full = line.substr(1, line.len() - 1);
|
||||
let split = str::words(full);
|
||||
let len = split.len();
|
||||
|
||||
if len > 0 {
|
||||
let cmd = split[0];
|
||||
|
||||
if !cmd.is_empty() {
|
||||
let args = if len > 1 {
|
||||
do vec::view(split, 1, len - 1).map |arg| {
|
||||
*arg
|
||||
}
|
||||
} else { ~[] };
|
||||
|
||||
match run_cmd(repl, in, out, cmd, args) {
|
||||
action_none => { }
|
||||
action_run_line(multiline_cmd) => {
|
||||
if !multiline_cmd.is_empty() {
|
||||
return run_line(repl, in, out, multiline_cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let r = *repl;
|
||||
let result = do task::try |copy r| {
|
||||
run(r, line)
|
||||
};
|
||||
|
||||
if result.is_ok() {
|
||||
return Some(result.get());
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let args = os::args();
|
||||
let in = io::stdin();
|
||||
let out = io::stdout();
|
||||
let mut repl = Repl {
|
||||
prompt: ~"rusti> ",
|
||||
binary: args[0],
|
||||
running: true,
|
||||
view_items: ~"",
|
||||
stmts: ~""
|
||||
};
|
||||
|
||||
unsafe {
|
||||
do rl::complete |line, suggest| {
|
||||
if line.starts_with(":") {
|
||||
suggest(~":clear");
|
||||
suggest(~":exit");
|
||||
suggest(~":help");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while repl.running {
|
||||
match get_line(repl.prompt) {
|
||||
None => break,
|
||||
Some(line) => {
|
||||
if line.is_empty() {
|
||||
io::println(~"()");
|
||||
loop;
|
||||
}
|
||||
match run_line(&mut repl, in, out, line) {
|
||||
Some(new_repl) => repl = new_repl,
|
||||
None => { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
128
src/libsyntax/alternate_crate.rc
Normal file
128
src/libsyntax/alternate_crate.rc
Normal file
@ -0,0 +1,128 @@
|
||||
#[link(name = "syntax",
|
||||
vers = "0.5",
|
||||
uuid = "9311401b-d6ea-4cd9-a1d9-61f89499c645")];
|
||||
|
||||
|
||||
|
||||
#[crate_type = "lib"];
|
||||
|
||||
#[no_core];
|
||||
|
||||
#[legacy_modes];
|
||||
#[legacy_exports];
|
||||
|
||||
#[allow(vecs_implicitly_copyable)];
|
||||
#[allow(non_camel_case_types)];
|
||||
#[allow(deprecated_mode)];
|
||||
#[allow(deprecated_pattern)];
|
||||
|
||||
extern mod core(vers = "0.5");
|
||||
extern mod std(vers = "0.5");
|
||||
|
||||
use core::*;
|
||||
|
||||
#[legacy_exports]
|
||||
mod attr;
|
||||
#[legacy_exports]
|
||||
mod diagnostic;
|
||||
mod codemap;
|
||||
#[legacy_exports]
|
||||
mod ast;
|
||||
#[legacy_exports]
|
||||
mod ast_util;
|
||||
#[legacy_exports]
|
||||
mod ast_map;
|
||||
#[legacy_exports]
|
||||
mod visit;
|
||||
#[legacy_exports]
|
||||
mod fold;
|
||||
#[legacy_exports]
|
||||
mod util {
|
||||
#[legacy_exports];
|
||||
#[legacy_exports]
|
||||
#[path = "util/interner.rs"]
|
||||
mod interner;
|
||||
}
|
||||
|
||||
#[merge = "parse/mod.rs"]
|
||||
mod parse;
|
||||
|
||||
mod print {
|
||||
#[legacy_exports];
|
||||
#[legacy_exports]
|
||||
#[path = "print/pp.rs"]
|
||||
mod pp;
|
||||
#[legacy_exports]
|
||||
#[path = "print/pprust.rs"]
|
||||
mod pprust;
|
||||
}
|
||||
|
||||
mod ext {
|
||||
#[legacy_exports];
|
||||
#[legacy_exports]
|
||||
#[path = "ext/base.rs"]
|
||||
mod base;
|
||||
#[legacy_exports]
|
||||
#[path = "ext/expand.rs"]
|
||||
mod expand;
|
||||
#[legacy_exports]
|
||||
#[path = "ext/qquote.rs"]
|
||||
mod qquote;
|
||||
|
||||
#[path = "ext/quote.rs"]
|
||||
mod quote;
|
||||
#[path = "ext/deriving.rs"]
|
||||
mod deriving;
|
||||
|
||||
#[legacy_exports]
|
||||
#[path = "ext/build.rs"]
|
||||
mod build;
|
||||
|
||||
mod tt {
|
||||
#[legacy_exports];
|
||||
#[legacy_exports]
|
||||
#[path = "ext/tt/transcribe.rs"]
|
||||
mod transcribe;
|
||||
#[legacy_exports]
|
||||
#[path = "ext/tt/macro_parser.rs"]
|
||||
mod macro_parser;
|
||||
#[legacy_exports]
|
||||
#[path = "ext/tt/macro_rules.rs"]
|
||||
mod macro_rules;
|
||||
}
|
||||
|
||||
|
||||
#[legacy_exports]
|
||||
#[path = "ext/simplext.rs"]
|
||||
mod simplext;
|
||||
#[legacy_exports]
|
||||
#[path = "ext/fmt.rs"]
|
||||
mod fmt;
|
||||
#[legacy_exports]
|
||||
#[path = "ext/env.rs"]
|
||||
mod env;
|
||||
#[legacy_exports]
|
||||
#[path = "ext/concat_idents.rs"]
|
||||
mod concat_idents;
|
||||
#[legacy_exports]
|
||||
#[path = "ext/ident_to_str.rs"]
|
||||
mod ident_to_str;
|
||||
#[legacy_exports]
|
||||
#[path = "ext/log_syntax.rs"]
|
||||
mod log_syntax;
|
||||
#[legacy_exports]
|
||||
#[path = "ext/auto_serialize.rs"]
|
||||
mod auto_serialize;
|
||||
#[legacy_exports]
|
||||
#[path = "ext/source_util.rs"]
|
||||
mod source_util;
|
||||
|
||||
#[legacy_exports]
|
||||
#[path = "ext/pipes.rs"]
|
||||
#[merge = "ext/pipes/mod.rs"]
|
||||
mod pipes;
|
||||
|
||||
#[legacy_exports]
|
||||
#[path = "ext/trace_macros.rs"]
|
||||
mod trace_macros;
|
||||
}
|
@ -406,25 +406,10 @@ type crate_cfg = ~[@meta_item];
|
||||
type crate = spanned<crate_>;
|
||||
|
||||
type crate_ =
|
||||
{directives: ~[@crate_directive],
|
||||
module: _mod,
|
||||
{module: _mod,
|
||||
attrs: ~[attribute],
|
||||
config: crate_cfg};
|
||||
|
||||
enum crate_directive_ {
|
||||
cdir_src_mod(visibility, ident, ~[attribute]),
|
||||
cdir_dir_mod(visibility, ident, ~[@crate_directive], ~[attribute]),
|
||||
|
||||
// NB: cdir_view_item is *not* processed by the rest of the compiler, the
|
||||
// attached view_items are sunk into the crate's module during parsing,
|
||||
// and processed (resolved, imported, etc.) there. This enum-variant
|
||||
// exists only to preserve the view items in order in case we decide to
|
||||
// pretty-print crates in the future.
|
||||
cdir_view_item(@view_item),
|
||||
}
|
||||
|
||||
type crate_directive = spanned<crate_directive_>;
|
||||
|
||||
type meta_item = spanned<meta_item_>;
|
||||
|
||||
#[auto_serialize]
|
||||
|
12
src/libsyntax/ext/pipes/mod.rs
Normal file
12
src/libsyntax/ext/pipes/mod.rs
Normal file
@ -0,0 +1,12 @@
|
||||
#[legacy_exports]
|
||||
mod ast_builder;
|
||||
#[legacy_exports]
|
||||
mod parse_proto;
|
||||
#[legacy_exports]
|
||||
mod pipec;
|
||||
#[legacy_exports]
|
||||
mod proto;
|
||||
#[legacy_exports]
|
||||
mod check;
|
||||
#[legacy_exports]
|
||||
mod liveness;
|
@ -21,7 +21,6 @@ export extensions;
|
||||
|
||||
trait ast_fold {
|
||||
fn fold_crate(crate) -> crate;
|
||||
fn fold_crate_directive(&&v: @crate_directive) -> @crate_directive;
|
||||
fn fold_view_item(&&v: @view_item) -> @view_item;
|
||||
fn fold_foreign_item(&&v: @foreign_item) -> @foreign_item;
|
||||
fn fold_item(&&v: @item) -> Option<@item>;
|
||||
@ -51,8 +50,6 @@ trait ast_fold {
|
||||
type ast_fold_precursor = @{
|
||||
//unlike the others, item_ is non-trivial
|
||||
fold_crate: fn@(crate_, span, ast_fold) -> (crate_, span),
|
||||
fold_crate_directive: fn@(crate_directive_, span,
|
||||
ast_fold) -> (crate_directive_, span),
|
||||
fold_view_item: fn@(view_item_, ast_fold) -> view_item_,
|
||||
fold_foreign_item: fn@(&&v: @foreign_item, ast_fold) -> @foreign_item,
|
||||
fold_item: fn@(&&v: @item, ast_fold) -> Option<@item>,
|
||||
@ -150,29 +147,12 @@ fn noop_fold_crate(c: crate_, fld: ast_fold) -> crate_ {
|
||||
let fold_attribute = |x| fold_attribute_(x, fld);
|
||||
|
||||
return {
|
||||
directives: vec::map(c.directives, |x| fld.fold_crate_directive(*x)),
|
||||
module: fld.fold_mod(c.module),
|
||||
attrs: vec::map(c.attrs, |x| fold_attribute(*x)),
|
||||
config: vec::map(c.config, |x| fold_meta_item(*x))
|
||||
};
|
||||
}
|
||||
|
||||
fn noop_fold_crate_directive(cd: crate_directive_, fld: ast_fold) ->
|
||||
crate_directive_ {
|
||||
return match cd {
|
||||
cdir_src_mod(vis, id, attrs) => {
|
||||
cdir_src_mod(vis, fld.fold_ident(id),
|
||||
/* FIXME (#2543) */ copy attrs)
|
||||
}
|
||||
cdir_dir_mod(vis, id, cds, attrs) => {
|
||||
cdir_dir_mod(vis, fld.fold_ident(id),
|
||||
vec::map(cds, |x| fld.fold_crate_directive(*x)),
|
||||
/* FIXME (#2543) */ copy attrs)
|
||||
}
|
||||
cdir_view_item(vi) => cdir_view_item(fld.fold_view_item(vi)),
|
||||
}
|
||||
}
|
||||
|
||||
fn noop_fold_view_item(vi: view_item_, _fld: ast_fold) -> view_item_ {
|
||||
return /* FIXME (#2543) */ copy vi;
|
||||
}
|
||||
@ -635,7 +615,6 @@ fn noop_span(sp: span) -> span { return sp; }
|
||||
|
||||
fn default_ast_fold() -> ast_fold_precursor {
|
||||
return @{fold_crate: wrap(noop_fold_crate),
|
||||
fold_crate_directive: wrap(noop_fold_crate_directive),
|
||||
fold_view_item: noop_fold_view_item,
|
||||
fold_foreign_item: noop_fold_foreign_item,
|
||||
fold_item: noop_fold_item,
|
||||
@ -666,12 +645,6 @@ impl ast_fold_precursor: ast_fold {
|
||||
let (n, s) = self.fold_crate(c.node, c.span, self as ast_fold);
|
||||
return {node: n, span: self.new_span(s)};
|
||||
}
|
||||
fn fold_crate_directive(&&c: @crate_directive) -> @crate_directive {
|
||||
let (n, s) = self.fold_crate_directive(c.node, c.span,
|
||||
self as ast_fold);
|
||||
return @{node: n,
|
||||
span: self.new_span(s)};
|
||||
}
|
||||
fn fold_view_item(&&x: @view_item) ->
|
||||
@view_item {
|
||||
return @{node: self.fold_view_item(x.node, self as ast_fold),
|
||||
|
@ -1,5 +1,16 @@
|
||||
//! The main parser interface
|
||||
|
||||
#[legacy_exports];
|
||||
|
||||
export parser;
|
||||
export common;
|
||||
export lexer;
|
||||
export token;
|
||||
export comments;
|
||||
export prec;
|
||||
export classify;
|
||||
export attr;
|
||||
|
||||
export parse_sess;
|
||||
export new_parse_sess, new_parse_sess_special_handler;
|
||||
export next_node_id;
|
||||
@ -51,40 +62,6 @@ fn new_parse_sess_special_handler(sh: span_handler, cm: @codemap::CodeMap)
|
||||
|
||||
fn parse_crate_from_file(input: &Path, cfg: ast::crate_cfg,
|
||||
sess: parse_sess) -> @ast::crate {
|
||||
if input.filetype() == Some(~".rc") {
|
||||
parse_crate_from_crate_file(input, cfg, sess)
|
||||
} else if input.filetype() == Some(~".rs") {
|
||||
parse_crate_from_source_file(input, cfg, sess)
|
||||
} else {
|
||||
sess.span_diagnostic.handler().fatal(~"unknown input file type: " +
|
||||
input.to_str())
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_crate_from_crate_file(input: &Path, cfg: ast::crate_cfg,
|
||||
sess: parse_sess) -> @ast::crate {
|
||||
let p = new_crate_parser_from_file(sess, cfg, input);
|
||||
let lo = p.span.lo;
|
||||
let prefix = input.dir_path();
|
||||
let leading_attrs = p.parse_inner_attrs_and_next();
|
||||
let { inner: crate_attrs, next: first_cdir_attr } = leading_attrs;
|
||||
let cdirs = p.parse_crate_directives(token::EOF, first_cdir_attr);
|
||||
let cx = @{sess: sess, cfg: /* FIXME (#2543) */ copy p.cfg};
|
||||
let companionmod = input.filestem().map(|s| Path(*s));
|
||||
let (m, attrs) = eval::eval_crate_directives_to_mod(
|
||||
cx, cdirs, &prefix, &companionmod);
|
||||
let mut hi = p.span.hi;
|
||||
p.expect(token::EOF);
|
||||
p.abort_if_errors();
|
||||
return @ast_util::respan(ast_util::mk_sp(lo, hi),
|
||||
{directives: cdirs,
|
||||
module: m,
|
||||
attrs: vec::append(crate_attrs, attrs),
|
||||
config: /* FIXME (#2543) */ copy p.cfg});
|
||||
}
|
||||
|
||||
fn parse_crate_from_source_file(input: &Path, cfg: ast::crate_cfg,
|
||||
sess: parse_sess) -> @ast::crate {
|
||||
let p = new_crate_parser_from_file(sess, cfg, input);
|
||||
let r = p.parse_crate_mod(cfg);
|
||||
return r;
|
||||
|
28
src/libsyntax/parse/mod.rs
Normal file
28
src/libsyntax/parse/mod.rs
Normal file
@ -0,0 +1,28 @@
|
||||
|
||||
#[legacy_exports]
|
||||
mod lexer;
|
||||
#[legacy_exports]
|
||||
mod parser;
|
||||
#[legacy_exports]
|
||||
mod token;
|
||||
#[legacy_exports]
|
||||
mod comments;
|
||||
#[legacy_exports]
|
||||
mod attr;
|
||||
#[legacy_exports]
|
||||
|
||||
/// Common routines shared by parser mods
|
||||
#[legacy_exports]
|
||||
mod common;
|
||||
|
||||
/// Functions dealing with operator precedence
|
||||
#[legacy_exports]
|
||||
mod prec;
|
||||
|
||||
/// Routines the parser uses to classify AST nodes
|
||||
#[legacy_exports]
|
||||
mod classify;
|
||||
|
||||
/// Reporting obsolete syntax
|
||||
#[legacy_exports]
|
||||
mod obsolete;
|
@ -27,9 +27,8 @@ use ast::{_mod, add, arg, arm, attribute,
|
||||
bind_by_ref, bind_by_implicit_ref, bind_by_value, bind_by_move,
|
||||
bitand, bitor, bitxor, blk, blk_check_mode, box, by_copy,
|
||||
by_move, by_ref, by_val, capture_clause,
|
||||
capture_item, cdir_dir_mod, cdir_src_mod, cdir_view_item,
|
||||
class_immutable, class_mutable,
|
||||
crate, crate_cfg, crate_directive, decl, decl_item, decl_local,
|
||||
capture_item, class_immutable, class_mutable,
|
||||
crate, crate_cfg, decl, decl_item, decl_local,
|
||||
default_blk, deref, div, enum_def, enum_variant_kind, expl, expr,
|
||||
expr_, expr_addr_of, expr_match, expr_again, expr_assert,
|
||||
expr_assign, expr_assign_op, expr_binary, expr_block, expr_break,
|
||||
@ -2966,15 +2965,7 @@ impl Parser {
|
||||
let info_ = if self.token == token::SEMI {
|
||||
self.bump();
|
||||
// This mod is in an external file. Let's go get it!
|
||||
let eval_ctx = @{
|
||||
sess: self.sess,
|
||||
cfg: self.cfg
|
||||
};
|
||||
let prefix = Path(self.sess.cm.span_to_filename(copy self.span));
|
||||
let prefix = prefix.dir_path();
|
||||
let (m, attrs) = eval::eval_src_mod(eval_ctx, &prefix,
|
||||
outer_attrs,
|
||||
id, id_span);
|
||||
let (m, attrs) = self.eval_src_mod(id, outer_attrs, id_span);
|
||||
(id, m, Some(move attrs))
|
||||
} else {
|
||||
self.expect(token::LBRACE);
|
||||
@ -2990,20 +2981,18 @@ impl Parser {
|
||||
// its contents
|
||||
match ::attr::first_attr_value_str_by_name(outer_attrs, ~"merge") {
|
||||
Some(path) => {
|
||||
let eval_ctx = @{
|
||||
sess: self.sess,
|
||||
cfg: self.cfg
|
||||
};
|
||||
let prefix = Path(self.sess.cm.span_to_filename(copy self.span));
|
||||
let prefix = Path(
|
||||
self.sess.cm.span_to_filename(copy self.span));
|
||||
let prefix = prefix.dir_path();
|
||||
let path = Path(path);
|
||||
let (new_mod_item, new_attrs) = eval::eval_src_mod_from_path(
|
||||
eval_ctx, &prefix, &path, ~[], id_span);
|
||||
let (new_mod_item, new_attrs) = self.eval_src_mod_from_path(
|
||||
prefix, path, ~[], id_span);
|
||||
|
||||
let (main_id, main_mod_item, main_attrs) = info_;
|
||||
let main_attrs = main_attrs.get();
|
||||
|
||||
let (main_mod, new_mod) = match (main_mod_item, new_mod_item) {
|
||||
let (main_mod, new_mod) =
|
||||
match (main_mod_item, new_mod_item) {
|
||||
(item_mod(m), item_mod(n)) => (m, n),
|
||||
_ => self.bug(~"parsed mod item should be mod")
|
||||
};
|
||||
@ -3019,6 +3008,51 @@ impl Parser {
|
||||
}
|
||||
}
|
||||
|
||||
fn eval_src_mod(id: ast::ident,
|
||||
outer_attrs: ~[ast::attribute],
|
||||
id_sp: span) -> (ast::item_, ~[ast::attribute]) {
|
||||
let prefix = Path(self.sess.cm.span_to_filename(copy self.span));
|
||||
let prefix = prefix.dir_path();
|
||||
let default_path = self.sess.interner.get(id) + ~".rs";
|
||||
let file_path = match ::attr::first_attr_value_str_by_name(
|
||||
outer_attrs, ~"path") {
|
||||
|
||||
Some(d) => d,
|
||||
None => default_path
|
||||
};
|
||||
|
||||
let file_path = Path(file_path);
|
||||
self.eval_src_mod_from_path(prefix, file_path,
|
||||
outer_attrs, id_sp)
|
||||
}
|
||||
|
||||
fn eval_src_mod_from_path(prefix: Path, path: Path,
|
||||
outer_attrs: ~[ast::attribute],
|
||||
id_sp: span
|
||||
) -> (ast::item_, ~[ast::attribute]) {
|
||||
|
||||
let full_path = if path.is_absolute {
|
||||
path
|
||||
} else {
|
||||
prefix.push_many(path.components)
|
||||
};
|
||||
let p0 =
|
||||
new_sub_parser_from_file(self.sess, self.cfg,
|
||||
&full_path, id_sp);
|
||||
let inner_attrs = p0.parse_inner_attrs_and_next();
|
||||
let mod_attrs = vec::append(outer_attrs, inner_attrs.inner);
|
||||
let first_item_outer_attrs = inner_attrs.next;
|
||||
let m0 = p0.parse_mod_items(token::EOF, first_item_outer_attrs);
|
||||
return (ast::item_mod(m0), mod_attrs);
|
||||
|
||||
fn cdir_path_opt(default: ~str, attrs: ~[ast::attribute]) -> ~str {
|
||||
match ::attr::first_attr_value_str_by_name(attrs, ~"path") {
|
||||
Some(d) => d,
|
||||
None => default
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_item_foreign_fn( +attrs: ~[attribute]) -> @foreign_item {
|
||||
let lo = self.span.lo;
|
||||
let vis = self.parse_visibility();
|
||||
@ -3699,8 +3733,7 @@ impl Parser {
|
||||
let first_item_outer_attrs = crate_attrs.next;
|
||||
let m = self.parse_mod_items(token::EOF, first_item_outer_attrs);
|
||||
return @spanned(lo, self.span.lo,
|
||||
{directives: ~[],
|
||||
module: m,
|
||||
{module: m,
|
||||
attrs: crate_attrs.inner,
|
||||
config: self.cfg});
|
||||
}
|
||||
@ -3711,78 +3744,6 @@ impl Parser {
|
||||
_ => self.fatal(~"expected string literal")
|
||||
}
|
||||
}
|
||||
|
||||
// Logic for parsing crate files (.rc)
|
||||
//
|
||||
// Each crate file is a sequence of directives.
|
||||
//
|
||||
// Each directive imperatively extends its environment with 0 or more
|
||||
// items.
|
||||
fn parse_crate_directive(first_outer_attr: ~[attribute]) ->
|
||||
crate_directive {
|
||||
|
||||
// Collect the next attributes
|
||||
let outer_attrs = vec::append(first_outer_attr,
|
||||
self.parse_outer_attributes());
|
||||
// In a crate file outer attributes are only going to apply to mods
|
||||
let expect_mod = vec::len(outer_attrs) > 0u;
|
||||
|
||||
let lo = self.span.lo;
|
||||
let vis = self.parse_visibility();
|
||||
if expect_mod || self.is_keyword(~"mod") {
|
||||
|
||||
self.expect_keyword(~"mod");
|
||||
|
||||
let id = self.parse_ident();
|
||||
match self.token {
|
||||
// mod x = "foo.rs";
|
||||
token::SEMI => {
|
||||
let mut hi = self.span.hi;
|
||||
self.bump();
|
||||
return spanned(lo, hi, cdir_src_mod(vis, id, outer_attrs));
|
||||
}
|
||||
// mod x = "foo_dir" { ...directives... }
|
||||
token::LBRACE => {
|
||||
self.bump();
|
||||
let inner_attrs = self.parse_inner_attrs_and_next();
|
||||
let mod_attrs = vec::append(outer_attrs, inner_attrs.inner);
|
||||
let next_outer_attr = inner_attrs.next;
|
||||
let cdirs = self.parse_crate_directives(token::RBRACE,
|
||||
next_outer_attr);
|
||||
let mut hi = self.span.hi;
|
||||
self.expect(token::RBRACE);
|
||||
return spanned(lo, hi,
|
||||
cdir_dir_mod(vis, id, cdirs, mod_attrs));
|
||||
}
|
||||
_ => self.unexpected()
|
||||
}
|
||||
} else if self.is_view_item() {
|
||||
let vi = self.parse_view_item(outer_attrs, vis);
|
||||
return spanned(lo, vi.span.hi, cdir_view_item(vi));
|
||||
}
|
||||
return self.fatal(~"expected crate directive");
|
||||
}
|
||||
|
||||
fn parse_crate_directives(term: token::Token,
|
||||
first_outer_attr: ~[attribute]) ->
|
||||
~[@crate_directive] {
|
||||
|
||||
// This is pretty ugly. If we have an outer attribute then we can't
|
||||
// accept seeing the terminator next, so if we do see it then fail the
|
||||
// same way parse_crate_directive would
|
||||
if vec::len(first_outer_attr) > 0u && self.token == term {
|
||||
self.expect_keyword(~"mod");
|
||||
}
|
||||
|
||||
let mut cdirs: ~[@crate_directive] = ~[];
|
||||
let mut first_outer_attr = first_outer_attr;
|
||||
while self.token != term {
|
||||
let cdir = @self.parse_crate_directive(first_outer_attr);
|
||||
cdirs.push(cdir);
|
||||
first_outer_attr = ~[];
|
||||
}
|
||||
return cdirs;
|
||||
}
|
||||
}
|
||||
|
||||
impl restriction : cmp::Eq {
|
||||
|
@ -1,3 +1,5 @@
|
||||
// DIVERT
|
||||
|
||||
#[link(name = "syntax",
|
||||
vers = "0.5",
|
||||
uuid = "9311401b-d6ea-4cd9-a1d9-61f89499c645")];
|
||||
@ -54,8 +56,6 @@ mod parse {
|
||||
export classify;
|
||||
export attr;
|
||||
|
||||
#[legacy_exports]
|
||||
mod eval;
|
||||
#[legacy_exports]
|
||||
mod lexer;
|
||||
#[legacy_exports]
|
||||
|
@ -93,16 +93,6 @@ fn visit_crate<E>(c: crate, e: E, v: vt<E>) {
|
||||
v.visit_mod(c.node.module, c.span, crate_node_id, e, v);
|
||||
}
|
||||
|
||||
fn visit_crate_directive<E>(cd: @crate_directive, e: E, v: vt<E>) {
|
||||
match cd.node {
|
||||
cdir_src_mod(_, _, _) => (),
|
||||
cdir_dir_mod(_, _, cdirs, _) => for cdirs.each |cdir| {
|
||||
visit_crate_directive(*cdir, e, v);
|
||||
},
|
||||
cdir_view_item(vi) => v.visit_view_item(vi, e, v),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_mod<E>(m: _mod, _sp: span, _id: node_id, e: E, v: vt<E>) {
|
||||
for m.view_items.each |vi| { v.visit_view_item(*vi, e, v); }
|
||||
for m.items.each |i| { v.visit_item(*i, e, v); }
|
||||
|
@ -1,4 +1,4 @@
|
||||
// error-pattern: expected `mod`
|
||||
// error-pattern: expected item
|
||||
|
||||
#[attr = "val"];
|
||||
#[attr = "val"] // Unterminated
|
||||
|
@ -1,2 +0,0 @@
|
||||
use g = x::f;
|
||||
export g;
|
@ -1 +0,0 @@
|
||||
fn f() -> ~str { ~"ralph" }
|
@ -1,2 +0,0 @@
|
||||
use g = x::f;
|
||||
export g;
|
@ -1 +0,0 @@
|
||||
fn f() -> ~str { ~"nelson" }
|
@ -1,19 +0,0 @@
|
||||
// xfail-win32 don't understand what's wrong
|
||||
// Test that crates and directory modules can contain code
|
||||
#[legacy_exports];
|
||||
|
||||
#[path = "companionmod-src"]
|
||||
mod a {
|
||||
#[legacy_exports];
|
||||
mod b {
|
||||
#[legacy_exports];
|
||||
#[legacy_exports]
|
||||
mod x;
|
||||
}
|
||||
#[path = "d"]
|
||||
mod c {
|
||||
#[legacy_exports];
|
||||
#[legacy_exports]
|
||||
mod x;
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
// This isn't really xfailed; it's used by the companionmod.rc test
|
||||
// xfail-test
|
||||
|
||||
#[legacy_exports];
|
||||
fn main() {
|
||||
assert a::b::g() == ~"ralph";
|
||||
assert a::c::g() == ~"nelson";
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
// These are attributes of the foo module
|
||||
#[legacy_exports];
|
||||
#[attr1 = "val"];
|
||||
#[attr2 = "val"];
|
||||
|
||||
// Attributes of the following function
|
||||
#[attr1 = "val"]
|
||||
#[attr2 = "val"]
|
||||
fn main() { }
|
@ -1,13 +0,0 @@
|
||||
#[name = "crate-attributes"];
|
||||
#[vers = "1.0"];
|
||||
|
||||
#[attr1]
|
||||
#[path = "crate-attributes-src"]
|
||||
mod m {
|
||||
#[legacy_exports];
|
||||
#[attr_inner];
|
||||
|
||||
#[attr2]
|
||||
#[legacy_exports]
|
||||
mod foo;
|
||||
}
|
@ -1 +0,0 @@
|
||||
type T = f32;
|
@ -1 +0,0 @@
|
||||
type T = f64;
|
@ -1 +0,0 @@
|
||||
type T = float;
|
@ -1,3 +0,0 @@
|
||||
fn plus(x: T, y: T) -> T {
|
||||
x + y
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
#[path = "module-polymorphism-files"]
|
||||
mod my_float {
|
||||
#[legacy_exports];
|
||||
|
||||
// The type of the float
|
||||
use inst::T;
|
||||
|
||||
// Define T as float
|
||||
#[path = "inst_float.rs"]
|
||||
#[legacy_exports]
|
||||
mod inst;
|
||||
|
||||
// Add in the implementation from a single source file
|
||||
#[path = "template.rs"]
|
||||
#[legacy_exports]
|
||||
mod template;
|
||||
|
||||
}
|
||||
|
||||
#[path = "module-polymorphism-files"]
|
||||
mod my_f64 {
|
||||
#[legacy_exports];
|
||||
|
||||
use inst::T;
|
||||
|
||||
// Define T as f64
|
||||
#[path = "inst_f64.rs"]
|
||||
#[legacy_exports]
|
||||
mod inst;
|
||||
|
||||
// Use the implementation for the same source file!
|
||||
#[path = "template.rs"]
|
||||
#[legacy_exports]
|
||||
mod template;
|
||||
|
||||
}
|
||||
|
||||
#[path = "module-polymorphism-files"]
|
||||
mod my_f32 {
|
||||
#[legacy_exports];
|
||||
use inst::T;
|
||||
|
||||
#[path = "inst_f32.rs"]
|
||||
#[legacy_exports]
|
||||
mod inst;
|
||||
|
||||
#[path = "template.rs"]
|
||||
#[legacy_exports]
|
||||
mod template;
|
||||
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
// This isn't really xfailed; it's used by the
|
||||
// module-polymorphism.rc test
|
||||
// xfail-test
|
||||
|
||||
fn main() {
|
||||
// All of these functions are defined by a single module
|
||||
// source file but instantiated for different types
|
||||
assert my_float::template::plus(1.0f, 2.0f) == 3.0f;
|
||||
assert my_f64::template::plus(1.0f64, 2.0f64) == 3.0f64;
|
||||
assert my_f32::template::plus(1.0f32, 2.0f32) == 3.0f32;
|
||||
}
|
@ -1 +0,0 @@
|
||||
type T = f32;
|
@ -1 +0,0 @@
|
||||
type T = f64;
|
@ -1 +0,0 @@
|
||||
type T = float;
|
@ -1,3 +0,0 @@
|
||||
fn plus(x: T, y: T) -> T {
|
||||
x + y
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
#[path = "module-polymorphism2-files"]
|
||||
mod mystd {
|
||||
#[legacy_exports];
|
||||
|
||||
#[path = "float-template"]
|
||||
mod float {
|
||||
#[legacy_exports];
|
||||
// The type of the float
|
||||
use inst::T;
|
||||
|
||||
// Unfortunate
|
||||
use template::*;
|
||||
export plus;
|
||||
|
||||
// Define T as float
|
||||
#[path = "inst_float.rs"]
|
||||
#[legacy_exports]
|
||||
mod inst;
|
||||
|
||||
// Add in the implementation from a single source file
|
||||
#[path = "template.rs"]
|
||||
#[legacy_exports]
|
||||
mod template;
|
||||
}
|
||||
|
||||
|
||||
#[path = "float-template"]
|
||||
mod f64 {
|
||||
#[legacy_exports];
|
||||
|
||||
use inst::T;
|
||||
|
||||
// Unfortunate
|
||||
use template::*;
|
||||
export plus;
|
||||
|
||||
// Define T as f64
|
||||
#[path = "inst_f64.rs"]
|
||||
#[legacy_exports]
|
||||
mod inst;
|
||||
|
||||
// Use the implementation for the same source file!
|
||||
#[path = "template.rs"]
|
||||
#[legacy_exports]
|
||||
mod template;
|
||||
|
||||
}
|
||||
|
||||
#[path = "float-template"]
|
||||
mod f32 {
|
||||
#[legacy_exports];
|
||||
use inst::T;
|
||||
|
||||
// Unfortunate
|
||||
use template::*;
|
||||
export plus;
|
||||
|
||||
#[path = "inst_f32.rs"]
|
||||
#[legacy_exports]
|
||||
mod inst;
|
||||
|
||||
#[path = "template.rs"]
|
||||
#[legacy_exports]
|
||||
mod template;
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
// This isn't really xfailed; it's used by the
|
||||
// module-polymorphism.rc test
|
||||
// xfail-test
|
||||
|
||||
fn main() {
|
||||
// All of these functions are defined by a single module
|
||||
// source file but instantiated for different types
|
||||
assert mystd::float::plus(1.0f, 2.0f) == 3.0f;
|
||||
assert mystd::f64::plus(1.0f64, 2.0f64) == 3.0f64;
|
||||
assert mystd::f32::plus(1.0f32, 2.0f32) == 3.0f32;
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
fn plus(x: T, y: T) -> T {
|
||||
x + y
|
||||
}
|
@ -1 +0,0 @@
|
||||
type T = f32;
|
@ -1 +0,0 @@
|
||||
type T = f64;
|
@ -1 +0,0 @@
|
||||
type T = float;
|
@ -1,41 +0,0 @@
|
||||
// Use one template module to specify in a single file the implementation
|
||||
// of functions for multiple types
|
||||
|
||||
#[path = "module-polymorphism3-files"]
|
||||
mod mystd {
|
||||
#[legacy_exports];
|
||||
|
||||
// The template is specified in float-template.rs
|
||||
#[path = "float-template"]
|
||||
mod float {
|
||||
#[legacy_exports];
|
||||
// The type of the float
|
||||
use inst::T;
|
||||
|
||||
// Define T as appropriate for platform
|
||||
#[path = "inst_float.rs"]
|
||||
mod inst;
|
||||
}
|
||||
|
||||
// Use the same template
|
||||
#[path = "float-template"]
|
||||
mod f64 {
|
||||
#[legacy_exports];
|
||||
|
||||
use inst::T;
|
||||
|
||||
// Define T as f64
|
||||
#[path = "inst_f64.rs"]
|
||||
mod inst;
|
||||
}
|
||||
|
||||
#[path = "float-template"]
|
||||
mod f32 {
|
||||
#[legacy_exports];
|
||||
use inst::T;
|
||||
|
||||
#[path = "inst_f32.rs"]
|
||||
mod inst;
|
||||
}
|
||||
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
// This isn't really xfailed; it's used by the
|
||||
// module-polymorphism.rc test
|
||||
// xfail-test
|
||||
|
||||
fn main() {
|
||||
// All of these functions are defined by a single module
|
||||
// source file but instantiated for different types
|
||||
assert mystd::float::plus(1.0f, 2.0f) == 3.0f;
|
||||
assert mystd::f64::plus(1.0f64, 2.0f64) == 3.0f64;
|
||||
assert mystd::f32::plus(1.0f32, 2.0f32) == 3.0f32;
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
type T = cat;
|
||||
|
||||
enum cat {
|
||||
howlycat,
|
||||
meowlycat
|
||||
}
|
||||
|
||||
fn animal() -> ~str { ~"cat" }
|
||||
fn talk(c: cat) -> ~str {
|
||||
match c {
|
||||
howlycat => { ~"howl" }
|
||||
meowlycat => { ~"meow" }
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
type T = dog;
|
||||
|
||||
enum dog {
|
||||
dog
|
||||
}
|
||||
|
||||
fn animal() -> ~str { ~"dog" }
|
||||
fn talk(_d: dog) -> ~str { ~"woof" }
|
||||
|
@ -1,13 +0,0 @@
|
||||
trait says {
|
||||
fn says() -> ~str;
|
||||
}
|
||||
|
||||
impl T: says {
|
||||
|
||||
// 'animal' and 'talk' functions are implemented by the module
|
||||
// instantiating the talky trait. They are 'abstract'
|
||||
fn says() -> ~str {
|
||||
animal() + ~" says '" + talk(self) + ~"'"
|
||||
}
|
||||
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
|
||||
#[path = "module-polymorphism4-files"]
|
||||
mod cat {
|
||||
#[legacy_exports];
|
||||
|
||||
use inst::*;
|
||||
|
||||
#[path = "cat.rs"]
|
||||
#[legacy_exports]
|
||||
mod inst;
|
||||
|
||||
#[path = "trait_.rs"]
|
||||
#[legacy_exports]
|
||||
mod trait_;
|
||||
|
||||
}
|
||||
|
||||
#[path = "module-polymorphism4-files"]
|
||||
mod dog {
|
||||
#[legacy_exports];
|
||||
|
||||
use inst::*;
|
||||
|
||||
#[path = "dog.rs"]
|
||||
#[legacy_exports]
|
||||
mod inst;
|
||||
|
||||
#[path = "trait_.rs"]
|
||||
#[legacy_exports]
|
||||
mod trait_;
|
||||
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
// This isn't really xfailed; it's used by the
|
||||
// module-polymorphism.rc test
|
||||
// xfail-test
|
||||
|
||||
fn main() {
|
||||
let cat1 = cat::inst::meowlycat;
|
||||
let cat2 = cat::inst::howlycat;
|
||||
let dog = dog::inst::dog;
|
||||
assert cat1.says() == ~"cat says 'meow'";
|
||||
assert cat2.says() == ~"cat says 'howl'";
|
||||
assert dog.says() == ~"dog says 'woof'";
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
|
||||
|
||||
fn other() { debug!("yes"); }
|
@ -1,3 +0,0 @@
|
||||
|
||||
|
||||
fn main() { debug!("hello, multi-file world."); bar::other(); }
|
@ -1,11 +0,0 @@
|
||||
#[path = "multi-src"]
|
||||
mod multi {
|
||||
#[legacy_exports];
|
||||
// implicitly #[path = "foo.rs"]
|
||||
#[legacy_exports]
|
||||
mod foo;
|
||||
|
||||
#[path = "bar.rs"]
|
||||
#[legacy_exports]
|
||||
mod bar;
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
mod trait_mix {
|
||||
#[legacy_exports];
|
||||
#[path = "trait-mix.rs"]
|
||||
#[legacy_exports]
|
||||
mod trait_mix;
|
||||
#[legacy_exports]
|
||||
mod u_trait_mix;
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
|
||||
impl f32: u_trait_mix::num {
|
||||
pure fn add(&&other: f32) -> f32 { return self + other; }
|
||||
pure fn sub(&&other: f32) -> f32 { return self - other; }
|
||||
pure fn mul(&&other: f32) -> f32 { return self * other; }
|
||||
pure fn div(&&other: f32) -> f32 { return self / other; }
|
||||
pure fn modulo(&&other: f32) -> f32 { return self % other; }
|
||||
pure fn neg() -> f32 { return -self; }
|
||||
|
||||
pure fn to_int() -> int { return self as int; }
|
||||
static pure fn from_int(n: int) -> f32 { return n as f32; }
|
||||
}
|
||||
|
||||
/*
|
||||
It seems that this will fail if I try using it from another crate.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
// ICEs if I put this in num -- ???
|
||||
trait from_int {
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
fn main() {}
|
@ -1,13 +0,0 @@
|
||||
trait num {
|
||||
// FIXME: Trait composition. (#2616)
|
||||
pure fn add(&&other: self) -> self;
|
||||
pure fn sub(&&other: self) -> self;
|
||||
pure fn mul(&&other: self) -> self;
|
||||
pure fn div(&&other: self) -> self;
|
||||
pure fn modulo(&&other: self) -> self;
|
||||
pure fn neg() -> self;
|
||||
|
||||
pure fn to_int() -> int;
|
||||
static pure fn from_int(n: int) -> self;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user