I created a new branch rust-llvm-2013-09-11 in my llvm repo to mark this momentous occasion
* `Clone` and `DeepClone`, to perform (deep) copies.
* `IterBytes`, to iterate over the bytes in a data type.
* `Rand`, to create a random instance of a data type.
-* `Zero`, to create an zero (or empty) instance of a data type.
+* `Default`, to create an empty instance of a data type.
+* `Zero`, to create an zero instance of a numeric data type.
* `ToStr`, to convert to a string. For a type with this instance,
`obj.to_str()` has similar output as `fmt!("%?", obj)`, but it differs in that
each constituent field of the type must also implement `ToStr` and will have
### For expressions
~~~~~~~~{.ebnf .gram}
-for_expr : "for" expr [ '|' ident_list '|' ] ? '{' block '}' ;
+for_expr : "for" pat "in" expr '{' block '}' ;
~~~~~~~~
-A _for expression_ is similar to a [`do` expression](#do-expressions),
-in that it provides a special block-form of lambda expression,
-suited to passing the `block` function to a higher-order function implementing a loop.
-
-In contrast to a `do` expression, a `for` expression is designed to work
-with methods such as `each` and `times`, that require the body block to
-return a boolean. The `for` expression accommodates this by implicitly
-returning `true` at the end of each block, unless a `break` expression
-is evaluated.
-
-In addition, [`break`](#break-expressions) and [`loop`](#loop-expressions) expressions
-are rewritten inside `for` expressions in the same way that `return` expressions are,
-with a combination of local flag variables,
-and early boolean-valued returns from the `block` function,
-such that the meaning of `break` and `loop` is preserved in a primitive loop
-when rewritten as a `for` loop controlled by a higher order function.
+A `for` expression is a syntactic construct for looping
+over elements provided by an implementation of
+`std::iterator::Iterator`.
An example of a for loop over the contents of a vector:
rustpkg will install libraries for bar to `foo/lib/x86_64-apple-darwin/`.
The libraries will have names of the form `foo/lib/x86_64-apple-darwin/libbar-[hash].dylib`,
where [hash] is a hash of the package ID.
-* 'bin/': `rustpkg install` installs executable binaries into a target-specific subdirectory of this directory.
+* 'bin/': `rustpkg install` installs executable binaries into this directory.
- For example, on a 64-bit machine running Mac OS X,
- if `foo` is a workspace, containing the package `bar`,
- rustpkg will install executables for `bar` to
- `foo/bin/x86_64-apple-darwin/`.
- The executables will have names of the form `foo/bin/x86_64-apple-darwin/bar`.
+ For example, rustpkg will install executables for `bar` to
+ `foo/bin`.
+ The executables will have names of the form `foo/bin/bar`.
* 'build/': `rustpkg build` stores temporary build artifacts in a target-specific subdirectory of this directory.
For example, on a 64-bit machine running Mac OS X,
Thus, `github.com/mozilla/rust#5c4cd30f80` is also a valid package ID,
since git can deduce that 5c4cd30f80 refers to a revision of the desired repository.
+A package identifier can name a subdirectory of another package.
+For example, if `foo` is a workspace, and `foo/src/bar/lib.rs` exists,
+as well as `foo/src/bar/extras/baz/lib.rs`,
+then both `bar` and `bar/extras/baz` are valid package identifiers
+in the workspace `foo`.
+
## Source files
rustpkg searches for four different fixed filenames in order to determine the crates to build:
## install
-`rustpkg install foo` builds the libraries and/or executables that are targets for `foo`,
-and then installs them either into `foo`'s `lib` and `bin` directories,
-or into the `lib` and `bin` subdirectories of the first entry in `RUST_PATH`.
+`rustpkg install foo` builds the libraries and/or executables that are targets for `foo`.
+If `RUST_PATH` is declared as an environment variable, then rustpkg installs the
+libraries and executables into the `lib` and `bin` subdirectories
+of the first entry in `RUST_PATH`.
+Otherwise, it installs them into `foo`'s `lib` and `bin` directories.
## test
[a, b] => {
// 5. Try parsing both fields as ints.
- match (int::from_str(a), int::from_str(b)) {
+ match (from_str::<int>(a), from_str::<int>(b)) {
// 6. If parsing succeeded for both, push both.
(Some(a), Some(b)) => pairs.push((a,b)),
_or_ the sentinel `None`, to indicate the absence of a `T` value.
For simple APIs, it may be sufficient to encode errors as `Option<T>`,
returning `Some(T)` on success and `None` on error.
-In the example program, the call to `int::from_str` returns `Option<int>`
+In the example program, the call to `from_str::<int>` returns `Option<int>`
with the understanding that "all parse errors" result in `None`.
The resulting `Option<int>` values are matched against the pattern `(Some(a), Some(b))`
in steps 5 and 6 in the example program,
The type `std::result::Result<T,E>` is another simple `enum` type with two forms, `Ok(T)` and `Err(E)`.
The `Result` type is not substantially different from the `Option` type in terms of its ergonomics.
Its main advantage is that the error constructor `Err(E)` can convey _more detail_ about the error.
-For example, the `int::from_str` API could be reformed
+For example, the `from_str` API could be reformed
to return a `Result` carrying an informative description of a parse error,
like this:
BadChar(char)
}
-fn int::from_str(&str) -> Result<int,IntParseErr> {
+fn from_str(&str) -> Result<int,IntParseErr> {
// ...
}
~~~~
let line = fi.read_line();
let fields = line.word_iter().to_owned_vec();
match fields {
- [a, b] => pairs.push((int::from_str(a).unwrap(),
- int::from_str(b).unwrap())),
+ [a, b] => pairs.push((from_str::<int>(a).unwrap(),
+ from_str::<int>(b).unwrap())),
// Explicitly fail on malformed lines.
_ => fail!()
let line = fi.read_line();
let fields = line.word_iter().to_owned_vec();
match fields {
- [a, b] => pairs.push((int::from_str(a).unwrap(),
- int::from_str(b).unwrap())),
+ [a, b] => pairs.push((from_str::<int>(a).unwrap(),
+ from_str::<int>(b).unwrap())),
// On malformed lines, call the condition handler and
// push whatever the condition handler returns.
let line = fi.read_line();
let fields = line.word_iter().to_owned_vec();
match fields {
- [a, b] => pairs.push((int::from_str(a).unwrap(),
- int::from_str(b).unwrap())),
+ [a, b] => pairs.push((from_str::<int>(a).unwrap(),
+ from_str::<int>(b).unwrap())),
_ => pairs.push(malformed_line::cond.raise(line.clone()))
}
}
let line = fi.read_line();
let fields = line.word_iter().to_owned_vec();
match fields {
- [a, b] => pairs.push((int::from_str(a).unwrap(),
- int::from_str(b).unwrap())),
+ [a, b] => pairs.push((from_str::<int>(a).unwrap(),
+ from_str::<int>(b).unwrap())),
// On malformed lines, call the condition handler and
// either ignore the line (if the handler returns `None`)
let line = fi.read_line();
let fields = line.word_iter().to_owned_vec();
match fields {
- [a, b] => pairs.push((int::from_str(a).unwrap(),
- int::from_str(b).unwrap())),
+ [a, b] => pairs.push((from_str::<int>(a).unwrap(),
+ from_str::<int>(b).unwrap())),
// On malformed lines, call the condition handler and
// take action appropriate to the enum value returned.
// Parse an int; if parsing fails, call the condition handler and
// return whatever it returns.
fn parse_int(x: &str) -> int {
- match int::from_str(x) {
+ match from_str::<int>(x) {
Some(v) => v,
None => malformed_int::cond.raise(x.to_owned())
}
so long as the `raise` occurs within a callee (of any depth) of the logic protected by the `trap` call,
it will invoke the handler.
- - This variant insulates callers from a design choice in the `int` library:
- the `int::from_str` function was designed to return an `Option<int>`,
+ - This variant insulates callers from a design choice in the library:
+ the `from_str` function was designed to return an `Option<int>`,
but this program insulates callers from that choice,
routing all `None` values that arise from parsing integers in this file into the condition.
or else risk introducing silent and very difficult-to-debug errors due to control resuming in a corrupted heap after a caught exception.
These errors are frequently memory-safety errors, which Rust strives to eliminate,
and so Rust unwinding is unrecoverable within a single task:
-once unwinding starts, the entire local heap of a task is destroyed and the task is terminated.
\ No newline at end of file
+once unwinding starts, the entire local heap of a task is destroyed and the task is terminated.
The full list of derivable traits is `Eq`, `TotalEq`, `Ord`,
`TotalOrd`, `Encodable` `Decodable`, `Clone`, `DeepClone`,
-`IterBytes`, `Rand`, `Zero`, and `ToStr`.
+`IterBytes`, `Rand`, `Default`, `Zero`, and `ToStr`.
# Crates and the module system
rt/rust_rng.cpp \
rt/rust_upcall.cpp \
rt/rust_uv.cpp \
- rt/rust_crate_map.cpp \
rt/isaac/randport.cpp \
rt/miniz.cpp \
rt/memory_region.cpp \
let filename = path.filename();
let p = path.pop();
let dir = p.filename();
- fmt!("%s/%s", dir.unwrap_or_default(""), filename.unwrap_or_default(""))
+ fmt!("%s/%s", dir.unwrap_or(""), filename.unwrap_or(""))
}
test::DynTestName(fmt!("[%s] %s",
-rust-mode: A major emacs mode for editing Rust source code
-==========================================================
+`rust-mode`: A major Emacs mode for editing Rust source code
+============================================================
-`rust-mode` makes editing [Rust](http://rust-lang.org) code with emacs
+`rust-mode` makes editing [Rust](http://rust-lang.org) code with Emacs
enjoyable.
### Manual Installation
-To install manually, check out this repository and add this to your .emacs
-file:
+To install manually, check out this repository and add this to your
+`.emacs` file:
- (add-to-list 'load-path "/path/to/rust-mode/")
- (require 'rust-mode)
+```lisp
+(add-to-list 'load-path "/path/to/rust-mode/")
+(require 'rust-mode)
+```
-Rust mode will automatically be associated with .rs files. To enable it
-explicitly, do `M-x rust-mode`.
+`rust-mode` will automatically be associated with `.rs` files. To enable it
+explicitly, do <kbd>M-x rust-mode</kbd>.
-### package.el installation via Marmalade or MELPA
+### `package.el` installation via Marmalade or MELPA
It can be more convenient to use Emacs's package manager to handle
installation for you if you use many elisp libraries. If you have
-package.el but haven't added Marmalade or MELPA, the community package source,
-yet, add this to ~/.emacs.d/init.el:
+`package.el` but haven't added Marmalade or MELPA, the community
+package source, yet, add this to `~/.emacs.d/init.el`:
Using Marmalade:
* <kbd>M-x package-refresh-contents</kbd>
If you use a version of Emacs prior to 24 that doesn't include
-package.el, you can get it from http://bit.ly/pkg-el23.
+`package.el`, you can get it from [here](http://bit.ly/pkg-el23).
-If you have an older ELPA package.el installed from tromey.com, you
+If you have an older ELPA `package.el` installed from tromey.com, you
should upgrade in order to support installation from multiple sources.
The ELPA archive is deprecated and no longer accepting new packages,
so the version there (1.7.1) is very outdated.
-#### Install rust-mode
+#### Install `rust-mode`
-From there you can install rust-mode or any other modes by choosing
-them from a list:
+One you have `package.el`, you can install `rust-mode` or any other
+modes by choosing them from a list:
* <kbd>M-x package-list-packages</kbd>
-Now, to install packages, move your cursor to them and press i. This
-will mark the packages for installation. When you're done with
-marking, press x, and ELPA will install the packages for you (under
-~/.emacs.d/elpa/).
+Now, to install packages, move your cursor to them and press
+<kbd>i</kbd>. This will mark the packages for installation. When
+you're done with marking, press <kbd>x</kbd>, and ELPA will install
+the packages for you (under `~/.emacs.d/elpa/`).
-* or using <kbd>M-x package-install rust-mode
+* or using <kbd>M-x package-install rust-mode</kbd>
### Tests via ERT
-The file `rust-mode-tests.el` contains tests that can be run via ERT. You can
-use `run_rust_emacs_tests.sh` to run them in batch mode, if emacs is somewhere
-in your `$PATH`.
+The file `rust-mode-tests.el` contains tests that can be run via
+[ERT](http://www.gnu.org/software/emacs/manual/html_node/ert/index.html).
+You can use `run_rust_emacs_tests.sh` to run them in batch mode, if
+Emacs is somewhere in your `$PATH`.
### Known bugs
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
})
}
+/// An extension of `pipes::stream` that provides synchronous message sending.
+pub struct SyncChan<T> { priv duplex_stream: DuplexStream<T, ()> }
+/// An extension of `pipes::stream` that acknowledges each message received.
+pub struct SyncPort<T> { priv duplex_stream: DuplexStream<(), T> }
+
+impl<T: Send> GenericChan<T> for SyncChan<T> {
+ fn send(&self, val: T) {
+ assert!(self.try_send(val), "SyncChan.send: receiving port closed");
+ }
+}
+
+impl<T: Send> GenericSmartChan<T> for SyncChan<T> {
+ /// Sends a message, or report if the receiver has closed the connection before receiving.
+ fn try_send(&self, val: T) -> bool {
+ self.duplex_stream.try_send(val) && self.duplex_stream.try_recv().is_some()
+ }
+}
+
+impl<T: Send> GenericPort<T> for SyncPort<T> {
+ fn recv(&self) -> T {
+ self.try_recv().expect("SyncPort.recv: sending channel closed")
+ }
+
+ fn try_recv(&self) -> Option<T> {
+ do self.duplex_stream.try_recv().map_move |val| {
+ self.duplex_stream.try_send(());
+ val
+ }
+ }
+}
+
+impl<T: Send> Peekable<T> for SyncPort<T> {
+ fn peek(&self) -> bool {
+ self.duplex_stream.peek()
+ }
+}
+
+/// Creates a stream whose channel, upon sending a message, blocks until the message is received.
+pub fn rendezvous<T: Send>() -> (SyncPort<T>, SyncChan<T>) {
+ let (chan_stream, port_stream) = DuplexStream();
+ (SyncPort { duplex_stream: port_stream }, SyncChan { duplex_stream: chan_stream })
+}
+
#[cfg(test)]
mod test {
- use comm::DuplexStream;
+ use comm::{DuplexStream, rendezvous};
+ use std::rt::test::run_in_newsched_task;
+ use std::task::spawn_unlinked;
+
#[test]
pub fn DuplexStream1() {
assert!(left.recv() == 123);
assert!(right.recv() == ~"abc");
}
+
+ #[test]
+ pub fn basic_rendezvous_test() {
+ let (port, chan) = rendezvous();
+
+ do spawn {
+ chan.send("abc");
+ }
+
+ assert!(port.recv() == "abc");
+ }
+
+ #[test]
+ fn recv_a_lot() {
+ // Rendezvous streams should be able to handle any number of messages being sent
+ do run_in_newsched_task {
+ let (port, chan) = rendezvous();
+ do spawn {
+ do 1000000.times { chan.send(()) }
+ }
+ do 1000000.times { port.recv() }
+ }
+ }
+
+ #[test]
+ fn send_and_fail_and_try_recv() {
+ let (port, chan) = rendezvous();
+ do spawn_unlinked {
+ chan.duplex_stream.send(()); // Can't access this field outside this module
+ fail!()
+ }
+ port.recv()
+ }
+
+ #[test]
+ fn try_send_and_recv_then_fail_before_ack() {
+ let (port, chan) = rendezvous();
+ do spawn_unlinked {
+ port.duplex_stream.recv();
+ fail!()
+ }
+ chan.try_send(());
+ }
+
+ #[test]
+ #[should_fail]
+ fn send_and_recv_then_fail_before_ack() {
+ let (port, chan) = rendezvous();
+ do spawn_unlinked {
+ port.duplex_stream.recv();
+ fail!()
+ }
+ chan.send(());
+ }
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::uint;
+use std::iter::range_step;
use cryptoutil::{write_u32_le, read_u32v_le, FixedBuffer, FixedBuffer64, StandardPadding};
use digest::Digest;
read_u32v_le(data, input);
// round 1
- do uint::range_step(0, 16, 4) |i| {
+ for i in range_step(0u, 16, 4) {
a = op_f(a, b, c, d, data[i] + C1[i], 7);
d = op_f(d, a, b, c, data[i + 1] + C1[i + 1], 12);
c = op_f(c, d, a, b, data[i + 2] + C1[i + 2], 17);
b = op_f(b, c, d, a, data[i + 3] + C1[i + 3], 22);
- true
- };
+ }
// round 2
let mut t = 1;
- do uint::range_step(0, 16, 4) |i| {
+ for i in range_step(0u, 16, 4) {
a = op_g(a, b, c, d, data[t & 0x0f] + C2[i], 5);
d = op_g(d, a, b, c, data[(t + 5) & 0x0f] + C2[i + 1], 9);
c = op_g(c, d, a, b, data[(t + 10) & 0x0f] + C2[i + 2], 14);
b = op_g(b, c, d, a, data[(t + 15) & 0x0f] + C2[i + 3], 20);
t += 20;
- true
- };
+ }
// round 3
t = 5;
- do uint::range_step(0, 16, 4) |i| {
+ for i in range_step(0u, 16, 4) {
a = op_h(a, b, c, d, data[t & 0x0f] + C3[i], 4);
d = op_h(d, a, b, c, data[(t + 3) & 0x0f] + C3[i + 1], 11);
c = op_h(c, d, a, b, data[(t + 6) & 0x0f] + C3[i + 2], 16);
b = op_h(b, c, d, a, data[(t + 9) & 0x0f] + C3[i + 3], 23);
t += 12;
- true
- };
+ }
// round 4
t = 0;
- do uint::range_step(0, 16, 4) |i| {
+ for i in range_step(0u, 16, 4) {
a = op_i(a, b, c, d, data[t & 0x0f] + C4[i], 6);
d = op_i(d, a, b, c, data[(t + 7) & 0x0f] + C4[i + 1], 10);
c = op_i(c, d, a, b, data[(t + 14) & 0x0f] + C4[i + 2], 15);
b = op_i(b, c, d, a, data[(t + 21) & 0x0f] + C4[i + 3], 21);
t += 28;
- true
- };
+ }
self.s0 += a;
self.s1 += b;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::uint;
+use std::iter::range_step;
use cryptoutil::{write_u64_be, write_u32_be, read_u64v_be, read_u32v_be, add_bytes_to_bits,
add_bytes_to_bits_tuple, FixedBuffer, FixedBuffer128, FixedBuffer64, StandardPadding};
// Putting the message schedule inside the same loop as the round calculations allows for
// the compiler to generate better code.
- do uint::range_step(0, 64, 8) |t| {
+ for t in range_step(0u, 64, 8) {
schedule_round!(t + 16);
schedule_round!(t + 17);
schedule_round!(t + 18);
sha2_round!(d, e, f, g, h, a, b, c, K64, t + 5);
sha2_round!(c, d, e, f, g, h, a, b, K64, t + 6);
sha2_round!(b, c, d, e, f, g, h, a, K64, t + 7);
- true
- };
+ }
- do uint::range_step(64, 80, 8) |t| {
+ for t in range_step(64u, 80, 8) {
sha2_round!(a, b, c, d, e, f, g, h, K64, t);
sha2_round!(h, a, b, c, d, e, f, g, K64, t + 1);
sha2_round!(g, h, a, b, c, d, e, f, K64, t + 2);
sha2_round!(d, e, f, g, h, a, b, c, K64, t + 5);
sha2_round!(c, d, e, f, g, h, a, b, K64, t + 6);
sha2_round!(b, c, d, e, f, g, h, a, K64, t + 7);
- true
- };
+ }
self.H0 += a;
self.H1 += b;
// Putting the message schedule inside the same loop as the round calculations allows for
// the compiler to generate better code.
- do uint::range_step(0, 48, 8) |t| {
+ for t in range_step(0u, 48, 8) {
schedule_round!(t + 16);
schedule_round!(t + 17);
schedule_round!(t + 18);
sha2_round!(d, e, f, g, h, a, b, c, K32, t + 5);
sha2_round!(c, d, e, f, g, h, a, b, K32, t + 6);
sha2_round!(b, c, d, e, f, g, h, a, K32, t + 7);
- true
- };
+ }
- do uint::range_step(48, 64, 8) |t| {
+ for t in range_step(48u, 64, 8) {
sha2_round!(a, b, c, d, e, f, g, h, K32, t);
sha2_round!(h, a, b, c, d, e, f, g, K32, t + 1);
sha2_round!(g, h, a, b, c, d, e, f, K32, t + 2);
sha2_round!(d, e, f, g, h, a, b, c, K32, t + 5);
sha2_round!(c, d, e, f, g, h, a, b, K32, t + 6);
sha2_round!(b, c, d, e, f, g, h, a, K32, t + 7);
- true
- };
+ }
self.H0 += a;
self.H1 += b;
use super::{FileInput, make_path_option_vec, input_vec, input_vec_state};
- use std::io;
+ use std::rt::io;
+ use std::rt::io::Writer;
+ use std::rt::io::file;
use std::uint;
use std::vec;
fn make_file(path : &Path, contents: &[~str]) {
- let file = io::file_writer(path, [io::Create, io::Truncate]).unwrap();
+ let mut file = file::open(path, io::CreateOrTruncate, io::Write).unwrap();
for str in contents.iter() {
- file.write_str(*str);
- file.write_char('\n');
+ file.write(str.as_bytes());
+ file.write(['\n' as u8]);
}
}
#[test]
+ #[ignore(cfg(windows))] // FIXME(#8810): rt::io::file and windows don't agree
fn test_make_path_option_vec() {
let strs = [~"some/path",
~"some/other/path"];
}
#[test]
+ #[ignore(cfg(windows))] // FIXME(#8810): rt::io::file and windows don't agree
fn test_fileinput_read_byte() {
let filenames = make_path_option_vec(vec::from_fn(
3,
}
#[test]
+ #[ignore(cfg(windows))] // FIXME(#8810): rt::io::file and windows don't agree
fn test_fileinput_read() {
let filenames = make_path_option_vec(vec::from_fn(
3,
}
#[test]
+ #[ignore(cfg(windows))] // FIXME(#8810): rt::io::file and windows don't agree
fn test_input_vec() {
let mut all_lines = ~[];
let filenames = make_path_option_vec(vec::from_fn(
}
#[test]
+ #[ignore(cfg(windows))] // FIXME(#8810): rt::io::file and windows don't agree
fn test_input_vec_state() {
let filenames = make_path_option_vec(vec::from_fn(
3,
do input_vec_state(filenames) |line, state| {
let nums: ~[&str] = line.split_iter(' ').collect();
- let file_num = uint::from_str(nums[0]).unwrap();
- let line_num = uint::from_str(nums[1]).unwrap();
+ let file_num = from_str::<uint>(nums[0]).unwrap();
+ let line_num = from_str::<uint>(nums[1]).unwrap();
assert_eq!(line_num, state.line_num_file);
assert_eq!(file_num * 3 + line_num, state.line_num);
true
}
#[test]
+ #[ignore(cfg(windows))] // FIXME(#8810): rt::io::file and windows don't agree
fn test_empty_files() {
let filenames = make_path_option_vec(vec::from_fn(
3,
}
#[test]
+ #[ignore(cfg(windows))] // FIXME(#8810): rt::io::file and windows don't agree
fn test_no_trailing_newline() {
let f1 =
Some(Path("tmp/lib-fileinput-test-no-trailing-newline-1.tmp"));
let f2 =
Some(Path("tmp/lib-fileinput-test-no-trailing-newline-2.tmp"));
- let wr = io::file_writer(f1.get_ref(),
- [io::Create, io::Truncate]).unwrap();
- wr.write_str("1\n2");
- let wr = io::file_writer(f2.get_ref(),
- [io::Create, io::Truncate]).unwrap();
- wr.write_str("3\n4");
+ {
+ let mut wr = file::open(f1.get_ref(), io::CreateOrTruncate,
+ io::Write).unwrap();
+ wr.write("1\n2".as_bytes());
+ let mut wr = file::open(f2.get_ref(), io::CreateOrTruncate,
+ io::Write).unwrap();
+ wr.write("3\n4".as_bytes());
+ }
let mut lines = ~[];
do input_vec(~[f1, f2]) |line| {
#[test]
+ #[ignore(cfg(windows))] // FIXME(#8810): rt::io::file and windows don't agree
fn test_next_file() {
let filenames = make_path_option_vec(vec::from_fn(
3,
#[test]
#[should_fail]
+ #[ignore(cfg(windows))] // FIXME(#8810): rt::io::file and windows don't agree
fn test_input_vec_missing_file() {
do input_vec(make_path_option_vec([~"this/file/doesnt/exist"], true)) |line| {
println(line);
/**
* A compiled Unix shell style pattern.
*/
-#[deriving(Clone, Eq, TotalEq, Ord, TotalOrd, IterBytes, Zero)]
+#[cfg(stage0)]
+#[deriving(Clone, Eq, TotalEq, Ord, TotalOrd, IterBytes)]
+pub struct Pattern {
+ priv tokens: ~[PatternToken]
+}
+
+/**
+ * A compiled Unix shell style pattern.
+ */
+#[cfg(not(stage0))]
+#[deriving(Clone, Eq, TotalEq, Ord, TotalOrd, IterBytes, Default)]
pub struct Pattern {
priv tokens: ~[PatternToken]
}
Char(char),
AnyChar,
AnySequence,
- AnyWithin(~[char]),
- AnyExcept(~[char])
+ AnyWithin(~[CharSpecifier]),
+ AnyExcept(~[CharSpecifier])
+}
+
+#[deriving(Clone, Eq, TotalEq, Ord, TotalOrd, IterBytes)]
+enum CharSpecifier {
+ SingleChar(char),
+ CharRange(char, char)
}
#[deriving(Eq)]
* This function compiles Unix shell style patterns: `?` matches any single character,
* `*` matches any (possibly empty) sequence of characters and `[...]` matches any character
* inside the brackets, unless the first character is `!` in which case it matches any
- * character except those between the `!` and the `]`.
+ * character except those between the `!` and the `]`. Character sequences can also specify
+ * ranges of characters, as ordered by Unicode, so e.g. `[0-9]` specifies any character
+ * between 0 and 9 inclusive.
*
* The metacharacters `?`, `*`, `[`, `]` can be matched by using brackets (e.g. `[?]`).
* When a `]` occurs immediately following `[` or `[!` then it is interpreted as
* being part of, rather then ending, the character set, so `]` and NOT `]` can be
- * matched by `[]]` and `[!]]` respectively.
+ * matched by `[]]` and `[!]]` respectively. The `-` character can be specified inside a
+ * character sequence pattern by placing it at the start or the end, e.g. `[abc-]`.
*
* When a `[` does not have a closing `]` before the end of the string then the `[` will
* be treated literally.
match chars.slice_from(i + 3).position_elem(&']') {
None => (),
Some(j) => {
- tokens.push(AnyExcept(chars.slice(i + 2, i + 3 + j).to_owned()));
+ let cs = parse_char_specifiers(chars.slice(i + 2, i + 3 + j));
+ tokens.push(AnyExcept(cs));
i += j + 4;
loop;
}
match chars.slice_from(i + 2).position_elem(&']') {
None => (),
Some(j) => {
- tokens.push(AnyWithin(chars.slice(i + 1, i + 2 + j).to_owned()));
+ let cs = parse_char_specifiers(chars.slice(i + 1, i + 2 + j));
+ tokens.push(AnyWithin(cs));
i += j + 3;
loop;
}
let require_literal = |c| {
(options.require_literal_separator && is_sep(c)) ||
(options.require_literal_leading_dot && c == '.'
- && is_sep(prev_char.unwrap_or_default('/')))
+ && is_sep(prev_char.unwrap_or('/')))
};
for (ti, token) in self.tokens.slice_from(i).iter().enumerate() {
AnyChar => {
!require_literal(c)
}
- AnyWithin(ref chars) => {
- !require_literal(c) &&
- chars.iter()
- .rposition(|&e| chars_eq(e, c, options.case_sensitive)).is_some()
+ AnyWithin(ref specifiers) => {
+ !require_literal(c) && in_char_specifiers(*specifiers, c, options)
}
- AnyExcept(ref chars) => {
- !require_literal(c) &&
- chars.iter()
- .rposition(|&e| chars_eq(e, c, options.case_sensitive)).is_none()
+ AnyExcept(ref specifiers) => {
+ !require_literal(c) && !in_char_specifiers(*specifiers, c, options)
}
Char(c2) => {
chars_eq(c, c2, options.case_sensitive)
}
+fn parse_char_specifiers(s: &[char]) -> ~[CharSpecifier] {
+ let mut cs = ~[];
+ let mut i = 0;
+ while i < s.len() {
+ if i + 3 <= s.len() && s[i + 1] == '-' {
+ cs.push(CharRange(s[i], s[i + 2]));
+ i += 3;
+ } else {
+ cs.push(SingleChar(s[i]));
+ i += 1;
+ }
+ }
+ cs
+}
+
+fn in_char_specifiers(specifiers: &[CharSpecifier], c: char, options: MatchOptions) -> bool {
+
+ for &specifier in specifiers.iter() {
+ match specifier {
+ SingleChar(sc) => {
+ if chars_eq(c, sc, options.case_sensitive) {
+ return true;
+ }
+ }
+ CharRange(start, end) => {
+
+ // FIXME: work with non-ascii chars properly (issue #1347)
+ if !options.case_sensitive && c.is_ascii() && start.is_ascii() && end.is_ascii() {
+
+ let start = start.to_ascii().to_lower();
+ let end = end.to_ascii().to_lower();
+
+ let start_up = start.to_upper();
+ let end_up = end.to_upper();
+
+ // only allow case insensitive matching when
+ // both start and end are within a-z or A-Z
+ if start != start_up && end != end_up {
+ let start = start.to_char();
+ let end = end.to_char();
+ let c = c.to_ascii().to_lower().to_char();
+ if c >= start && c <= end {
+ return true;
+ }
+ }
+ }
+
+ if c >= start && c <= end {
+ return true;
+ }
+ }
+ }
+ }
+
+ false
+}
+
/// A helper function to determine if two chars are (possibly case-insensitively) equal.
fn chars_eq(a: char, b: char, case_sensitive: bool) -> bool {
if cfg!(windows) && path::windows::is_sep(a) && path::windows::is_sep(b) {
/**
* Configuration options to modify the behaviour of `Pattern::matches_with(..)`
*/
-#[deriving(Clone, Eq, TotalEq, Ord, TotalOrd, IterBytes, Zero)]
+#[cfg(stage0)]
+#[deriving(Clone, Eq, TotalEq, Ord, TotalOrd, IterBytes)]
+pub struct MatchOptions {
+
+ /**
+ * Whether or not patterns should be matched in a case-sensitive manner. This
+ * currently only considers upper/lower case relationships between ASCII characters,
+ * but in future this might be extended to work with Unicode.
+ */
+ case_sensitive: bool,
+
+ /**
+ * If this is true then path-component separator characters (e.g. `/` on Posix)
+ * must be matched by a literal `/`, rather than by `*` or `?` or `[...]`
+ */
+ require_literal_separator: bool,
+
+ /**
+ * If this is true then paths that contain components that start with a `.` will
+ * not match unless the `.` appears literally in the pattern: `*`, `?` or `[...]`
+ * will not match. This is useful because such files are conventionally considered
+ * hidden on Unix systems and it might be desirable to skip them when listing files.
+ */
+ require_literal_leading_dot: bool
+}
+
+/**
+ * Configuration options to modify the behaviour of `Pattern::matches_with(..)`
+ */
+#[cfg(not(stage0))]
+#[deriving(Clone, Eq, TotalEq, Ord, TotalOrd, IterBytes, Default)]
pub struct MatchOptions {
/**
use super::*;
use tempfile;
- #[test]
- fn test_relative_pattern() {
-
- fn change_then_remove(p: &Path, f: &fn()) {
- do (|| {
- unstable::change_dir_locked(p, || f());
- }).finally {
- os::remove_dir_recursive(p);
- }
- }
-
- fn mk_file(path: &str, directory: bool) {
- if directory {
- os::make_dir(&Path(path), 0xFFFF);
- } else {
- io::mk_file_writer(&Path(path), [io::Create]);
- }
- }
-
- fn abs_path(path: &str) -> Path {
- os::getcwd().push_many(Path(path).components)
- }
-
- fn glob_vec(pattern: &str) -> ~[Path] {
- glob(pattern).collect()
- }
-
- let root = tempfile::mkdtemp(&os::tmpdir(), "glob-tests");
- let root = root.expect("Should have created a temp directory");
-
- do change_then_remove(&root) {
-
- mk_file("aaa", true);
- mk_file("aaa/apple", true);
- mk_file("aaa/orange", true);
- mk_file("aaa/tomato", true);
- mk_file("aaa/tomato/tomato.txt", false);
- mk_file("aaa/tomato/tomoto.txt", false);
- mk_file("bbb", true);
- mk_file("bbb/specials", true);
- mk_file("bbb/specials/!", false);
-
- // windows does not allow `*` or `?` characters to exist in filenames
- if os::consts::FAMILY != os::consts::windows::FAMILY {
- mk_file("bbb/specials/*", false);
- mk_file("bbb/specials/?", false);
- }
-
- mk_file("bbb/specials/[", false);
- mk_file("bbb/specials/]", false);
- mk_file("ccc", true);
- mk_file("xyz", true);
- mk_file("xyz/x", false);
- mk_file("xyz/y", false);
- mk_file("xyz/z", false);
-
- assert_eq!(glob_vec(""), ~[]);
- assert_eq!(glob_vec("."), ~[]);
- assert_eq!(glob_vec(".."), ~[]);
-
- assert_eq!(glob_vec("aaa"), ~[abs_path("aaa")]);
- assert_eq!(glob_vec("aaa/"), ~[abs_path("aaa")]);
- assert_eq!(glob_vec("a"), ~[]);
- assert_eq!(glob_vec("aa"), ~[]);
- assert_eq!(glob_vec("aaaa"), ~[]);
-
- assert_eq!(glob_vec("aaa/apple"), ~[abs_path("aaa/apple")]);
- assert_eq!(glob_vec("aaa/apple/nope"), ~[]);
-
- // windows should support both / and \ as directory separators
- if os::consts::FAMILY == os::consts::windows::FAMILY {
- assert_eq!(glob_vec("aaa\\apple"), ~[abs_path("aaa/apple")]);
- }
-
- assert_eq!(glob_vec("???/"), ~[
- abs_path("aaa"),
- abs_path("bbb"),
- abs_path("ccc"),
- abs_path("xyz")]);
-
- assert_eq!(glob_vec("aaa/tomato/tom?to.txt"), ~[
- abs_path("aaa/tomato/tomato.txt"),
- abs_path("aaa/tomato/tomoto.txt")]);
-
- assert_eq!(glob_vec("xyz/?"), ~[
- abs_path("xyz/x"),
- abs_path("xyz/y"),
- abs_path("xyz/z")]);
-
- assert_eq!(glob_vec("a*"), ~[abs_path("aaa")]);
- assert_eq!(glob_vec("*a*"), ~[abs_path("aaa")]);
- assert_eq!(glob_vec("a*a"), ~[abs_path("aaa")]);
- assert_eq!(glob_vec("aaa*"), ~[abs_path("aaa")]);
- assert_eq!(glob_vec("*aaa"), ~[abs_path("aaa")]);
- assert_eq!(glob_vec("*aaa*"), ~[abs_path("aaa")]);
- assert_eq!(glob_vec("*a*a*a*"), ~[abs_path("aaa")]);
- assert_eq!(glob_vec("aaa*/"), ~[abs_path("aaa")]);
-
- assert_eq!(glob_vec("aaa/*"), ~[
- abs_path("aaa/apple"),
- abs_path("aaa/orange"),
- abs_path("aaa/tomato")]);
-
- assert_eq!(glob_vec("aaa/*a*"), ~[
- abs_path("aaa/apple"),
- abs_path("aaa/orange"),
- abs_path("aaa/tomato")]);
-
- assert_eq!(glob_vec("*/*/*.txt"), ~[
- abs_path("aaa/tomato/tomato.txt"),
- abs_path("aaa/tomato/tomoto.txt")]);
-
- assert_eq!(glob_vec("*/*/t[aob]m?to[.]t[!y]t"), ~[
- abs_path("aaa/tomato/tomato.txt"),
- abs_path("aaa/tomato/tomoto.txt")]);
-
- assert_eq!(glob_vec("aa[a]"), ~[abs_path("aaa")]);
- assert_eq!(glob_vec("aa[abc]"), ~[abs_path("aaa")]);
- assert_eq!(glob_vec("a[bca]a"), ~[abs_path("aaa")]);
- assert_eq!(glob_vec("aa[b]"), ~[]);
- assert_eq!(glob_vec("aa[xyz]"), ~[]);
- assert_eq!(glob_vec("aa[]]"), ~[]);
-
- assert_eq!(glob_vec("aa[!b]"), ~[abs_path("aaa")]);
- assert_eq!(glob_vec("aa[!bcd]"), ~[abs_path("aaa")]);
- assert_eq!(glob_vec("a[!bcd]a"), ~[abs_path("aaa")]);
- assert_eq!(glob_vec("aa[!a]"), ~[]);
- assert_eq!(glob_vec("aa[!abc]"), ~[]);
-
- assert_eq!(glob_vec("bbb/specials/[[]"), ~[abs_path("bbb/specials/[")]);
- assert_eq!(glob_vec("bbb/specials/!"), ~[abs_path("bbb/specials/!")]);
- assert_eq!(glob_vec("bbb/specials/[]]"), ~[abs_path("bbb/specials/]")]);
-
- if os::consts::FAMILY != os::consts::windows::FAMILY {
- assert_eq!(glob_vec("bbb/specials/[*]"), ~[abs_path("bbb/specials/*")]);
- assert_eq!(glob_vec("bbb/specials/[?]"), ~[abs_path("bbb/specials/?")]);
- }
-
- if os::consts::FAMILY == os::consts::windows::FAMILY {
-
- assert_eq!(glob_vec("bbb/specials/[![]"), ~[
- abs_path("bbb/specials/!"),
- abs_path("bbb/specials/]")]);
-
- assert_eq!(glob_vec("bbb/specials/[!]]"), ~[
- abs_path("bbb/specials/!"),
- abs_path("bbb/specials/[")]);
-
- assert_eq!(glob_vec("bbb/specials/[!!]"), ~[
- abs_path("bbb/specials/["),
- abs_path("bbb/specials/]")]);
-
- } else {
-
- assert_eq!(glob_vec("bbb/specials/[![]"), ~[
- abs_path("bbb/specials/!"),
- abs_path("bbb/specials/*"),
- abs_path("bbb/specials/?"),
- abs_path("bbb/specials/]")]);
-
- assert_eq!(glob_vec("bbb/specials/[!]]"), ~[
- abs_path("bbb/specials/!"),
- abs_path("bbb/specials/*"),
- abs_path("bbb/specials/?"),
- abs_path("bbb/specials/[")]);
-
- assert_eq!(glob_vec("bbb/specials/[!!]"), ~[
- abs_path("bbb/specials/*"),
- abs_path("bbb/specials/?"),
- abs_path("bbb/specials/["),
- abs_path("bbb/specials/]")]);
-
- assert_eq!(glob_vec("bbb/specials/[!*]"), ~[
- abs_path("bbb/specials/!"),
- abs_path("bbb/specials/?"),
- abs_path("bbb/specials/["),
- abs_path("bbb/specials/]")]);
-
- assert_eq!(glob_vec("bbb/specials/[!?]"), ~[
- abs_path("bbb/specials/!"),
- abs_path("bbb/specials/*"),
- abs_path("bbb/specials/["),
- abs_path("bbb/specials/]")]);
-
- }
- };
- }
-
#[test]
fn test_absolute_pattern() {
// assume that the filesystem is not empty!
glob("/*/*/*/*").skip(10000).next();
}
+ #[test]
+ fn test_range_pattern() {
+
+ let pat = Pattern::new("a[0-9]b");
+ for i in range(0, 10) {
+ assert!(pat.matches(fmt!("a%db", i)));
+ }
+ assert!(!pat.matches("a_b"));
+
+ let pat = Pattern::new("a[!0-9]b");
+ for i in range(0, 10) {
+ assert!(!pat.matches(fmt!("a%db", i)));
+ }
+ assert!(pat.matches("a_b"));
+
+ let pats = ["[a-z123]", "[1a-z23]", "[123a-z]"];
+ for &p in pats.iter() {
+ let pat = Pattern::new(p);
+ for c in "abcdefghijklmnopqrstuvwxyz".iter() {
+ assert!(pat.matches(c.to_str()));
+ }
+ for c in "ABCDEFGHIJKLMNOPQRSTUVWXYZ".iter() {
+ let options = MatchOptions {case_sensitive: false, .. MatchOptions::new()};
+ assert!(pat.matches_with(c.to_str(), options));
+ }
+ assert!(pat.matches("1"));
+ assert!(pat.matches("2"));
+ assert!(pat.matches("3"));
+ }
+
+ let pats = ["[abc-]", "[-abc]", "[a-c-]"];
+ for &p in pats.iter() {
+ let pat = Pattern::new(p);
+ assert!(pat.matches("a"));
+ assert!(pat.matches("b"));
+ assert!(pat.matches("c"));
+ assert!(pat.matches("-"));
+ assert!(!pat.matches("d"));
+ }
+
+ let pat = Pattern::new("[2-1]");
+ assert!(!pat.matches("1"));
+ assert!(!pat.matches("2"));
+
+ assert!(Pattern::new("[-]").matches("-"));
+ assert!(!Pattern::new("[!-]").matches("-"));
+ }
+
#[test]
fn test_unclosed_bracket() {
// unclosed `[` should be treated literally
use std::int;
use std::num;
use std::num::{IntConvertible, Zero, One, ToStrRadix, FromStrRadix, Orderable};
+use std::rand::{Rng, RngUtil};
use std::str;
use std::uint;
use std::vec;
impl IntConvertible for BigUint {
#[inline]
fn to_int(&self) -> int {
- num::min(self.to_uint(), int::max_value as uint) as int
+ self.to_int_opt().expect("BigUint conversion would overflow int")
}
#[inline]
}
- /// Converts this big integer into a uint, returning the uint::max_value if
- /// it's too large to fit in a uint.
+ /// Converts this BigUint into a uint, failing if the conversion
+ /// would overflow.
#[inline]
pub fn to_uint(&self) -> uint {
+ self.to_uint_opt().expect("BigUint conversion would overflow uint")
+ }
+
+ /// Converts this BigUint into a uint, unless it would overflow.
+ #[inline]
+ pub fn to_uint_opt(&self) -> Option<uint> {
match self.data.len() {
- 0 => 0,
- 1 => self.data[0] as uint,
- 2 => BigDigit::to_uint(self.data[1], self.data[0]),
- _ => uint::max_value
+ 0 => Some(0),
+ 1 => Some(self.data[0] as uint),
+ 2 => Some(BigDigit::to_uint(self.data[1], self.data[0])),
+ _ => None
}
}
+ // Converts this BigUint into an int, unless it would overflow.
+ pub fn to_int_opt(&self) -> Option<int> {
+ self.to_uint_opt().and_then(|n| {
+ // If top bit of uint is set, it's too large to convert to
+ // int.
+ if (n >> (2*BigDigit::bits - 1) != 0) {
+ None
+ } else {
+ Some(n as int)
+ }
+ })
+ }
+
+ /// Converts this BigUint into a BigInt.
+ #[inline]
+ pub fn to_bigint(&self) -> BigInt {
+ BigInt::from_biguint(Plus, self.clone())
+ }
+
#[inline]
fn shl_unit(&self, n_unit: uint) -> BigUint {
if n_unit == 0 || self.is_zero() { return (*self).clone(); }
impl IntConvertible for BigInt {
#[inline]
fn to_int(&self) -> int {
- match self.sign {
- Plus => num::min(self.to_uint(), int::max_value as uint) as int,
- Zero => 0,
- Minus => num::min((-self).to_uint(),
- (int::max_value as uint) + 1) as int
- }
+ self.to_int_opt().expect("BigInt conversion would overflow int")
}
#[inline]
}
}
+trait RandBigInt {
+ /// Generate a random BigUint of the given bit size.
+ fn gen_biguint(&mut self, bit_size: uint) -> BigUint;
+
+ /// Generate a random BigInt of the given bit size.
+ fn gen_bigint(&mut self, bit_size: uint) -> BigInt;
+}
+
+impl<R: Rng> RandBigInt for R {
+ /// Generate a random BigUint of the given bit size.
+ fn gen_biguint(&mut self, bit_size: uint) -> BigUint {
+ let (digits, rem) = bit_size.div_rem(&BigDigit::bits);
+ let mut data = vec::with_capacity(digits+1);
+ for _ in range(0, digits) {
+ data.push(self.gen());
+ }
+ if rem > 0 {
+ let final_digit: BigDigit = self.gen();
+ data.push(final_digit >> (BigDigit::bits - rem));
+ }
+ return BigUint::new(data);
+ }
+
+ /// Generate a random BigInt of the given bit size.
+ fn gen_bigint(&mut self, bit_size: uint) -> BigInt {
+ // Generate a random BigUint...
+ let biguint = self.gen_biguint(bit_size);
+ // ...and then randomly assign it a Sign...
+ let sign = if biguint.is_zero() {
+ // ...except that if the BigUint is zero, we need to try
+ // again with probability 0.5. This is because otherwise,
+ // the probability of generating a zero BigInt would be
+ // double that of any other number.
+ if self.gen() {
+ return self.gen_bigint(bit_size);
+ } else {
+ Zero
+ }
+ } else if self.gen() {
+ Plus
+ } else {
+ Minus
+ };
+ return BigInt::from_biguint(sign, biguint);
+ }
+}
+
impl BigInt {
/// Creates and initializes an BigInt.
#[inline]
.map_move(|bu| BigInt::from_biguint(sign, bu));
}
+ /// Converts this BigInt into a uint, failing if the conversion
+ /// would overflow.
#[inline]
pub fn to_uint(&self) -> uint {
+ self.to_uint_opt().expect("BigInt conversion would overflow uint")
+ }
+
+ /// Converts this BigInt into a uint, unless it would overflow.
+ #[inline]
+ pub fn to_uint_opt(&self) -> Option<uint> {
match self.sign {
- Plus => self.data.to_uint(),
- Zero => 0,
- Minus => 0
+ Plus => self.data.to_uint_opt(),
+ Zero => Some(0),
+ Minus => None
+ }
+ }
+
+ /// Converts this BigInt into an int, unless it would overflow.
+ pub fn to_int_opt(&self) -> Option<int> {
+ match self.sign {
+ Plus => self.data.to_int_opt(),
+ Zero => Some(0),
+ Minus => self.data.to_uint_opt().and_then(|n| {
+ let m: uint = 1 << (2*BigDigit::bits-1);
+ if (n > m) {
+ None
+ } else if (n == m) {
+ Some(int::min_value)
+ } else {
+ Some(-(n as int))
+ }
+ })
+ }
+ }
+
+ /// Converts this BigInt into a BigUint, failing if BigInt is
+ /// negative.
+ #[inline]
+ pub fn to_biguint(&self) -> BigUint {
+ self.to_biguint_opt().expect("negative BigInt cannot convert to BigUint")
+ }
+
+ /// Converts this BigInt into a BigUint, if it's not negative.
+ #[inline]
+ pub fn to_biguint_opt(&self) -> Option<BigUint> {
+ match self.sign {
+ Plus => Some(self.data.clone()),
+ Zero => Some(Zero::zero()),
+ Minus => None
}
}
}
use std::cmp::{Less, Equal, Greater};
use std::int;
use std::num::{IntConvertible, Zero, One, FromStrRadix};
+ use std::rand::{task_rng};
use std::str;
use std::uint;
use std::vec;
check(~[ 0, 1], ((uint::max_value >> BigDigit::bits) + 1) as int);
check(~[-1, -1 >> 1], int::max_value);
- assert_eq!(BigUint::new(~[0, -1]).to_int(), int::max_value);
- assert_eq!(BigUint::new(~[0, 0, 1]).to_int(), int::max_value);
- assert_eq!(BigUint::new(~[0, 0, -1]).to_int(), int::max_value);
+ assert_eq!(BigUint::new(~[0, -1]).to_int_opt(), None);
+ assert_eq!(BigUint::new(~[0, 0, 1]).to_int_opt(), None);
+ assert_eq!(BigUint::new(~[0, 0, -1]).to_int_opt(), None);
}
#[test]
check(~[ 0, -1], uint::max_value << BigDigit::bits);
check(~[-1, -1], uint::max_value);
- assert_eq!(BigUint::new(~[0, 0, 1]).to_uint(), uint::max_value);
- assert_eq!(BigUint::new(~[0, 0, -1]).to_uint(), uint::max_value);
+ assert_eq!(BigUint::new(~[0, 0, 1]).to_uint_opt(), None);
+ assert_eq!(BigUint::new(~[0, 0, -1]).to_uint_opt(), None);
+ }
+
+ #[test]
+ fn test_convert_to_bigint() {
+ fn check(n: BigUint, ans: BigInt) {
+ assert_eq!(n.to_bigint(), ans);
+ assert_eq!(n.to_bigint().to_biguint(), n);
+ }
+ check(Zero::zero(), Zero::zero());
+ check(BigUint::new(~[1,2,3]),
+ BigInt::from_biguint(Plus, BigUint::new(~[1,2,3])));
}
static sum_triples: &'static [(&'static [BigDigit],
check(20, "2432902008176640000");
check(30, "265252859812191058636308480000000");
}
+
+ #[test]
+ fn test_rand() {
+ let mut rng = task_rng();
+ let _n: BigUint = rng.gen_biguint(137);
+ assert!(rng.gen_biguint(0).is_zero());
+ }
}
#[cfg(test)]
use std::cmp::{Less, Equal, Greater};
use std::int;
use std::num::{IntConvertible, Zero, One, FromStrRadix};
+ use std::rand::{task_rng};
use std::uint;
#[test]
Plus, BigUint::from_uint(int::max_value as uint)
), int::max_value);
- assert!(BigInt::from_biguint(
+ assert_eq!(BigInt::from_biguint(
Plus, BigUint::from_uint(int::max_value as uint + 1)
- ).to_int() == int::max_value);
- assert!(BigInt::from_biguint(
+ ).to_int_opt(), None);
+ assert_eq!(BigInt::from_biguint(
Plus, BigUint::new(~[1, 2, 3])
- ).to_int() == int::max_value);
+ ).to_int_opt(), None);
check(BigInt::from_biguint(
- Minus, BigUint::from_uint(-int::min_value as uint)
+ Minus, BigUint::new(~[0, 1<<(BigDigit::bits-1)])
), int::min_value);
- assert!(BigInt::from_biguint(
- Minus, BigUint::from_uint(-int::min_value as uint + 1)
- ).to_int() == int::min_value);
- assert!(BigInt::from_biguint(
- Minus, BigUint::new(~[1, 2, 3])
- ).to_int() == int::min_value);
+ assert_eq!(BigInt::from_biguint(
+ Minus, BigUint::new(~[1, 1<<(BigDigit::bits-1)])
+ ).to_int_opt(), None);
+ assert_eq!(BigInt::from_biguint(
+ Minus, BigUint::new(~[1, 2, 3])).to_int_opt(), None);
}
#[test]
check(
BigInt::from_biguint(Plus, BigUint::from_uint(uint::max_value)),
uint::max_value);
- assert!(BigInt::from_biguint(
- Plus, BigUint::new(~[1, 2, 3])
- ).to_uint() == uint::max_value);
+ assert_eq!(BigInt::from_biguint(
+ Plus, BigUint::new(~[1, 2, 3])).to_uint_opt(), None);
+
+ assert_eq!(BigInt::from_biguint(
+ Minus, BigUint::from_uint(uint::max_value)).to_uint_opt(), None);
+ assert_eq!(BigInt::from_biguint(
+ Minus, BigUint::new(~[1, 2, 3])).to_uint_opt(), None);
+ }
+
+ #[test]
+ fn test_convert_to_biguint() {
+ fn check(n: BigInt, ans_1: BigUint) {
+ assert_eq!(n.to_biguint(), ans_1);
+ assert_eq!(n.to_biguint().to_bigint(), n);
+ }
+ let zero: BigInt = Zero::zero();
+ let unsigned_zero: BigUint = Zero::zero();
+ let positive = BigInt::from_biguint(
+ Plus, BigUint::new(~[1,2,3]));
+ let negative = -positive;
+
+ check(zero, unsigned_zero);
+ check(positive, BigUint::new(~[1,2,3]));
- assert!(BigInt::from_biguint(
- Minus, BigUint::from_uint(uint::max_value)
- ).to_uint() == 0);
- assert!(BigInt::from_biguint(
- Minus, BigUint::new(~[1, 2, 3])
- ).to_uint() == 0);
+ assert_eq!(negative.to_biguint_opt(), None);
}
static sum_triples: &'static [(&'static [BigDigit],
let zero: BigInt = Zero::zero();
assert_eq!(-zero, zero);
}
+
+ #[test]
+ fn test_rand() {
+ let mut rng = task_rng();
+ let _n: BigInt = rng.gen_bigint(137);
+ assert!(rng.gen_bigint(0).is_zero());
+ }
}
#[cfg(test)]
return None
}
let a_option: Option<T> = FromStr::from_str(split[0]);
- do a_option.chain |a| {
+ do a_option.and_then |a| {
let b_option: Option<T> = FromStr::from_str(split[1]);
- do b_option.chain |b| {
+ do b_option.and_then |b| {
Some(Ratio::new(a.clone(), b.clone()))
}
}
} else {
let a_option: Option<T> = FromStrRadix::from_str_radix(split[0],
radix);
- do a_option.chain |a| {
+ do a_option.and_then |a| {
let b_option: Option<T> =
FromStrRadix::from_str_radix(split[1], radix);
- do b_option.chain |b| {
+ do b_option.and_then |b| {
Some(Ratio::new(a.clone(), b.clone()))
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// FIXME #3921. This is unsafe because linenoise uses global mutable
-// state without mutexes.
-
use std::c_str::ToCStr;
use std::libc::{c_char, c_int};
-use std::local_data;
-use std::str;
+use std::{local_data, str, rt};
+use std::unstable::finally::Finally;
#[cfg(stage0)]
pub mod rustrt {
fn linenoiseHistoryLoad(file: *c_char) -> c_int;
fn linenoiseSetCompletionCallback(callback: *u8);
fn linenoiseAddCompletion(completions: *(), line: *c_char);
+
+ fn rust_take_linenoise_lock();
+ fn rust_drop_linenoise_lock();
}
}
externfn!(fn linenoiseHistoryLoad(file: *c_char) -> c_int)
externfn!(fn linenoiseSetCompletionCallback(callback: extern "C" fn(*i8, *())))
externfn!(fn linenoiseAddCompletion(completions: *(), line: *c_char))
+
+ externfn!(fn rust_take_linenoise_lock())
+ externfn!(fn rust_drop_linenoise_lock())
+}
+
+macro_rules! locked {
+ ($expr:expr) => {
+ unsafe {
+ // FIXME #9105: can't use a static mutex in pure Rust yet.
+ rustrt::rust_take_linenoise_lock();
+ let x = $expr;
+ rustrt::rust_drop_linenoise_lock();
+ x
+ }
+ }
}
/// Add a line to history
-pub unsafe fn add_history(line: &str) -> bool {
+pub fn add_history(line: &str) -> bool {
do line.with_c_str |buf| {
- rustrt::linenoiseHistoryAdd(buf) == 1 as c_int
+ (locked!(rustrt::linenoiseHistoryAdd(buf))) == 1 as c_int
}
}
/// Set the maximum amount of lines stored
-pub unsafe fn set_history_max_len(len: int) -> bool {
- rustrt::linenoiseHistorySetMaxLen(len as c_int) == 1 as c_int
+pub fn set_history_max_len(len: int) -> bool {
+ (locked!(rustrt::linenoiseHistorySetMaxLen(len as c_int))) == 1 as c_int
}
/// Save line history to a file
-pub unsafe fn save_history(file: &str) -> bool {
+pub fn save_history(file: &str) -> bool {
do file.with_c_str |buf| {
- rustrt::linenoiseHistorySave(buf) == 1 as c_int
+ // 0 on success, -1 on failure
+ (locked!(rustrt::linenoiseHistorySave(buf))) == 0 as c_int
}
}
/// Load line history from a file
-pub unsafe fn load_history(file: &str) -> bool {
+pub fn load_history(file: &str) -> bool {
do file.with_c_str |buf| {
- rustrt::linenoiseHistoryLoad(buf) == 1 as c_int
+ // 0 on success, -1 on failure
+ (locked!(rustrt::linenoiseHistoryLoad(buf))) == 0 as c_int
}
}
/// Print out a prompt and then wait for input and return it
-pub unsafe fn read(prompt: &str) -> Option<~str> {
+pub fn read(prompt: &str) -> Option<~str> {
do prompt.with_c_str |buf| {
- let line = rustrt::linenoise(buf);
+ let line = locked!(rustrt::linenoise(buf));
if line.is_null() { None }
- else { Some(str::raw::from_c_str(line)) }
+ else {
+ unsafe {
+ do (|| {
+ Some(str::raw::from_c_str(line))
+ }).finally {
+ // linenoise's return value is from strdup, so we
+ // better not leak it.
+ rt::global_heap::exchange_free(line);
+ }
+ }
+ }
}
}
pub type CompletionCb = @fn(~str, @fn(~str));
-static complete_key: local_data::Key<@CompletionCb> = &local_data::Key;
-
-/// Bind to the main completion callback
-pub unsafe fn complete(cb: CompletionCb) {
- local_data::set(complete_key, @cb);
-
- extern fn callback(line: *c_char, completions: *()) {
- do local_data::get(complete_key) |cb| {
- let cb = **cb.unwrap();
-
- unsafe {
- do cb(str::raw::from_c_str(line)) |suggestion| {
- do suggestion.with_c_str |buf| {
- rustrt::linenoiseAddCompletion(completions, buf);
+static complete_key: local_data::Key<CompletionCb> = &local_data::Key;
+
+/// Bind to the main completion callback in the current task.
+///
+/// The completion callback should not call any `extra::rl` functions
+/// other than the closure that it receives as its second
+/// argument. Calling such a function will deadlock on the mutex used
+/// to ensure that the calls are thread-safe.
+pub fn complete(cb: CompletionCb) {
+ local_data::set(complete_key, cb);
+
+ extern fn callback(c_line: *c_char, completions: *()) {
+ do local_data::get(complete_key) |opt_cb| {
+ // only fetch completions if a completion handler has been
+ // registered in the current task.
+ match opt_cb {
+ None => {},
+ Some(cb) => {
+ let line = unsafe { str::raw::from_c_str(c_line) };
+ do (*cb)(line) |suggestion| {
+ do suggestion.with_c_str |buf| {
+ // This isn't locked, because `callback` gets
+ // called inside `rustrt::linenoise`, which
+ // *is* already inside the mutex, so
+ // re-locking would be a deadlock.
+ unsafe {
+ rustrt::linenoiseAddCompletion(completions, buf);
+ }
+ }
}
}
}
}
}
- rustrt::linenoiseSetCompletionCallback(callback);
+ locked!(rustrt::linenoiseSetCompletionCallback(callback));
}
use std::io;
use std::option::{Option, Some, None};
use std::to_str::ToStr;
-use std::uint;
#[deriving(Clone, Eq)]
pub enum Identifier {
fn take_num(rdr: @io::Reader, ch: char) -> (uint, char) {
let (s, ch) = take_nonempty_prefix(rdr, ch, char::is_digit);
- match uint::from_str(s) {
+ match from_str::<uint>(s) {
None => { bad_parse::cond.raise(()); (0, ch) },
Some(i) => (i, ch)
}
fn take_ident(rdr: @io::Reader, ch: char) -> (Identifier, char) {
let (s,ch) = take_nonempty_prefix(rdr, ch, char::is_alphanumeric);
if s.iter().all(char::is_digit) {
- match uint::from_str(s) {
+ match from_str::<uint>(s) {
None => { bad_parse::cond.raise(()); (Numeric(0), ch) },
Some(i) => (Numeric(i), ch)
}
None
}
-#[cfg(test)]
-mod tests {
-
- use tempfile::mkdtemp;
-
- use std::os;
-
- #[test]
- fn test_mkdtemp() {
- let p = mkdtemp(&Path("."), "foobar").unwrap();
- os::remove_dir(&p);
- assert!(p.to_str().ends_with("foobar"));
- }
-
- // Ideally these would be in std::os but then core would need
- // to depend on std
- #[test]
- fn recursive_mkdir_rel() {
- use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
- use std::os;
- use std::unstable::change_dir_locked;
-
- let root = mkdtemp(&os::tmpdir(), "recursive_mkdir_rel").
- expect("recursive_mkdir_rel");
- assert!(do change_dir_locked(&root) {
- let path = Path("frob");
- debug!("recursive_mkdir_rel: Making: %s in cwd %s [%?]", path.to_str(),
- os::getcwd().to_str(),
- os::path_exists(&path));
- assert!(os::mkdir_recursive(&path, (S_IRUSR | S_IWUSR | S_IXUSR) as i32));
- assert!(os::path_is_dir(&path));
- assert!(os::mkdir_recursive(&path, (S_IRUSR | S_IWUSR | S_IXUSR) as i32));
- assert!(os::path_is_dir(&path));
- });
- }
-
- #[test]
- fn recursive_mkdir_dot() {
- use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
- use std::os;
-
- let dot = Path(".");
- assert!(os::mkdir_recursive(&dot, (S_IRUSR | S_IWUSR | S_IXUSR) as i32));
- let dotdot = Path("..");
- assert!(os::mkdir_recursive(&dotdot, (S_IRUSR | S_IWUSR | S_IXUSR) as i32));
- }
-
- #[test]
- fn recursive_mkdir_rel_2() {
- use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
- use std::os;
- use std::unstable::change_dir_locked;
-
- let root = mkdtemp(&os::tmpdir(), "recursive_mkdir_rel_2").
- expect("recursive_mkdir_rel_2");
- assert!(do change_dir_locked(&root) {
- let path = Path("./frob/baz");
- debug!("recursive_mkdir_rel_2: Making: %s in cwd %s [%?]", path.to_str(),
- os::getcwd().to_str(), os::path_exists(&path));
- assert!(os::mkdir_recursive(&path, (S_IRUSR | S_IWUSR | S_IXUSR) as i32));
- assert!(os::path_is_dir(&path));
- assert!(os::path_is_dir(&path.pop()));
- let path2 = Path("quux/blat");
- debug!("recursive_mkdir_rel_2: Making: %s in cwd %s", path2.to_str(),
- os::getcwd().to_str());
- assert!(os::mkdir_recursive(&path2, (S_IRUSR | S_IWUSR | S_IXUSR) as i32));
- assert!(os::path_is_dir(&path2));
- assert!(os::path_is_dir(&path2.pop()));
- });
- }
-
- // Ideally this would be in core, but needs mkdtemp
- #[test]
- pub fn test_rmdir_recursive_ok() {
- use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
- use std::os;
-
- let rwx = (S_IRUSR | S_IWUSR | S_IXUSR) as i32;
-
- let tmpdir = mkdtemp(&os::tmpdir(), "test").expect("test_rmdir_recursive_ok: \
- couldn't create temp dir");
- let root = tmpdir.push("foo");
-
- debug!("making %s", root.to_str());
- assert!(os::make_dir(&root, rwx));
- assert!(os::make_dir(&root.push("foo"), rwx));
- assert!(os::make_dir(&root.push("foo").push("bar"), rwx));
- assert!(os::make_dir(&root.push("foo").push("bar").push("blat"), rwx));
- assert!(os::remove_dir_recursive(&root));
- assert!(!os::path_exists(&root));
- assert!(!os::path_exists(&root.push("bar")));
- assert!(!os::path_exists(&root.push("bar").push("blat")));
- }
-}
+// the tests for this module need to change the path using change_dir,
+// and this doesn't play nicely with other tests so these unit tests are located
+// in src/test/run-pass/tempfile.rs
use std::clone::Clone;
use std::comm::{stream, SharedChan, GenericPort, GenericChan};
use std::libc;
-use std::either;
use std::io;
use std::result;
use std::task;
use std::to_str::ToStr;
use std::f64;
use std::os;
-use std::uint;
// The name of a test. By convention this follows the rules for rust
pub fn test_main(args: &[~str], tests: ~[TestDescAndFn]) {
let opts =
match parse_opts(args) {
- either::Left(o) => o,
- either::Right(m) => fail!(m)
+ Ok(o) => o,
+ Err(msg) => fail!(msg)
};
if !run_tests_console(&opts, tests) { fail!("Some tests failed"); }
}
logfile: Option<Path>
}
-type OptRes = Either<TestOpts, ~str>;
+type OptRes = Result<TestOpts, ~str>;
fn optgroups() -> ~[getopts::groups::OptGroup] {
~[groups::optflag("", "ignored", "Run ignored tests"),
let matches =
match groups::getopts(args_, optgroups()) {
Ok(m) => m,
- Err(f) => return either::Right(getopts::fail_str(f))
+ Err(f) => return Err(getopts::fail_str(f))
};
if getopts::opt_present(&matches, "h") { usage(args[0], "h"); }
let ratchet_metrics = ratchet_metrics.map_move(|s| Path(s));
let ratchet_noise_percent = getopts::opt_maybe_str(&matches, "ratchet-noise-percent");
- let ratchet_noise_percent = ratchet_noise_percent.map_move(|s| f64::from_str(s).unwrap());
+ let ratchet_noise_percent = ratchet_noise_percent.map_move(|s| from_str::<f64>(s).unwrap());
let save_metrics = getopts::opt_maybe_str(&matches, "save-metrics");
let save_metrics = save_metrics.map_move(|s| Path(s));
logfile: logfile
};
- either::Left(test_opts)
+ Ok(test_opts)
}
pub fn opt_shard(maybestr: Option<~str>) -> Option<(uint,uint)> {
None => None,
Some(s) => {
match s.split_iter('.').to_owned_vec() {
- [a, b] => match (uint::from_str(a), uint::from_str(b)) {
+ [a, b] => match (from_str::<uint>(a), from_str::<uint>(b)) {
(Some(a), Some(b)) => Some((a,b)),
_ => None
},
StaticTestName, DynTestName, DynTestFn};
use test::{TestOpts, run_test};
- use std::either;
use std::comm::{stream, SharedChan};
use tempfile;
use std::os;
fn first_free_arg_should_be_a_filter() {
let args = ~[~"progname", ~"filter"];
let opts = match parse_opts(args) {
- either::Left(o) => o,
- _ => fail!("Malformed arg in first_free_arg_should_be_a_filter")
+ Ok(o) => o,
+ _ => fail!("Malformed arg in first_free_arg_should_be_a_filter")
};
assert!("filter" == opts.filter.clone().unwrap());
}
fn parse_ignored_flag() {
let args = ~[~"progname", ~"filter", ~"--ignored"];
let opts = match parse_opts(args) {
- either::Left(o) => o,
- _ => fail!("Malformed arg in parse_ignored_flag")
+ Ok(o) => o,
+ _ => fail!("Malformed arg in parse_ignored_flag")
};
assert!((opts.run_ignored));
}
},
'c' => {
parse_type(s, pos, 'a', &mut *tm)
- .chain(|pos| parse_char(s, pos, ' '))
- .chain(|pos| parse_type(s, pos, 'b', &mut *tm))
- .chain(|pos| parse_char(s, pos, ' '))
- .chain(|pos| parse_type(s, pos, 'e', &mut *tm))
- .chain(|pos| parse_char(s, pos, ' '))
- .chain(|pos| parse_type(s, pos, 'T', &mut *tm))
- .chain(|pos| parse_char(s, pos, ' '))
- .chain(|pos| parse_type(s, pos, 'Y', &mut *tm))
+ .and_then(|pos| parse_char(s, pos, ' '))
+ .and_then(|pos| parse_type(s, pos, 'b', &mut *tm))
+ .and_then(|pos| parse_char(s, pos, ' '))
+ .and_then(|pos| parse_type(s, pos, 'e', &mut *tm))
+ .and_then(|pos| parse_char(s, pos, ' '))
+ .and_then(|pos| parse_type(s, pos, 'T', &mut *tm))
+ .and_then(|pos| parse_char(s, pos, ' '))
+ .and_then(|pos| parse_type(s, pos, 'Y', &mut *tm))
}
'D' | 'x' => {
parse_type(s, pos, 'm', &mut *tm)
- .chain(|pos| parse_char(s, pos, '/'))
- .chain(|pos| parse_type(s, pos, 'd', &mut *tm))
- .chain(|pos| parse_char(s, pos, '/'))
- .chain(|pos| parse_type(s, pos, 'y', &mut *tm))
+ .and_then(|pos| parse_char(s, pos, '/'))
+ .and_then(|pos| parse_type(s, pos, 'd', &mut *tm))
+ .and_then(|pos| parse_char(s, pos, '/'))
+ .and_then(|pos| parse_type(s, pos, 'y', &mut *tm))
}
'd' => match match_digits_in_range(s, pos, 2u, false, 1_i32,
31_i32) {
}
'F' => {
parse_type(s, pos, 'Y', &mut *tm)
- .chain(|pos| parse_char(s, pos, '-'))
- .chain(|pos| parse_type(s, pos, 'm', &mut *tm))
- .chain(|pos| parse_char(s, pos, '-'))
- .chain(|pos| parse_type(s, pos, 'd', &mut *tm))
+ .and_then(|pos| parse_char(s, pos, '-'))
+ .and_then(|pos| parse_type(s, pos, 'm', &mut *tm))
+ .and_then(|pos| parse_char(s, pos, '-'))
+ .and_then(|pos| parse_type(s, pos, 'd', &mut *tm))
}
'H' => {
match match_digits_in_range(s, pos, 2u, false, 0_i32, 23_i32) {
},
'R' => {
parse_type(s, pos, 'H', &mut *tm)
- .chain(|pos| parse_char(s, pos, ':'))
- .chain(|pos| parse_type(s, pos, 'M', &mut *tm))
+ .and_then(|pos| parse_char(s, pos, ':'))
+ .and_then(|pos| parse_type(s, pos, 'M', &mut *tm))
}
'r' => {
parse_type(s, pos, 'I', &mut *tm)
- .chain(|pos| parse_char(s, pos, ':'))
- .chain(|pos| parse_type(s, pos, 'M', &mut *tm))
- .chain(|pos| parse_char(s, pos, ':'))
- .chain(|pos| parse_type(s, pos, 'S', &mut *tm))
- .chain(|pos| parse_char(s, pos, ' '))
- .chain(|pos| parse_type(s, pos, 'p', &mut *tm))
+ .and_then(|pos| parse_char(s, pos, ':'))
+ .and_then(|pos| parse_type(s, pos, 'M', &mut *tm))
+ .and_then(|pos| parse_char(s, pos, ':'))
+ .and_then(|pos| parse_type(s, pos, 'S', &mut *tm))
+ .and_then(|pos| parse_char(s, pos, ' '))
+ .and_then(|pos| parse_type(s, pos, 'p', &mut *tm))
}
'S' => {
match match_digits_in_range(s, pos, 2u, false, 0_i32, 60_i32) {
//'s' {}
'T' | 'X' => {
parse_type(s, pos, 'H', &mut *tm)
- .chain(|pos| parse_char(s, pos, ':'))
- .chain(|pos| parse_type(s, pos, 'M', &mut *tm))
- .chain(|pos| parse_char(s, pos, ':'))
- .chain(|pos| parse_type(s, pos, 'S', &mut *tm))
+ .and_then(|pos| parse_char(s, pos, ':'))
+ .and_then(|pos| parse_type(s, pos, 'M', &mut *tm))
+ .and_then(|pos| parse_char(s, pos, ':'))
+ .and_then(|pos| parse_type(s, pos, 'S', &mut *tm))
}
't' => parse_char(s, pos, '\t'),
'u' => {
}
'v' => {
parse_type(s, pos, 'e', &mut *tm)
- .chain(|pos| parse_char(s, pos, '-'))
- .chain(|pos| parse_type(s, pos, 'b', &mut *tm))
- .chain(|pos| parse_char(s, pos, '-'))
- .chain(|pos| parse_type(s, pos, 'Y', &mut *tm))
+ .and_then(|pos| parse_char(s, pos, '-'))
+ .and_then(|pos| parse_type(s, pos, 'b', &mut *tm))
+ .and_then(|pos| parse_char(s, pos, '-'))
+ .and_then(|pos| parse_type(s, pos, 'Y', &mut *tm))
}
//'W' {}
'w' => {
}
}
+impl Default for Uuid {
+ /// Returns the nil UUID, which is all zeroes
+ fn default() -> Uuid {
+ Uuid::new_nil()
+ }
+}
+
impl Zero for Uuid {
/// Returns the nil UUID, which is all zeroes
fn zero() -> Uuid {
use treemap::TreeMap;
use std::cell::Cell;
use std::comm::{PortOne, oneshot};
-use std::either::{Either, Left, Right};
use std::{io, os, task};
/**
discovered_outputs: WorkMap
}
-struct Work<'self, T> {
- prep: &'self Prep<'self>,
- res: Option<Either<T,PortOne<(Exec,T)>>>
+enum Work<'self, T> {
+ WorkValue(T),
+ WorkFromTask(&'self Prep<'self>, PortOne<(Exec, T)>),
}
fn json_encode<T:Encodable<json::Encoder>>(t: &T) -> ~str {
db.prepare(self.fn_name, &self.declared_inputs)
};
- let res = match cached {
+ match cached {
Some((ref disc_in, ref disc_out, ref res))
if self.all_fresh("declared input",&self.declared_inputs) &&
self.all_fresh("discovered input", disc_in) &&
debug!("Cache hit!");
debug!("Trying to decode: %? / %? / %?",
disc_in, disc_out, *res);
- Left(json_decode(*res))
+ Work::from_value(json_decode(*res))
}
_ => {
let v = blk(&mut exe);
chan.send((exe, v));
}
- Right(port)
+ Work::from_task(self, port)
}
- };
- Work::new(self, res)
+ }
}
}
Decodable<json::Decoder>>
Work<'self, T> { // FIXME(#5121)
- pub fn new(p: &'self Prep<'self>, e: Either<T,PortOne<(Exec,T)>>) -> Work<'self, T> {
- Work { prep: p, res: Some(e) }
+ pub fn from_value(elt: T) -> Work<'self, T> {
+ WorkValue(elt)
+ }
+ pub fn from_task(prep: &'self Prep<'self>, port: PortOne<(Exec, T)>)
+ -> Work<'self, T> {
+ WorkFromTask(prep, port)
}
pub fn unwrap(self) -> T {
- let Work { prep, res } = self;
- match res {
- None => fail!(),
- Some(Left(v)) => v,
- Some(Right(port)) => {
+ match self {
+ WorkValue(v) => v,
+ WorkFromTask(prep, port) => {
let (exe, v) = port.recv();
let s = json_encode(&v);
do prep.ctxt.db.write |db| {
usage_full: UsageSource<'self>,
}
-static NUM_OF_COMMANDS: uint = 7;
-
-// FIXME(#7617): should just be &'static [Command<'static>]
-// but mac os doesn't seem to like that and tries to loop
-// past the end of COMMANDS in usage thus passing garbage
-// to str::repeat and eventually malloc and crashing.
-static COMMANDS: [Command<'static>, .. NUM_OF_COMMANDS] = [
- Command{
+static COMMANDS: &'static [Command<'static>] = &'static [
+ Command {
cmd: "build",
action: CallMain("rustc", rustc::main_args),
usage_line: "compile rust source files",
usage_full: UsgCall(rustc_help),
},
- Command{
+ Command {
cmd: "run",
action: Call(cmd_run),
usage_line: "build an executable, and run it",
\n\nUsage:\trust run <filename> [<arguments>...]"
)
},
- Command{
+ Command {
cmd: "test",
action: Call(cmd_test),
usage_line: "build a test executable, and run it",
usage_full: UsgStr(
"The test command is an shortcut for the command line \n\
\"rustc --test <filename> -o <filestem>test~ && \
- ./<filestem>test~\"\n\nUsage:\trust test <filename>"
+ ./<filestem>test~ [<arguments>...]\"\
+ \n\nUsage:\trust test <filename> [<arguments>...]"
)
},
- Command{
+ Command {
cmd: "doc",
action: CallMain("rustdoc", rustdoc::main_args),
usage_line: "generate documentation from doc comments",
usage_full: UsgCall(rustdoc::config::usage),
},
- Command{
+ Command {
cmd: "pkg",
action: CallMain("rustpkg", rustpkg::main_args),
usage_line: "download, build, install rust packages",
usage_full: UsgCall(rustpkg::usage::general),
},
- Command{
+ Command {
cmd: "sketch",
action: CallMain("rusti", rusti::main_args),
usage_line: "run a rust interpreter",
usage_full: UsgStr("\nUsage:\trusti"),
},
- Command{
+ Command {
cmd: "help",
action: Call(cmd_help),
usage_line: "show detailed usage of a command",
fn cmd_test(args: &[~str]) -> ValidUsage {
match args {
- [ref filename] => {
+ [ref filename, ..prog_args] => {
let p = Path(*filename);
let test_exec = p.filestem().unwrap() + "test~";
invoke("rustc", &[~"--test", filename.to_owned(),
~"-o", test_exec.to_owned()], rustc::main_args);
- let exit_code = run::process_status(~"./" + test_exec, []);
+ let exit_code = run::process_status(~"./" + test_exec, prog_args);
Valid(exit_code)
}
_ => Invalid
link::output_type_bitcode
} else { link::output_type_exe };
let sysroot_opt = getopts::opt_maybe_str(matches, "sysroot").map_move(|m| @Path(m));
- let target = getopts::opt_maybe_str(matches, "target").unwrap_or_default(host_triple());
- let target_cpu = getopts::opt_maybe_str(matches, "target-cpu").unwrap_or_default(~"generic");
- let target_feature = getopts::opt_maybe_str(matches, "target-feature").unwrap_or_default(~"");
+ let target = getopts::opt_maybe_str(matches, "target").unwrap_or(host_triple());
+ let target_cpu = getopts::opt_maybe_str(matches, "target-cpu").unwrap_or(~"generic");
+ let target_feature = getopts::opt_maybe_str(matches, "target-feature").unwrap_or(~"");
let save_temps = getopts::opt_present(matches, "save-temps");
let opt_level = {
if (debugging_opts & session::no_opt) != 0 {
if !linkage_metas.is_empty() {
// But if a linkage meta is present, that overrides
let maybe_name = linkage_metas.iter().find(|m| "name" == m.name());
- match maybe_name.chain(|m| m.value_str()) {
+ match maybe_name.and_then(|m| m.value_str()) {
Some(s) => stem = s,
_ => ()
}
fn fold_mod(cx: @Context, m: &ast::_mod, fld: @fold::ast_fold) -> ast::_mod {
let filtered_items = do m.items.iter().filter_map |a| {
- filter_item(cx, *a).chain(|x| fld.fold_item(x))
+ filter_item(cx, *a).and_then(|x| fld.fold_item(x))
}.collect();
let filtered_view_items = do m.view_items.iter().filter_map |a| {
do filter_view_item(cx, a).map_move |x| {
fld: @fold::ast_fold
) -> ast::Block {
let resulting_stmts = do b.stmts.iter().filter_map |a| {
- filter_stmt(cx, *a).chain(|stmt| fld.fold_stmt(stmt))
+ filter_stmt(cx, *a).and_then(|stmt| fld.fold_stmt(stmt))
}.collect();
let filtered_view_items = do b.view_items.iter().filter_map |a| {
filter_view_item(cx, a).map(|x| fld.fold_view_item(*x))
ArgNo: c_uint)
-> ValueRef;
+ #[fast_ffi]
+ pub fn LLVMDIBuilderCreateNameSpace(Builder: DIBuilderRef,
+ Scope: ValueRef,
+ Name: *c_char,
+ File: ValueRef,
+ LineNo: c_uint)
+ -> ValueRef;
+
+ #[fast_ffi]
+ pub fn LLVMDICompositeTypeSetTypeArray(CompositeType: ValueRef, TypeArray: ValueRef);
+
#[fast_ffi]
pub fn LLVMIsAArgument(value_ref: ValueRef) -> ValueRef;
ast::named => {
let link_name = i.attrs.iter()
.find(|at| "link_name" == at.name())
- .chain(|at| at.value_str());
+ .and_then(|at| at.value_str());
let foreign_name = match link_name {
Some(nn) => {
Mod, // m
ForeignMod, // n
Enum, // t
- Variant, // v
+ TupleVariant, // v
+ StructVariant, // V
Impl, // i
Trait, // I
Struct, // S
'm' => Mod,
'n' => ForeignMod,
't' => Enum,
- 'v' => Variant,
+ 'v' => TupleVariant,
+ 'V' => StructVariant,
'i' => Impl,
'I' => Trait,
'S' => Struct,
}
fn variant_disr_val(d: ebml::Doc) -> Option<ty::Disr> {
- do reader::maybe_get_doc(d, tag_disr_val).chain |val_doc| {
+ do reader::maybe_get_doc(d, tag_disr_val).and_then |val_doc| {
do reader::with_doc_data(val_doc) |data| { u64::parse_bytes(data, 10u) }
}
}
Type | ForeignType => DlDef(ast::DefTy(did)),
Mod => DlDef(ast::DefMod(did)),
ForeignMod => DlDef(ast::DefForeignMod(did)),
- Variant => {
+ StructVariant => {
let enum_did = item_reqd_and_translated_parent_item(cnum, item);
- DlDef(ast::DefVariant(enum_did, did))
+ DlDef(ast::DefVariant(enum_did, did, true))
+ }
+ TupleVariant => {
+ let enum_did = item_reqd_and_translated_parent_item(cnum, item);
+ DlDef(ast::DefVariant(enum_did, did, false))
}
Trait => DlDef(ast::DefTrait(did)),
Enum => DlDef(ast::DefTy(did)),
}
ImmStatic | MutStatic | Struct | UnsafeFn | Fn | ForeignFn |
UnsafeStaticMethod | StaticMethod | Type | ForeignType |
- Variant | Enum | PublicField | PrivateField |
- InheritedField => {}
+ TupleVariant | StructVariant | Enum | PublicField |
+ PrivateField | InheritedField => {}
}
}
do reader::tagged_docs(item, tag_item_field) |an_item| {
let f = item_family(an_item);
if f == PublicField || f == PrivateField || f == InheritedField {
+ // FIXME #6993: name should be of type Name, not Ident
let name = item_name(intr, an_item);
let did = item_def_id(an_item, cdata);
result.push(ty::field_ty {
- ident: name,
+ name: name.name,
id: did, vis:
struct_field_family_to_visibility(f),
});
do reader::tagged_docs(item, tag_item_unnamed_field) |an_item| {
let did = item_def_id(an_item, cdata);
result.push(ty::field_ty {
- ident: special_idents::unnamed_field,
+ name: special_idents::unnamed_field.name,
id: did,
vis: ast::inherited,
});
Mod => ~"mod",
ForeignMod => ~"foreign mod",
Enum => ~"enum",
- Variant => ~"variant",
+ StructVariant => ~"struct variant",
+ TupleVariant => ~"tuple variant",
Impl => ~"impl",
Trait => ~"trait",
Struct => ~"struct",
ebml_w.end_tag();
}
+fn encode_struct_fields(ecx: &EncodeContext,
+ ebml_w: &mut writer::Encoder,
+ def: @struct_def) {
+ for f in def.fields.iter() {
+ match f.node.kind {
+ named_field(ident, vis) => {
+ ebml_w.start_tag(tag_item_field);
+ encode_struct_field_family(ebml_w, vis);
+ encode_name(ecx, ebml_w, ident);
+ encode_def_id(ebml_w, local_def(f.node.id));
+ ebml_w.end_tag();
+ }
+ unnamed_field => {
+ ebml_w.start_tag(tag_item_unnamed_field);
+ encode_def_id(ebml_w, local_def(f.node.id));
+ ebml_w.end_tag();
+ }
+ }
+ }
+}
+
fn encode_enum_variant_info(ecx: &EncodeContext,
ebml_w: &mut writer::Encoder,
id: NodeId,
pos: ebml_w.writer.tell()});
ebml_w.start_tag(tag_items_data_item);
encode_def_id(ebml_w, def_id);
- encode_family(ebml_w, 'v');
+ match variant.node.kind {
+ ast::tuple_variant_kind(_) => encode_family(ebml_w, 'v'),
+ ast::struct_variant_kind(_) => encode_family(ebml_w, 'V')
+ }
encode_name(ecx, ebml_w, variant.node.name);
encode_parent_item(ebml_w, local_def(id));
encode_visibility(ebml_w, variant.node.vis);
if args.len() > 0 && generics.ty_params.len() == 0 => {
encode_symbol(ecx, ebml_w, variant.node.id);
}
- ast::tuple_variant_kind(_) | ast::struct_variant_kind(_) => {}
+ ast::tuple_variant_kind(_) => {},
+ ast::struct_variant_kind(def) => {
+ let idx = encode_info_for_struct(ecx, ebml_w, path,
+ def.fields, index);
+ encode_struct_fields(ecx, ebml_w, def);
+ let bkts = create_index(idx);
+ encode_index(ebml_w, bkts, write_i64);
+ }
}
if vi[i].disr_val != disr_val {
encode_disr_val(ecx, ebml_w, vi[i].disr_val);
/* Encode def_ids for each field and method
for methods, write all the stuff get_trait_method
needs to know*/
- for f in struct_def.fields.iter() {
- match f.node.kind {
- named_field(ident, vis) => {
- ebml_w.start_tag(tag_item_field);
- encode_struct_field_family(ebml_w, vis);
- encode_name(ecx, ebml_w, ident);
- encode_def_id(ebml_w, local_def(f.node.id));
- ebml_w.end_tag();
- }
- unnamed_field => {
- ebml_w.start_tag(tag_item_unnamed_field);
- encode_def_id(ebml_w, local_def(f.node.id));
- ebml_w.end_tag();
- }
- }
- }
+ encode_struct_fields(ecx, ebml_w, struct_def);
// Encode inherent implementations for this structure.
encode_inherent_implementations(ecx, ebml_w, def_id);
if !found {
let rustpath = rust_path();
for path in rustpath.iter() {
- debug!("is %s in visited_dirs? %?",
- path.push("lib").to_str(),
- visited_dirs.contains(&path.push("lib").to_str()));
+ let tlib_path = make_rustpkg_target_lib_path(path, self.target_triple);
+ debug!("is %s in visited_dirs? %?", tlib_path.to_str(),
+ visited_dirs.contains(&tlib_path.to_str()));
- if !visited_dirs.contains(&path.push("lib").to_str()) {
- visited_dirs.insert(path.push("lib").to_str());
+ if !visited_dirs.contains(&tlib_path.to_str()) {
+ visited_dirs.insert(tlib_path.to_str());
// Don't keep searching the RUST_PATH if one match turns up --
// if we did, we'd get a "multiple matching crates" error
- match f(&path.push("lib")) {
+ match f(&tlib_path) {
FileMatches => {
break;
}
sysroot.push_rel(&relative_target_lib_path(target_triple))
}
+fn make_rustpkg_target_lib_path(dir: &Path,
+ target_triple: &str) -> Path {
+ dir.push_rel(&Path(libdir()).push(target_triple.to_owned()))
+}
+
fn get_or_default_sysroot() -> Path {
match os::self_exe_path() {
option::Some(ref p) => (*p).pop(),
ast::DefStatic(did, m) => { ast::DefStatic(did.tr(xcx), m) }
ast::DefArg(nid, b) => { ast::DefArg(xcx.tr_id(nid), b) }
ast::DefLocal(nid, b) => { ast::DefLocal(xcx.tr_id(nid), b) }
- ast::DefVariant(e_did, v_did) => {
- ast::DefVariant(e_did.tr(xcx), v_did.tr(xcx))
+ ast::DefVariant(e_did, v_did, is_s) => {
+ ast::DefVariant(e_did.tr(xcx), v_did.tr(xcx), is_s)
},
ast::DefTrait(did) => ast::DefTrait(did.tr(xcx)),
ast::DefTy(did) => ast::DefTy(did.tr(xcx)),
match def_map.find(&e.id) {
Some(&DefStatic(*)) |
Some(&DefFn(_, _)) |
- Some(&DefVariant(_, _)) |
+ Some(&DefVariant(_, _, _)) |
Some(&DefStruct(_)) => { }
Some(&def) => {
PatWild => { None }
PatIdent(_, _, _) | PatEnum(_, _) => {
match cx.tcx.def_map.find(&pat.id) {
- Some(&DefVariant(_, id)) => Some(variant(id)),
+ Some(&DefVariant(_, id, _)) => Some(variant(id)),
Some(&DefStatic(did, false)) => {
let const_expr = lookup_const_by_id(cx.tcx, did).unwrap();
Some(val(eval_const_expr(cx.tcx, const_expr)))
}
PatStruct(*) => {
match cx.tcx.def_map.find(&pat.id) {
- Some(&DefVariant(_, id)) => Some(variant(id)),
+ Some(&DefVariant(_, id, _)) => Some(variant(id)),
_ => Some(single)
}
}
PatWild => { true }
PatIdent(_, _, _) => {
match cx.tcx.def_map.find(&pat.id) {
- Some(&DefVariant(_, _)) | Some(&DefStatic(*)) => { false }
+ Some(&DefVariant(_, _, _)) | Some(&DefStatic(*)) => { false }
_ => { true }
}
}
}
PatIdent(_, _, _) => {
match cx.tcx.def_map.find(&pat_id) {
- Some(&DefVariant(_, id)) => {
+ Some(&DefVariant(_, id, _)) => {
if variant(id) == *ctor_id {
Some(r.tail().to_owned())
} else {
None
}
}
- DefVariant(_, id) if variant(id) == *ctor_id => {
+ DefVariant(_, id, _) if variant(id) == *ctor_id => {
let args = match args {
Some(args) => args,
None => vec::from_elem(arity, wild())
};
Some(vec::append(args, r.tail()))
}
- DefVariant(_, _) => None,
+ DefVariant(_, _, _) => None,
DefFn(*) |
DefStruct(*) => {
PatStruct(_, ref flds, _) => {
// Is this a struct or an enum variant?
match cx.tcx.def_map.get_copy(&pat_id) {
- DefVariant(_, variant_id) => {
+ DefVariant(_, variant_id, _) => {
if variant(variant_id) == *ctor_id {
// FIXME #4731: Is this right? --pcw
let args = flds.map(|ty_field| {
}
let args = class_fields.iter().map(|class_field| {
match flds.iter().find(|f|
- f.ident == class_field.ident) {
+ f.ident.name == class_field.name) {
Some(f) => f.pat,
_ => wild()
}
pub fn is_refutable(cx: &MatchCheckCtxt, pat: &Pat) -> bool {
match cx.tcx.def_map.find(&pat.id) {
- Some(&DefVariant(enum_id, _)) => {
+ Some(&DefVariant(enum_id, _, _)) => {
if ty::enum_variants(cx.tcx, enum_id).len() != 1u {
return true;
}
pub fn lookup_const(tcx: ty::ctxt, e: &Expr) -> Option<@Expr> {
match tcx.def_map.find(&e.id) {
Some(&ast::DefStatic(def_id, false)) => lookup_const_by_id(tcx, def_id),
- Some(&ast::DefVariant(enum_def, variant_def)) => lookup_variant_by_id(tcx,
+ Some(&ast::DefVariant(enum_def, variant_def, _)) => lookup_variant_by_id(tcx,
enum_def,
variant_def),
_ => None
fn visit_block(&mut self, block:&Block, _:()) {
let old_unsafe_context = self.context.unsafe_context;
- if block.rules == ast::UnsafeBlock &&
- self.context.unsafe_context == SafeContext {
+ let is_unsafe = match block.rules {
+ ast::UnsafeBlock(*) => true, ast::DefaultBlock => false
+ };
+ if is_unsafe && self.context.unsafe_context == SafeContext {
self.context.unsafe_context = UnsafeBlock(block.id)
}
match ex.node {
ExprPath(_) => {
match cx.tcx.def_map.get_copy(&ex.id) {
- DefVariant(edid, vdid) => {
+ DefVariant(edid, vdid, _) => {
ty::enum_variant_with_id(cx.tcx, edid, vdid).args.is_empty()
}
_ => false
fn visit_expr(&mut self, e:@ast::Expr, cx:@mut Context) {
match e.node {
- ast::ExprBlock(ref blk) if blk.rules == ast::UnsafeBlock => {
- if !cx.tcx.used_unsafe.contains(&blk.id) {
+ // Don't warn about generated blocks, that'll just pollute the
+ // output.
+ ast::ExprBlock(ref blk) => {
+ if blk.rules == ast::UnsafeBlock(ast::UserProvided) &&
+ !cx.tcx.used_unsafe.contains(&blk.id) {
cx.span_lint(unused_unsafe, blk.span,
"unnecessary `unsafe` block");
}
}
ast::PatEnum(_, Some(ref subpats)) => {
match self.tcx.def_map.find(&pat.id) {
- Some(&ast::DefVariant(enum_did, _)) => {
+ Some(&ast::DefVariant(enum_did, _, _)) => {
// variant(x, y, z)
let downcast_cmt = {
/// an enum to determine which variant is in use.
pub fn field_mutbl(tcx: ty::ctxt,
base_ty: ty::t,
+ // FIXME #6993: change type to Name
f_name: ast::Ident,
node_id: ast::NodeId)
-> Option<ast::Mutability> {
ty::ty_struct(did, _) => {
let r = ty::lookup_struct_fields(tcx, did);
for fld in r.iter() {
- if fld.ident == f_name {
+ if fld.name == f_name.name {
return Some(ast::MutImmutable);
}
}
}
ty::ty_enum(*) => {
match tcx.def_map.get_copy(&node_id) {
- ast::DefVariant(_, variant_id) => {
+ ast::DefVariant(_, variant_id, _) => {
let r = ty::lookup_struct_fields(tcx, variant_id);
for fld in r.iter() {
- if fld.ident == f_name {
+ if fld.name == f_name.name {
return Some(ast::MutImmutable);
}
}
}
// Checks that a private field is in scope.
+ // FIXME #6993: change type (and name) from Ident to Name
fn check_field(&mut self, span: Span, id: ast::DefId, ident: ast::Ident) {
let fields = ty::lookup_struct_fields(self.tcx, id);
for field in fields.iter() {
- if field.ident.name != ident.name { loop; }
+ if field.name != ident.name { loop; }
if field.vis == private {
self.tcx.sess.span_err(span, fmt!("field `%s` is private",
token::ident_to_str(&ident)));
// If the method is a default method, we need to use the def_id of
// the default implementation.
// Having to do this this is really unfortunate.
- let method_id = ty::method(self.tcx, method_id).provided_source
- .unwrap_or_default(method_id);
+ let method_id = ty::method(self.tcx, method_id).provided_source.unwrap_or(method_id);
if method_id.crate == LOCAL_CRATE {
let is_private = self.method_is_private(span, method_id.node);
if id.crate != LOCAL_CRATE ||
!self.privileged_items.iter().any(|x| x == &(id.node)) {
match self.tcx.def_map.get_copy(&expr.id) {
- DefVariant(_, variant_id) => {
+ DefVariant(_, variant_id, _) => {
for field in (*fields).iter() {
debug!("(privacy checking) \
checking field in \
if enum_id.crate != LOCAL_CRATE ||
!self.privileged_items.iter().any(|x| x == &enum_id.node) {
match self.tcx.def_map.find(&pattern.id) {
- Some(&DefVariant(_, variant_id)) => {
+ Some(&DefVariant(_, variant_id, _)) => {
for field in fields.iter() {
debug!("(privacy checking) \
checking field in \
variant.span);
child.define_value(privacy,
DefVariant(item_id,
- local_def(variant.node.id)),
+ local_def(variant.node.id), false),
variant.span);
}
struct_variant_kind(_) => {
variant.span);
child.define_type(privacy,
DefVariant(item_id,
- local_def(variant.node.id)),
+ local_def(variant.node.id), true),
variant.span);
self.structs.insert(local_def(variant.node.id));
}
match def {
DefMod(_) | DefForeignMod(_) => {}
- DefVariant(*) => {
+ DefVariant(_, variant_id, is_struct) => {
debug!("(building reduced graph for external crate) building \
variant %s",
final_ident);
// We assume the parent is visible, or else we wouldn't have seen
// it.
let privacy = variant_visibility_to_privacy(visibility, true);
- child_name_bindings.define_value(privacy, def, dummy_sp());
+ if is_struct {
+ child_name_bindings.define_type(privacy, def, dummy_sp());
+ self.structs.insert(variant_id);
+ }
+ else {
+ child_name_bindings.define_value(privacy, def, dummy_sp());
+ }
}
DefFn(*) | DefStaticMethod(*) | DefStatic(*) => {
debug!("(building reduced graph for external \
assert!(self.structs.contains(&class_id));
self.record_def(pattern.id, definition);
}
- Some(definition @ DefVariant(_, variant_id))
+ Some(definition @ DefVariant(_, variant_id, _))
if self.structs.contains(&variant_id) => {
self.record_def(pattern.id, definition);
}
let class_def = DefStruct(class_id);
self.record_def(expr.id, class_def);
}
- Some(definition @ DefVariant(_, class_id))
+ Some(definition @ DefVariant(_, class_id, _))
if self.structs.contains(&class_id) => {
self.record_def(expr.id, definition);
}
visit::walk_method_helper(&mut v, method, new_cx);
}
}
+ ast::item_trait(_, _, ref methods) => {
+ for method in methods.iter() {
+ match *method {
+ ast::provided(@ref method) => {
+ let safe_stack = fixed_stack_segment(method.attrs);
+ let new_cx = Context {safe_stack: safe_stack, ..in_cx};
+ visit::walk_method_helper(&mut v, method, new_cx);
+ }
+ ast::required(*) => ()
+ }
+ }
+ }
_ => {
visit::walk_item(&mut v, item, in_cx);
}
-> Opt {
let ccx = bcx.ccx();
match ccx.tcx.def_map.get_copy(&pat_id) {
- ast::DefVariant(enum_id, var_id) => {
+ ast::DefVariant(enum_id, var_id, _) => {
let variants = ty::enum_variants(ccx.tcx, enum_id);
for v in (*variants).iter() {
if var_id == v.id {
// Look up the struct variant ID.
let struct_id;
match tcx.def_map.get_copy(&p.id) {
- ast::DefVariant(_, found_struct_id) => {
+ ast::DefVariant(_, found_struct_id, _) => {
struct_id = found_struct_id;
}
_ => {
let r = ty::lookup_struct_fields(tcx, struct_id);
for field in r.iter() {
match field_pats.iter().find(|p| p.ident.name
- == field.ident.name) {
+ == field.name) {
None => reordered_patterns.push(dummy),
Some(fp) => reordered_patterns.push(fp.pat)
}
}
ast::PatEnum(_, ref sub_pats) => {
match bcx.tcx().def_map.find(&pat.id) {
- Some(&ast::DefVariant(enum_id, var_id)) => {
+ Some(&ast::DefVariant(enum_id, var_id, _)) => {
let repr = adt::represent_node(bcx, pat.id);
let vinfo = ty::enum_variant_with_id(ccx.tcx,
enum_id,
use syntax::print::pprust::stmt_to_str;
use syntax::{ast, ast_util, codemap, ast_map};
use syntax::abi::{X86, X86_64, Arm, Mips};
+use syntax::visit;
use syntax::visit::Visitor;
pub use middle::trans::context::task_llcx;
};
}
-pub fn invoke(bcx: @mut Block, llfn: ValueRef, llargs: ~[ValueRef])
+pub fn invoke(bcx: @mut Block, llfn: ValueRef, llargs: ~[ValueRef],
+ attributes: &[(uint, lib::llvm::Attribute)])
-> (ValueRef, @mut Block) {
let _icx = push_ctxt("invoke_");
if bcx.unreachable {
debug!("arg: %x", ::std::cast::transmute(llarg));
}
}
- let llresult = Call(bcx, llfn, llargs);
+ let llresult = Call(bcx, llfn, llargs, attributes);
return (llresult, bcx);
}
}
// Because we may have unwound across a stack boundary, we must call into
// the runtime to figure out which stack segment we are on and place the
// stack limit back into the TLS.
- Call(pad_bcx, bcx.ccx().upcalls.reset_stack_limit, []);
+ Call(pad_bcx, bcx.ccx().upcalls.reset_stack_limit, [], []);
// We store the retval in a function-central alloca, so that calls to
// Resume can find it.
let V_trace_str = PointerCast(bcx, V_trace_str, Type::i8p());
let V_filename = PointerCast(bcx, V_filename, Type::i8p());
let args = ~[V_trace_str, V_filename, C_int(ccx, V_line)];
- Call(bcx, ccx.upcalls.trace, args);
+ Call(bcx, ccx.upcalls.trace, args, []);
}
pub fn ignore_lhs(_bcx: @mut Block, local: &ast::Local) -> bool {
let size = IntCast(cx, n_bytes, ccx.int_type);
let align = C_i32(align as i32);
let volatile = C_i1(false);
- Call(cx, memcpy, [dst_ptr, src_ptr, size, align, volatile]);
+ Call(cx, memcpy, [dst_ptr, src_ptr, size, align, volatile], []);
}
pub fn memcpy_ty(bcx: @mut Block, dst: ValueRef, src: ValueRef, t: ty::t) {
let size = machine::llsize_of(ccx, ty);
let align = C_i32(llalign_of_min(ccx, ty) as i32);
let volatile = C_i1(false);
- b.call(llintrinsicfn, [llptr, llzeroval, size, align, volatile]);
+ b.call(llintrinsicfn, [llptr, llzeroval, size, align, volatile], []);
}
pub fn alloc_ty(bcx: @mut Block, t: ty::t, name: &str) -> ValueRef {
trans_struct_def(ccx, struct_def);
}
}
+ ast::item_trait(*) => {
+ // Inside of this trait definition, we won't be actually translating any
+ // functions, but the trait still needs to be walked. Otherwise default
+ // methods with items will not get translated and will cause ICE's when
+ // metadata time comes around.
+ let mut v = TransItemVisitor;
+ visit::walk_item(&mut v, item, ccx);
+ }
_ => {/* fall through */ }
}
}
llvm::LLVMGetParam(llfdecl, env_arg as c_uint)
};
let args = ~[llenvarg];
- Call(bcx, main_llfn, args);
+ Call(bcx, main_llfn, args, []);
finish_fn(fcx, bcx);
return llfdecl;
pub fn trap(bcx: @mut Block) {
match bcx.ccx().intrinsics.find_equiv(& &"llvm.trap") {
- Some(&x) => { Call(bcx, x, []); },
+ Some(&x) => { Call(bcx, x, [], []); },
_ => bcx.sess().bug("unbound llvm.trap in trap")
}
}
link_meta,
analysis.reachable);
+ if ccx.sess.opts.debuginfo {
+ debuginfo::initialize(ccx, crate);
+ }
+
{
let _icx = push_ctxt("text");
trans_mod(ccx, &crate.module);
B(cx).inline_asm_call(asm, cons, inputs, output, volatile, alignstack, dia)
}
-pub fn Call(cx: @mut Block, Fn: ValueRef, Args: &[ValueRef]) -> ValueRef {
+pub fn Call(cx: @mut Block, Fn: ValueRef, Args: &[ValueRef],
+ attributes: &[(uint, lib::llvm::Attribute)]) -> ValueRef {
if cx.unreachable { return _UndefReturn(cx, Fn); }
- B(cx).call(Fn, Args)
+ B(cx).call(Fn, Args, attributes)
}
-pub fn FastCall(cx: @mut Block, Fn: ValueRef, Args: &[ValueRef]) -> ValueRef {
+pub fn CallWithConv(cx: @mut Block, Fn: ValueRef, Args: &[ValueRef], Conv: CallConv,
+ attributes: &[(uint, lib::llvm::Attribute)]) -> ValueRef {
if cx.unreachable { return _UndefReturn(cx, Fn); }
- B(cx).call(Fn, Args)
-}
-
-pub fn CallWithConv(cx: @mut Block, Fn: ValueRef, Args: &[ValueRef],
- Conv: CallConv) -> ValueRef {
- if cx.unreachable { return _UndefReturn(cx, Fn); }
- B(cx).call_with_conv(Fn, Args, Conv)
+ B(cx).call_with_conv(Fn, Args, Conv, attributes)
}
pub fn AtomicFence(cx: @mut Block, order: AtomicOrdering) {
c, noname(), False, False)
}
};
- self.call(asm, []);
+ self.call(asm, [], []);
}
}
unsafe {
let v = llvm::LLVMInlineAsm(
fty.to_ref(), asm, cons, volatile, alignstack, dia as c_uint);
- self.call(v, inputs)
+ self.call(v, inputs, [])
}
}
- pub fn call(&self, llfn: ValueRef, args: &[ValueRef]) -> ValueRef {
+ pub fn call(&self, llfn: ValueRef, args: &[ValueRef],
+ attributes: &[(uint, lib::llvm::Attribute)]) -> ValueRef {
self.count_insn("call");
-
- debug!("Call(llfn=%s, args=%?)",
- self.ccx.tn.val_to_str(llfn),
- args.map(|arg| self.ccx.tn.val_to_str(*arg)));
-
- do args.as_imm_buf |ptr, len| {
- unsafe {
- llvm::LLVMBuildCall(self.llbuilder, llfn, ptr, len as c_uint, noname())
- }
- }
- }
-
- pub fn fastcall(&self, llfn: ValueRef, args: &[ValueRef]) -> ValueRef {
- self.count_insn("fastcall");
unsafe {
let v = llvm::LLVMBuildCall(self.llbuilder, llfn, vec::raw::to_ptr(args),
args.len() as c_uint, noname());
- lib::llvm::SetInstructionCallConv(v, lib::llvm::FastCallConv);
+ for &(idx, attr) in attributes.iter() {
+ llvm::LLVMAddInstrAttribute(v, idx as c_uint, attr as c_uint);
+ }
v
}
}
pub fn call_with_conv(&self, llfn: ValueRef, args: &[ValueRef],
- conv: CallConv) -> ValueRef {
+ conv: CallConv, attributes: &[(uint, lib::llvm::Attribute)]) -> ValueRef {
self.count_insn("callwithconv");
- unsafe {
- let v = llvm::LLVMBuildCall(self.llbuilder, llfn, vec::raw::to_ptr(args),
- args.len() as c_uint, noname());
- lib::llvm::SetInstructionCallConv(v, conv);
- v
- }
+ let v = self.call(llfn, args, attributes);
+ lib::llvm::SetInstructionCallConv(v, conv);
+ v
}
pub fn select(&self, cond: ValueRef, then_val: ValueRef, else_val: ValueRef) -> ValueRef {
trait_did,
ref_expr.id))
}
- ast::DefVariant(tid, vid) => {
+ ast::DefVariant(tid, vid, _) => {
// nullary variants are not callable
assert!(ty::enum_variant_with_id(bcx.tcx(),
tid,
}
// Invoke the actual rust fn and update bcx/llresult.
- let (llret, b) = base::invoke(bcx, llfn, llargs);
+ let (llret, b) = base::invoke(bcx, llfn, llargs, []);
bcx = b;
llresult = llret;
impl get_node_info for Option<@ast::Expr> {
fn info(&self) -> Option<NodeInfo> {
- self.chain_ref(|s| s.info())
+ self.and_then_ref(|s| s.info())
}
}
Some(&ast::DefStatic(def_id, false)) => {
get_const_val(cx, def_id)
}
- Some(&ast::DefVariant(enum_did, variant_did)) => {
+ Some(&ast::DefVariant(enum_did, variant_did, _)) => {
let ety = ty::expr_ty(cx.tcx, e);
let repr = adt::represent_type(cx, ety);
let vinfo = ty::enum_variant_with_id(cx.tcx,
let arg_vals = args.map(|a| const_expr(cx, *a));
adt::trans_const(cx, repr, 0, arg_vals)
}
- Some(&ast::DefVariant(enum_did, variant_did)) => {
+ Some(&ast::DefVariant(enum_did, variant_did, _)) => {
let ety = ty::expr_ty(cx.tcx, e);
let repr = adt::represent_type(cx, ety);
let vinfo = ty::enum_variant_with_id(cx.tcx,
2. Module-internal metadata creation functions
3. Minor utility functions
+
+## Recursive Types
+Some kinds of types, such as structs and enums can be recursive. That means that the type definition
+of some type X refers to some other type which in turn (transitively) refers to X. This introduces
+cycles into the type referral graph. A naive algorithm doing an on-demand, depth-first traversal of
+this graph when describing types, can get trapped in an endless loop when it reaches such a cycle.
+
+For example, the following simple type for a singly-linked list...
+
+```
+struct List {
+ value: int,
+ tail: Option<@List>,
+}
+```
+
+will generate the following callstack with a naive DFS algorithm:
+
+```
+describe(t = List)
+ describe(t = int)
+ describe(t = Option<@List>)
+ describe(t = @List)
+ describe(t = List) // at the beginning again...
+ ...
+```
+
+To break cycles like these, we use "forward declarations". That is, when the algorithm encounters a
+possibly recursive type (any struct or enum), it immediately creates a type description node and
+inserts it into the cache *before* describing the members of the type. This type description is just
+a stub (as type members are not described and added to it yet) but it allows the algorithm to
+already refer to the type. After the stub is inserted into the cache, the algorithm continues as
+before. If it now encounters a recursive reference, it will hit the cache and does not try to
+describe the type anew.
+
+This behaviour is encapsulated in the 'RecursiveTypeDescription' enum, which represents a kind of
+continuation, storing all state needed to continue traversal at the type members after the type has
+been registered with the cache. (This implementation approach might be a tad over-engineered and
+may change in the future)
+
*/
use middle::trans;
use middle::ty;
use middle::pat_util;
-use util::ppaux::ty_to_str;
+use util::ppaux;
use std::c_str::ToCStr;
use std::hashmap::HashMap;
use std::ptr;
use std::vec;
use syntax::codemap::Span;
-use syntax::{ast, codemap, ast_util, ast_map, opt_vec};
+use syntax::{ast, codemap, ast_util, ast_map, opt_vec, visit};
use syntax::parse::token;
use syntax::parse::token::special_idents;
static DW_ATE_unsigned: c_uint = 0x07;
static DW_ATE_unsigned_char: c_uint = 0x08;
-
-
-
//=-------------------------------------------------------------------------------------------------
// Public Interface of debuginfo module
//=-------------------------------------------------------------------------------------------------
priv crate_file: ~str,
priv llcontext: ContextRef,
priv builder: DIBuilderRef,
- priv curr_loc: DebugLocation,
+ priv current_debug_location: DebugLocation,
priv created_files: HashMap<~str, DIFile>,
priv created_types: HashMap<uint, DIType>,
+ priv local_namespace_map: HashMap<ast::NodeId, @NamespaceTreeNode>,
+ priv extern_namespaces: HashMap<~[ast::Ident], @NamespaceTreeNode>,
}
impl CrateDebugContext {
crate_file: crate,
llcontext: llcontext,
builder: builder,
- curr_loc: UnknownLocation,
+ current_debug_location: UnknownLocation,
created_files: HashMap::new(),
created_types: HashMap::new(),
+ local_namespace_map: HashMap::new(),
+ extern_namespaces: HashMap::new(),
};
}
}
match *self {
FunctionDebugContext(~ref data) => data,
DebugInfoDisabled => {
- cx.sess.span_bug(span, "debuginfo: Error trying to access FunctionDebugContext \
- although debug info is disabled!");
+ cx.sess.span_bug(span, FunctionDebugContext::debuginfo_disabled_message());
}
FunctionWithoutDebugInfo => {
- cx.sess.span_bug(span, "debuginfo: Error trying to access FunctionDebugContext \
- for function that should be ignored by debug info!");
+ cx.sess.span_bug(span, FunctionDebugContext::should_be_ignored_message());
}
}
}
match *self {
FunctionDebugContext(~ref mut data) => data,
DebugInfoDisabled => {
- cx.sess.span_bug(span, "debuginfo: Error trying to access FunctionDebugContext \
- although debug info is disabled!");
+ cx.sess.span_bug(span, FunctionDebugContext::debuginfo_disabled_message());
}
FunctionWithoutDebugInfo => {
- cx.sess.span_bug(span, "debuginfo: Error trying to access FunctionDebugContext \
- for function that should be ignored by debug info!");
+ cx.sess.span_bug(span, FunctionDebugContext::should_be_ignored_message());
}
}
}
+
+ fn debuginfo_disabled_message() -> &'static str {
+ "debuginfo: Error trying to access FunctionDebugContext although debug info is disabled!"
+ }
+
+ fn should_be_ignored_message() -> &'static str {
+ "debuginfo: Error trying to access FunctionDebugContext for function that should be \
+ ignored by debug info!"
+ }
}
struct FunctionDebugContextData {
CapturedVariable,
}
+pub fn initialize(cx: &mut CrateContext, crate: &ast::Crate) {
+ if cx.dbg_cx.is_none() {
+ return;
+ }
+
+ let crate_namespace_ident = token::str_to_ident(cx.link_meta.name);
+ let mut visitor = NamespaceVisitor::new_crate_visitor(cx, crate_namespace_ident);
+ visit::walk_crate(&mut visitor, crate, ());
+}
+
/// Create any deferred debug metadata nodes
pub fn finalize(cx: @mut CrateContext) {
+ if cx.dbg_cx.is_none() {
+ return;
+ }
+
debug!("finalize");
compile_unit_metadata(cx);
unsafe {
ast_map::node_item(ref item, _) => {
match item.node {
ast::item_fn(ref fn_decl, _, _, ref generics, ref top_level_block) => {
- (item.ident, fn_decl, generics, Some(top_level_block), item.span)
+ (item.ident, fn_decl, generics, top_level_block, item.span)
}
_ => {
cx.sess.span_bug(item.span,
},
_,
_) => {
- (ident, fn_decl, generics, Some(top_level_block), span)
+ (ident, fn_decl, generics, top_level_block, span)
}
ast_map::node_expr(ref expr) => {
match expr.node {
// This is not quite right. It should actually inherit the generics of the
// enclosing function.
&empty_generics,
- Some(top_level_block),
+ top_level_block,
expr.span)
}
_ => cx.sess.span_bug(expr.span,
}),
_,
_) => {
- (ident, fn_decl, generics, Some(top_level_block), span)
- }
- ast_map::node_foreign_item(@ast::foreign_item {
- ident: ident,
- node: ast::foreign_item_fn(ref fn_decl, ref generics),
- span: span,
- _
- },
- _,
- _,
- _) => {
- (ident, fn_decl, generics, None, span)
+ (ident, fn_decl, generics, top_level_block, span)
}
- ast_map::node_variant(*) |
+ ast_map::node_foreign_item(@ast::foreign_item { _ }, _, _, _) |
+ ast_map::node_variant(*) |
ast_map::node_struct_ctor(*) => {
return FunctionWithoutDebugInfo;
}
let file_metadata = file_metadata(cx, loc.file.name);
let function_type_metadata = unsafe {
- let fn_signature = get_function_signature(cx, fn_ast_id, fn_decl, param_substs);
+ let fn_signature = get_function_signature(cx, fn_ast_id, fn_decl, param_substs, span);
llvm::LLVMDIBuilderCreateSubroutineType(DIB(cx), file_metadata, fn_signature)
};
// get_template_parameters() will append a `<...>` clause to the function name if necessary.
- let mut function_name = cx.sess.str_of(ident).to_owned();
- let template_parameters = if cx.sess.opts.extra_debuginfo {
- get_template_parameters(cx, generics, param_substs, file_metadata, &mut function_name)
- } else {
- ptr::null()
+ let mut function_name = token::ident_to_str(&ident).to_owned();
+ let template_parameters = get_template_parameters(cx,
+ generics,
+ param_substs,
+ file_metadata,
+ &mut function_name);
+
+ let namespace_node = debug_context(cx).local_namespace_map.find_copy(&fn_ast_id);
+ let (linkage_name, containing_scope) = match namespace_node {
+ Some(namespace_node) => {
+ (namespace_node.mangled_name_of_contained_item(function_name), namespace_node.scope)
+ }
+ None => {
+ // This branch is only hit when there is a bug in the NamespaceVisitor.
+ cx.sess.span_warn(span, fmt!("debuginfo: Could not find namespace node for function
+ with name %s. This is a bug! Please report this to
+ github.com/mozilla/rust/issues", function_name));
+ (function_name.clone(), file_metadata)
+ }
};
let scope_line = get_scope_line(cx, top_level_block, loc.line);
- let fn_metadata = do function_name.to_c_str().with_ref |function_name| {
+ let fn_metadata = do function_name.with_c_str |function_name| {
+ do linkage_name.with_c_str |linkage_name| {
unsafe {
llvm::LLVMDIBuilderCreateFunction(
DIB(cx),
- file_metadata,
- function_name,
+ containing_scope,
function_name,
+ linkage_name,
file_metadata,
loc.line as c_uint,
function_type_metadata,
template_parameters,
ptr::null())
}
- };
+ }};
- // Initialize fn debug context (including scope map)
+ // Initialize fn debug context (including scope map and namespace map)
let mut fn_debug_context = ~FunctionDebugContextData {
scope_map: HashMap::new(),
fn_metadata: fn_metadata,
let arg_pats = do fn_decl.inputs.map |arg_ref| { arg_ref.pat };
populate_scope_map(cx, arg_pats, top_level_block, fn_metadata, &mut fn_debug_context.scope_map);
+ // Create namespaces for the interior of this function
+ {
+ let mut namespace_visitor = NamespaceVisitor::new_function_visitor(cx,
+ function_name,
+ namespace_node,
+ file_metadata,
+ span);
+ visit::walk_block(&mut namespace_visitor, top_level_block, ());
+ }
+
return FunctionDebugContext(fn_debug_context);
fn get_function_signature(cx: &mut CrateContext,
fn_ast_id: ast::NodeId,
fn_decl: &ast::fn_decl,
- param_substs: Option<@param_substs>) -> DIArray {
+ param_substs: Option<@param_substs>,
+ error_span: Span) -> DIArray {
if !cx.sess.opts.extra_debuginfo {
return create_DIArray(DIB(cx), []);
}
signature.push(ptr::null());
}
_ => {
+ assert_type_for_node_id(cx, fn_ast_id, error_span);
+
let return_type = ty::node_id_to_type(cx.tcx, fn_ast_id);
let return_type = match param_substs {
None => return_type,
}
}
- // arguments types
+ // Arguments types
for arg in fn_decl.inputs.iter() {
+ assert_type_for_node_id(cx, arg.pat.id, arg.pat.span);
let arg_type = ty::node_id_to_type(cx.tcx, arg.pat.id);
let arg_type = match param_substs {
None => arg_type,
let has_self_type = self_type.is_some();
if !generics.is_type_parameterized() && !has_self_type {
- return ptr::null();
+ return create_DIArray(DIB(cx), []);
}
name_to_append_suffix_to.push_char('<');
// Handle self type
if has_self_type {
let actual_self_type = self_type.unwrap();
- let actual_self_type_metadata = type_metadata(cx,
- actual_self_type,
- codemap::dummy_sp());
-
// Add self type name to <...> clause of function name
- let actual_self_type_name = ty_to_str(cx.tcx, actual_self_type);
+ let actual_self_type_name = ppaux::ty_to_str(cx.tcx, actual_self_type);
name_to_append_suffix_to.push_str(actual_self_type_name);
+
if generics.is_type_parameterized() {
name_to_append_suffix_to.push_str(",");
}
- let ident = special_idents::type_self;
-
- let param_metadata = do cx.sess.str_of(ident).to_c_str().with_ref |name| {
- unsafe {
- llvm::LLVMDIBuilderCreateTemplateTypeParameter(
- DIB(cx),
- file_metadata,
- name,
- actual_self_type_metadata,
- ptr::null(),
- 0,
- 0)
- }
- };
+ // Only create type information if extra_debuginfo is enabled
+ if cx.sess.opts.extra_debuginfo {
+ let actual_self_type_metadata = type_metadata(cx,
+ actual_self_type,
+ codemap::dummy_sp());
+
+ let ident = special_idents::type_self;
+
+ let param_metadata = do token::ident_to_str(&ident).to_c_str().with_ref |name| {
+ unsafe {
+ llvm::LLVMDIBuilderCreateTemplateTypeParameter(
+ DIB(cx),
+ file_metadata,
+ name,
+ actual_self_type_metadata,
+ ptr::null(),
+ 0,
+ 0)
+ }
+ };
- template_params.push(param_metadata);
+ template_params.push(param_metadata);
+ }
}
// Handle other generic parameters
for (index, &ast::TyParam{ ident: ident, _ }) in generics.ty_params.iter().enumerate() {
let actual_type = actual_types[index];
- let actual_type_metadata = type_metadata(cx, actual_type, codemap::dummy_sp());
-
// Add actual type name to <...> clause of function name
- let actual_type_name = ty_to_str(cx.tcx, actual_type);
+ let actual_type_name = ppaux::ty_to_str(cx.tcx, actual_type);
name_to_append_suffix_to.push_str(actual_type_name);
if index != generics.ty_params.len() - 1 {
name_to_append_suffix_to.push_str(",");
}
- let param_metadata = do cx.sess.str_of(ident).to_c_str().with_ref |name| {
- unsafe {
- llvm::LLVMDIBuilderCreateTemplateTypeParameter(
- DIB(cx),
- file_metadata,
- name,
- actual_type_metadata,
- ptr::null(),
- 0,
- 0)
- }
- };
-
- template_params.push(param_metadata);
+ // Again, only create type information if extra_debuginfo is enabled
+ if cx.sess.opts.extra_debuginfo {
+ let actual_type_metadata = type_metadata(cx, actual_type, codemap::dummy_sp());
+ let param_metadata = do token::ident_to_str(&ident).to_c_str().with_ref |name| {
+ unsafe {
+ llvm::LLVMDIBuilderCreateTemplateTypeParameter(
+ DIB(cx),
+ file_metadata,
+ name,
+ actual_type_metadata,
+ ptr::null(),
+ 0,
+ 0)
+ }
+ };
+ template_params.push(param_metadata);
+ }
}
name_to_append_suffix_to.push_char('>');
}
fn get_scope_line(cx: &CrateContext,
- top_level_block: Option<&ast::Block>,
+ top_level_block: &ast::Block,
default: uint)
-> uint {
- match top_level_block {
- Some(&ast::Block { stmts: ref statements, _ }) if statements.len() > 0 => {
+ match *top_level_block {
+ ast::Block { stmts: ref statements, _ } if statements.len() > 0 => {
span_start(cx, statements[0].span).line
}
- Some(&ast::Block { expr: Some(@ref expr), _ }) => {
+ ast::Block { expr: Some(@ref expr), _ } => {
span_start(cx, expr.span).line
}
_ => default
}
fn compile_unit_metadata(cx: @mut CrateContext) {
- let dcx = dbg_cx(cx);
+ let dcx = debug_context(cx);
let crate_name: &str = dcx.crate_file;
debug!("compile_unit_metadata: %?", crate_name);
let filename = span_start(cx, span).file.name;
let file_metadata = file_metadata(cx, filename);
- let name: &str = cx.sess.str_of(variable_ident);
+ let name: &str = token::ident_to_str(&variable_ident);
let loc = span_start(cx, span);
let type_metadata = type_metadata(cx, variable_type, span);
assert!(!bcx.fcx.debug_context.get_ref(cx, span).source_locations_enabled);
set_debug_location(cx, UnknownLocation);
}
- _ => { /* fallthrough */ }
+ _ => { /* nothing to do */ }
}
}
fn file_metadata(cx: &mut CrateContext, full_path: &str) -> DIFile {
- match dbg_cx(cx).created_files.find_equiv(&full_path) {
+ match debug_context(cx).created_files.find_equiv(&full_path) {
Some(file_metadata) => return *file_metadata,
None => ()
}
}
}};
- dbg_cx(cx).created_files.insert(full_path.to_owned(), file_metadata);
+ debug_context(cx).created_files.insert(full_path.to_owned(), file_metadata);
return file_metadata;
}
-> DIType {
let pointer_llvm_type = type_of::type_of(cx, pointer_type);
let (pointer_size, pointer_align) = size_and_align_of(cx, pointer_llvm_type);
- let name = ty_to_str(cx.tcx, pointer_type);
+ let name = ppaux::ty_to_str(cx.tcx, pointer_type);
let ptr_metadata = do name.with_c_str |name| {
unsafe {
llvm::LLVMDIBuilderCreatePointerType(
return ptr_metadata;
}
-fn struct_metadata(cx: &mut CrateContext,
- struct_type: ty::t,
- fields: ~[ty::field],
- span: Span)
- -> DICompositeType {
- let struct_name = ty_to_str(cx.tcx, struct_type);
- debug!("struct_metadata: %s", struct_name);
-
+fn prepare_struct_metadata(cx: &mut CrateContext,
+ struct_type: ty::t,
+ def_id: ast::DefId,
+ substs: &ty::substs,
+ span: Span)
+ -> RecursiveTypeDescription {
+ let struct_name = ppaux::ty_to_str(cx.tcx, struct_type);
let struct_llvm_type = type_of::type_of(cx, struct_type);
- let field_llvm_types = do fields.map |field| { type_of::type_of(cx, field.mt.ty) };
- let field_names = do fields.map |field| {
- if field.ident.name == special_idents::unnamed_field.name {
- ~""
- } else {
- cx.sess.str_of(field.ident).to_owned()
- }
- };
- let field_types_metadata = do fields.map |field| {
- type_metadata(cx, field.mt.ty, span)
- };
+ let (containing_scope, definition_span) = get_namespace_and_span_for_item(cx, def_id, span);
+
+ let file_name = span_start(cx, definition_span).file.name;
+ let file_metadata = file_metadata(cx, file_name);
+
+ let struct_metadata_stub = create_struct_stub(cx,
+ struct_llvm_type,
+ struct_name,
+ containing_scope,
+ file_metadata,
+ definition_span);
+
+ let fields = ty::struct_fields(cx.tcx, def_id, substs);
+
+ UnfinishedMetadata {
+ cache_id: cache_id_for_type(struct_type),
+ metadata_stub: struct_metadata_stub,
+ llvm_type: struct_llvm_type,
+ file_metadata: file_metadata,
+ member_description_factory: |cx| {
+ do fields.map |field| {
+ let name = if field.ident.name == special_idents::unnamed_field.name {
+ @""
+ } else {
+ token::ident_to_str(&field.ident)
+ };
- return composite_type_metadata(
- cx,
- struct_llvm_type,
- struct_name,
- field_llvm_types,
- field_names,
- field_types_metadata,
- span);
+ MemberDescription {
+ name: name,
+ llvm_type: type_of::type_of(cx, field.mt.ty),
+ type_metadata: type_metadata(cx, field.mt.ty, span),
+ offset: ComputedMemberOffset,
+ }
+ }
+ }
+ }
}
-fn tuple_metadata(cx: &mut CrateContext,
- tuple_type: ty::t,
- component_types: &[ty::t],
- span: Span)
- -> DICompositeType {
+enum RecursiveTypeDescription {
+ UnfinishedMetadata {
+ cache_id: uint,
+ metadata_stub: DICompositeType,
+ llvm_type: Type,
+ file_metadata: DIFile,
+ member_description_factory: @fn(cx: &mut CrateContext) -> ~[MemberDescription],
+ },
+ FinalMetadata(DICompositeType)
+}
- let tuple_name = ty_to_str(cx.tcx, tuple_type);
- let tuple_llvm_type = type_of::type_of(cx, tuple_type);
+impl RecursiveTypeDescription {
- let component_names = do component_types.map |_| { ~"" };
- let component_llvm_types = do component_types.map |it| { type_of::type_of(cx, *it) };
- let component_types_metadata = do component_types.map |it| {
- type_metadata(cx, *it, span)
- };
+ fn metadata(&self) -> DICompositeType {
+ match *self {
+ UnfinishedMetadata { metadata_stub, _ } => metadata_stub,
+ FinalMetadata(metadata) => metadata
+ }
+ }
- return composite_type_metadata(
- cx,
- tuple_llvm_type,
- tuple_name,
- component_llvm_types,
- component_names,
- component_types_metadata,
- span);
+ fn finalize(&self, cx: &mut CrateContext) -> DICompositeType {
+ match *self {
+ FinalMetadata(metadata) => metadata,
+ UnfinishedMetadata {
+ cache_id,
+ metadata_stub,
+ llvm_type,
+ file_metadata,
+ member_description_factory
+ } => {
+ // Insert the stub into the cache in order to allow recursive references ...
+ debug_context(cx).created_types.insert(cache_id, metadata_stub);
+
+ // ... then create the member descriptions ...
+ let member_descriptions = member_description_factory(cx);
+
+ // ... and attach them to the stub to complete it.
+ set_members_of_composite_type(cx,
+ metadata_stub,
+ llvm_type,
+ member_descriptions,
+ file_metadata,
+ codemap::dummy_sp());
+ return metadata_stub;
+ }
+ }
+ }
}
-fn enum_metadata(cx: &mut CrateContext,
- enum_type: ty::t,
- enum_def_id: ast::DefId,
- span: Span)
- -> DIType {
+fn prepare_tuple_metadata(cx: &mut CrateContext,
+ tuple_type: ty::t,
+ component_types: &[ty::t],
+ span: Span)
+ -> RecursiveTypeDescription {
+ let tuple_name = ppaux::ty_to_str(cx.tcx, tuple_type);
+ let tuple_llvm_type = type_of::type_of(cx, tuple_type);
+
+ let loc = span_start(cx, span);
+ let file_metadata = file_metadata(cx, loc.file.name);
+ // Needs to be copied for closure below :(
+ let component_types = component_types.to_owned();
+
+ UnfinishedMetadata {
+ cache_id: cache_id_for_type(tuple_type),
+ metadata_stub: create_struct_stub(cx,
+ tuple_llvm_type,
+ tuple_name,
+ file_metadata,
+ file_metadata,
+ span),
+ llvm_type: tuple_llvm_type,
+ file_metadata: file_metadata,
+ member_description_factory: |cx| {
+ do component_types.map |&component_type| {
+ MemberDescription {
+ name: @"",
+ llvm_type: type_of::type_of(cx, component_type),
+ type_metadata: type_metadata(cx, component_type, span),
+ offset: ComputedMemberOffset,
+ }
+ }
+ }
+ }
+}
- let enum_name = ty_to_str(cx.tcx, enum_type);
+fn prepare_enum_metadata(cx: &mut CrateContext,
+ enum_type: ty::t,
+ enum_def_id: ast::DefId,
+ span: Span)
+ -> RecursiveTypeDescription {
+ let enum_name = ppaux::ty_to_str(cx.tcx, enum_type);
+
+ let (containing_scope, definition_span) = get_namespace_and_span_for_item(cx,
+ enum_def_id,
+ span);
+ let loc = span_start(cx, definition_span);
+ let file_metadata = file_metadata(cx, loc.file.name);
// For empty enums there is an early exit. Just describe it as an empty struct with the
// appropriate type name
if ty::type_is_empty(cx.tcx, enum_type) {
- return composite_type_metadata(cx, Type::nil(), enum_name, [], [], [], span);
+ let empty_type_metadata = composite_type_metadata(cx,
+ Type::nil(),
+ enum_name,
+ [],
+ containing_scope,
+ file_metadata,
+ definition_span);
+
+ return FinalMetadata(empty_type_metadata);
}
- // Prepare some data (llvm type, size, align, ...) about the discriminant. This data will be
+ // Prepare some data (llvm type, size, align, etc) about the discriminant. This data will be
// needed in all of the following cases.
let discriminant_llvm_type = Type::enum_discrim(cx);
let (discriminant_size, discriminant_align) = size_and_align_of(cx, discriminant_llvm_type);
assert!(Type::enum_discrim(cx) == cx.int_type);
- let discriminant_type_metadata = type_metadata(cx, ty::mk_int(), span);
+ let discriminant_base_type_metadata = type_metadata(cx, ty::mk_int(), codemap::dummy_sp());
- let variants: &[@ty::VariantInfo] = *ty::enum_variants(cx.tcx, enum_def_id);
+ let variants = ty::enum_variants(cx.tcx, enum_def_id);
let enumerators_metadata: ~[DIDescriptor] = variants
.iter()
.map(|v| {
- let name: &str = cx.sess.str_of(v.name);
+ let name: &str = token::ident_to_str(&v.name);
let discriminant_value = v.disr_val as c_ulonglong;
do name.with_c_str |name| {
})
.collect();
- let loc = span_start(cx, span);
- let file_metadata = file_metadata(cx, loc.file.name);
-
let discriminant_type_metadata = do enum_name.with_c_str |enum_name| {
unsafe {
llvm::LLVMDIBuilderCreateEnumerationType(
DIB(cx),
- file_metadata,
+ containing_scope,
enum_name,
file_metadata,
loc.line as c_uint,
bytes_to_bits(discriminant_size),
bytes_to_bits(discriminant_align),
create_DIArray(DIB(cx), enumerators_metadata),
- discriminant_type_metadata)
+ discriminant_base_type_metadata)
}
};
let type_rep = adt::represent_type(cx, enum_type);
- match *type_rep {
+ return match *type_rep {
adt::CEnum(*) => {
- return discriminant_type_metadata;
+ FinalMetadata(discriminant_type_metadata)
}
adt::Univariant(ref struct_def, _) => {
assert!(variants.len() == 1);
- return adt_struct_metadata(cx, struct_def, variants[0], None, span);
+ let (metadata_stub,
+ variant_llvm_type,
+ member_description_factory) = describe_variant(cx,
+ struct_def,
+ variants[0],
+ None,
+ containing_scope,
+ file_metadata,
+ span);
+ UnfinishedMetadata {
+ cache_id: cache_id_for_type(enum_type),
+ metadata_stub: metadata_stub,
+ llvm_type: variant_llvm_type,
+ file_metadata: file_metadata,
+ member_description_factory: member_description_factory
+ }
}
- adt::General(ref struct_defs) => {
- let variants_member_metadata: ~[DIDescriptor] = do struct_defs
- .iter()
- .enumerate()
- .map |(i, struct_def)| {
- let variant_type_metadata = adt_struct_metadata(
- cx,
- struct_def,
- variants[i],
- Some(discriminant_type_metadata),
- span);
-
- do "".with_c_str |name| {
- unsafe {
- llvm::LLVMDIBuilderCreateMemberType(
- DIB(cx),
- file_metadata,
- name,
- file_metadata,
- loc.line as c_uint,
- bytes_to_bits(struct_def.size as uint),
- bytes_to_bits(struct_def.align as uint),
- bytes_to_bits(0),
- 0,
- variant_type_metadata)
- }
- }
- }.collect();
-
+ adt::General(_) => {
let enum_llvm_type = type_of::type_of(cx, enum_type);
let (enum_type_size, enum_type_align) = size_and_align_of(cx, enum_llvm_type);
- return do enum_name.with_c_str |enum_name| {
+ let enum_metadata = do enum_name.with_c_str |enum_name| {
unsafe {
llvm::LLVMDIBuilderCreateUnionType(
DIB(cx),
- file_metadata,
+ containing_scope,
enum_name,
file_metadata,
loc.line as c_uint,
bytes_to_bits(enum_type_size),
bytes_to_bits(enum_type_align),
0, // Flags
- create_DIArray(DIB(cx), variants_member_metadata),
+ ptr::null(),
0) // RuntimeLang
}};
+
+ UnfinishedMetadata {
+ cache_id: cache_id_for_type(enum_type),
+ metadata_stub: enum_metadata,
+ llvm_type: enum_llvm_type,
+ file_metadata: file_metadata,
+ member_description_factory: |cx| {
+ // Capture type_rep, so we don't have to copy the struct_defs array
+ let struct_defs = match *type_rep {
+ adt::General(ref struct_defs) => struct_defs,
+ _ => cx.sess.bug("unreachable")
+ };
+
+ do struct_defs
+ .iter()
+ .enumerate()
+ .map |(i, struct_def)| {
+ let (variant_type_metadata, variant_llvm_type, member_desc_factory) =
+ describe_variant(cx,
+ struct_def,
+ variants[i],
+ Some(discriminant_type_metadata),
+ containing_scope,
+ file_metadata,
+ span);
+
+ let member_descriptions = member_desc_factory(cx);
+
+ set_members_of_composite_type(cx,
+ variant_type_metadata,
+ variant_llvm_type,
+ member_descriptions,
+ file_metadata,
+ codemap::dummy_sp());
+ MemberDescription {
+ name: @"",
+ llvm_type: variant_llvm_type,
+ type_metadata: variant_type_metadata,
+ offset: FixedMemberOffset { bytes: 0 },
+ }
+ }.collect()
+ }
+ }
}
adt::NullablePointer { nonnull: ref struct_def, nndiscr, _ } => {
- return adt_struct_metadata(cx, struct_def, variants[nndiscr], None, span);
+ let (metadata_stub,
+ variant_llvm_type,
+ member_description_factory) = describe_variant(cx,
+ struct_def,
+ variants[nndiscr],
+ None,
+ containing_scope,
+ file_metadata,
+ span);
+ UnfinishedMetadata {
+ cache_id: cache_id_for_type(enum_type),
+ metadata_stub: metadata_stub,
+ llvm_type: variant_llvm_type,
+ file_metadata: file_metadata,
+ member_description_factory: member_description_factory
+ }
}
- }
+ };
- fn adt_struct_metadata(cx: &mut CrateContext,
- struct_def: &adt::Struct,
- variant_info: &ty::VariantInfo,
- discriminant_type_metadata: Option<DIType>,
- span: Span)
- -> DICompositeType
- {
- let arg_llvm_types: ~[Type] = do struct_def.fields.map |&ty| { type_of::type_of(cx, ty) };
- let arg_metadata: ~[DIType] = do struct_def.fields.iter().enumerate()
- .map |(i, &ty)| {
- match discriminant_type_metadata {
- Some(metadata) if i == 0 => metadata,
- _ => type_metadata(cx, ty, span)
+ fn describe_variant(cx: &mut CrateContext,
+ struct_def: &adt::Struct,
+ variant_info: &ty::VariantInfo,
+ discriminant_type_metadata: Option<DIType>,
+ containing_scope: DIScope,
+ file_metadata: DIFile,
+ span: Span)
+ -> (DICompositeType, Type, @fn(&mut CrateContext) -> ~[MemberDescription]) {
+ let variant_name = token::ident_to_str(&variant_info.name);
+ let variant_llvm_type = Type::struct_(struct_def.fields.map(|&t| type_of::type_of(cx, t)),
+ struct_def.packed);
+ // Could some consistency checks here: size, align, field count, discr type
+
+ // Find the source code location of the variant's definition
+ let variant_definition_span = if variant_info.id.crate == ast::LOCAL_CRATE {
+ match cx.tcx.items.find(&variant_info.id.node) {
+ Some(&ast_map::node_variant(ref variant, _, _)) => variant.span,
+ ref node => {
+ cx.sess.span_warn(span,
+ fmt!("debuginfo::enum_metadata()::adt_struct_metadata() - Unexpected node \
+ type: %?. This is a bug.", node));
+ codemap::dummy_sp()
}
- }.collect();
+ }
+ } else {
+ // For definitions from other crates we have no location information available.
+ codemap::dummy_sp()
+ };
+
+ let metadata_stub = create_struct_stub(cx,
+ variant_llvm_type,
+ variant_name,
+ containing_scope,
+ file_metadata,
+ variant_definition_span);
+ // Get the argument names from the enum variant info
let mut arg_names = match variant_info.arg_names {
- Some(ref names) => do names.map |ident| { cx.sess.str_of(*ident).to_owned() },
- None => do variant_info.args.map |_| { ~"" }
+ Some(ref names) => do names.map |ident| { token::ident_to_str(ident) },
+ None => do variant_info.args.map |_| { @"" }
};
+ // If this is not a univariant enum, there is also the (unnamed) discriminant field
if discriminant_type_metadata.is_some() {
- arg_names.insert(0, ~"");
+ arg_names.insert(0, @"");
}
- let variant_llvm_type = Type::struct_(arg_llvm_types, struct_def.packed);
- let variant_name: &str = cx.sess.str_of(variant_info.name);
+ // Build an array of (field name, field type) pairs to be captured in the factory closure.
+ let args: ~[(@str, ty::t)] = arg_names.iter()
+ .zip(struct_def.fields.iter())
+ .map(|(&s, &t)| (s, t))
+ .collect();
+
+ let member_description_factory: @fn(cx: &mut CrateContext) -> ~[MemberDescription] = |cx| {
+ do args.iter().enumerate().map |(i, &(name, ty))| {
+ MemberDescription {
+ name: name,
+ llvm_type: type_of::type_of(cx, ty),
+ type_metadata: match discriminant_type_metadata {
+ Some(metadata) if i == 0 => metadata,
+ _ => type_metadata(cx, ty, span)
+ },
+ offset: ComputedMemberOffset,
+ }
+ }.collect()
+ };
- return composite_type_metadata(
- cx,
- variant_llvm_type,
- variant_name,
- arg_llvm_types,
- arg_names,
- arg_metadata,
- span);
+ (metadata_stub, variant_llvm_type, member_description_factory)
}
}
+enum MemberOffset {
+ FixedMemberOffset { bytes: uint },
+ // For ComputedMemberOffset, the offset is read from the llvm type definition
+ ComputedMemberOffset
+}
+
+struct MemberDescription {
+ name: @str,
+ llvm_type: Type,
+ type_metadata: DIType,
+ offset: MemberOffset,
+}
+
/// Creates debug information for a composite type, that is, anything that results in a LLVM struct.
///
/// Examples of Rust types to use this are: structs, tuples, boxes, vecs, and enums.
fn composite_type_metadata(cx: &mut CrateContext,
composite_llvm_type: Type,
composite_type_name: &str,
- member_llvm_types: &[Type],
- member_names: &[~str],
- member_type_metadata: &[DIType],
- span: Span)
+ member_descriptions: &[MemberDescription],
+ containing_scope: DIScope,
+ file_metadata: DIFile,
+ definition_span: Span)
-> DICompositeType {
+ // Create the (empty) struct metadata node ...
+ let composite_type_metadata = create_struct_stub(cx,
+ composite_llvm_type,
+ composite_type_name,
+ containing_scope,
+ file_metadata,
+ definition_span);
+
+ // ... and immediately create and add the member descriptions.
+ set_members_of_composite_type(cx,
+ composite_type_metadata,
+ composite_llvm_type,
+ member_descriptions,
+ file_metadata,
+ definition_span);
+
+ return composite_type_metadata;
+}
- let loc = span_start(cx, span);
- let file_metadata = file_metadata(cx, loc.file.name);
-
- let (composite_size, composite_align) = size_and_align_of(cx, composite_llvm_type);
+fn set_members_of_composite_type(cx: &mut CrateContext,
+ composite_type_metadata: DICompositeType,
+ composite_llvm_type: Type,
+ member_descriptions: &[MemberDescription],
+ file_metadata: DIFile,
+ definition_span: Span) {
+ let loc = span_start(cx, definition_span);
- let member_metadata: ~[DIDescriptor] = member_llvm_types
+ let member_metadata: ~[DIDescriptor] = member_descriptions
.iter()
.enumerate()
- .map(|(i, &member_llvm_type)| {
- let (member_size, member_align) = size_and_align_of(cx, member_llvm_type);
- let member_offset = machine::llelement_offset(cx, composite_llvm_type, i);
- let member_name: &str = member_names[i];
+ .map(|(i, member_description)| {
+ let (member_size, member_align) = size_and_align_of(cx, member_description.llvm_type);
+ let member_offset = match member_description.offset {
+ FixedMemberOffset { bytes } => bytes,
+ ComputedMemberOffset => machine::llelement_offset(cx, composite_llvm_type, i)
+ };
- do member_name.with_c_str |member_name| {
+ do member_description.name.with_c_str |member_name| {
unsafe {
llvm::LLVMDIBuilderCreateMemberType(
DIB(cx),
- file_metadata,
+ composite_type_metadata,
member_name,
file_metadata,
loc.line as c_uint,
bytes_to_bits(member_align),
bytes_to_bits(member_offset),
0,
- member_type_metadata[i])
+ member_description.type_metadata)
}
}
})
.collect();
- return do composite_type_name.with_c_str |name| {
+ unsafe {
+ let type_array = create_DIArray(DIB(cx), member_metadata);
+ llvm::LLVMDICompositeTypeSetTypeArray(composite_type_metadata, type_array);
+ }
+}
+
+// A convenience wrapper around LLVMDIBuilderCreateStructType(). Does not do any caching, does not
+// add any fields to the struct. This can be done later with set_members_of_composite_type().
+fn create_struct_stub(cx: &mut CrateContext,
+ struct_llvm_type: Type,
+ struct_type_name: &str,
+ containing_scope: DIScope,
+ file_metadata: DIFile,
+ definition_span: Span)
+ -> DICompositeType {
+ let loc = span_start(cx, definition_span);
+ let (struct_size, struct_align) = size_and_align_of(cx, struct_llvm_type);
+
+ return do struct_type_name.with_c_str |name| {
unsafe {
+ // LLVMDIBuilderCreateStructType() wants an empty array. A null pointer will lead to
+ // hard to trace and debug LLVM assertions later on in llvm/lib/IR/Value.cpp
+ let empty_array = create_DIArray(DIB(cx), []);
+
llvm::LLVMDIBuilderCreateStructType(
DIB(cx),
- file_metadata,
+ containing_scope,
name,
file_metadata,
loc.line as c_uint,
- bytes_to_bits(composite_size),
- bytes_to_bits(composite_align),
+ bytes_to_bits(struct_size),
+ bytes_to_bits(struct_align),
0,
ptr::null(),
- create_DIArray(DIB(cx), member_metadata),
+ empty_array,
0,
ptr::null())
- }
- };
+ }};
}
fn boxed_type_metadata(cx: &mut CrateContext,
content_type_metadata: DIType,
span: Span)
-> DICompositeType {
-
let box_type_name = match content_type_name {
Some(content_type_name) => fmt!("Boxed<%s>", content_type_name),
None => ~"BoxedType"
let box_llvm_type = Type::box(cx, &content_llvm_type);
let member_llvm_types = box_llvm_type.field_types();
- let member_names = [~"refcnt", ~"tydesc", ~"prev", ~"next", ~"val"];
-
assert!(box_layout_is_correct(cx, member_llvm_types, content_llvm_type));
let int_type = ty::mk_int();
let nil_pointer_type = ty::mk_nil_ptr(cx.tcx);
-
- let member_types_metadata = [
- type_metadata(cx, int_type, span),
- type_metadata(cx, nil_pointer_type, span),
- type_metadata(cx, nil_pointer_type, span),
- type_metadata(cx, nil_pointer_type, span),
- content_type_metadata
+ let nil_pointer_type_metadata = type_metadata(cx, nil_pointer_type, codemap::dummy_sp());
+
+ let member_descriptions = [
+ MemberDescription {
+ name: @"refcnt",
+ llvm_type: member_llvm_types[0],
+ type_metadata: type_metadata(cx, int_type, codemap::dummy_sp()),
+ offset: ComputedMemberOffset,
+ },
+ MemberDescription {
+ name: @"tydesc",
+ llvm_type: member_llvm_types[1],
+ type_metadata: nil_pointer_type_metadata,
+ offset: ComputedMemberOffset,
+ },
+ MemberDescription {
+ name: @"prev",
+ llvm_type: member_llvm_types[2],
+ type_metadata: nil_pointer_type_metadata,
+ offset: ComputedMemberOffset,
+ },
+ MemberDescription {
+ name: @"next",
+ llvm_type: member_llvm_types[3],
+ type_metadata: nil_pointer_type_metadata,
+ offset: ComputedMemberOffset,
+ },
+ MemberDescription {
+ name: @"val",
+ llvm_type: member_llvm_types[4],
+ type_metadata: content_type_metadata,
+ offset: ComputedMemberOffset,
+ }
];
+ let loc = span_start(cx, span);
+ let file_metadata = file_metadata(cx, loc.file.name);
+
return composite_type_metadata(
cx,
box_llvm_type,
box_type_name,
- member_llvm_types,
- member_names,
- member_types_metadata,
+ member_descriptions,
+ file_metadata,
+ file_metadata,
span);
// Unfortunately, we cannot assert anything but the correct types here---and not whether the
let (element_size, element_align) = size_and_align_of(cx, element_llvm_type);
let vec_llvm_type = Type::vec(cx.sess.targ_cfg.arch, &element_llvm_type);
- let vec_type_name: &str = fmt!("[%s]", ty_to_str(cx.tcx, element_type));
+ let vec_type_name: &str = fmt!("[%s]", ppaux::ty_to_str(cx.tcx, element_type));
let member_llvm_types = vec_llvm_type.field_types();
- let member_names = &[~"fill", ~"alloc", ~"elements"];
let int_type_metadata = type_metadata(cx, ty::mk_int(), span);
let array_type_metadata = unsafe {
create_DIArray(DIB(cx), [llvm::LLVMDIBuilderGetOrCreateSubrange(DIB(cx), 0, 0)]))
};
- // fill alloc elements
- let member_type_metadata = &[int_type_metadata, int_type_metadata, array_type_metadata];
+ let member_descriptions = [
+ MemberDescription {
+ name: @"fill",
+ llvm_type: member_llvm_types[0],
+ type_metadata: int_type_metadata,
+ offset: ComputedMemberOffset,
+ },
+ MemberDescription {
+ name: @"alloc",
+ llvm_type: member_llvm_types[1],
+ type_metadata: int_type_metadata,
+ offset: ComputedMemberOffset,
+ },
+ MemberDescription {
+ name: @"elements",
+ llvm_type: member_llvm_types[2],
+ type_metadata: array_type_metadata,
+ offset: ComputedMemberOffset,
+ }
+ ];
+
+ assert!(member_descriptions.len() == member_llvm_types.len());
+
+ let loc = span_start(cx, span);
+ let file_metadata = file_metadata(cx, loc.file.name);
return composite_type_metadata(
cx,
vec_llvm_type,
vec_type_name,
- member_llvm_types,
- member_names,
- member_type_metadata,
+ member_descriptions,
+ file_metadata,
+ file_metadata,
span);
}
element_type: ty::t,
span: Span)
-> DICompositeType {
-
let element_llvm_type = type_of::type_of(cx, element_type);
let vec_llvm_type = Type::vec(cx.sess.targ_cfg.arch, &element_llvm_type);
- let vec_type_name: &str = fmt!("[%s]", ty_to_str(cx.tcx, element_type));
+ let vec_type_name: &str = fmt!("[%s]", ppaux::ty_to_str(cx.tcx, element_type));
let vec_metadata = vec_metadata(cx, element_type, span);
return boxed_type_metadata(
debug!("vec_slice_metadata: %?", ty::get(vec_type));
let slice_llvm_type = type_of::type_of(cx, vec_type);
- let slice_type_name = ty_to_str(cx.tcx, vec_type);
+ let slice_type_name = ppaux::ty_to_str(cx.tcx, vec_type);
let member_llvm_types = slice_llvm_type.field_types();
- let member_names = &[~"data_ptr", ~"size_in_bytes"];
-
assert!(slice_layout_is_correct(cx, member_llvm_types, element_type));
let data_ptr_type = ty::mk_ptr(cx.tcx, ty::mt { ty: element_type, mutbl: ast::MutImmutable });
- let member_type_metadata = &[type_metadata(cx, data_ptr_type, span),
- type_metadata(cx, ty::mk_uint(), span)];
+ let member_descriptions = [
+ MemberDescription {
+ name: @"data_ptr",
+ llvm_type: member_llvm_types[0],
+ type_metadata: type_metadata(cx, data_ptr_type, span),
+ offset: ComputedMemberOffset,
+ },
+ MemberDescription {
+ name: @"size_in_bytes",
+ llvm_type: member_llvm_types[1],
+ type_metadata: type_metadata(cx, ty::mk_uint(), span),
+ offset: ComputedMemberOffset,
+ },
+ ];
+
+ assert!(member_descriptions.len() == member_llvm_types.len());
+
+ let loc = span_start(cx, span);
+ let file_metadata = file_metadata(cx, loc.file.name);
return composite_type_metadata(
cx,
slice_llvm_type,
slice_type_name,
- member_llvm_types,
- member_names,
- member_type_metadata,
+ member_descriptions,
+ file_metadata,
+ file_metadata,
span);
fn slice_layout_is_correct(cx: &mut CrateContext,
};
}
+fn trait_metadata(cx: &mut CrateContext,
+ def_id: ast::DefId,
+ trait_type: ty::t,
+ substs: &ty::substs,
+ trait_store: ty::TraitStore,
+ mutability: ast::Mutability,
+ _: &ty::BuiltinBounds,
+ usage_site_span: Span)
+ -> DIType {
+ // The implementation provided here is a stub. It makes sure that the trait type is
+ // assigned the correct name, size, namespace, and source location. But it does not describe
+ // the trait's methods.
+ let path = ty::item_path(cx.tcx, def_id);
+ let ident = path.last().ident();
+ let name = ppaux::trait_store_to_str(cx.tcx, trait_store) +
+ ppaux::mutability_to_str(mutability) +
+ token::ident_to_str(&ident);
+ // Add type and region parameters
+ let name = ppaux::parameterized(cx.tcx, name, &substs.regions, substs.tps);
+
+ let (containing_scope, definition_span) =
+ get_namespace_and_span_for_item(cx, def_id, usage_site_span);
+
+ let file_name = span_start(cx, definition_span).file.name;
+ let file_metadata = file_metadata(cx, file_name);
+
+ let trait_llvm_type = type_of::type_of(cx, trait_type);
+
+ return composite_type_metadata(cx,
+ trait_llvm_type,
+ name,
+ [],
+ containing_scope,
+ file_metadata,
+ definition_span);
+}
+
fn unimplemented_type_metadata(cx: &mut CrateContext, t: ty::t) -> DIType {
debug!("unimplemented_type_metadata: %?", ty::get(t));
- let name = ty_to_str(cx.tcx, t);
+ let name = ppaux::ty_to_str(cx.tcx, t);
let metadata = do fmt!("NYI<%s>", name).with_c_str |name| {
unsafe {
llvm::LLVMDIBuilderCreateBasicType(
return metadata;
}
+fn cache_id_for_type(t: ty::t) -> uint {
+ ty::type_id(t)
+}
+
fn type_metadata(cx: &mut CrateContext,
t: ty::t,
- span: Span)
+ usage_site_span: Span)
-> DIType {
- let type_id = ty::type_id(t);
- match dbg_cx(cx).created_types.find(&type_id) {
+ let cache_id = cache_id_for_type(t);
+ match debug_context(cx).created_types.find(&cache_id) {
Some(type_metadata) => return *type_metadata,
None => ()
}
pointer_type: ty::t,
type_in_box: ty::t)
-> DIType {
-
- let content_type_name: &str = ty_to_str(cx.tcx, type_in_box);
+ let content_type_name: &str = ppaux::ty_to_str(cx.tcx, type_in_box);
let content_llvm_type = type_of::type_of(cx, type_in_box);
let content_type_metadata = type_metadata(
cx,
let i8_t = ty::mk_i8();
match *vstore {
ty::vstore_fixed(len) => {
- fixed_vec_metadata(cx, i8_t, len + 1, span)
+ fixed_vec_metadata(cx, i8_t, len + 1, usage_site_span)
},
ty::vstore_uniq => {
- let vec_metadata = vec_metadata(cx, i8_t, span);
+ let vec_metadata = vec_metadata(cx, i8_t, usage_site_span);
pointer_type_metadata(cx, t, vec_metadata)
}
ty::vstore_box => {
- let boxed_vec_metadata = boxed_vec_metadata(cx, i8_t, span);
+ let boxed_vec_metadata = boxed_vec_metadata(cx, i8_t, usage_site_span);
pointer_type_metadata(cx, t, boxed_vec_metadata)
}
ty::vstore_slice(_region) => {
- vec_slice_metadata(cx, t, i8_t, span)
+ vec_slice_metadata(cx, t, i8_t, usage_site_span)
}
}
},
ty::ty_enum(def_id, _) => {
- enum_metadata(cx, t, def_id, span)
+ prepare_enum_metadata(cx, t, def_id, usage_site_span).finalize(cx)
},
ty::ty_box(ref mt) => {
create_pointer_to_box_metadata(cx, t, mt.ty)
ty::ty_evec(ref mt, ref vstore) => {
match *vstore {
ty::vstore_fixed(len) => {
- fixed_vec_metadata(cx, mt.ty, len, span)
+ fixed_vec_metadata(cx, mt.ty, len, usage_site_span)
}
ty::vstore_uniq if ty::type_contents(cx.tcx, mt.ty).contains_managed() => {
- let boxed_vec_metadata = boxed_vec_metadata(cx, mt.ty, span);
+ let boxed_vec_metadata = boxed_vec_metadata(cx, mt.ty, usage_site_span);
pointer_type_metadata(cx, t, boxed_vec_metadata)
}
ty::vstore_uniq => {
- let vec_metadata = vec_metadata(cx, mt.ty, span);
+ let vec_metadata = vec_metadata(cx, mt.ty, usage_site_span);
pointer_type_metadata(cx, t, vec_metadata)
}
ty::vstore_box => {
- let boxed_vec_metadata = boxed_vec_metadata(cx, mt.ty, span);
+ let boxed_vec_metadata = boxed_vec_metadata(cx, mt.ty, usage_site_span);
pointer_type_metadata(cx, t, boxed_vec_metadata)
}
ty::vstore_slice(_) => {
- vec_slice_metadata(cx, t, mt.ty, span)
+ vec_slice_metadata(cx, t, mt.ty, usage_site_span)
}
}
},
ty::ty_uniq(ref mt) |
ty::ty_ptr(ref mt) |
ty::ty_rptr(_, ref mt) => {
- let pointee = type_metadata(cx, mt.ty, span);
+ let pointee = type_metadata(cx, mt.ty, usage_site_span);
pointer_type_metadata(cx, t, pointee)
},
ty::ty_bare_fn(ref barefnty) => {
- subroutine_type_metadata(cx, &barefnty.sig, span)
+ subroutine_type_metadata(cx, &barefnty.sig, usage_site_span)
},
ty::ty_closure(ref closurety) => {
- subroutine_type_metadata(cx, &closurety.sig, span)
+ subroutine_type_metadata(cx, &closurety.sig, usage_site_span)
},
- ty::ty_trait(_did, ref _substs, ref _vstore, _, _bounds) => {
- cx.sess.span_note(span, "debuginfo for trait NYI");
- unimplemented_type_metadata(cx, t)
+ ty::ty_trait(def_id, ref substs, trait_store, mutability, ref bounds) => {
+ trait_metadata(cx, def_id, t, substs, trait_store, mutability, bounds, usage_site_span)
},
- ty::ty_struct(did, ref substs) => {
- let fields = ty::struct_fields(cx.tcx, did, substs);
- struct_metadata(cx, t, fields, span)
+ ty::ty_struct(def_id, ref substs) => {
+ prepare_struct_metadata(cx, t, def_id, substs, usage_site_span).finalize(cx)
},
ty::ty_tup(ref elements) => {
- tuple_metadata(cx, t, *elements, span)
+ prepare_tuple_metadata(cx, t, *elements, usage_site_span).finalize(cx)
},
ty::ty_opaque_box => {
- cx.sess.span_note(span, "debuginfo for ty_opaque_box NYI");
- unimplemented_type_metadata(cx, t)
+ create_pointer_to_box_metadata(cx, t, ty::mk_nil())
}
_ => cx.sess.bug(fmt!("debuginfo: unexpected type in type_metadata: %?", sty))
};
- dbg_cx(cx).created_types.insert(type_id, type_metadata);
+ debug_context(cx).created_types.insert(cache_id, type_metadata);
return type_metadata;
}
}
fn set_debug_location(cx: &mut CrateContext, debug_location: DebugLocation) {
- if debug_location == dbg_cx(cx).curr_loc {
+ if debug_location == debug_context(cx).current_debug_location {
return;
}
debug!("setting debug location to %u %u", line, col);
let elements = [C_i32(line as i32), C_i32(col as i32), scope, ptr::null()];
unsafe {
- metadata_node = llvm::LLVMMDNodeInContext(dbg_cx(cx).llcontext,
+ metadata_node = llvm::LLVMMDNodeInContext(debug_context(cx).llcontext,
vec::raw::to_ptr(elements),
elements.len() as c_uint);
}
llvm::LLVMSetCurrentDebugLocation(cx.builder.B, metadata_node);
}
- dbg_cx(cx).curr_loc = debug_location;
+ debug_context(cx).current_debug_location = debug_location;
}
//=-------------------------------------------------------------------------------------------------
}
#[inline]
-fn dbg_cx<'a>(cx: &'a mut CrateContext) -> &'a mut CrateDebugContext {
+fn debug_context<'a>(cx: &'a mut CrateContext) -> &'a mut CrateDebugContext {
cx.dbg_cx.get_mut_ref()
}
cx.dbg_cx.get_ref().builder
}
-fn assert_fcx_has_span(fcx: &FunctionContext) {
- if fcx.span.is_none() {
- fcx.ccx.sess.bug(fmt!("debuginfo: Encountered function %s with invalid source span. \
- This function should have been ignored by debuginfo generation.",
- ast_map::path_to_str(fcx.path, fcx.ccx.sess.intr())));
- }
-}
-
fn fn_should_be_ignored(fcx: &FunctionContext) -> bool {
match fcx.debug_context {
FunctionDebugContext(_) => false,
}
}
+fn assert_type_for_node_id(cx: &CrateContext, node_id: ast::NodeId, error_span: Span) {
+ if !cx.tcx.node_types.contains_key(&(node_id as uint)) {
+ cx.sess.span_bug(error_span, "debuginfo: Could not find type for node id!");
+ }
+}
+
+fn get_namespace_and_span_for_item(cx: &mut CrateContext,
+ def_id: ast::DefId,
+ warning_span: Span)
+ -> (DIScope, Span) {
+ if def_id.crate == ast::LOCAL_CRATE {
+ let containing_scope = debug_context(cx).local_namespace_map.get_copy(&def_id.node).scope;
+ let definition_span = match cx.tcx.items.find(&def_id.node) {
+ Some(&ast_map::node_item(@ast::item { span, _ }, _)) => span,
+ ref node => {
+ cx.sess.span_warn(warning_span, fmt!("debuginfo::get_namespace_and_span_for_item() \
+ - Unexpected node type: %?", *node));
+ codemap::dummy_sp()
+ }
+ };
+ (containing_scope, definition_span)
+ } else {
+ let item_path = ty::item_path(cx.tcx, def_id);
+ // For external items there is no span information
+ (namespace_for_external_item(cx, &item_path).scope, codemap::dummy_sp())
+ }
+}
+
// This procedure builds the *scope map* for a given function, which maps any given ast::NodeId in
// the function's AST to the correct DIScope metadata instance.
//
// shadowing.
fn populate_scope_map(cx: &mut CrateContext,
arg_pats: &[@ast::Pat],
- fn_entry_block: Option<&ast::Block>,
+ fn_entry_block: &ast::Block,
fn_metadata: DISubprogram,
scope_map: &mut HashMap<ast::NodeId, DIScope>) {
let def_map = cx.tcx.def_map;
}
}
- for &fn_entry_block in fn_entry_block.iter() {
- walk_block(cx, fn_entry_block, &mut scope_stack, scope_map);
- }
-
+ walk_block(cx, fn_entry_block, &mut scope_stack, scope_map);
// local helper functions for walking the AST.
-
fn with_new_scope(cx: &mut CrateContext,
scope_span: Span,
scope_stack: &mut ~[ScopeStackEntry],
}
}
}
+
+
+//=-------------------------------------------------------------------------------------------------
+// Namespace Handling
+//=-------------------------------------------------------------------------------------------------
+
+struct NamespaceTreeNode {
+ ident: ast::Ident,
+ scope: DIScope,
+ parent: Option<@NamespaceTreeNode>,
+}
+
+impl NamespaceTreeNode {
+ fn mangled_name_of_contained_item(&self, item_name: &str) -> ~str {
+ let mut name = ~"_ZN";
+ fill_nested(self, &mut name);
+
+ name.push_str(fmt!("%u%s", item_name.len(), item_name));
+ name.push_char('E');
+
+ return name;
+
+ fn fill_nested(node: &NamespaceTreeNode, output: &mut ~str) {
+ match node.parent {
+ Some(parent) => {
+ fill_nested(parent, output);
+ }
+ None => {}
+ }
+ let name = token::ident_to_str(&node.ident);
+ output.push_str(fmt!("%u%s", name.len(), name));
+ }
+ }
+}
+
+fn namespace_for_external_item(cx: &mut CrateContext,
+ item_path: &ast_map::path)
+ -> @NamespaceTreeNode {
+ if item_path.len() < 2 {
+ cx.sess.bug(fmt!("debuginfo::namespace_for_external_item() - Invalid item_path: %s",
+ ast_map::path_to_str(*item_path, token::get_ident_interner())));
+ }
+
+ let path_excluding_item = item_path.slice_to(item_path.len() - 1);
+ let mut current_key = vec::with_capacity(path_excluding_item.len());
+ let mut parent_node: Option<@NamespaceTreeNode> = None;
+ let last_index = path_excluding_item.len() - 1;
+
+ for (i, &path_element) in path_excluding_item.iter().enumerate() {
+ let ident = match path_element {
+ ast_map::path_mod(ident) |
+ ast_map::path_name(ident) |
+ ast_map::path_pretty_name(ident, _) => ident
+ };
+
+ current_key.push(ident);
+
+ let existing_node = debug_context(cx).extern_namespaces.find_copy(¤t_key);
+ let current_node = match existing_node {
+ Some(existing_node) => existing_node,
+ None => {
+ // create and insert
+ let parent_scope = match parent_node {
+ Some(node) => node.scope,
+ None => ptr::null()
+ };
+ let namespace_name = token::ident_to_str(&ident);
+
+ let namespace_metadata = unsafe {
+ do namespace_name.with_c_str |namespace_name| {
+ llvm::LLVMDIBuilderCreateNameSpace(
+ DIB(cx),
+ parent_scope,
+ namespace_name,
+ ptr::null(), // cannot reconstruct file ...
+ 0) // ... or line information
+ }
+ };
+
+ let node = @NamespaceTreeNode {
+ ident: ident,
+ scope: namespace_metadata,
+ parent: parent_node,
+ };
+
+ debug_context(cx).extern_namespaces.insert(current_key.clone(), node);
+
+ node
+ }
+ };
+
+ if i == last_index {
+ return current_node;
+ } else {
+ parent_node = Some(current_node);
+ }
+ }
+
+ cx.sess.bug("debuginfo::namespace_for_external_item() - Code path should be unreachable");
+}
+
+struct NamespaceVisitor<'self> {
+ module_ident: ast::Ident,
+ scope_stack: ~[@NamespaceTreeNode],
+ crate_context: &'self mut CrateContext,
+}
+
+impl<'self> NamespaceVisitor<'self> {
+
+ fn new_crate_visitor<'a>(cx: &'a mut CrateContext,
+ crate_ident: ast::Ident)
+ -> NamespaceVisitor<'a> {
+ NamespaceVisitor {
+ module_ident: crate_ident,
+ scope_stack: ~[],
+ crate_context: cx,
+ }
+ }
+
+ fn new_function_visitor<'a>(cx: &'a mut CrateContext,
+ function_name: &str,
+ parent_node: Option<@NamespaceTreeNode>,
+ file_metadata: DIFile,
+ span: Span)
+ -> NamespaceVisitor<'a> {
+ let companion_name = function_name + "()";
+ let companion_ident = token::str_to_ident(companion_name);
+ let parent_scope = match parent_node {
+ Some(parent_node) => parent_node.scope,
+ None => ptr::null()
+ };
+ let line = span_start(cx, span).line as c_uint;
+
+ let namespace_metadata = unsafe {
+ do companion_name.with_c_str |companion_name| {
+ llvm::LLVMDIBuilderCreateNameSpace(
+ DIB(cx),
+ parent_scope,
+ companion_name,
+ file_metadata,
+ line)
+ }
+ };
+
+ let function_node = @NamespaceTreeNode {
+ scope: namespace_metadata,
+ ident: companion_ident,
+ parent: parent_node,
+ };
+
+ return NamespaceVisitor {
+ module_ident: special_idents::invalid,
+ scope_stack: ~[function_node],
+ crate_context: cx,
+ };
+ }
+}
+
+// Possible optimization: Only recurse if needed.
+impl<'self> visit::Visitor<()> for NamespaceVisitor<'self> {
+
+ fn visit_mod(&mut self,
+ module: &ast::_mod,
+ span: Span,
+ _: ast::NodeId,
+ _: ()) {
+ let module_name = token::ident_to_str(&self.module_ident);
+
+ let (parent_node, parent_scope) = if self.scope_stack.len() > 0 {
+ let parent_node = *self.scope_stack.last();
+ (Some(parent_node), parent_node.scope)
+ } else {
+ (None, ptr::null())
+ };
+
+ let loc = span_start(self.crate_context, span);
+ let file_metadata = file_metadata(self.crate_context, loc.file.name);
+
+ let namespace_metadata = unsafe {
+ do module_name.with_c_str |module_name| {
+ llvm::LLVMDIBuilderCreateNameSpace(
+ DIB(self.crate_context),
+ parent_scope,
+ module_name,
+ file_metadata,
+ loc.line as c_uint)
+ }
+ };
+
+ let this_node = @NamespaceTreeNode {
+ scope: namespace_metadata,
+ ident: self.module_ident,
+ parent: parent_node,
+ };
+
+ self.scope_stack.push(this_node);
+
+ visit::walk_mod(self, module, ());
+
+ self.scope_stack.pop();
+ }
+
+ fn visit_item(&mut self, item: @ast::item, _: ()) {
+ match item.node {
+ ast::item_mod(*) => {
+ // always store the last module ident so visit_mod() has it available
+ self.module_ident = item.ident;
+ }
+ ast::item_fn(*) => { /* handled by visit_fn */ }
+ _ => {
+ debug_context(self.crate_context)
+ .local_namespace_map
+ .insert(item.id, *self.scope_stack.last());
+ }
+ }
+
+ visit::walk_item(self, item, ());
+ }
+
+ fn visit_foreign_item(&mut self, item: @ast::foreign_item, _: ()) {
+ debug_context(self.crate_context)
+ .local_namespace_map
+ .insert(item.id, *self.scope_stack.last());
+ }
+
+ fn visit_fn(&mut self,
+ _: &visit::fn_kind,
+ _: &ast::fn_decl,
+ _: &ast::Block,
+ _: Span,
+ node_id: ast::NodeId,
+ _: ()) {
+ debug_context(self.crate_context)
+ .local_namespace_map
+ .insert(node_id, *self.scope_stack.last());
+ }
+}
};
match def {
- ast::DefVariant(tid, vid) => {
+ ast::DefVariant(tid, vid, _) => {
let variant_info = ty::enum_variant_with_id(ccx.tcx, tid, vid);
if variant_info.args.len() > 0u {
// N-ary variant.
}
Some(node_id) => {
match tcx.def_map.get_copy(&node_id) {
- ast::DefVariant(enum_id, variant_id) => {
+ ast::DefVariant(enum_id, variant_id, _) => {
let variant_info = ty::enum_variant_with_id(
tcx, enum_id, variant_id);
op(variant_info.disr_val,
use back::{link};
use std::libc::c_uint;
-use lib::llvm::{ValueRef, Attribute, CallConv};
+use lib::llvm::{ValueRef, Attribute, CallConv, StructRetAttribute};
use lib::llvm::llvm;
use lib;
use middle::trans::machine;
}
};
- let llforeign_retval = CallWithConv(bcx, llfn, llargs_foreign, cc);
+ let attrs;
+ if fn_type.sret {
+ attrs = &[(1, StructRetAttribute)];
+ } else {
+ attrs = &[];
+ }
+ let llforeign_retval = CallWithConv(bcx, llfn, llargs_foreign, cc, attrs);
// If the function we just called does not use an outpointer,
// store the result into the rust outpointer. Cast the outpointer
}
};
- Call(bcx, llfn, [C_null(Type::nil().ptr_to()), llrawptr]);
+ Call(bcx, llfn, [C_null(Type::nil().ptr_to()), llrawptr], []);
}
// See [Note-arg-mode]
let self_arg = PointerCast(bcx, v0, params[0]);
let args = ~[self_arg];
- Call(bcx, dtor_addr, args);
+ Call(bcx, dtor_addr, args, []);
// Drop the fields
let field_tys = ty::struct_fields(bcx.tcx(), class_did, substs);
let self_arg = PointerCast(bcx, v0, params[0]);
let args = ~[self_arg];
- Call(bcx, dtor_addr, args);
+ Call(bcx, dtor_addr, args, []);
// Drop the fields
let field_tys = ty::struct_fields(bcx.tcx(), class_did, substs);
args[i] = get_param(bcx.fcx.llfn, first_real_arg + i);
}
let llfn = bcx.ccx().intrinsics.get_copy(&name);
- Ret(bcx, Call(bcx, llfn, args.slice(0, num_args)));
+ Ret(bcx, Call(bcx, llfn, args.slice(0, num_args), []));
}
fn with_overflow_instrinsic(bcx: @mut Block, name: &'static str) {
let llfn = bcx.ccx().intrinsics.get_copy(&name);
// convert `i1` to a `bool`, and write to the out parameter
- let val = Call(bcx, llfn, [a, b]);
+ let val = Call(bcx, llfn, [a, b], []);
let result = ExtractValue(bcx, val, 0);
let overflow = ZExt(bcx, ExtractValue(bcx, val, 1), Type::bool());
let retptr = get_param(bcx.fcx.llfn, bcx.fcx.out_arg_pos());
let count = get_param(decl, first_real_arg + 2);
let volatile = C_i1(false);
let llfn = bcx.ccx().intrinsics.get_copy(&name);
- Call(bcx, llfn, [dst_ptr, src_ptr, Mul(bcx, size, count), align, volatile]);
+ Call(bcx, llfn, [dst_ptr, src_ptr, Mul(bcx, size, count), align, volatile], []);
RetVoid(bcx);
}
let count = get_param(decl, first_real_arg + 2);
let volatile = C_i1(false);
let llfn = bcx.ccx().intrinsics.get_copy(&name);
- Call(bcx, llfn, [dst_ptr, val, Mul(bcx, size, count), align, volatile]);
+ Call(bcx, llfn, [dst_ptr, val, Mul(bcx, size, count), align, volatile], []);
RetVoid(bcx);
}
let x = get_param(bcx.fcx.llfn, bcx.fcx.arg_pos(0u));
let y = C_i1(false);
let llfn = bcx.ccx().intrinsics.get_copy(&name);
- Ret(bcx, Call(bcx, llfn, [x, y]));
+ Ret(bcx, Call(bcx, llfn, [x, y], []));
}
let output_type = ty::ty_fn_ret(ty::node_id_to_type(ccx.tcx, item.id));
}
"frame_address" => {
let frameaddress = ccx.intrinsics.get_copy(& &"llvm.frameaddress");
- let frameaddress_val = Call(bcx, frameaddress, [C_i32(0i32)]);
+ let frameaddress_val = Call(bcx, frameaddress, [C_i32(0i32)], []);
let star_u8 = ty::mk_imm_ptr(
bcx.tcx(),
ty::mk_mach_uint(ast::ty_u8));
Ret(bcx, morestack_addr);
}
"offset" => {
- let ptr = get_param(decl, first_real_arg);
- let offset = get_param(decl, first_real_arg + 1);
- Ret(bcx, GEP(bcx, ptr, [offset]));
- }
- "offset_inbounds" => {
let ptr = get_param(decl, first_real_arg);
let offset = get_param(decl, first_real_arg + 1);
Ret(bcx, InBoundsGEP(bcx, ptr, [offset]));
/// must be the only user of this value, and there must not be any conditional
/// branches between the store and the given block.
pub fn get_dominating_store(self, bcx: @mut Block) -> Option<Value> {
- match self.get_single_user().chain(|user| user.as_store_inst()) {
+ match self.get_single_user().and_then(|user| user.as_store_inst()) {
Some(store) => {
- do store.get_parent().chain |store_bb| {
+ do store.get_parent().and_then |store_bb| {
let mut bb = BasicBlock(bcx.llbb);
let mut ret = Some(store);
while *bb != *store_bb {
fn next(&mut self) -> Option<Value> {
let current = self.next;
- self.next = do current.chain |u| { u.get_next_use() };
+ self.next = do current.and_then |u| { u.get_next_use() };
do current.map |u| { u.get_user() }
}
}
pub struct field_ty {
- ident: Ident,
+ name: Name,
id: DefId,
vis: ast::visibility,
}
ty_struct(def_id, ref substs) => {
let fields = struct_fields(cx, def_id, substs);
fields.len() == 1 &&
- fields[0].ident == token::special_idents::unnamed_field &&
+ fields[0].ident.name == token::special_idents::unnamed_field.name &&
type_is_immediate(cx, fields[0].mt.ty)
}
_ => false
pub fn def_has_ty_params(def: ast::Def) -> bool {
match def {
- ast::DefFn(_, _) | ast::DefVariant(_, _) | ast::DefStruct(_)
+ ast::DefFn(_, _) | ast::DefVariant(_, _, _) | ast::DefStruct(_)
=> true,
_ => false
}
pub fn from_ast_variant(cx: ctxt,
ast_variant: &ast::variant,
discriminant: Disr) -> VariantInfo {
-
let ctor_ty = node_id_to_type(cx, ast_variant.node.id);
match ast_variant.node.kind {
match field.node.kind {
named_field(ident, visibility) => {
field_ty {
- ident: ident,
+ name: ident.name,
id: ast_util::local_def(field.node.id),
vis: visibility,
}
}
unnamed_field => {
field_ty {
- ident:
- syntax::parse::token::special_idents::unnamed_field,
+ name:
+ syntax::parse::token::special_idents::unnamed_field.name,
id: ast_util::local_def(field.node.id),
vis: ast::public,
}
-> ~[field] {
do lookup_struct_fields(cx, did).map |f| {
field {
- ident: f.ident,
+ // FIXME #6993: change type of field to Name and get rid of new()
+ ident: ast::Ident::new(f.name),
mt: mt {
ty: lookup_field_type(cx, did, f.id, substs),
mutbl: MutImmutable
static tycat_int: int = 3;
static tycat_float: int = 4;
static tycat_bot: int = 5;
+ static tycat_raw_ptr: int = 6;
static opcat_add: int = 0;
static opcat_sub: int = 1;
ty_int(_) | ty_uint(_) | ty_infer(IntVar(_)) => tycat_int,
ty_float(_) | ty_infer(FloatVar(_)) => tycat_float,
ty_bot => tycat_bot,
+ ty_ptr(_) => tycat_raw_ptr,
_ => tycat_other
}
}
/*char*/ [f, f, f, f, t, t, f, f],
/*int*/ [t, t, t, t, t, t, t, f],
/*float*/ [t, t, t, f, t, t, f, f],
- /*bot*/ [t, t, t, t, f, f, t, t]];
+ /*bot*/ [t, t, t, t, t, t, t, t],
+ /*raw ptr*/ [f, f, f, f, t, t, f, f]];
return tbl[tycat(cx, ty)][opcat(op)];
}
RegionParamNames(bound_lifetime_names.clone()));
let input_tys = do decl.inputs.iter().enumerate().map |(i, a)| {
- let expected_arg_ty = do expected_sig.chain_ref |e| {
+ let expected_arg_ty = do expected_sig.and_then_ref |e| {
// no guarantee that the correct number of expected args
// were supplied
if i < e.inputs.len() {Some(e.inputs[i])} else {None}
use std::hashmap::{HashMap, HashSet};
use syntax::ast;
use syntax::ast_util;
+use syntax::parse::token;
use syntax::codemap::Span;
use syntax::print::pprust;
fcx.write_error(pat.id);
kind_name = "[error]";
arg_types = (*subpats).clone()
- .unwrap_or_default(~[])
+ .unwrap_or_default()
.map(|_| ty::mk_err());
}
}
fcx.write_error(pat.id);
kind_name = "[error]";
arg_types = (*subpats).clone()
- .unwrap_or_default(~[])
+ .unwrap_or_default()
.map(|_| ty::mk_err());
}
}
// Index the class fields.
let mut field_map = HashMap::new();
for (i, class_field) in class_fields.iter().enumerate() {
- field_map.insert(class_field.ident.name, i);
+ field_map.insert(class_field.name, i);
}
// Typecheck each field.
}
tcx.sess.span_err(span,
fmt!("pattern does not mention field `%s`",
- tcx.sess.str_of(field.ident)));
+ token::interner_get(field.name)));
}
}
}
// Find the variant that was specified.
match tcx.def_map.find(&pat_id) {
- Some(&ast::DefVariant(found_enum_id, variant_id))
+ Some(&ast::DefVariant(found_enum_id, variant_id, _))
if found_enum_id == enum_id => {
// Get the struct fields from this struct-like enum variant.
let class_fields = ty::lookup_struct_fields(tcx, variant_id);
purity => {
let (purity, def) = match blk.rules {
- ast::UnsafeBlock => (ast::unsafe_fn, blk.id),
+ ast::UnsafeBlock(*) => (ast::unsafe_fn, blk.id),
ast::DefaultBlock => (purity, self.def),
};
PurityState{ def: def,
fieldname: ast::Name,
substs: &ty::substs) -> Option<ty::t> {
- let o_field = items.iter().find(|f| f.ident.name == fieldname);
+ let o_field = items.iter().find(|f| f.name == fieldname);
do o_field.map() |f| {
ty::lookup_field_type(tcx, class_id, f.id, substs)
}
let mut class_field_map = HashMap::new();
let mut fields_found = 0;
for field in field_types.iter() {
- class_field_map.insert(field.ident.name, (field.id, false));
+ class_field_map.insert(field.name, (field.id, false));
}
let mut error_happened = false;
if fields_found < field_types.len() {
let mut missing_fields = ~[];
for class_field in field_types.iter() {
- let name = class_field.ident.name;
+ let name = class_field.name;
let (_, seen) = *class_field_map.get(&name);
if !seen {
missing_fields.push(
check_struct_constructor(fcx, id, expr.span, type_def_id,
*fields, base_expr);
}
- Some(&ast::DefVariant(enum_id, variant_id)) => {
+ Some(&ast::DefVariant(enum_id, variant_id, _)) => {
check_struct_enum_variant(fcx, id, expr.span, enum_id,
variant_id, *fields);
}
return no_params(typ);
}
ast::DefFn(id, _) | ast::DefStaticMethod(id, _, _) |
- ast::DefStatic(id, _) | ast::DefVariant(_, id) |
+ ast::DefStatic(id, _) | ast::DefVariant(_, id, _) |
ast::DefStruct(id) => {
return ty::lookup_item_type(fcx.ccx.tcx, id);
}
// the trait `Combine` and contains methods for combining two
// instances of various things and yielding a new instance. These
// combiner methods always yield a `result<T>`---failure is propagated
-// upward using `chain()` methods. There is a lot of common code for
+// upward using `and_then()` methods. There is a lot of common code for
// these operations, implemented as default methods on the `Combine`
// trait.
//
(Some(a), Some(b)) => {
// FIXME(#5781) this should be eq_tys
// eq_tys(self, a, b).then(|| Ok(Some(a)) )
- self.contratys(a, b).chain(|t| Ok(Some(t)))
+ self.contratys(a, b).and_then(|t| Ok(Some(t)))
}
(None, Some(_)) |
(Some(_), None) => {
}
ty::rv_covariant => {
- do this.regions(a_r, b_r).chain |r| {
+ do this.regions(a_r, b_r).and_then |r| {
Ok(ty::NonerasedRegions(opt_vec::with(r)))
}
}
ty::rv_contravariant => {
- do this.contraregions(a_r, b_r).chain |r| {
+ do this.contraregions(a_r, b_r).and_then |r| {
Ok(ty::NonerasedRegions(opt_vec::with(r)))
}
}
}
}
- do self.tps(as_.tps, bs.tps).chain |tps| {
- do self.self_tys(as_.self_ty, bs.self_ty).chain |self_ty| {
+ do self.tps(as_.tps, bs.tps).and_then |tps| {
+ do self.self_tys(as_.self_ty, bs.self_ty).and_then |self_ty| {
do relate_region_params(self,
generics,
&as_.regions,
- &bs.regions).chain |regions| {
+ &bs.regions).and_then |regions| {
Ok(substs {
regions: regions,
self_ty: self_ty,
fn flds(&self, a: ty::field, b: ty::field) -> cres<ty::field> {
if a.ident == b.ident {
self.mts(&a.mt, &b.mt)
- .chain(|mt| Ok(ty::field {ident: a.ident, mt: mt}) )
- .chain_err(|e| Err(ty::terr_in_field(@e, a.ident)) )
+ .and_then(|mt| Ok(ty::field {ident: a.ident, mt: mt}) )
+ .or_else(|e| Err(ty::terr_in_field(@e, a.ident)) )
} else {
Err(ty::terr_record_fields(
expected_found(self,
}
fn args(&self, a: ty::t, b: ty::t) -> cres<ty::t> {
- do self.contratys(a, b).chain |t| {
+ do self.contratys(a, b).and_then |t| {
Ok(t)
}
}
match (a, b) {
(ty::vstore_slice(a_r), ty::vstore_slice(b_r)) => {
- do self.contraregions(a_r, b_r).chain |r| {
+ do self.contraregions(a_r, b_r).and_then |r| {
Ok(ty::vstore_slice(r))
}
}
match (a, b) {
(ty::RegionTraitStore(a_r), ty::RegionTraitStore(b_r)) => {
- do self.contraregions(a_r, b_r).chain |r| {
+ do self.contraregions(a_r, b_r).and_then |r| {
Ok(ty::RegionTraitStore(r))
}
}
pub fn eq_tys<C:Combine>(this: &C, a: ty::t, b: ty::t) -> ures {
let suber = this.sub();
do this.infcx().try {
- do suber.tys(a, b).chain |_ok| {
+ do suber.tys(a, b).and_then |_ok| {
suber.contratys(a, b)
}.to_ures()
}
let sub = this.sub();
do indent {
this.infcx().try(|| {
- do sub.regions(a, b).chain |_r| {
+ do sub.regions(a, b).and_then |_r| {
sub.contraregions(a, b)
}
- }).chain_err(|e| {
+ }).or_else(|e| {
// substitute a better error, but use the regions
// found in the original error
match e {
}
do argvecs(this, a.inputs, b.inputs)
- .chain |inputs| {
- do this.tys(a.output, b.output).chain |output| {
+ .and_then |inputs| {
+ do this.tys(a.output, b.output).and_then |output| {
Ok(FnSig {bound_lifetime_names: opt_vec::Empty, // FIXME(#4846)
inputs: inputs.clone(),
output: output})
&ty::ty_enum(b_id, ref b_substs))
if a_id == b_id => {
let type_def = ty::lookup_item_type(tcx, a_id);
- do this.substs(&type_def.generics, a_substs, b_substs).chain |substs| {
+ do this.substs(&type_def.generics, a_substs, b_substs).and_then |substs| {
Ok(ty::mk_enum(tcx, a_id, substs))
}
}
&ty::ty_trait(b_id, ref b_substs, b_store, b_mutbl, b_bounds))
if a_id == b_id && a_mutbl == b_mutbl => {
let trait_def = ty::lookup_trait_def(tcx, a_id);
- do this.substs(&trait_def.generics, a_substs, b_substs).chain |substs| {
- do this.trait_stores(ty::terr_trait, a_store, b_store).chain |s| {
- do this.bounds(a_bounds, b_bounds).chain |bounds| {
+ do this.substs(&trait_def.generics, a_substs, b_substs).and_then |substs| {
+ do this.trait_stores(ty::terr_trait, a_store, b_store).and_then |s| {
+ do this.bounds(a_bounds, b_bounds).and_then |bounds| {
Ok(ty::mk_trait(tcx,
a_id,
substs.clone(),
(&ty::ty_struct(a_id, ref a_substs), &ty::ty_struct(b_id, ref b_substs))
if a_id == b_id => {
let type_def = ty::lookup_item_type(tcx, a_id);
- do this.substs(&type_def.generics, a_substs, b_substs).chain |substs| {
+ do this.substs(&type_def.generics, a_substs, b_substs).and_then |substs| {
Ok(ty::mk_struct(tcx, a_id, substs))
}
}
(&ty::ty_box(ref a_mt), &ty::ty_box(ref b_mt)) => {
- do this.mts(a_mt, b_mt).chain |mt| {
+ do this.mts(a_mt, b_mt).and_then |mt| {
Ok(ty::mk_box(tcx, mt))
}
}
(&ty::ty_uniq(ref a_mt), &ty::ty_uniq(ref b_mt)) => {
- do this.mts(a_mt, b_mt).chain |mt| {
+ do this.mts(a_mt, b_mt).and_then |mt| {
Ok(ty::mk_uniq(tcx, mt))
}
}
(&ty::ty_ptr(ref a_mt), &ty::ty_ptr(ref b_mt)) => {
- do this.mts(a_mt, b_mt).chain |mt| {
+ do this.mts(a_mt, b_mt).and_then |mt| {
Ok(ty::mk_ptr(tcx, mt))
}
}
}
(&ty::ty_evec(ref a_mt, vs_a), &ty::ty_evec(ref b_mt, vs_b)) => {
- do this.mts(a_mt, b_mt).chain |mt| {
- do this.vstores(ty::terr_vec, vs_a, vs_b).chain |vs| {
+ do this.mts(a_mt, b_mt).and_then |mt| {
+ do this.vstores(ty::terr_vec, vs_a, vs_b).and_then |vs| {
Ok(ty::mk_evec(tcx, mt, vs))
}
}
}
(&ty::ty_estr(vs_a), &ty::ty_estr(vs_b)) => {
- do this.vstores(ty::terr_str, vs_a, vs_b).chain |vs| {
+ do this.vstores(ty::terr_str, vs_a, vs_b).and_then |vs| {
Ok(ty::mk_estr(tcx,vs))
}
}
if as_.len() == bs.len() {
result::collect(as_.iter().zip(bs.iter())
.map(|(a, b)| this.tys(*a, *b)))
- .chain(|ts| Ok(ty::mk_tup(tcx, ts)) )
+ .and_then(|ts| Ok(ty::mk_tup(tcx, ts)) )
} else {
Err(ty::terr_tuple_size(
expected_found(this, as_.len(), bs.len())))
}
(&ty::ty_bare_fn(ref a_fty), &ty::ty_bare_fn(ref b_fty)) => {
- do this.bare_fn_tys(a_fty, b_fty).chain |fty| {
+ do this.bare_fn_tys(a_fty, b_fty).and_then |fty| {
Ok(ty::mk_bare_fn(tcx, fty))
}
}
(&ty::ty_closure(ref a_fty), &ty::ty_closure(ref b_fty)) => {
- do this.closure_tys(a_fty, b_fty).chain |fty| {
+ do this.closure_tys(a_fty, b_fty).and_then |fty| {
Ok(ty::mk_closure(tcx, fty))
}
}
// If one side or both is immutable, we can use the GLB of
// both sides but mutbl must be `MutImmutable`.
(MutImmutable, MutImmutable) => {
- self.tys(a.ty, b.ty).chain(|t| {
+ self.tys(a.ty, b.ty).and_then(|t| {
Ok(ty::mt {ty: t, mutbl: MutImmutable})
})
}
(&Some(_), &None) => Ok((*a).clone()),
(&None, &Some(_)) => Ok((*b).clone()),
(&Some(ref v_a), &Some(ref v_b)) => {
- do lattice_op(self, v_a, v_b).chain |v| {
+ do lattice_op(self, v_a, v_b).and_then |v| {
Ok(Some(v))
}
}
let m = a.mutbl;
match m {
MutImmutable => {
- self.tys(a.ty, b.ty).chain(|t| Ok(ty::mt {ty: t, mutbl: m}) )
+ self.tys(a.ty, b.ty).and_then(|t| Ok(ty::mt {ty: t, mutbl: m}) )
}
MutMutable => {
eq_tys(self, a.ty, b.ty).then(|| {
Ok(ty::mt {ty: a.ty, mutbl: m})
})
- }).chain_err(|e| Err(e))
+ }).or_else(|e| Err(e))
}
}
}
impl then for ures {
fn then<T:Clone>(&self, f: &fn() -> Result<T,ty::type_err>)
-> Result<T,ty::type_err> {
- self.chain(|_i| f())
+ self.and_then(|_i| f())
}
}
impl<T:Clone + Eq> CresCompare<T> for cres<T> {
fn compare(&self, t: T, f: &fn() -> ty::type_err) -> cres<T> {
- do (*self).clone().chain |s| {
+ do (*self).clone().and_then |s| {
if s == t {
(*self).clone()
} else {
}
MutImmutable => {
// Otherwise we can be covariant:
- self.tys(a.ty, b.ty).chain(|_t| Ok(*a) )
+ self.tys(a.ty, b.ty).and_then(|_t| Ok(*a) )
}
}
}
if !self.region_param_names.has_ident(id) {
return RegionParamNames::undeclared_name(None);
}
- do EmptyRscope.named_region(span, id).chain_err |_e| {
+ do EmptyRscope.named_region(span, id).or_else |_e| {
result::Err(RegionError {
msg: ~"lifetime is not in scope",
replacement: ty::re_bound(ty::br_self)
}
fn named_region(&self, span: Span, id: ast::Ident)
-> Result<ty::Region, RegionError> {
- do EmptyRscope.named_region(span, id).chain_err |_e| {
+ do EmptyRscope.named_region(span, id).or_else |_e| {
result::Err(RegionError {
msg: ~"only 'self is allowed as part of a type declaration",
replacement: self.replacement()
span: Span,
id: ast::Ident) -> Result<ty::Region, RegionError>
{
- do self.base.named_region(span, id).chain_err |_e| {
+ do self.base.named_region(span, id).or_else |_e| {
let result = ty::re_bound(ty::br_named(id));
if self.region_param_names.has_ident(id) {
result::Ok(result)
}
}
-fn mutability_to_str(m: ast::Mutability) -> ~str {
+pub fn mutability_to_str(m: ast::Mutability) -> ~str {
match m {
ast::MutMutable => ~"mut ",
ast::MutImmutable => ~"",
doc::CrateDoc {
topmod: doc::ModDoc {
item: doc::ItemDoc {
- name: attrs.name.clone().unwrap_or_default(doc.topmod.name_()),
+ name: attrs.name.clone().unwrap_or(doc.topmod.name_()),
.. doc.topmod.item.clone()
},
.. doc.topmod.clone()
let config = default_config(input_crate);
let result = result::Ok(config);
- let result = do result.chain |config| {
+ let result = do result.and_then |config| {
let output_dir = getopts::opt_maybe_str(matches, opt_output_dir());
let output_dir = output_dir.map_move(|s| Path(s));
result::Ok(Config {
- output_dir: output_dir.unwrap_or_default(config.output_dir.clone()),
+ output_dir: output_dir.unwrap_or(config.output_dir.clone()),
.. config
})
};
- let result = do result.chain |config| {
+ let result = do result.and_then |config| {
let output_format = getopts::opt_maybe_str(matches, opt_output_format());
do output_format.map_move_default(result::Ok(config.clone())) |output_format| {
- do parse_output_format(output_format).chain |output_format| {
+ do parse_output_format(output_format).and_then |output_format| {
result::Ok(Config {
output_format: output_format,
.. config.clone()
}
}
};
- let result = do result.chain |config| {
+ let result = do result.and_then |config| {
let output_style =
getopts::opt_maybe_str(matches, opt_output_style());
do output_style.map_move_default(result::Ok(config.clone())) |output_style| {
- do parse_output_style(output_style).chain |output_style| {
+ do parse_output_style(output_style).and_then |output_style| {
result::Ok(Config {
output_style: output_style,
.. config.clone()
}
};
let process_output = Cell::new(process_output);
- let result = do result.chain |config| {
+ let result = do result.and_then |config| {
let pandoc_cmd = getopts::opt_maybe_str(matches, opt_pandoc_cmd());
let pandoc_cmd = maybe_find_pandoc(
&config, pandoc_cmd, process_output.take());
- do pandoc_cmd.chain |pandoc_cmd| {
+ do pandoc_cmd.and_then |pandoc_cmd| {
result::Ok(Config {
pandoc_cmd: pandoc_cmd,
.. config.clone()
/// None if no input was read (e.g. EOF was reached).
fn get_line(use_rl: bool, prompt: &str) -> Option<~str> {
if use_rl {
- let result = unsafe { rl::read(prompt) };
+ let result = rl::read(prompt);
match result {
None => None,
Some(line) => {
- unsafe { rl::add_history(line) };
+ rl::add_history(line);
Some(line)
}
}
println("unstable. If you encounter problems, please use the");
println("compiler instead. Type :help for help.");
- unsafe {
- do rl::complete |line, suggest| {
- if line.starts_with(":") {
- suggest(~":clear");
- suggest(~":exit");
- suggest(~":help");
- suggest(~":load");
- }
+ do rl::complete |line, suggest| {
+ if line.starts_with(":") {
+ suggest(~":clear");
+ suggest(~":exit");
+ suggest(~":help");
+ suggest(~":load");
}
}
}
pub fn new_default_context(c: workcache::Context, p: Path) -> BuildContext {
BuildContext {
context: Context {
+ cfgs: ~[],
+ rustc_flags: RustcFlags::default(),
use_rust_path_hack: false,
sysroot: p
},
in_hash == digest_only_date(&Path(path))
}
-
pub fn new_workcache_context(p: &Path) -> workcache::Context {
let db_file = p.push("rustpkg_db.json"); // ??? probably wrong
debug!("Workcache database file: %s", db_file.to_str());
// Context data structure used by rustpkg
-use std::os;
+use std::{io, os};
use extra::workcache;
+use rustc::driver::session::{OptLevel, No};
#[deriving(Clone)]
pub struct Context {
+ // Config strings that the user passed in with --cfg
+ cfgs: ~[~str],
+ // Flags to pass to rustc
+ rustc_flags: RustcFlags,
// If use_rust_path_hack is true, rustpkg searches for sources
// in *package* directories that are in the RUST_PATH (for example,
// FOO/src/bar-0.1 instead of FOO). The flag doesn't affect where
pub fn sysroot_to_use(&self) -> Path {
self.context.sysroot_to_use()
}
+
+ /// Returns the flags to pass to rustc, as a vector of strings
+ pub fn flag_strs(&self) -> ~[~str] {
+ self.context.flag_strs()
+ }
+
+ pub fn compile_upto(&self) -> StopBefore {
+ self.context.compile_upto()
+ }
+}
+
+/*
+Deliberately unsupported rustc flags:
+ --bin, --lib inferred from crate file names
+ -L inferred from extern mods
+ --out-dir inferred from RUST_PATH
+ --test use `rustpkg test`
+ -v -h --ls don't make sense with rustpkg
+ -W -A -D -F - use pragmas instead
+
+rustc flags that aren't implemented yet:
+ --passes
+ --llvm-arg
+ --target-feature
+ --android-cross-path
+*/
+pub struct RustcFlags {
+ compile_upto: StopBefore,
+ // Linker to use with the --linker flag
+ linker: Option<~str>,
+ // Extra arguments to pass to rustc with the --link-args flag
+ link_args: Option<~str>,
+ // Optimization level. 0 = default. -O = 2.
+ optimization_level: OptLevel,
+ // True if the user passed in --save-temps
+ save_temps: bool,
+ // Target (defaults to rustc's default target)
+ target: Option<~str>,
+ // Target CPU (defaults to rustc's default target CPU)
+ target_cpu: Option<~str>,
+ // Any -Z features
+ experimental_features: Option<~[~str]>
+}
+
+impl Clone for RustcFlags {
+ fn clone(&self) -> RustcFlags {
+ RustcFlags {
+ compile_upto: self.compile_upto,
+ linker: self.linker.clone(),
+ link_args: self.link_args.clone(),
+ optimization_level: self.optimization_level,
+ save_temps: self.save_temps,
+ target: self.target.clone(),
+ target_cpu: self.target_cpu.clone(),
+ experimental_features: self.experimental_features.clone()
+ }
+ }
+}
+
+#[deriving(Eq)]
+pub enum StopBefore {
+ Nothing, // compile everything
+ Link, // --no-link
+ LLVMCompileBitcode, // --emit-llvm without -S
+ LLVMAssemble, // -S --emit-llvm
+ Assemble, // -S without --emit-llvm
+ Trans, // --no-trans
+ Pretty, // --pretty
+ Analysis, // --parse-only
}
impl Context {
pub fn sysroot(&self) -> Path {
self.sysroot.clone()
}
-}
-impl Context {
/// Debugging
pub fn sysroot_str(&self) -> ~str {
self.sysroot.to_str()
self.sysroot.pop().pop().pop()
}
}
+
+ /// Returns the flags to pass to rustc, as a vector of strings
+ pub fn flag_strs(&self) -> ~[~str] {
+ self.rustc_flags.flag_strs()
+ }
+
+ pub fn compile_upto(&self) -> StopBefore {
+ self.rustc_flags.compile_upto
+ }
}
/// We assume that if ../../rustc exists, then we're running
debug!("Checking whether %s is in target", sysroot.to_str());
os::path_is_dir(&sysroot.pop().pop().push("rustc"))
}
+
+impl RustcFlags {
+ fn flag_strs(&self) -> ~[~str] {
+ let linker_flag = match self.linker {
+ Some(ref l) => ~[~"--linker", l.clone()],
+ None => ~[]
+ };
+ let link_args_flag = match self.link_args {
+ Some(ref l) => ~[~"--link-args", l.clone()],
+ None => ~[]
+ };
+ let save_temps_flag = if self.save_temps { ~[~"--save-temps"] } else { ~[] };
+ let target_flag = match self.target {
+ Some(ref l) => ~[~"--target", l.clone()],
+ None => ~[]
+ };
+ let target_cpu_flag = match self.target_cpu {
+ Some(ref l) => ~[~"--target-cpu", l.clone()],
+ None => ~[]
+ };
+ let z_flags = match self.experimental_features {
+ Some(ref ls) => ls.flat_map(|s| ~[~"-Z", s.clone()]),
+ None => ~[]
+ };
+ linker_flag
+ + link_args_flag
+ + save_temps_flag
+ + target_flag
+ + target_cpu_flag
+ + z_flags + (match self.compile_upto {
+ LLVMCompileBitcode => ~[~"--emit-llvm"],
+ LLVMAssemble => ~[~"--emit-llvm", ~"-S"],
+ Link => ~[~"-c"],
+ Trans => ~[~"--no-trans"],
+ Assemble => ~[~"-S"],
+ // n.b. Doesn't support all flavors of --pretty (yet)
+ Pretty => ~[~"--pretty"],
+ Analysis => ~[~"--parse-only"],
+ Nothing => ~[]
+ })
+ }
+
+ pub fn default() -> RustcFlags {
+ RustcFlags {
+ linker: None,
+ link_args: None,
+ compile_upto: Nothing,
+ optimization_level: No,
+ save_temps: false,
+ target: None,
+ target_cpu: None,
+ experimental_features: None
+ }
+ }
+}
+
+/// Returns true if any of the flags given are incompatible with the cmd
+pub fn flags_ok_for_cmd(flags: &RustcFlags,
+ cfgs: &[~str],
+ cmd: &str, user_supplied_opt_level: bool) -> bool {
+ let complain = |s| {
+ io::println(fmt!("The %s option can only be used with the build command:
+ rustpkg [options..] build %s [package-ID]", s, s));
+ };
+
+ if flags.linker.is_some() && cmd != "build" && cmd != "install" {
+ io::println("The --linker option can only be used with the build or install commands.");
+ return true;
+ }
+ if flags.link_args.is_some() && cmd != "build" && cmd != "install" {
+ io::println("The --link-args option can only be used with the build or install commands.");
+ return true;
+ }
+
+ if !cfgs.is_empty() && cmd != "build" && cmd != "install" {
+ io::println("The --cfg option can only be used with the build or install commands.");
+ return true;
+ }
+
+ if user_supplied_opt_level && cmd != "build" && cmd != "install" {
+ io::println("The -O and --opt-level options can only be used with the build \
+ or install commands.");
+ return true;
+ }
+
+ if flags.save_temps && cmd != "build" && cmd != "install" {
+ io::println("The --save-temps option can only be used with the build \
+ or install commands.");
+ return true;
+ }
+
+ if flags.target.is_some() && cmd != "build" && cmd != "install" {
+ io::println("The --target option can only be used with the build \
+ or install commands.");
+ return true;
+ }
+ if flags.target_cpu.is_some() && cmd != "build" && cmd != "install" {
+ io::println("The --target-cpu option can only be used with the build \
+ or install commands.");
+ return true;
+ }
+ if flags.experimental_features.is_some() && cmd != "build" && cmd != "install" {
+ io::println("The -Z option can only be used with the build or install commands.");
+ return true;
+ }
+
+ match flags.compile_upto {
+ Link if cmd != "build" => {
+ complain("--no-link");
+ true
+ }
+ Trans if cmd != "build" => {
+ complain("--no-trans");
+ true
+ }
+ Assemble if cmd != "build" => {
+ complain("-S");
+ true
+ }
+ Pretty if cmd != "build" => {
+ complain("--pretty");
+ true
+ }
+ Analysis if cmd != "build" => {
+ complain("--parse-only");
+ true
+ }
+ LLVMCompileBitcode if cmd != "build" => {
+ complain("--emit-llvm");
+ true
+ }
+ LLVMAssemble if cmd != "build" => {
+ complain("--emit-llvm");
+ true
+ }
+ _ => false
+ }
+}
/// True if the ID has multiple components
pub fn is_complex(&self) -> bool {
self.short_name != self.path.to_str()
- }
+ }
+
+ pub fn prefixes_iter(&self) -> Prefixes {
+ Prefixes {
+ components: self.path.components().to_owned(),
+ remaining: ~[]
+ }
+ }
+
+}
+
+struct Prefixes {
+ priv components: ~[~str],
+ priv remaining: ~[~str]
+}
+
+impl Iterator<(Path, Path)> for Prefixes {
+ #[inline]
+ fn next(&mut self) -> Option<(Path, Path)> {
+ if self.components.len() <= 1 {
+ None
+ }
+ else {
+ let last = self.components.pop();
+ self.remaining.push(last);
+ // converting to str and then back is a little unfortunate
+ Some((Path(self.components.to_str()), Path(self.remaining.to_str())))
+ }
+ }
}
impl ToStr for PkgId {
write(hasher, data);
hasher.result_str()
}
+
use crate::Crate;
use messages::*;
use source_control::{git_clone, git_clone_general};
-use path_util::{find_dir_using_rust_path_hack, default_workspace};
+use path_util::{find_dir_using_rust_path_hack, default_workspace, make_dir_rwx_recursive};
use util::compile_crate;
use workspace::is_workspace;
use workcache_support;
let dir: Path = match path {
Some(d) => (*d).clone(),
None => {
+ // See if any of the prefixes of this package ID form a valid package ID
+ // That is, is this a package ID that points into the middle of a workspace?
+ for (prefix, suffix) in id.prefixes_iter() {
+ let package_id = PkgId::new(prefix.to_str());
+ let path = workspace.push("src").push_rel(&package_id.path);
+ debug!("in loop: checking if %s is a directory", path.to_str());
+ if os::path_is_dir(&path) {
+ let ps = PkgSrc::new(workspace.clone(),
+ use_rust_path_hack,
+ PkgId::new(prefix.to_str()));
+ debug!("pkgsrc: Returning [%s|%s|%s]", workspace.to_str(),
+ ps.start_dir.push_rel(&suffix).to_str(), ps.id.to_str());
+
+ return PkgSrc {
+ workspace: workspace,
+ start_dir: ps.start_dir.push_rel(&suffix),
+ id: ps.id,
+ libs: ~[],
+ mains: ~[],
+ tests: ~[],
+ benchs: ~[]
+ }
+
+ };
+ }
+
+ // Ok, no prefixes work, so try fetching from git
let mut ok_d = None;
for w in to_try.iter() {
debug!("Calling fetch_git on %s", w.to_str());
if use_rust_path_hack {
match find_dir_using_rust_path_hack(&id) {
Some(d) => d,
- None => cond.raise((id.clone(),
- ~"supplied path for package dir does not \
- exist, and couldn't interpret it as a URL fragment"))
+ None => {
+ cond.raise((id.clone(),
+ ~"supplied path for package dir does not \
+ exist, and couldn't interpret it as a URL fragment"))
+ }
}
}
else {
cond.raise((id.clone(),
- ~"supplied path for package dir does not \
- exist, and couldn't interpret it as a URL fragment"))
-
+ ~"supplied path for package dir does not \
+ exist, and couldn't interpret it as a URL fragment"))
}
}
}
non-directory"));
}
+ debug!("pkgsrc: Returning {%s|%s|%s}", workspace.to_str(),
+ dir.to_str(), id.to_str());
+
PkgSrc {
workspace: workspace,
start_dir: dir,
url, clone_target.to_str(), pkgid.version.to_str());
if git_clone_general(url, &clone_target, &pkgid.version) {
- // since the operation succeeded, move clone_target to local
- if !os::rename_file(&clone_target, local) {
- None
+ // Since the operation succeeded, move clone_target to local.
+ // First, create all ancestor directories.
+ if make_dir_rwx_recursive(&local.pop())
+ && os::rename_file(&clone_target, local) {
+ Some(local.clone())
}
else {
- Some(local.clone())
+ None
}
}
else {
pub use target::{OutputType, Main, Lib, Test, Bench, Target, Build, Install};
pub use version::{Version, NoVersion, split_version_general, try_parsing_version};
pub use rustc::metadata::filesearch::rust_path;
+use rustc::driver::driver::host_triple;
use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
use std::os::mkdir_recursive;
/// succeeded.
pub fn make_dir_rwx(p: &Path) -> bool { os::make_dir(p, U_RWX) }
+pub fn make_dir_rwx_recursive(p: &Path) -> bool { os::mkdir_recursive(p, U_RWX) }
+
// n.b. The next three functions ignore the package version right
// now. Should fix that.
/// True if there's a directory in <workspace> with
/// pkgid's short name
pub fn workspace_contains_package_id(pkgid: &PkgId, workspace: &Path) -> bool {
- debug!("Checking in src dir of %s for %s",
- workspace.to_str(), pkgid.to_str());
workspace_contains_package_id_(pkgid, workspace, |p| { p.push("src") }).is_some()
}
pub fn workspace_contains_package_id_(pkgid: &PkgId, workspace: &Path,
// Returns the directory it was actually found in
workspace_to_src_dir: &fn(&Path) -> Path) -> Option<Path> {
+ if !os::path_is_dir(workspace) {
+ return None;
+ }
+
let src_dir = workspace_to_src_dir(workspace);
let mut found = None;
found
}
+/// Return the target-specific build subdirectory, pushed onto `base`;
+/// doesn't check that it exists or create it
+pub fn target_build_dir(workspace: &Path) -> Path {
+ workspace.push("build").push(host_triple())
+}
+
+/// Return the target-specific lib subdirectory, pushed onto `base`;
+/// doesn't check that it exists or create it
+fn target_lib_dir(workspace: &Path) -> Path {
+ workspace.push("lib").push(host_triple())
+}
+
+/// Return the bin subdirectory, pushed onto `base`;
+/// doesn't check that it exists or create it
+/// note: this isn't target-specific
+fn target_bin_dir(workspace: &Path) -> Path {
+ workspace.push("bin")
+}
+
/// Figure out what the executable name for <pkgid> in <workspace>'s build
/// directory is, and if the file exists, return it.
pub fn built_executable_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Path> {
- let mut result = workspace.push("build");
+ let mut result = target_build_dir(workspace);
// should use a target-specific subdirectory
result = mk_output_path(Main, Build, pkgid, result);
debug!("built_executable_in_workspace: checking whether %s exists",
}
fn output_in_workspace(pkgid: &PkgId, workspace: &Path, what: OutputType) -> Option<Path> {
- let mut result = workspace.push("build");
+ let mut result = target_build_dir(workspace);
// should use a target-specific subdirectory
result = mk_output_path(what, Build, pkgid, result);
debug!("output_in_workspace: checking whether %s exists",
}
/// Does the actual searching stuff
-pub fn installed_library_in_workspace(short_name: &str, workspace: &Path) -> Option<Path> {
+pub fn installed_library_in_workspace(pkg_path: &Path, workspace: &Path) -> Option<Path> {
// This could break once we're handling multiple versions better -- I should add a test for it
- library_in_workspace(&Path(short_name), short_name, Install, workspace, "lib", &NoVersion)
+ match pkg_path.filename() {
+ None => None,
+ Some(short_name) => library_in_workspace(pkg_path,
+ short_name,
+ Install,
+ workspace,
+ "lib",
+ &NoVersion)
+ }
}
/// `workspace` is used to figure out the directory to search.
prefix = %s", short_name, where, workspace.to_str(), prefix);
let dir_to_search = match where {
- Build => workspace.push(prefix).push_rel(path),
- Install => workspace.push(prefix)
+ Build => target_build_dir(workspace).push_rel(path),
+ Install => target_lib_dir(workspace)
};
+
+ library_in(short_name, version, &dir_to_search)
+}
+
+// rustc doesn't use target-specific subdirectories
+pub fn system_library(sysroot: &Path, lib_name: &str) -> Option<Path> {
+ library_in(lib_name, &NoVersion, &sysroot.push("lib"))
+}
+
+fn library_in(short_name: &str, version: &Version, dir_to_search: &Path) -> Option<Path> {
debug!("Listing directory %s", dir_to_search.to_str());
- let dir_contents = os::list_dir(&dir_to_search);
+ let dir_contents = os::list_dir(dir_to_search);
debug!("dir has %? entries", dir_contents.len());
let lib_prefix = fmt!("%s%s", os::consts::DLL_PREFIX, short_name);
};
// Artifacts in the build directory live in a package-ID-specific subdirectory,
// but installed ones don't.
- let result = match where {
- Build => workspace.push(subdir).push_rel(&pkgid.path),
- _ => workspace.push(subdir)
+ let result = match (where, what) {
+ (Build, _) => target_build_dir(workspace).push_rel(&pkgid.path),
+ (Install, Lib) => target_lib_dir(workspace),
+ (Install, _) => target_bin_dir(workspace)
};
if !os::path_exists(&result) && !mkdir_recursive(&result, U_RWX) {
cond.raise((result.clone(), fmt!("target_file_in_workspace couldn't \
pub fn build_pkg_id_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path {
use conditions::bad_path::cond;
- let mut result = workspace.push("build");
- // n.b. Should actually use a target-specific
- // subdirectory of build/
+ let mut result = target_build_dir(workspace);
result = result.push_rel(&pkgid.path);
+ debug!("Creating build dir %s for package id %s", result.to_str(),
+ pkgid.to_str());
if os::path_exists(&result) || os::mkdir_recursive(&result, U_RWX) {
result
}
}
None
}
+
+/// True if the user set RUST_PATH to something non-empty --
+/// as opposed to the default paths that rustpkg adds automatically
+pub fn user_set_rust_path() -> bool {
+ match os::getenv("RUST_PATH") {
+ None | Some(~"") => false,
+ Some(_) => true
+ }
+}
use extra::{getopts};
use syntax::{ast, diagnostic};
use util::*;
-use messages::*;
+use messages::{error, warn, note};
use path_util::build_pkg_id_in_workspace;
use path_util::{U_RWX, in_rust_path};
use path_util::{built_executable_in_workspace, built_library_in_workspace, default_workspace};
use path_util::{target_executable_in_workspace, target_library_in_workspace};
use source_control::is_git_dir;
use workspace::{each_pkg_parent_workspace, pkg_parent_workspaces, cwd_to_workspace};
-use context::{BuildContext, Context};
+use context::{Context, BuildContext,
+ RustcFlags, Trans, Link, Nothing, Pretty, Analysis, Assemble,
+ LLVMAssemble, LLVMCompileBitcode};
use package_id::PkgId;
use package_source::PkgSrc;
use workcache_support::{discover_outputs, digest_only_date};
let exe = self.build_dir.push(~"pkg" + util::exe_suffix());
util::compile_crate_from_input(&self.input,
exec,
+ Nothing,
&self.build_dir,
sess,
crate);
/// second is a list of declared and discovered inputs
fn install(&self, src: PkgSrc) -> (~[Path], ~[(~str, ~str)]);
/// Returns a list of installed files
- fn install_no_build(&self, workspace: &Path, id: &PkgId) -> ~[Path];
+ fn install_no_build(&self,
+ source_workspace: &Path,
+ target_workspace: &Path,
+ id: &PkgId) -> ~[Path];
fn prefer(&self, _id: &str, _vers: Option<~str>);
fn test(&self);
fn uninstall(&self, _id: &str, _vers: Option<~str>);
debug!("No package script, continuing");
~[]
}
- };
+ } + self.context.cfgs;
// If there was a package script, it should have finished
// the build already. Otherwise...
// install to the first workspace in the RUST_PATH if there's
// a non-default RUST_PATH. This code installs to the same
// workspace the package was built in.
- debug!("install: destination workspace = %s, id = %s",
- destination_workspace, id_str);
- let result = subself.install_no_build(&Path(destination_workspace), &sub_id);
+ let actual_workspace = if path_util::user_set_rust_path() {
+ default_workspace()
+ }
+ else {
+ Path(destination_workspace)
+ };
+ debug!("install: destination workspace = %s, id = %s, installing to %s",
+ destination_workspace, id_str, actual_workspace.to_str());
+ let result = subself.install_no_build(&Path(destination_workspace),
+ &actual_workspace,
+ &sub_id);
debug!("install: id = %s, about to call discover_outputs, %?",
id_str, result.to_str());
discover_outputs(exec, result.clone());
sub_files.write(|r| { *r = result.clone(); });
sub_inputs.write(|r| { *r = *r + exec.lookup_discovered_inputs() });
+ note(fmt!("Installed package %s to %s", id_str, actual_workspace.to_str()));
}
};
(installed_files.unwrap(), inputs.unwrap())
}
- fn install_no_build(&self, workspace: &Path, id: &PkgId) -> ~[Path] {
+ fn install_no_build(&self,
+ source_workspace: &Path,
+ target_workspace: &Path,
+ id: &PkgId) -> ~[Path] {
use conditions::copy_failed::cond;
// Now copy stuff into the install dirs
- let maybe_executable = built_executable_in_workspace(id, workspace);
- let maybe_library = built_library_in_workspace(id, workspace);
- let target_exec = target_executable_in_workspace(id, workspace);
- let target_lib = maybe_library.map(|_p| target_library_in_workspace(id, workspace));
+ let maybe_executable = built_executable_in_workspace(id, source_workspace);
+ let maybe_library = built_library_in_workspace(id, source_workspace);
+ let target_exec = target_executable_in_workspace(id, target_workspace);
+ let target_lib = maybe_library.map(|_p| target_library_in_workspace(id, target_workspace));
debug!("target_exec = %s target_lib = %? \
maybe_executable = %? maybe_library = %?",
pub fn main_args(args: &[~str]) {
let opts = ~[getopts::optflag("h"), getopts::optflag("help"),
+ getopts::optflag("no-link"),
+ getopts::optflag("no-trans"),
+ // n.b. Ignores different --pretty options for now
+ getopts::optflag("pretty"),
+ getopts::optflag("parse-only"),
+ getopts::optflag("S"), getopts::optflag("assembly"),
getopts::optmulti("c"), getopts::optmulti("cfg"),
getopts::optflag("v"), getopts::optflag("version"),
- getopts::optflag("r"), getopts::optflag("rust-path-hack")];
+ getopts::optflag("r"), getopts::optflag("rust-path-hack"),
+ getopts::optopt("sysroot"),
+ getopts::optflag("emit-llvm"),
+ getopts::optopt("linker"),
+ getopts::optopt("link-args"),
+ getopts::optopt("opt-level"),
+ getopts::optflag("O"),
+ getopts::optflag("save-temps"),
+ getopts::optopt("target"),
+ getopts::optopt("target-cpu"),
+ getopts::optmulti("Z") ];
let matches = &match getopts::getopts(args, opts) {
result::Ok(m) => m,
result::Err(f) => {
return;
}
};
- let help = getopts::opt_present(matches, "h") ||
- getopts::opt_present(matches, "help");
+ let mut help = getopts::opt_present(matches, "h") ||
+ getopts::opt_present(matches, "help");
+ let no_link = getopts::opt_present(matches, "no-link");
+ let no_trans = getopts::opt_present(matches, "no-trans");
+ let supplied_sysroot = getopts::opt_val(matches, "sysroot");
+ let generate_asm = getopts::opt_present(matches, "S") ||
+ getopts::opt_present(matches, "assembly");
+ let parse_only = getopts::opt_present(matches, "parse-only");
+ let pretty = getopts::opt_present(matches, "pretty");
+ let emit_llvm = getopts::opt_present(matches, "emit-llvm");
if getopts::opt_present(matches, "v") ||
getopts::opt_present(matches, "version") {
let use_rust_path_hack = getopts::opt_present(matches, "r") ||
getopts::opt_present(matches, "rust-path-hack");
+ let linker = getopts::opt_maybe_str(matches, "linker");
+ let link_args = getopts::opt_maybe_str(matches, "link-args");
+ let cfgs = getopts::opt_strs(matches, "cfg") + getopts::opt_strs(matches, "c");
+ let mut user_supplied_opt_level = true;
+ let opt_level = match getopts::opt_maybe_str(matches, "opt-level") {
+ Some(~"0") => session::No,
+ Some(~"1") => session::Less,
+ Some(~"2") => session::Default,
+ Some(~"3") => session::Aggressive,
+ _ if getopts::opt_present(matches, "O") => session::Default,
+ _ => {
+ user_supplied_opt_level = false;
+ session::No
+ }
+ };
+
+ let save_temps = getopts::opt_present(matches, "save-temps");
+ let target = getopts::opt_maybe_str(matches, "target");
+ let target_cpu = getopts::opt_maybe_str(matches, "target-cpu");
+ let experimental_features = {
+ let strs = getopts::opt_strs(matches, "Z");
+ if getopts::opt_present(matches, "Z") {
+ Some(strs)
+ }
+ else {
+ None
+ }
+ };
+
let mut args = matches.free.clone();
args.shift();
return usage::general();
}
+ let rustc_flags = RustcFlags {
+ linker: linker,
+ link_args: link_args,
+ optimization_level: opt_level,
+ compile_upto: if no_trans {
+ Trans
+ } else if no_link {
+ Link
+ } else if pretty {
+ Pretty
+ } else if parse_only {
+ Analysis
+ } else if emit_llvm && generate_asm {
+ LLVMAssemble
+ } else if generate_asm {
+ Assemble
+ } else if emit_llvm {
+ LLVMCompileBitcode
+ } else {
+ Nothing
+ },
+ save_temps: save_temps,
+ target: target,
+ target_cpu: target_cpu,
+ experimental_features: experimental_features
+ };
+
let mut cmd_opt = None;
for a in args.iter() {
if util::is_cmd(*a) {
}
let cmd = match cmd_opt {
None => return usage::general(),
- Some(cmd) => if help {
- return match *cmd {
- ~"build" => usage::build(),
- ~"clean" => usage::clean(),
- ~"do" => usage::do_cmd(),
- ~"info" => usage::info(),
- ~"install" => usage::install(),
- ~"list" => usage::list(),
- ~"prefer" => usage::prefer(),
- ~"test" => usage::test(),
- ~"uninstall" => usage::uninstall(),
- ~"unprefer" => usage::unprefer(),
- _ => usage::general()
- };
- }
- else {
- cmd
+ Some(cmd) => {
+ help |= context::flags_ok_for_cmd(&rustc_flags, cfgs, *cmd, user_supplied_opt_level);
+ if help {
+ return match *cmd {
+ ~"build" => usage::build(),
+ ~"clean" => usage::clean(),
+ ~"do" => usage::do_cmd(),
+ ~"info" => usage::info(),
+ ~"install" => usage::install(),
+ ~"list" => usage::list(),
+ ~"prefer" => usage::prefer(),
+ ~"test" => usage::test(),
+ ~"uninstall" => usage::uninstall(),
+ ~"unprefer" => usage::unprefer(),
+ _ => usage::general()
+ };
+ } else {
+ cmd
+ }
}
};
// I had to add this type annotation to get the code to typecheck
let mut remaining_args: ~[~str] = remaining_args.map(|s| (*s).clone()).collect();
remaining_args.shift();
- let sroot = filesearch::get_or_default_sysroot();
+ let sroot = match supplied_sysroot {
+ Some(getopts::Val(s)) => Path(s),
+ _ => filesearch::get_or_default_sysroot()
+ };
+
debug!("Using sysroot: %s", sroot.to_str());
debug!("Will store workcache in %s", default_workspace().to_str());
BuildContext {
context: Context {
- use_rust_path_hack: use_rust_path_hack,
- sysroot: sroot, // Currently, only tests override this
- },
+ cfgs: cfgs,
+ rustc_flags: rustc_flags,
+ use_rust_path_hack: use_rust_path_hack,
+ sysroot: sroot, // Currently, only tests override this
+ },
workcache_context: api::default_context(default_workspace()).workcache_context
}.run(*cmd, remaining_args)
}
/// return Some(p) (returns the first one of there are multiple matches.) Return
/// None if there's no such path.
/// FIXME #8711: This ignores the desired version.
-pub fn find_installed_library_in_rust_path(short_name: &str, _version: &Version) -> Option<Path> {
+pub fn find_installed_library_in_rust_path(pkg_path: &Path, _version: &Version) -> Option<Path> {
let rp = rust_path();
+ debug!("find_installed_library_in_rust_path: looking for path %s", pkg_path.to_str());
for p in rp.iter() {
- match installed_library_in_workspace(short_name, p) {
+ match installed_library_in_workspace(pkg_path, p) {
Some(path) => return Some(path),
None => ()
}
// rustpkg unit tests
-use context::{BuildContext, Context};
+use context::{BuildContext, Context, RustcFlags};
use std::{io, libc, os, run, str, task};
use extra::arc::Arc;
use extra::arc::RWArc;
use extra::workcache;
use extra::workcache::{Database, Logger};
use extra::treemap::TreeMap;
+use extra::getopts::groups::getopts;
use std::run::ProcessOutput;
use installed_packages::list_installed_packages;
use package_id::{PkgId};
target_bench_in_workspace, make_dir_rwx, U_RWX,
library_in_workspace, installed_library_in_workspace,
built_bench_in_workspace, built_test_in_workspace,
- built_library_in_workspace, built_executable_in_workspace};
+ built_library_in_workspace, built_executable_in_workspace, target_build_dir};
+use rustc::back::link::get_cc_prog;
use rustc::metadata::filesearch::rust_path;
-use rustc::driver::driver::host_triple;
+use rustc::driver::driver::{build_session, build_session_options, host_triple, optgroups};
+use syntax::diagnostic;
use target::*;
use package_source::PkgSrc;
BuildContext {
workcache_context: context,
context: Context {
+ cfgs: ~[],
+ rustc_flags: RustcFlags::default(),
+
use_rust_path_hack: false,
sysroot: sysroot
}
fn mk_workspace(workspace: &Path, short_name: &Path, version: &Version) -> Path {
// include version number in directory name
- let package_dir = workspace.push("src").push(fmt!("%s-%s",
- short_name.to_str(), version.to_str()));
+ let package_dir = workspace.push_many([~"src", fmt!("%s-%s",
+ short_name.to_str(), version.to_str())]);
assert!(os::mkdir_recursive(&package_dir, U_RWX));
package_dir
}
fn mk_temp_workspace(short_name: &Path, version: &Version) -> Path {
let package_dir = mk_empty_workspace(short_name,
- version, "temp_workspace").push("src").push(fmt!("%s-%s",
+ version, "temp_workspace").push_many([~"src", fmt!("%s-%s",
short_name.to_str(),
- version.to_str()));
+ version.to_str())]);
debug!("Created %s and does it exist? %?", package_dir.to_str(),
os::path_is_dir(&package_dir));
// Returns the path to rustpkg
fn rustpkg_exec() -> Path {
// Ugh
- let first_try = test_sysroot().push("lib").push("rustc")
- .push(host_triple()).push("bin").push("rustpkg");
+ let first_try = test_sysroot().push_many(
+ [~"lib", ~"rustc", host_triple(), ~"bin", ~"rustpkg"]);
if is_executable(&first_try) {
first_try
}
else {
- let second_try = test_sysroot().push("bin").push("rustpkg");
+ let second_try = test_sysroot().push_many([~"bin", ~"rustpkg"]);
if is_executable(&second_try) {
second_try
}
}
fn command_line_test(args: &[~str], cwd: &Path) -> ProcessOutput {
+ command_line_test_with_env(args, cwd, None).expect("Command line test failed")
+}
+
+fn command_line_test_partial(args: &[~str], cwd: &Path) -> Option<ProcessOutput> {
command_line_test_with_env(args, cwd, None)
}
/// invoked from) with the given arguments, in the given working directory.
/// Returns the process's output.
fn command_line_test_with_env(args: &[~str], cwd: &Path, env: Option<~[(~str, ~str)]>)
- -> ProcessOutput {
+ -> Option<ProcessOutput> {
let cmd = rustpkg_exec().to_str();
- debug!("cd %s; %s %s",
- cwd.to_str(), cmd, args.connect(" "));
+ let env_str = match env {
+ Some(ref pairs) => pairs.map(|&(ref k, ref v)| { fmt!("%s=%s", *k, *v) }).connect(","),
+ None => ~""
+ };
+ debug!("%s cd %s; %s %s", env_str, cwd.to_str(), cmd, args.connect(" "));
assert!(os::path_is_dir(&*cwd));
let cwd = (*cwd).clone();
let mut prog = run::Process::new(cmd, args, run::ProcessOptions {
to make sure the command succeeded
*/
if output.status != 0 {
- fail!("Command %s %? failed with exit code %?; its output was {{{ %s }}}",
+ debug!("Command %s %? failed with exit code %?; its output was {{{ %s }}}",
cmd, args, output.status,
str::from_utf8(output.output) + str::from_utf8(output.error));
+ None
+ }
+ else {
+ Some(output)
}
- output
}
fn create_local_package(pkgid: &PkgId) -> Path {
fn create_local_package_in(pkgid: &PkgId, pkgdir: &Path) -> Path {
- let package_dir = pkgdir.push("src").push(pkgid.to_str());
+ let package_dir = pkgdir.push_many([~"src", pkgid.to_str()]);
// Create main, lib, test, and bench files
assert!(os::mkdir_recursive(&package_dir, U_RWX));
let package_dir = create_local_package(pkgid);
create_local_package_in(subord_pkgid, &package_dir);
// Write a main.rs file into pkgid that references subord_pkgid
- writeFile(&package_dir.push("src").push(pkgid.to_str()).push("main.rs"),
+ writeFile(&package_dir.push_many([~"src", pkgid.to_str(), ~"main.rs"]),
fmt!("extern mod %s;\nfn main() {}",
subord_pkgid.short_name));
// Write a lib.rs file into subord_pkgid that has something in it
- writeFile(&package_dir.push("src").push(subord_pkgid.to_str()).push("lib.rs"),
+ writeFile(&package_dir.push_many([~"src", subord_pkgid.to_str(), ~"lib.rs"]),
"pub fn f() {}");
- debug!("Dry run -- would create packages %s and %s in %s",
- pkgid.to_str(),
- subord_pkgid.to_str(),
- package_dir.to_str());
package_dir
}
}
-fn assert_lib_exists(repo: &Path, short_name: &str, v: Version) {
- assert!(lib_exists(repo, short_name, v));
+fn assert_lib_exists(repo: &Path, pkg_path: &Path, v: Version) {
+ assert!(lib_exists(repo, pkg_path, v));
}
-fn lib_exists(repo: &Path, short_name: &str, _v: Version) -> bool { // ??? version?
- debug!("assert_lib_exists: repo = %s, short_name = %s", repo.to_str(), short_name);
- let lib = installed_library_in_workspace(short_name, repo);
+fn lib_exists(repo: &Path, pkg_path: &Path, _v: Version) -> bool { // ??? version?
+ debug!("assert_lib_exists: repo = %s, pkg_path = %s", repo.to_str(), pkg_path.to_str());
+ let lib = installed_library_in_workspace(pkg_path, repo);
debug!("assert_lib_exists: checking whether %? exists", lib);
lib.is_some() && {
let libname = lib.get_ref();
}
}
+fn object_file_exists(repo: &Path, short_name: &str) -> bool {
+ file_exists(repo, short_name, "o")
+}
+
+fn assembly_file_exists(repo: &Path, short_name: &str) -> bool {
+ file_exists(repo, short_name, "s")
+}
+
+fn llvm_assembly_file_exists(repo: &Path, short_name: &str) -> bool {
+ file_exists(repo, short_name, "ll")
+}
+
+fn llvm_bitcode_file_exists(repo: &Path, short_name: &str) -> bool {
+ file_exists(repo, short_name, "bc")
+}
+
+fn file_exists(repo: &Path, short_name: &str, extension: &str) -> bool {
+ os::path_exists(&target_build_dir(repo).push_many([short_name.to_owned(),
+ fmt!("%s.%s", short_name, extension)]))
+}
+
fn assert_built_library_exists(repo: &Path, short_name: &str) {
assert!(built_library_exists(repo, short_name));
}
fn command_line_test_output_with_env(args: &[~str], env: ~[(~str, ~str)]) -> ~[~str] {
let mut result = ~[];
- let p_output = command_line_test_with_env(args, &os::getcwd(), Some(env));
+ let p_output = command_line_test_with_env(args,
+ &os::getcwd(), Some(env)).expect("Command-line test failed");
let test_output = str::from_utf8(p_output.output);
for s in test_output.split_iter('\n') {
result.push(s.to_owned());
&NoVersion).expect("lib_output_file_name")
}
-fn output_file_name(workspace: &Path, short_name: &str) -> Path {
- workspace.push("build").push(short_name).push(fmt!("%s%s", short_name, os::EXE_SUFFIX))
+fn output_file_name(workspace: &Path, short_name: ~str) -> Path {
+ target_build_dir(workspace).push(short_name).push(fmt!("%s%s", short_name, os::EXE_SUFFIX))
}
fn touch_source_file(workspace: &Path, pkgid: &PkgId) {
use conditions::bad_path::cond;
- let pkg_src_dir = workspace.push("src").push(pkgid.to_str());
+ let pkg_src_dir = workspace.push_many([~"src", pkgid.to_str()]);
let contents = os::list_dir_path(&pkg_src_dir);
for p in contents.iter() {
if p.filetype() == Some(".rs") {
/// Add a comment at the end
fn frob_source_file(workspace: &Path, pkgid: &PkgId) {
use conditions::bad_path::cond;
- let pkg_src_dir = workspace.push("src").push(pkgid.to_str());
+ let pkg_src_dir = workspace.push_many([~"src", pkgid.to_str()]);
let contents = os::list_dir_path(&pkg_src_dir);
let mut maybe_p = None;
for p in contents.iter() {
assert!(os::path_exists(&exec));
assert!(is_rwx(&exec));
- let lib = installed_library_in_workspace(temp_pkg_id.short_name, &temp_workspace);
+ let lib = installed_library_in_workspace(&temp_pkg_id.path, &temp_workspace);
debug!("lib = %?", lib);
assert!(lib.map_default(false, |l| os::path_exists(l)));
assert!(lib.map_default(false, |l| is_rwx(l)));
let temp_pkg_id = git_repo_pkg();
let repo = init_git_repo(&temp_pkg_id.path);
debug!("repo = %s", repo.to_str());
- let repo_subdir = repo.push("mockgithub.com").push("catamorphism").push("test-pkg");
+ let repo_subdir = repo.push_many([~"mockgithub.com", ~"catamorphism", ~"test-pkg"]);
debug!("repo_subdir = %s", repo_subdir.to_str());
writeFile(&repo_subdir.push("main.rs"),
let _built_lib =
built_library_in_workspace(&temp_pkg_id,
&ws).expect("test_install_git: built lib should exist");
- assert_lib_exists(&ws, temp_pkg_id.short_name, temp_pkg_id.version.clone());
+ assert_lib_exists(&ws, &temp_pkg_id.path, temp_pkg_id.version.clone());
let built_test = built_test_in_workspace(&temp_pkg_id,
&ws).expect("test_install_git: built test should exist");
assert!(os::path_exists(&built_test));
fn test_package_version() {
let local_path = "mockgithub.com/catamorphism/test_pkg_version";
let repo = init_git_repo(&Path(local_path));
- let repo_subdir = repo.push("mockgithub.com").push("catamorphism").push("test_pkg_version");
+ let repo_subdir = repo.push_many([~"mockgithub.com", ~"catamorphism", ~"test_pkg_version"]);
debug!("Writing files in: %s", repo_subdir.to_str());
writeFile(&repo_subdir.push("main.rs"),
"fn main() { let _x = (); }");
None => false
});
assert!(built_executable_in_workspace(&temp_pkg_id, &ws)
- == Some(ws.push("build").
- push("mockgithub.com").
- push("catamorphism").
- push("test_pkg_version").
- push("test_pkg_version")));
+ == Some(target_build_dir(&ws).push_many([~"mockgithub.com",
+ ~"catamorphism",
+ ~"test_pkg_version",
+ ~"test_pkg_version"])));
}
#[test]
fn test_package_request_version() {
let local_path = "mockgithub.com/catamorphism/test_pkg_version";
let repo = init_git_repo(&Path(local_path));
- let repo_subdir = repo.push("mockgithub.com").push("catamorphism").push("test_pkg_version");
+ let repo_subdir = repo.push_many([~"mockgithub.com", ~"catamorphism", ~"test_pkg_version"]);
debug!("Writing files in: %s", repo_subdir.to_str());
writeFile(&repo_subdir.push("main.rs"),
"fn main() { let _x = (); }");
command_line_test([~"install", fmt!("%s#0.3", local_path)], &repo);
- assert!(match installed_library_in_workspace("test_pkg_version", &repo.push(".rust")) {
+ assert!(match installed_library_in_workspace(&Path("test_pkg_version"), &repo.push(".rust")) {
Some(p) => {
debug!("installed: %s", p.to_str());
p.to_str().ends_with(fmt!("0.3%s", os::consts::DLL_SUFFIX))
});
let temp_pkg_id = PkgId::new("mockgithub.com/catamorphism/test_pkg_version#0.3");
assert!(target_executable_in_workspace(&temp_pkg_id, &repo.push(".rust"))
- == repo.push(".rust").push("bin").push("test_pkg_version"));
+ == repo.push_many([~".rust", ~"bin", ~"test_pkg_version"]));
+
+ let dir = &repo.push_many([~".rust",
+ ~"src",
+ ~"mockgithub.com",
+ ~"catamorphism",
+ ~"test_pkg_version-0.3"]);
- assert!(os::path_exists(&repo.push(".rust").push("src")
- .push("mockgithub.com").push("catamorphism")
- .push("test_pkg_version-0.3")
- .push("version-0.3-file.txt")));
- assert!(!os::path_exists(&repo.push(".rust").push("src")
- .push("mockgithub.com").push("catamorphism")
- .push("test_pkg_version-0.3")
- .push("version-0.4-file.txt")));
+ assert!(os::path_exists(&dir.push("version-0.3-file.txt")));
+ assert!(!os::path_exists(&dir.push("version-0.4-file.txt")));
}
#[test]
add_git_tag(&package_dir, ~"1.0");
command_line_test([~"install", ~"foo"], &foo_repo);
- assert_lib_exists(&foo_repo.push(".rust"), "foo", ExactRevision(~"1.0"));
+ assert_lib_exists(&foo_repo.push(".rust"), &Path("foo"), ExactRevision(~"1.0"));
}
#[test]
fn package_script_with_default_build() {
let dir = create_local_package(&PkgId::new("fancy-lib"));
debug!("dir = %s", dir.to_str());
- let source = test_sysroot().pop().pop().pop().push("src").push("librustpkg").
- push("testsuite").push("pass").push("src").push("fancy-lib").push("pkg.rs");
+ let source = test_sysroot().pop().pop().pop().push_many(
+ [~"src", ~"librustpkg", ~"testsuite", ~"pass", ~"src", ~"fancy-lib", ~"pkg.rs"]);
debug!("package_script_with_default_build: %s", source.to_str());
if !os::copy_file(&source,
- &dir.push("src").push("fancy-lib-0.1").push("pkg.rs")) {
+ &dir.push_many([~"src", ~"fancy-lib-0.1", ~"pkg.rs"])) {
fail!("Couldn't copy file");
}
command_line_test([~"install", ~"fancy-lib"], &dir);
- assert_lib_exists(&dir, "fancy-lib", NoVersion);
- assert!(os::path_exists(&dir.push("build").push("fancy-lib").push("generated.rs")));
+ assert_lib_exists(&dir, &Path("fancy-lib"), NoVersion);
+ assert!(os::path_exists(&target_build_dir(&dir).push_many([~"fancy-lib", ~"generated.rs"])));
}
#[test]
fn rustpkg_build_no_arg() {
let tmp = mkdtemp(&os::tmpdir(), "rustpkg_build_no_arg").expect("rustpkg_build_no_arg failed")
.push(".rust");
- let package_dir = tmp.push("src").push("foo");
+ let package_dir = tmp.push_many([~"src", ~"foo"]);
assert!(os::mkdir_recursive(&package_dir, U_RWX));
writeFile(&package_dir.push("main.rs"),
let tmp = mkdtemp(&os::tmpdir(),
"rustpkg_install_no_arg").expect("rustpkg_install_no_arg failed")
.push(".rust");
- let package_dir = tmp.push("src").push("foo");
+ let package_dir = tmp.push_many([~"src", ~"foo"]);
assert!(os::mkdir_recursive(&package_dir, U_RWX));
writeFile(&package_dir.push("lib.rs"),
"fn main() { let _x = (); }");
debug!("install_no_arg: dir = %s", package_dir.to_str());
command_line_test([~"install"], &package_dir);
- assert_lib_exists(&tmp, "foo", NoVersion);
+ assert_lib_exists(&tmp, &Path("foo"), NoVersion);
}
#[test]
fn rustpkg_clean_no_arg() {
let tmp = mkdtemp(&os::tmpdir(), "rustpkg_clean_no_arg").expect("rustpkg_clean_no_arg failed")
.push(".rust");
- let package_dir = tmp.push("src").push("foo");
+ let package_dir = tmp.push_many([~"src", ~"foo"]);
assert!(os::mkdir_recursive(&package_dir, U_RWX));
writeFile(&package_dir.push("main.rs"),
}
#[test]
+#[ignore] // FIXME(#9184) tests can't change the cwd (other tests are sad then)
fn rust_path_contents() {
- use std::unstable::change_dir_locked;
-
let dir = mkdtemp(&os::tmpdir(), "rust_path").expect("rust_path_contents failed");
- let abc = &dir.push("A").push("B").push("C");
+ let abc = &dir.push_many([~"A", ~"B", ~"C"]);
assert!(os::mkdir_recursive(&abc.push(".rust"), U_RWX));
assert!(os::mkdir_recursive(&abc.pop().push(".rust"), U_RWX));
assert!(os::mkdir_recursive(&abc.pop().pop().push(".rust"), U_RWX));
- assert!(do change_dir_locked(&dir.push("A").push("B").push("C")) {
- let p = rust_path();
- let cwd = os::getcwd().push(".rust");
- let parent = cwd.pop().pop().push(".rust");
- let grandparent = cwd.pop().pop().pop().push(".rust");
- assert!(p.contains(&cwd));
- assert!(p.contains(&parent));
- assert!(p.contains(&grandparent));
- for a_path in p.iter() {
- assert!(!a_path.components.is_empty());
- }
- });
+ assert!(os::change_dir(abc));
+
+ let p = rust_path();
+ let cwd = os::getcwd().push(".rust");
+ let parent = cwd.pop().pop().push(".rust");
+ let grandparent = cwd.pop().pop().pop().push(".rust");
+ assert!(p.contains(&cwd));
+ assert!(p.contains(&parent));
+ assert!(p.contains(&grandparent));
+ for a_path in p.iter() {
+ assert!(!a_path.components.is_empty());
+ }
}
#[test]
// list doesn't output very much right now...
command_line_test([~"install", ~"foo"], &dir);
let env_arg = ~[(~"RUST_PATH", dir.to_str())];
- debug!("RUST_PATH = %s", dir.to_str());
let list_output = command_line_test_output_with_env([~"list"], env_arg.clone());
assert!(list_output.iter().any(|x| x.starts_with("foo")));
let bar_date_1 = datestamp(&lib_output_file_name(&workspace,
".rust",
"bar"));
- let foo_date_1 = datestamp(&output_file_name(&workspace, "foo"));
+ let foo_date_1 = datestamp(&output_file_name(&workspace, ~"foo"));
frob_source_file(&workspace, &p_id);
command_line_test([~"build", ~"foo"], &workspace);
let bar_date_2 = datestamp(&lib_output_file_name(&workspace,
".rust",
"bar"));
- let foo_date_2 = datestamp(&output_file_name(&workspace, "foo"));
+ let foo_date_2 = datestamp(&output_file_name(&workspace, ~"foo"));
assert_eq!(bar_date_1, bar_date_2);
assert!(foo_date_1 < foo_date_2);
assert!(foo_date_1 > bar_date_1);
fn test_non_numeric_tag() {
let temp_pkg_id = git_repo_pkg();
let repo = init_git_repo(&temp_pkg_id.path);
- let repo_subdir = repo.push("mockgithub.com").push("catamorphism").push("test-pkg");
+ let repo_subdir = repo.push_many([~"mockgithub.com", ~"catamorphism", ~"test-pkg"]);
writeFile(&repo_subdir.push("foo"), "foo");
writeFile(&repo_subdir.push("lib.rs"),
"pub fn f() { let _x = (); }");
command_line_test([~"install", ~"mockgithub.com/catamorphism/test_pkg"], &lib_depend_dir);
+ let exec_file = dir.push("out");
+ // Be sure to extend the existing environment
+ let env = Some([(~"RUST_PATH", lib_depend_dir.to_str())] + os::env());
+ let rustpkg_exec = rustpkg_exec();
+ let rustc = rustpkg_exec.with_filename("rustc");
+
+ let mut prog = run::Process::new(rustc.to_str(), [main_file.to_str(),
+ ~"--sysroot", test_sysroot().to_str(),
+ ~"-o", exec_file.to_str()],
+ run::ProcessOptions {
+ env: env,
+ dir: Some(&dir),
+ in_fd: None,
+ out_fd: None,
+ err_fd: None
+ });
+ let outp = prog.finish_with_output();
+ if outp.status != 0 {
+ fail!("output was %s, error was %s",
+ str::from_utf8(outp.output),
+ str::from_utf8(outp.error));
+ }
+ assert!(os::path_exists(&exec_file) && is_executable(&exec_file));
+}
+
+#[test]
+fn test_extern_mod_simpler() {
+ let dir = mkdtemp(&os::tmpdir(), "test_extern_mod_simpler").expect("test_extern_mod_simpler");
+ let main_file = dir.push("main.rs");
+ let lib_depend_dir = mkdtemp(&os::tmpdir(), "foo").expect("test_extern_mod_simpler");
+ let aux_dir = lib_depend_dir.push_many(["src", "rust-awesomeness"]);
+ assert!(os::mkdir_recursive(&aux_dir, U_RWX));
+ let aux_pkg_file = aux_dir.push("lib.rs");
+
+ writeFile(&aux_pkg_file, "pub mod bar { pub fn assert_true() { assert!(true); } }\n");
+ assert!(os::path_exists(&aux_pkg_file));
+
+ writeFile(&main_file,
+ "extern mod test = \"rust-awesomeness\";\nuse test::bar;\
+ fn main() { bar::assert_true(); }\n");
+
+ command_line_test([~"install", ~"rust-awesomeness"], &lib_depend_dir);
+
let exec_file = dir.push("out");
// Be sure to extend the existing environment
let env = Some([(~"RUST_PATH", lib_depend_dir.to_str())] + os::env());
fn test_import_rustpkg() {
let p_id = PkgId::new("foo");
let workspace = create_local_package(&p_id);
- writeFile(&workspace.push("src").push("foo-0.1").push("pkg.rs"),
+ writeFile(&workspace.push_many([~"src", ~"foo-0.1", ~"pkg.rs"]),
"extern mod rustpkg; fn main() {}");
command_line_test([~"build", ~"foo"], &workspace);
debug!("workspace = %s", workspace.to_str());
- assert!(os::path_exists(&workspace.push("build").push("foo").push(fmt!("pkg%s",
+ assert!(os::path_exists(&target_build_dir(&workspace).push("foo").push(fmt!("pkg%s",
os::EXE_SUFFIX))));
}
fn test_macro_pkg_script() {
let p_id = PkgId::new("foo");
let workspace = create_local_package(&p_id);
- writeFile(&workspace.push("src").push("foo-0.1").push("pkg.rs"),
+ writeFile(&workspace.push_many([~"src", ~"foo-0.1", ~"pkg.rs"]),
"extern mod rustpkg; fn main() { debug!(\"Hi\"); }");
command_line_test([~"build", ~"foo"], &workspace);
debug!("workspace = %s", workspace.to_str());
- assert!(os::path_exists(&workspace.push("build").push("foo").push(fmt!("pkg%s",
+ assert!(os::path_exists(&target_build_dir(&workspace).push("foo").push(fmt!("pkg%s",
os::EXE_SUFFIX))));
}
let dest_workspace = mk_empty_workspace(&Path("bar"), &NoVersion, "dest_workspace");
let rust_path = Some(~[(~"RUST_PATH",
fmt!("%s:%s", dest_workspace.to_str(), workspace.push_many(["src", "foo-0.1"]).to_str()))]);
- debug!("declare -x RUST_PATH=%s:%s",
- dest_workspace.to_str(), workspace.push_many(["src", "foo-0.1"]).to_str());
command_line_test_with_env(~[~"install"] + if hack_flag { ~[~"--rust-path-hack"] } else { ~[] } +
~[~"foo"], &dest_workspace, rust_path);
- assert_lib_exists(&dest_workspace, "foo", NoVersion);
+ assert_lib_exists(&dest_workspace, &Path("foo"), NoVersion);
assert_executable_exists(&dest_workspace, "foo");
assert_built_library_exists(&dest_workspace, "foo");
assert_built_executable_exists(&dest_workspace, "foo");
- assert!(!lib_exists(&workspace, "foo", NoVersion));
+ assert!(!lib_exists(&workspace, &Path("foo"), NoVersion));
assert!(!executable_exists(&workspace, "foo"));
assert!(!built_library_exists(&workspace, "foo"));
assert!(!built_executable_exists(&workspace, "foo"));
let dest_workspace = mk_empty_workspace(&Path("bar"), &NoVersion, "dest_workspace");
let rust_path = Some(~[(~"RUST_PATH", dest_workspace.to_str())]);
- debug!("declare -x RUST_PATH=%s", dest_workspace.to_str());
command_line_test_with_env([~"install", ~"--rust-path-hack", ~"foo"], &cwd, rust_path);
debug!("Checking that foo exists in %s", dest_workspace.to_str());
- assert_lib_exists(&dest_workspace, "foo", NoVersion);
+ assert_lib_exists(&dest_workspace, &Path("foo"), NoVersion);
assert_built_library_exists(&dest_workspace, "foo");
- assert!(!lib_exists(&cwd, "foo", NoVersion));
+ assert!(!lib_exists(&cwd, &Path("foo"), NoVersion));
assert!(!built_library_exists(&cwd, "foo"));
}
let dest_workspace = mk_empty_workspace(&Path("bar"), &NoVersion, "dest_workspace");
let rust_path = Some(~[(~"RUST_PATH", dest_workspace.to_str())]);
- debug!("declare -x RUST_PATH=%s", dest_workspace.to_str());
command_line_test_with_env([~"install", ~"--rust-path-hack", name.clone()], &subdir, rust_path);
debug!("Checking that %s exists in %s", name, dest_workspace.to_str());
- assert_lib_exists(&dest_workspace, "quux", NoVersion);
+ assert_lib_exists(&dest_workspace, &Path("quux"), NoVersion);
assert_built_library_exists(&dest_workspace, name);
- assert!(!lib_exists(&subdir, "quux", NoVersion));
+ assert!(!lib_exists(&subdir, &Path("quux"), NoVersion));
assert!(!built_library_exists(&subdir, name));
}
let dest_workspace = mk_empty_workspace(&Path("bar"), &NoVersion, "dest_workspace");
let rust_path = Some(~[(~"RUST_PATH", dest_workspace.to_str())]);
- debug!("declare -x RUST_PATH=%s", dest_workspace.to_str());
command_line_test_with_env([~"install", ~"--rust-path-hack"], &source_dir, rust_path);
debug!("Checking that foo exists in %s", dest_workspace.to_str());
- assert_lib_exists(&dest_workspace, "foo", NoVersion);
+ assert_lib_exists(&dest_workspace, &Path("foo"), NoVersion);
assert_built_library_exists(&dest_workspace, "foo");
- assert!(!lib_exists(&source_dir, "foo", NoVersion));
+ assert!(!lib_exists(&source_dir, &Path("foo"), NoVersion));
assert!(!built_library_exists(&cwd, "foo"));
}
let dest_workspace = mk_empty_workspace(&Path("bar"), &NoVersion, "dest_workspace");
let rust_path = Some(~[(~"RUST_PATH", dest_workspace.to_str())]);
- debug!("declare -x RUST_PATH=%s", dest_workspace.to_str());
command_line_test_with_env([~"build", ~"--rust-path-hack"], &source_dir, rust_path);
debug!("Checking that foo exists in %s", dest_workspace.to_str());
assert_built_library_exists(&dest_workspace, "foo");
let rust_path = Some(~[(~"RUST_PATH", fmt!("%s:%s", dir_to_install_to.to_str(),
dir.to_str()))]);
let cwd = os::getcwd();
-
- debug!("RUST_PATH=%s:%s", dir_to_install_to.to_str(), dir.to_str());
command_line_test_with_env([~"install", ~"foo"],
&cwd,
rust_path);
}
+#[test]
+fn sysroot_flag() {
+ let p_id = PkgId::new("foo");
+ let workspace = create_local_package(&p_id);
+ // no-op sysroot setting; I'm not sure how else to test this
+ command_line_test([~"--sysroot",
+ test_sysroot().to_str(),
+ ~"build",
+ ~"foo"],
+ &workspace);
+ assert_built_executable_exists(&workspace, "foo");
+}
+
+#[test]
+fn compile_flag_build() {
+ let p_id = PkgId::new("foo");
+ let workspace = create_local_package(&p_id);
+ command_line_test([test_sysroot().to_str(),
+ ~"build",
+ ~"--no-link",
+ ~"foo"],
+ &workspace);
+ assert!(!built_executable_exists(&workspace, "foo"));
+ assert!(object_file_exists(&workspace, "foo"));
+}
+
+#[test]
+fn compile_flag_fail() {
+ // --no-link shouldn't be accepted for install
+ let p_id = PkgId::new("foo");
+ let workspace = create_local_package(&p_id);
+ command_line_test([test_sysroot().to_str(),
+ ~"install",
+ ~"--no-link",
+ ~"foo"],
+ &workspace);
+ assert!(!built_executable_exists(&workspace, "foo"));
+ assert!(!object_file_exists(&workspace, "foo"));
+}
+
+#[test]
+fn notrans_flag_build() {
+ let p_id = PkgId::new("foo");
+ let workspace = create_local_package(&p_id);
+ let flags_to_test = [~"--no-trans", ~"--parse-only",
+ ~"--pretty", ~"-S"];
+
+ for flag in flags_to_test.iter() {
+ command_line_test([test_sysroot().to_str(),
+ ~"build",
+ flag.clone(),
+ ~"foo"],
+ &workspace);
+ // Ideally we'd test that rustpkg actually succeeds, but
+ // since task failure doesn't set the exit code properly,
+ // we can't tell
+ assert!(!built_executable_exists(&workspace, "foo"));
+ assert!(!object_file_exists(&workspace, "foo"));
+ }
+}
+
+#[test]
+fn notrans_flag_fail() {
+ // --no-trans shouldn't be accepted for install
+ let p_id = PkgId::new("foo");
+ let workspace = create_local_package(&p_id);
+ let flags_to_test = [~"--no-trans", ~"--parse-only",
+ ~"--pretty", ~"-S"];
+ for flag in flags_to_test.iter() {
+ command_line_test([test_sysroot().to_str(),
+ ~"install",
+ flag.clone(),
+ ~"foo"],
+ &workspace);
+ // Ideally we'd test that rustpkg actually fails, but
+ // since task failure doesn't set the exit code properly,
+ // we can't tell
+ assert!(!built_executable_exists(&workspace, "foo"));
+ assert!(!object_file_exists(&workspace, "foo"));
+ assert!(!lib_exists(&workspace, &Path("foo"), NoVersion));
+ }
+}
+
+#[test]
+fn dash_S() {
+ let p_id = PkgId::new("foo");
+ let workspace = create_local_package(&p_id);
+ command_line_test([test_sysroot().to_str(),
+ ~"build",
+ ~"-S",
+ ~"foo"],
+ &workspace);
+ assert!(!built_executable_exists(&workspace, "foo"));
+ assert!(!object_file_exists(&workspace, "foo"));
+ assert!(assembly_file_exists(&workspace, "foo"));
+}
+
+#[test]
+fn dash_S_fail() {
+ let p_id = PkgId::new("foo");
+ let workspace = create_local_package(&p_id);
+ command_line_test([test_sysroot().to_str(),
+ ~"install",
+ ~"-S",
+ ~"foo"],
+ &workspace);
+ assert!(!built_executable_exists(&workspace, "foo"));
+ assert!(!object_file_exists(&workspace, "foo"));
+ assert!(!assembly_file_exists(&workspace, "foo"));
+}
+
+#[test]
+fn test_cfg_build() {
+ let p_id = PkgId::new("foo");
+ let workspace = create_local_package(&p_id);
+ // If the cfg flag gets messed up, this won't compile
+ writeFile(&workspace.push_many(["src", "foo-0.1", "main.rs"]),
+ "#[cfg(quux)] fn main() {}");
+ command_line_test([test_sysroot().to_str(),
+ ~"build",
+ ~"--cfg",
+ ~"quux",
+ ~"foo"],
+ &workspace);
+ assert_built_executable_exists(&workspace, "foo");
+}
+
+#[test]
+fn test_cfg_fail() {
+ let p_id = PkgId::new("foo");
+ let workspace = create_local_package(&p_id);
+ writeFile(&workspace.push_many(["src", "foo-0.1", "main.rs"]),
+ "#[cfg(quux)] fn main() {}");
+ assert!(command_line_test_partial([test_sysroot().to_str(),
+ ~"build",
+ ~"foo"],
+ &workspace).is_none());
+}
+
+
+#[test]
+fn test_emit_llvm_S_build() {
+ let p_id = PkgId::new("foo");
+ let workspace = create_local_package(&p_id);
+ command_line_test([test_sysroot().to_str(),
+ ~"build",
+ ~"-S", ~"--emit-llvm",
+ ~"foo"],
+ &workspace);
+ assert!(!built_executable_exists(&workspace, "foo"));
+ assert!(!object_file_exists(&workspace, "foo"));
+ assert!(llvm_assembly_file_exists(&workspace, "foo"));
+ assert!(!assembly_file_exists(&workspace, "foo"));
+}
+
+#[test]
+fn test_emit_llvm_S_fail() {
+ let p_id = PkgId::new("foo");
+ let workspace = create_local_package(&p_id);
+ command_line_test([test_sysroot().to_str(),
+ ~"install",
+ ~"-S", ~"--emit-llvm",
+ ~"foo"],
+ &workspace);
+ assert!(!built_executable_exists(&workspace, "foo"));
+ assert!(!object_file_exists(&workspace, "foo"));
+ assert!(!llvm_assembly_file_exists(&workspace, "foo"));
+ assert!(!assembly_file_exists(&workspace, "foo"));
+}
+
+#[test]
+fn test_emit_llvm_build() {
+ let p_id = PkgId::new("foo");
+ let workspace = create_local_package(&p_id);
+ command_line_test([test_sysroot().to_str(),
+ ~"build",
+ ~"--emit-llvm",
+ ~"foo"],
+ &workspace);
+ assert!(!built_executable_exists(&workspace, "foo"));
+ assert!(!object_file_exists(&workspace, "foo"));
+ assert!(llvm_bitcode_file_exists(&workspace, "foo"));
+ assert!(!assembly_file_exists(&workspace, "foo"));
+ assert!(!llvm_assembly_file_exists(&workspace, "foo"));
+}
+
+#[test]
+fn test_emit_llvm_fail() {
+ let p_id = PkgId::new("foo");
+ let workspace = create_local_package(&p_id);
+ command_line_test([test_sysroot().to_str(),
+ ~"install",
+ ~"--emit-llvm",
+ ~"foo"],
+ &workspace);
+ assert!(!built_executable_exists(&workspace, "foo"));
+ assert!(!object_file_exists(&workspace, "foo"));
+ assert!(!llvm_bitcode_file_exists(&workspace, "foo"));
+ assert!(!llvm_assembly_file_exists(&workspace, "foo"));
+ assert!(!assembly_file_exists(&workspace, "foo"));
+}
+
+#[test]
+fn test_linker_build() {
+ let p_id = PkgId::new("foo");
+ let workspace = create_local_package(&p_id);
+ let matches = getopts([], optgroups());
+ let options = build_session_options(@"rustpkg",
+ matches.get_ref(),
+ diagnostic::emit);
+ let sess = build_session(options, diagnostic::emit);
+ command_line_test([test_sysroot().to_str(),
+ ~"install",
+ ~"--linker",
+ get_cc_prog(sess),
+ ~"foo"],
+ &workspace);
+ assert_executable_exists(&workspace, "foo");
+}
+
+#[test]
+fn test_build_install_flags_fail() {
+ // The following flags can only be used with build or install:
+ let forbidden = [~[~"--linker", ~"ld"],
+ ~[~"--link-args", ~"quux"],
+ ~[~"-O"],
+ ~[~"--opt-level", ~"2"],
+ ~[~"--save-temps"],
+ ~[~"--target", host_triple()],
+ ~[~"--target-cpu", ~"generic"],
+ ~[~"-Z", ~"--time-passes"]];
+ for flag in forbidden.iter() {
+ let output = command_line_test_output([test_sysroot().to_str(),
+ ~"list"] + *flag);
+ assert!(output.len() > 1);
+ assert!(output[1].find_str("can only be used with").is_some());
+ }
+}
+
+#[test]
+fn test_optimized_build() {
+ let p_id = PkgId::new("foo");
+ let workspace = create_local_package(&p_id);
+ command_line_test([test_sysroot().to_str(),
+ ~"build",
+ ~"-O",
+ ~"foo"],
+ &workspace);
+ assert!(built_executable_exists(&workspace, "foo"));
+}
+
+fn pkgid_pointing_to_subdir() {
+ // The actual repo is mockgithub.com/mozilla/some_repo
+ // rustpkg should recognize that and treat the part after some_repo/ as a subdir
+ let workspace = mkdtemp(&os::tmpdir(), "parent_repo").expect("Couldn't create temp dir");
+ assert!(os::mkdir_recursive(&workspace.push_many([~"src", ~"mockgithub.com",
+ ~"mozilla", ~"some_repo"]), U_RWX));
+
+ let foo_dir = workspace.push_many([~"src", ~"mockgithub.com", ~"mozilla", ~"some_repo",
+ ~"extras", ~"foo"]);
+ let bar_dir = workspace.push_many([~"src", ~"mockgithub.com", ~"mozilla", ~"some_repo",
+ ~"extras", ~"bar"]);
+ assert!(os::mkdir_recursive(&foo_dir, U_RWX));
+ assert!(os::mkdir_recursive(&bar_dir, U_RWX));
+ writeFile(&foo_dir.push("lib.rs"), "pub fn f() {}");
+ writeFile(&bar_dir.push("lib.rs"), "pub fn g() {}");
+
+ debug!("Creating a file in %s", workspace.to_str());
+ let testpkg_dir = workspace.push_many([~"src", ~"testpkg-0.1"]);
+ assert!(os::mkdir_recursive(&testpkg_dir, U_RWX));
+
+ writeFile(&testpkg_dir.push("main.rs"),
+ "extern mod foo = \"mockgithub.com/mozilla/some_repo/extras/foo\";\n
+ extern mod bar = \"mockgithub.com/mozilla/some_repo/extras/bar\";\n
+ use foo::f; use bar::g; \n
+ fn main() { f(); g(); }");
+
+ command_line_test([~"install", ~"testpkg"], &workspace);
+ assert_executable_exists(&workspace, "testpkg");
+}
+
+fn test_recursive_deps() {
+ let a_id = PkgId::new("a");
+ let b_id = PkgId::new("b");
+ let c_id = PkgId::new("c");
+ let b_workspace = create_local_package_with_dep(&b_id, &c_id);
+ writeFile(&b_workspace.push("src").push("c-0.1").push("lib.rs"),
+ "pub fn g() {}");
+ let a_workspace = create_local_package(&a_id);
+ writeFile(&a_workspace.push("src").push("a-0.1").push("main.rs"),
+ "extern mod b; use b::f; fn main() { f(); }");
+ writeFile(&b_workspace.push("src").push("b-0.1").push("lib.rs"),
+ "extern mod c; use c::g; pub fn f() { g(); }");
+ let environment = Some(~[(~"RUST_PATH", b_workspace.to_str())]);
+ debug!("RUST_PATH=%s", b_workspace.to_str());
+ command_line_test_with_env([~"install", ~"a"],
+ &a_workspace,
+ environment);
+ assert_lib_exists(&a_workspace, &Path("a"), NoVersion);
+ assert_lib_exists(&b_workspace, &Path("b"), NoVersion);
+ assert_lib_exists(&b_workspace, &Path("c"), NoVersion);
+}
+
+#[test]
+fn test_install_to_rust_path() {
+ let p_id = PkgId::new("foo");
+ let second_workspace = create_local_package(&p_id);
+ let first_workspace = mk_empty_workspace(&Path("p"), &NoVersion, "dest");
+ let rust_path = Some(~[(~"RUST_PATH",
+ fmt!("%s:%s", first_workspace.to_str(),
+ second_workspace.to_str()))]);
+ debug!("RUST_PATH=%s:%s", first_workspace.to_str(), second_workspace.to_str());
+ command_line_test_with_env([test_sysroot().to_str(),
+ ~"install",
+ ~"foo"],
+ &os::getcwd(), rust_path);
+ assert!(!built_executable_exists(&first_workspace, "foo"));
+ assert!(built_executable_exists(&second_workspace, "foo"));
+ assert_executable_exists(&first_workspace, "foo");
+ assert!(!executable_exists(&second_workspace, "foo"));
+}
+
+fn test_target_specific_build_dir() {
+ let p_id = PkgId::new("foo");
+ let workspace = create_local_package(&p_id);
+ command_line_test([test_sysroot().to_str(),
+ ~"build",
+ ~"foo"],
+ &workspace);
+ assert!(os::path_is_dir(&target_build_dir(&workspace)));
+ assert!(built_executable_exists(&workspace, "foo"));
+ assert!(os::list_dir(&workspace.push("build")).len() == 1);
+}
+
+#[test]
+fn test_target_specific_install_dir() {
+ let p_id = PkgId::new("foo");
+ let workspace = create_local_package(&p_id);
+ command_line_test([test_sysroot().to_str(),
+ ~"install",
+ ~"foo"],
+ &workspace);
+ assert!(os::path_is_dir(&workspace.push("lib").push(host_triple())));
+ assert_lib_exists(&workspace, &Path("foo"), NoVersion);
+ assert!(os::list_dir(&workspace.push("lib")).len() == 1);
+ assert!(os::path_is_dir(&workspace.push("bin")));
+ assert_executable_exists(&workspace, "foo");
+}
/// Returns true if p exists and is executable
fn is_executable(p: &Path) -> bool {
Options:
-h, --help Display this message
+ --sysroot PATH Override the system root
<cmd> -h, <cmd> --help Display help for <cmd>");
}
pub fn build() {
- io::println("rustpkg [options..] build [package-ID]
+ io::println("rustpkg build [options..] [package-ID]
Build the given package ID if specified. With no package ID argument,
build the package in the current directory. In that case, the current
directory must be a direct child of an `src` directory in a workspace.
Options:
- -c, --cfg Pass a cfg flag to the package script");
+ -c, --cfg Pass a cfg flag to the package script
+ --no-link Compile and assemble, but don't link (like -c in rustc)
+ --no-trans Parse and translate, but don't generate any code
+ --pretty Pretty-print the code, but don't generate output
+ --parse-only Parse the code, but don't typecheck or generate code
+ -S Generate assembly code, but don't assemble or link it
+ -S --emit-llvm Generate LLVM assembly code
+ --emit-llvm Generate LLVM bitcode
+ --linker PATH Use a linker other than the system linker
+ --link-args [ARG..] Extra arguments to pass to the linker
+ --opt-level=n Set the optimization level (0 <= n <= 3)
+ -O Equivalent to --opt-level=2
+ --save-temps Don't delete temporary files
+ --target TRIPLE Set the target triple
+ --target-cpu CPU Set the target CPU
+ -Z FLAG Enable an experimental rustc feature (see `rustc --help`)");
}
pub fn clean() {
}
pub fn install() {
- io::println("rustpkg [options..] install [package-ID]
+ io::println("rustpkg install [options..] [package-ID]
Install the given package ID if specified. With no package ID
argument, install the package in the current directory.
rustpkg install github.com/mozilla/servo#0.1.2
Options:
- -c, --cfg Pass a cfg flag to the package script");
+ -c, --cfg Pass a cfg flag to the package script
+ --emit-llvm Generate LLVM bitcode
+ --linker PATH Use a linker other than the system linker
+ --link-args [ARG..] Extra arguments to pass to the linker
+ --opt-level=n Set the optimization level (0 <= n <= 3)
+ -O Equivalent to --opt-level=2
+ --save-temps Don't delete temporary files
+ --target TRIPLE Set the target triple
+ --target-cpu CPU Set the target CPU
+ -Z FLAG Enable an experimental rustc feature (see `rustc --help`)");
}
pub fn uninstall() {
use syntax::ext::base::ExtCtxt;
use syntax::{ast, attr, codemap, diagnostic, fold};
use syntax::attr::AttrMetaMethods;
-use rustc::back::link::output_type_exe;
+use rustc::back::link;
use rustc::driver::session::{lib_crate, bin_crate};
-use context::{in_target, BuildContext};
+use context::{in_target, StopBefore, Link, Assemble, BuildContext};
use package_id::PkgId;
use package_source::PkgSrc;
-use path_util::{installed_library_in_workspace, U_RWX};
+use workspace::pkg_parent_workspaces;
+use path_util::{installed_library_in_workspace, U_RWX, rust_path, system_library, target_build_dir};
+use messages::error;
pub use target::{OutputType, Main, Lib, Bench, Test};
use workcache_support::{digest_file_with_date, digest_only_date};
@fold.fold_crate(crate)
}
-pub fn compile_input(ctxt: &BuildContext,
+pub fn compile_input(context: &BuildContext,
exec: &mut workcache::Exec,
pkg_id: &PkgId,
in_file: &Path,
flags: &[~str],
cfgs: &[~str],
opt: bool,
- what: OutputType) -> Path {
+ what: OutputType) -> Option<Path> {
assert!(in_file.components.len() > 1);
let input = driver::file_input((*in_file).clone());
debug!("compile_input: %s / %?", in_file.to_str(), what);
// tjc: by default, use the package ID name as the link name
// not sure if we should support anything else
- let out_dir = workspace.push("build").push_rel(&pkg_id.path);
+ let out_dir = target_build_dir(workspace).push_rel(&pkg_id.path);
let binary = os::args()[0].to_managed();
debug!("flags: %s", flags.connect(" "));
debug!("cfgs: %s", cfgs.connect(" "));
- debug!("compile_input's sysroot = %s", ctxt.sysroot().to_str());
+ debug!("compile_input's sysroot = %s", context.sysroot().to_str());
let crate_type = match what {
Lib => lib_crate,
Main => ~[]
}
+ flags
+ + context.flag_strs()
+ cfgs.flat_map(|c| { ~[~"--cfg", (*c).clone()] }),
driver::optgroups()).unwrap();
+ debug!("rustc flags: %?", matches);
+
// Hack so that rustpkg can run either out of a rustc target dir,
// or the host dir
- let sysroot_to_use = @if !in_target(&ctxt.sysroot()) {
- ctxt.sysroot()
+ let sysroot_to_use = @if !in_target(&context.sysroot()) {
+ context.sysroot()
}
else {
- ctxt.sysroot().pop().pop().pop()
+ context.sysroot().pop().pop().pop()
};
- debug!("compile_input's sysroot = %s", ctxt.sysroot().to_str());
+ debug!("compile_input's sysroot = %s", context.sysroot().to_str());
debug!("sysroot_to_use = %s", sysroot_to_use.to_str());
+
+ let output_type = match context.compile_upto() {
+ Assemble => link::output_type_assembly,
+ Link => link::output_type_object,
+ Pretty | Trans | Analysis => link::output_type_none,
+ LLVMAssemble => link::output_type_llvm_assembly,
+ LLVMCompileBitcode => link::output_type_bitcode,
+ Nothing => link::output_type_exe
+ };
+
let options = @session::options {
crate_type: crate_type,
optimize: if opt { session::Aggressive } else { session::No },
test: what == Test || what == Bench,
maybe_sysroot: Some(sysroot_to_use),
addl_lib_search_paths: @mut (~[out_dir.clone()]),
- // output_type should be conditional
- output_type: output_type_exe, // Use this to get a library? That's weird
+ output_type: output_type,
.. (*driver::build_session_options(binary, &matches, diagnostic::emit)).clone()
};
let mut crate = driver::phase_1_parse_input(sess, cfg.clone(), &input);
crate = driver::phase_2_configure_and_expand(sess, cfg.clone(), crate);
- // Not really right. Should search other workspaces too, and the installed
- // database (which doesn't exist yet)
- find_and_install_dependencies(ctxt, sess, exec, workspace, crate,
+ find_and_install_dependencies(context, pkg_id, sess, exec, crate,
|p| {
debug!("a dependency: %s", p.to_str());
// Pass the directory containing a dependency
let link_options =
~[attr::mk_name_value_item_str(@"name", name_to_use),
attr::mk_name_value_item_str(@"vers", pkg_id.version.to_str().to_managed())] +
- if pkg_id.is_complex() {
- ~[attr::mk_name_value_item_str(@"package_id",
- pkg_id.path.to_str().to_managed())]
- } else { ~[] };
+ ~[attr::mk_name_value_item_str(@"package_id",
+ pkg_id.path.to_str().to_managed())];
debug!("link options: %?", link_options);
crate = @ast::Crate {
debug!("calling compile_crate_from_input, workspace = %s,
building_library = %?", out_dir.to_str(), sess.building_library);
- compile_crate_from_input(in_file, exec, &out_dir, sess, crate)
+ compile_crate_from_input(in_file, exec, context.compile_upto(), &out_dir, sess, crate)
}
// Should use workcache to avoid recompiling when not necessary
// also, too many arguments
pub fn compile_crate_from_input(input: &Path,
exec: &mut workcache::Exec,
+ stop_before: StopBefore,
// should be of the form <workspace>/build/<pkg id's path>
out_dir: &Path,
sess: session::Session,
- crate: @ast::Crate) -> Path {
+// Returns None if one of the flags that suppresses compilation output was
+// given
+ crate: @ast::Crate) -> Option<Path> {
debug!("Calling build_output_filenames with %s, building library? %?",
out_dir.to_str(), sess.building_library);
debug!("an additional library: %s", lib.to_str());
}
let analysis = driver::phase_3_run_analysis_passes(sess, crate);
+ if driver::stop_after_phase_3(sess) { return None; }
let translation = driver::phase_4_translate_to_llvm(sess, crate,
&analysis,
outputs);
driver::phase_5_run_llvm_passes(sess, &translation, outputs);
- if driver::stop_after_phase_5(sess) { return outputs.out_filename; }
+ // The second check shouldn't be necessary, but rustc seems to ignore
+ // -c
+ if driver::stop_after_phase_5(sess)
+ || stop_before == Link || stop_before == Assemble { return Some(outputs.out_filename); }
driver::phase_6_link_output(sess, &translation, outputs);
// Register dependency on the source file
exec.discover_input("file", input.to_str(), digest_file_with_date(input));
- outputs.out_filename
+ Some(outputs.out_filename)
}
#[cfg(windows)]
pkg_id: &PkgId,
crate: &Path, workspace: &Path,
flags: &[~str], cfgs: &[~str], opt: bool,
- what: OutputType) -> Path {
+ what: OutputType) -> Option<Path> {
debug!("compile_crate: crate=%s, workspace=%s", crate.to_str(), workspace.to_str());
debug!("compile_crate: short_name = %s, flags =...", pkg_id.to_str());
for fl in flags.iter() {
/// Collect all `extern mod` directives in `c`, then
/// try to install their targets, failing if any target
/// can't be found.
-pub fn find_and_install_dependencies(ctxt: &BuildContext,
- sess: session::Session,
- exec: &mut workcache::Exec,
- workspace: &Path,
- c: &ast::Crate,
- save: @fn(Path)
- ) {
- debug!("Finding and installing dependencies...");
- do c.each_view_item |vi| {
+pub fn find_and_install_dependencies(context: &BuildContext,
+ parent: &PkgId,
+ sess: session::Session,
+ exec: &mut workcache::Exec,
+ c: &ast::Crate,
+ save: @fn(Path)
+ ) {
+ use conditions::nonexistent_package::cond;
+
+ do c.each_view_item() |vi: &ast::view_item| {
debug!("A view item!");
match vi.node {
// ignore metadata, I guess
Some(p) => p,
None => sess.str_of(lib_ident)
};
- match installed_library_in_workspace(lib_name, &ctxt.sysroot()) {
+ debug!("Finding and installing... %s", lib_name);
+ // Check standard Rust library path first
+ match system_library(&context.sysroot(), lib_name) {
Some(ref installed_path) => {
debug!("It exists: %s", installed_path.to_str());
// Say that [path for c] has a discovered dependency on
lib_name.to_str());
// Try to install it
let pkg_id = PkgId::new(lib_name);
+ let workspaces = pkg_parent_workspaces(&context.context, &pkg_id);
+ let dep_workspace = if workspaces.is_empty() {
+ error(fmt!("Couldn't find package %s, which is needed by %s, \
+ in any of the workspaces in the RUST_PATH (%?)",
+ lib_name, parent.to_str(), rust_path()));
+ cond.raise((pkg_id.clone(), ~"Dependency not found"))
+ }
+ else {
+ workspaces[0]
+ };
let (outputs_disc, inputs_disc) =
- ctxt.install(PkgSrc::new(workspace.clone(), false, pkg_id));
+ context.install(PkgSrc::new(dep_workspace.clone(), false, pkg_id));
debug!("Installed %s, returned %? dependencies and \
%? transitive dependencies",
lib_name, outputs_disc.len(), inputs_disc.len());
}
}
// Also, add an additional search path
+ debug!("Adding additional search path: %s", lib_name);
let installed_library =
- installed_library_in_workspace(lib_name, workspace)
+ installed_library_in_workspace(&Path(lib_name), &dep_workspace)
.expect( fmt!("rustpkg failed to install dependency %s",
lib_name));
let install_dir = installed_library.pop();
if !l.is_whitespace() {
output = Some(l);
}
- match output.chain(try_parsing_version) {
+ match output.and_then(try_parsing_version) {
Some(v) => return Some(v),
None => ()
}
}
}
- output.chain(try_parsing_version)
+ output.and_then(try_parsing_version)
}
else {
None
return true;
}
+/// Given a package ID, return a vector of all of the workspaces in
+/// the RUST_PATH that contain it
pub fn pkg_parent_workspaces(cx: &Context, pkgid: &PkgId) -> ~[Path] {
let rs: ~[Path] = rust_path().move_iter()
.filter(|ws| workspace_contains_package_id(pkgid, ws))
#[inline]
pub fn build<A>(size: Option<uint>, builder: &fn(push: &fn(v: A))) -> @[A] {
let mut vec = @[];
- unsafe { raw::reserve(&mut vec, size.unwrap_or_default(4)); }
+ unsafe { raw::reserve(&mut vec, size.unwrap_or(4)); }
builder(|x| unsafe { raw::push(&mut vec, x) });
vec
}
* `Ord`
* `TotalOrd`
* `Eq`
+* `Default`
* `Zero`
## Various functions to compare `bool`s
#[cfg(not(test))] use cmp::{Eq, Ord, TotalOrd, Ordering};
#[cfg(not(test))] use ops::Not;
+#[cfg(not(test))] use default::Default;
#[cfg(not(test))] use num::Zero;
/**
fn eq(&self, other: &bool) -> bool { (*self) == (*other) }
}
+#[cfg(not(test))]
+impl Default for bool {
+ fn default() -> bool { false }
+}
+
#[cfg(not(test))]
impl Zero for bool {
fn zero() -> bool { false }
use cast::transmute;
use option::{None, Option, Some};
-use i32;
+use iter::{Iterator, range_step};
use str::StrSlice;
use unicode::{derived_property, general_category, decompose};
use to_str::ToStr;
#[cfg(test)] use str::OwnedStr;
#[cfg(not(test))] use cmp::{Eq, Ord};
+#[cfg(not(test))] use default::Default;
#[cfg(not(test))] use num::Zero;
// UTF-8 ranges and tags for encoding characters
(c <= '\uffff') { f('u'); 4 }
_ { f('U'); 8 }
);
- do i32::range_step(4 * (pad - 1), -1, -4) |offset| {
+ for offset in range_step::<i32>(4 * (pad - 1), -1, -4) {
unsafe {
match ((c as i32) >> offset) & 0xf {
i @ 0 .. 9 => { f(transmute('0' as i32 + i)); }
i => { f(transmute('a' as i32 + (i - 10))); }
}
}
- true
- };
+ }
}
///
fn lt(&self, other: &char) -> bool { *self < *other }
}
+#[cfg(not(test))]
+impl Default for char {
+ #[inline]
+ fn default() -> char { '\x00' }
+}
+
#[cfg(not(test))]
impl Zero for char {
+ #[inline]
fn zero() -> char { '\x00' }
+
+ #[inline]
fn is_zero(&self) -> bool { *self == '\x00' }
}
(Port { x: p }, Chan { x: c })
}
-pub struct SharedChan<T> { x: rtcomm::SharedChan<T> }
-
-impl<T: Send> SharedChan<T> {
- pub fn new(c: Chan<T>) -> SharedChan<T> {
- let Chan { x: c } = c;
- SharedChan { x: rtcomm::SharedChan::new(c) }
- }
-}
-
impl<T: Send> ChanOne<T> {
pub fn send(self, val: T) {
let ChanOne { x: c } = self;
}
}
+
+pub struct SharedChan<T> { x: rtcomm::SharedChan<T> }
+
+impl<T: Send> SharedChan<T> {
+ pub fn new(c: Chan<T>) -> SharedChan<T> {
+ let Chan { x: c } = c;
+ SharedChan { x: rtcomm::SharedChan::new(c) }
+ }
+}
+
impl<T: Send> GenericChan<T> for SharedChan<T> {
fn send(&self, val: T) {
let &SharedChan { x: ref c } = self;
SharedChan { x: c.clone() }
}
}
+
+pub struct SharedPort<T> { x: rtcomm::SharedPort<T> }
+
+impl<T: Send> SharedPort<T> {
+ pub fn new(p: Port<T>) -> SharedPort<T> {
+ let Port { x: p } = p;
+ SharedPort { x: rtcomm::SharedPort::new(p) }
+ }
+}
+
+impl<T: Send> GenericPort<T> for SharedPort<T> {
+ fn recv(&self) -> T {
+ let &SharedPort { x: ref p } = self;
+ p.recv()
+ }
+
+ fn try_recv(&self) -> Option<T> {
+ let &SharedPort { x: ref p } = self;
+ p.try_recv()
+ }
+}
+
+impl<T> Clone for SharedPort<T> {
+ fn clone(&self) -> SharedPort<T> {
+ let &SharedPort { x: ref p } = self;
+ SharedPort { x: p.clone() }
+ }
+}
/// Return the "default value" for a type.
fn default() -> Self;
}
+
+impl<T: Default + 'static> Default for @mut T {
+ fn default() -> @mut T { @mut Default::default() }
+}
+
+impl<T: Default + 'static> Default for @T {
+ fn default() -> @T { @Default::default() }
+}
+
+impl<T: Default> Default for ~T {
+ fn default() -> ~T { ~Default::default() }
+}
#[allow(missing_doc)];
use option::{Some, None};
+use option;
use clone::Clone;
use container::Container;
use cmp::Eq;
}
}
- /// Converts a `Either` to a `Result`
- ///
- /// Converts an `Either` type to a `Result` type, making the "right" choice
- /// an `Ok` result, and the "left" choice a `Err`
- #[inline]
- pub fn to_result(self) -> Result<R, L> {
- match self {
- Right(r) => result::Ok(r),
- Left(l) => result::Err(l)
- }
- }
-
/// Checks whether the given value is a `Left`
#[inline]
pub fn is_left(&self) -> bool {
}
}
+/// A generic trait for converting a value to a `Either`
+pub trait ToEither<L, R> {
+ /// Convert to the `either` type
+ fn to_either(&self) -> Either<L, R>;
+}
+
+/// A generic trait for converting a value to a `Either`
+pub trait IntoEither<L, R> {
+ /// Convert to the `either` type
+ fn into_either(self) -> Either<L, R>;
+}
+
+/// A generic trait for converting a value to a `Either`
+pub trait AsEither<L, R> {
+ /// Convert to the `either` type
+ fn as_either<'a>(&'a self) -> Either<&'a L, &'a R>;
+}
+
+impl<L, R: Clone> option::ToOption<R> for Either<L, R> {
+ #[inline]
+ fn to_option(&self)-> option::Option<R> {
+ match *self {
+ Left(_) => None,
+ Right(ref r) => Some(r.clone()),
+ }
+ }
+}
+
+impl<L, R> option::IntoOption<R> for Either<L, R> {
+ #[inline]
+ fn into_option(self)-> option::Option<R> {
+ match self {
+ Left(_) => None,
+ Right(r) => Some(r),
+ }
+ }
+}
+
+impl<L, R> option::AsOption<R> for Either<L, R> {
+ #[inline]
+ fn as_option<'a>(&'a self) -> option::Option<&'a R> {
+ match *self {
+ Left(_) => None,
+ Right(ref r) => Some(r),
+ }
+ }
+}
+
+impl<L: Clone, R: Clone> result::ToResult<R, L> for Either<L, R> {
+ #[inline]
+ fn to_result(&self)-> result::Result<R, L> {
+ match *self {
+ Left(ref l) => result::Err(l.clone()),
+ Right(ref r) => result::Ok(r.clone()),
+ }
+ }
+}
+
+impl<L, R> result::IntoResult<R, L> for Either<L, R> {
+ #[inline]
+ fn into_result(self)-> result::Result<R, L> {
+ match self {
+ Left(l) => result::Err(l),
+ Right(r) => result::Ok(r),
+ }
+ }
+}
+
+impl<L, R> result::AsResult<R, L> for Either<L, R> {
+ #[inline]
+ fn as_result<'a>(&'a self) -> result::Result<&'a R, &'a L> {
+ match *self {
+ Left(ref l) => result::Err(l),
+ Right(ref r) => result::Ok(r),
+ }
+ }
+}
+
+impl<L: Clone, R: Clone> ToEither<L, R> for Either<L, R> {
+ fn to_either(&self) -> Either<L, R> { self.clone() }
+}
+
+impl<L, R> IntoEither<L, R> for Either<L, R> {
+ fn into_either(self) -> Either<L, R> { self }
+}
+
+impl<L, R> AsEither<L, R> for Either<L, R> {
+ fn as_either<'a>(&'a self) -> Either<&'a L, &'a R> {
+ match *self {
+ Left(ref l) => Left(l),
+ Right(ref r) => Right(r),
+ }
+ }
+}
+
/// An iterator yielding the `Left` values of its source
pub type Lefts<L, R, Iter> = FilterMap<'static, Either<L, R>, L, Iter>;
mod tests {
use super::*;
+ use option::{IntoOption, ToOption, AsOption};
+ use option;
+ use result::{IntoResult, ToResult, AsResult};
+ use result;
+
#[test]
fn test_either_left() {
let val = Left(10);
assert_eq!(rights.len(), 0u);
}
+ #[test]
+ pub fn test_to_option() {
+ let right: Either<int, int> = Right(100);
+ let left: Either<int, int> = Left(404);
+
+ assert_eq!(right.to_option(), option::Some(100));
+ assert_eq!(left.to_option(), option::None);
+ }
+
+ #[test]
+ pub fn test_into_option() {
+ let right: Either<int, int> = Right(100);
+ let left: Either<int, int> = Left(404);
+
+ assert_eq!(right.into_option(), option::Some(100));
+ assert_eq!(left.into_option(), option::None);
+ }
+
+ #[test]
+ pub fn test_as_option() {
+ let right: Either<int, int> = Right(100);
+ let left: Either<int, int> = Left(404);
+
+ assert_eq!(right.as_option().unwrap(), &100);
+ assert_eq!(left.as_option(), option::None);
+ }
+
+ #[test]
+ pub fn test_to_result() {
+ let right: Either<int, int> = Right(100);
+ let left: Either<int, int> = Left(404);
+
+ assert_eq!(right.to_result(), result::Ok(100));
+ assert_eq!(left.to_result(), result::Err(404));
+ }
+
+ #[test]
+ pub fn test_into_result() {
+ let right: Either<int, int> = Right(100);
+ let left: Either<int, int> = Left(404);
+
+ assert_eq!(right.into_result(), result::Ok(100));
+ assert_eq!(left.into_result(), result::Err(404));
+ }
+
+ #[test]
+ pub fn test_as_result() {
+ let right: Either<int, int> = Right(100);
+ let left: Either<int, int> = Left(404);
+
+ let x = 100;
+ assert_eq!(right.as_result(), result::Ok(&x));
+
+ let x = 404;
+ assert_eq!(left.as_result(), result::Err(&x));
+ }
+
+ #[test]
+ pub fn test_to_either() {
+ let right: Either<int, int> = Right(100);
+ let left: Either<int, int> = Left(404);
+
+ assert_eq!(right.to_either(), Right(100));
+ assert_eq!(left.to_either(), Left(404));
+ }
+
+ #[test]
+ pub fn test_into_either() {
+ let right: Either<int, int> = Right(100);
+ let left: Either<int, int> = Left(404);
+
+ assert_eq!(right.into_either(), Right(100));
+ assert_eq!(left.into_either(), Left(404));
+ }
+
+ #[test]
+ pub fn test_as_either() {
+ let right: Either<int, int> = Right(100);
+ let left: Either<int, int> = Left(404);
+
+ assert_eq!(right.as_either().unwrap_right(), &100);
+ assert_eq!(left.as_either().unwrap_left(), &404);
+ }
}
format!("Hello") // => ~"Hello"
format!("Hello, {:s}!", "world") // => ~"Hello, world!"
format!("The number is {:d}", 1) // => ~"The number is 1"
-format!("{}", ~[3, 4]) // => ~"~[3, 4]"
+format!("{:?}", ~[3, 4]) // => ~"~[3, 4]"
format!("{value}", value=4) // => ~"4"
format!("{} {}", 1, 2) // => ~"1 2"
~~~
When implementing a format trait for your own time, you will have to implement a
method of the signature:
-~~~
+~~~{.rust}
fn fmt(value: &T, f: &mut std::fmt::Formatter);
~~~
struct. In order to help with this, the `Formatter` struct also provides some
helper methods.
+### Related macros
+
+There are a number of related macros in the `format!` family. The ones that are
+currently implemented are:
+
+~~~{.rust}
+format! // described above
+write! // first argument is a &mut rt::io::Writer, the destination
+writeln! // same as write but appends a newline
+print! // the format string is printed to the standard output
+println! // same as print but appends a newline
+format_args! // described below.
+~~~
+
+
+#### `write!`
+
+This and `writeln` are two macros which are used to emit the format string to a
+specified stream. This is used to prevent intermediate allocations of format
+strings and instead directly write the output. Under the hood, this function is
+actually invoking the `write` function defined in this module. Example usage is:
+
+~~~{.rust}
+use std::rt::io;
+
+let mut w = io::mem::MemWriter::new();
+write!(&mut w as &mut io::Writer, "Hello {}!", "world");
+~~~
+
+#### `print!`
+
+This and `println` emit their output to stdout. Similarly to the `write!` macro,
+the goal of these macros is to avoid intermediate allocations when printing
+output. Example usage is:
+
+~~~{.rust}
+print!("Hello {}!", "world");
+println!("I have a newline {}", "character at the end");
+~~~
+
+#### `format_args!`
+This is a curious macro which is used to safely pass around
+an opaque object describing the format string. This object
+does not require any heap allocations to create, and it only
+references information on the stack. Under the hood, all of
+the related macros are implemented in terms of this. First
+off, some example usage is:
+
+~~~{.rust}
+use std::fmt;
+
+format_args!(fmt::format, "this returns {}", "~str");
+format_args!(|args| { fmt::write(my_writer, args) }, "some {}", "args");
+format_args!(my_fn, "format {}", "string");
+~~~
+
+The first argument of the `format_args!` macro is a function (or closure) which
+takes one argument of type `&fmt::Arguments`. This structure can then be
+passed to the `write` and `format` functions inside this module in order to
+process the format string. The goal of this macro is to even further prevent
+intermediate allocations when dealing formatting strings.
+
+For example, a logging library could use the standard formatting syntax, but it
+would internally pass around this structure until it has been determined where
+output should go to.
+
+It is unsafe to programmatically create an instance of `fmt::Arguments` because
+the operations performed when executing a format string require the compile-time
+checks provided by the compiler. The `format_args!` macro is the only method of
+safely creating these structures, but they can be unsafely created with the
+constructor provided.
+
## Internationalization
The formatting syntax supported by the `format!` extension supports
to reference the string value of the argument which was selected upon. As an
example:
-~~~
+~~~{.rust}
format!("{0, select, other{#}}", "hello") // => ~"hello"
~~~
priv value: &'self util::Void,
}
+impl<'self> Arguments<'self> {
+ /// When using the format_args!() macro, this function is used to generate the
+ /// Arguments structure. The compiler inserts an `unsafe` block to call this,
+ /// which is valid because the compiler performs all necessary validation to
+ /// ensure that the resulting call to format/write would be safe.
+ #[doc(hidden)] #[inline]
+ pub unsafe fn new<'a>(fmt: &'static [rt::Piece<'static>],
+ args: &'a [Argument<'a>]) -> Arguments<'a> {
+ Arguments{ fmt: cast::transmute(fmt), args: args }
+ }
+}
+
+/// This structure represents a safely precompiled version of a format string
+/// and its arguments. This cannot be generated at runtime because it cannot
+/// safely be done so, so no constructors are given and the fields are private
+/// to prevent modification.
+///
+/// The `format_args!` macro will safely create an instance of this structure
+/// and pass it to a user-supplied function. The macro validates the format
+/// string at compile-time so usage of the `write` and `format` functions can
+/// be safely performed.
+pub struct Arguments<'self> {
+ priv fmt: &'self [rt::Piece<'self>],
+ priv args: &'self [Argument<'self>],
+}
+
/// When a format is not otherwise specified, types are formatted by ascribing
/// to this trait. There is not an explicit way of selecting this trait to be
/// used for formatting, it is only if no other format is specified.
/// and a list of arguments. The arguments will be formatted according to the
/// specified format string into the output stream provided.
///
+/// # Arguments
+///
+/// * output - the buffer to write output to
+/// * args - the precompiled arguments generated by `format_args!`
+///
+/// # Example
+///
+/// ~~~{.rust}
+/// use std::fmt;
+/// let w: &mut io::Writer = ...;
+/// format_args!(|args| { fmt::write(w, args) }, "Hello, {}!", "world");
+/// ~~~
+pub fn write(output: &mut io::Writer, args: &Arguments) {
+ unsafe { write_unsafe(output, args.fmt, args.args) }
+}
+
+/// The `writeln` function takes the same arguments as `write`, except that it
+/// will also write a newline (`\n`) character at the end of the format string.
+pub fn writeln(output: &mut io::Writer, args: &Arguments) {
+ unsafe { write_unsafe(output, args.fmt, args.args) }
+ output.write(['\n' as u8]);
+}
+
+/// The `write_unsafe` function takes an output stream, a precompiled format
+/// string, and a list of arguments. The arguments will be formatted according
+/// to the specified format string into the output stream provided.
+///
/// See the documentation for `format` for why this function is unsafe and care
/// should be taken if calling it manually.
///
///
/// Note that this function assumes that there are enough arguments for the
/// format string.
-pub unsafe fn write(output: &mut io::Writer,
- fmt: &[rt::Piece], args: &[Argument]) {
+pub unsafe fn write_unsafe(output: &mut io::Writer,
+ fmt: &[rt::Piece],
+ args: &[Argument]) {
let mut formatter = Formatter {
flags: 0,
width: None,
/// The format function takes a precompiled format string and a list of
/// arguments, to return the resulting formatted string.
///
+/// # Arguments
+///
+/// * args - a structure of arguments generated via the `format_args!` macro.
+/// Because this structure can only be safely generated at
+/// compile-time, this function is safe.
+///
+/// # Example
+///
+/// ~~~{.rust}
+/// use std::fmt;
+/// let s = format_args!(fmt::format, "Hello, {}!", "world");
+/// assert_eq!(s, "Hello, world!");
+/// ~~~
+pub fn format(args: &Arguments) -> ~str {
+ unsafe { format_unsafe(args.fmt, args.args) }
+}
+
+/// The unsafe version of the formatting function.
+///
/// This is currently an unsafe function because the types of all arguments
/// aren't verified by immediate callers of this function. This currently does
/// not validate that the correct types of arguments are specified for each
///
/// Note that this function assumes that there are enough arguments for the
/// format string.
-pub unsafe fn format(fmt: &[rt::Piece], args: &[Argument]) -> ~str {
+pub unsafe fn format_unsafe(fmt: &[rt::Piece], args: &[Argument]) -> ~str {
let mut output = MemWriter::new();
- write(&mut output as &mut io::Writer, fmt, args);
+ write_unsafe(&mut output as &mut io::Writer, fmt, args);
return str::from_utf8_owned(output.inner());
}
/// This is a function which calls are emitted to by the compiler itself to
/// create the Argument structures that are passed into the `format` function.
-#[doc(hidden)]
+#[doc(hidden)] #[inline]
pub fn argument<'a, T>(f: extern "Rust" fn(&T, &mut Formatter),
t: &'a T) -> Argument<'a> {
unsafe {
/// When the compiler determines that the type of an argument *must* be a string
/// (such as for select), then it invokes this method.
-#[doc(hidden)]
+#[doc(hidden)] #[inline]
pub fn argumentstr<'a>(s: &'a &str) -> Argument<'a> {
argument(String::fmt, s)
}
/// When the compiler determines that the type of an argument *must* be a uint
/// (such as for plural), then it invokes this method.
-#[doc(hidden)]
+#[doc(hidden)] #[inline]
pub fn argumentuint<'a>(s: &'a uint) -> Argument<'a> {
argument(Unsigned::fmt, s)
}
}
}
}
-
impl<T> Pointer for *mut T {
- fn fmt(t: &*mut T, f: &mut Formatter) {
- f.flags |= 1 << (parse::FlagAlternate as uint);
- do ::uint::to_str_bytes(*t as uint, 16) |buf| {
- f.pad_integral(buf, "0x", true);
- }
- }
+ fn fmt(t: &*mut T, f: &mut Formatter) { Pointer::fmt(&(*t as *T), f) }
}
// Implementation of Default for various core types
impl<T> Default for *T {
fn fmt(me: &*T, f: &mut Formatter) { Pointer::fmt(me, f) }
}
-
impl<T> Default for *mut T {
fn fmt(me: &*mut T, f: &mut Formatter) { Pointer::fmt(me, f) }
}
/// characters.
fn word(&mut self) -> &'self str {
let start = match self.cur.clone().next() {
- Some((pos, c)) if char::is_alphabetic(c) => {
+ Some((pos, c)) if char::is_XID_start(c) => {
self.cur.next();
pos
}
let mut end;
loop {
match self.cur.clone().next() {
- Some((_, c)) if char::is_alphanumeric(c) => {
+ Some((_, c)) if char::is_XID_continue(c) => {
self.cur.next();
}
Some((pos, _)) => { end = pos; break }
use container::{Container, Mutable, Map, MutableMap, Set, MutableSet};
use clone::Clone;
use cmp::{Eq, Equiv};
+use default::Default;
use hash::Hash;
use iter::{Iterator, FromIterator, Extendable};
use iter::{FilterMap, Chain, Repeat, Zip};
}
}
+impl<K: Eq + Hash, V> Default for HashMap<K, V> {
+ fn default() -> HashMap<K, V> { HashMap::new() }
+}
+
/// An implementation of a hash set using the underlying representation of a
/// HashMap where the value is (). As with the `HashMap` type, a `HashSet`
/// requires that the elements implement the `Eq` and `Hash` traits.
HashSet { map: HashMap::with_capacity(capacity) }
}
+ /// Create an empty HashSet with space for at least `capacity`
+ /// elements in the hash table, using `k0` and `k1` as the keys.
+ ///
+ /// Warning: `k0` and `k1` are normally randomly generated, and
+ /// are designed to allow HashSets to be resistant to attacks that
+ /// cause many collisions and very poor performance. Setting them
+ /// manually using this function can expose a DoS attack vector.
+ pub fn with_capacity_and_keys(k0: u64, k1: u64, capacity: uint) -> HashSet<T> {
+ HashSet { map: HashMap::with_capacity_and_keys(k0, k1, capacity) }
+ }
+
/// Reserve space for at least `n` elements in the hash table.
pub fn reserve_at_least(&mut self, n: uint) {
self.map.reserve_at_least(n)
}
}
+impl<K: Eq + Hash> Default for HashSet<K> {
+ fn default() -> HashSet<K> { HashSet::new() }
+}
+
// `Repeat` is used to feed the filter closure an explicit capture
// of a reference to the other set
/// Set operations iterator
}
pub fn file_writer(path: &Path, flags: &[FileFlag]) -> Result<@Writer, ~str> {
- mk_file_writer(path, flags).chain(|w| Ok(w))
+ mk_file_writer(path, flags).and_then(|w| Ok(w))
}
}
pub fn read_whole_file_str(file: &Path) -> Result<~str, ~str> {
- do read_whole_file(file).chain |bytes| {
+ do read_whole_file(file).and_then |bytes| {
if str::is_utf8(bytes) {
Ok(str::from_utf8(bytes))
} else {
// FIXME (#2004): implement this in a low-level way. Going through the
// abstractions is pointless.
pub fn read_whole_file(file: &Path) -> Result<~[u8], ~str> {
- do file_reader(file).chain |rdr| {
+ do file_reader(file).and_then |rdr| {
Ok(rdr.read_whole_stream())
}
}
use num::{Zero, One, Integer, CheckedAdd, CheckedSub, Saturating};
use option::{Option, Some, None};
use ops::{Add, Mul, Sub};
-use cmp::Ord;
+use cmp::{Eq, Ord};
use clone::Clone;
use uint;
use util;
impl<'self, A, B, T: Iterator<A>, St> Iterator<B> for Scan<'self, A, B, T, St> {
#[inline]
fn next(&mut self) -> Option<B> {
- self.iter.next().chain(|a| (self.f)(&mut self.state, a))
+ self.iter.next().and_then(|a| (self.f)(&mut self.state, a))
}
#[inline]
priv backiter: Option<U>,
}
-impl<'self, A, T: Iterator<A>, B, U: Iterator<B>> Iterator<B> for
- FlatMap<'self, A, T, U> {
+impl<'self, A, T: Iterator<A>, B, U: Iterator<B>> Iterator<B> for FlatMap<'self, A, T, U> {
#[inline]
fn next(&mut self) -> Option<B> {
loop {
}
}
match self.iter.next().map_move(|x| (self.f)(x)) {
- None => return self.backiter.chain_mut_ref(|it| it.next()),
+ None => return self.backiter.and_then_mut_ref(|it| it.next()),
next => self.frontiter = next,
}
}
}
}
match self.iter.next_back().map_move(|x| (self.f)(x)) {
- None => return self.frontiter.chain_mut_ref(|it| it.next_back()),
+ None => return self.frontiter.and_then_mut_ref(|it| it.next_back()),
next => self.backiter = next,
}
}
Counter{state: start, step: step}
}
-/// A range of numbers from [0, N)
+impl<A: Add<A, A> + Clone> Iterator<A> for Counter<A> {
+ #[inline]
+ fn next(&mut self) -> Option<A> {
+ let result = self.state.clone();
+ self.state = self.state + self.step;
+ Some(result)
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (uint, Option<uint>) {
+ (uint::max_value, None) // Too bad we can't specify an infinite lower bound
+ }
+}
+
+/// An iterator over the range [start, stop)
#[deriving(Clone, DeepClone)]
pub struct Range<A> {
priv state: A,
// Blocked on #8605 Need numeric trait for converting to `Option<uint>`
}
-impl<A: Sub<A, A> + Integer + Ord + Clone> DoubleEndedIterator<A> for Range<A> {
+/// `Integer` is required to ensure the range will be the same regardless of
+/// the direction it is consumed.
+impl<A: Integer + Ord + Clone> DoubleEndedIterator<A> for Range<A> {
#[inline]
fn next_back(&mut self) -> Option<A> {
if self.stop > self.state {
- // Integer doesn't technically define this rule, but we're going to assume that every
- // Integer is reachable from every other one by adding or subtracting enough Ones. This
- // seems like a reasonable-enough rule that every Integer should conform to, even if it
- // can't be statically checked.
self.stop = self.stop - self.one;
Some(self.stop.clone())
} else {
}
}
-/// A range of numbers from [0, N]
+/// An iterator over the range [start, stop]
#[deriving(Clone, DeepClone)]
pub struct RangeInclusive<A> {
priv range: Range<A>,
RangeInclusive{range: range(start, stop), done: false}
}
-impl<A: Add<A, A> + Ord + Clone> Iterator<A> for RangeInclusive<A> {
+impl<A: Add<A, A> + Eq + Ord + Clone> Iterator<A> for RangeInclusive<A> {
#[inline]
fn next(&mut self) -> Option<A> {
match self.range.next() {
Some(x) => Some(x),
None => {
- if self.done {
- None
- } else {
+ if !self.done && self.range.state == self.range.stop {
self.done = true;
Some(self.range.stop.clone())
+ } else {
+ None
}
}
}
let result = self.range.stop.clone();
self.range.stop = self.range.stop - self.range.one;
Some(result)
- } else if self.done {
- None
- } else {
+ } else if !self.done && self.range.state == self.range.stop {
self.done = true;
Some(self.range.stop.clone())
+ } else {
+ None
}
}
}
-impl<A: Add<A, A> + Clone> Iterator<A> for Counter<A> {
+/// An iterator over the range [start, stop) by `step`. It handles overflow by stopping.
+#[deriving(Clone, DeepClone)]
+pub struct RangeStep<A> {
+ priv state: A,
+ priv stop: A,
+ priv step: A,
+ priv rev: bool
+}
+
+/// Return an iterator over the range [start, stop) by `step`. It handles overflow by stopping.
+#[inline]
+pub fn range_step<A: CheckedAdd + Ord + Clone + Zero>(start: A, stop: A, step: A) -> RangeStep<A> {
+ let rev = step < Zero::zero();
+ RangeStep{state: start, stop: stop, step: step, rev: rev}
+}
+
+impl<A: CheckedAdd + Ord + Clone> Iterator<A> for RangeStep<A> {
#[inline]
fn next(&mut self) -> Option<A> {
- let result = self.state.clone();
- self.state = self.state + self.step;
- Some(result)
+ if (self.rev && self.state > self.stop) || (!self.rev && self.state < self.stop) {
+ let result = self.state.clone();
+ match self.state.checked_add(&self.step) {
+ Some(x) => self.state = x,
+ None => self.state = self.stop.clone()
+ }
+ Some(result)
+ } else {
+ None
+ }
}
+}
+/// An iterator over the range [start, stop] by `step`. It handles overflow by stopping.
+#[deriving(Clone, DeepClone)]
+pub struct RangeStepInclusive<A> {
+ priv state: A,
+ priv stop: A,
+ priv step: A,
+ priv rev: bool,
+ priv done: bool
+}
+
+/// Return an iterator over the range [start, stop] by `step`. It handles overflow by stopping.
+#[inline]
+pub fn range_step_inclusive<A: CheckedAdd + Ord + Clone + Zero>(start: A, stop: A,
+ step: A) -> RangeStepInclusive<A> {
+ let rev = step < Zero::zero();
+ RangeStepInclusive{state: start, stop: stop, step: step, rev: rev, done: false}
+}
+
+impl<A: CheckedAdd + Ord + Clone + Eq> Iterator<A> for RangeStepInclusive<A> {
#[inline]
- fn size_hint(&self) -> (uint, Option<uint>) {
- (uint::max_value, None) // Too bad we can't specify an infinite lower bound
+ fn next(&mut self) -> Option<A> {
+ if !self.done && ((self.rev && self.state >= self.stop) ||
+ (!self.rev && self.state <= self.stop)) {
+ let result = self.state.clone();
+ match self.state.checked_add(&self.step) {
+ Some(x) => self.state = x,
+ None => self.done = true
+ }
+ Some(result)
+ } else {
+ None
+ }
}
}
}
}
+ #[test]
+ fn test_range() {
+ assert_eq!(range(0i, 5).collect::<~[int]>(), ~[0i, 1, 2, 3, 4]);
+ assert_eq!(range(0i, 5).invert().collect::<~[int]>(), ~[4, 3, 2, 1, 0]);
+ assert_eq!(range(200, -5).collect::<~[int]>(), ~[]);
+ assert_eq!(range(200, -5).invert().collect::<~[int]>(), ~[]);
+ assert_eq!(range(200, 200).collect::<~[int]>(), ~[]);
+ assert_eq!(range(200, 200).invert().collect::<~[int]>(), ~[]);
+ }
+
#[test]
fn test_range_inclusive() {
assert_eq!(range_inclusive(0i, 5).collect::<~[int]>(), ~[0i, 1, 2, 3, 4, 5]);
assert_eq!(range_inclusive(0i, 5).invert().collect::<~[int]>(), ~[5i, 4, 3, 2, 1, 0]);
+ assert_eq!(range_inclusive(200, -5).collect::<~[int]>(), ~[]);
+ assert_eq!(range_inclusive(200, -5).invert().collect::<~[int]>(), ~[]);
+ assert_eq!(range_inclusive(200, 200).collect::<~[int]>(), ~[200]);
+ assert_eq!(range_inclusive(200, 200).invert().collect::<~[int]>(), ~[200]);
+ }
+
+ #[test]
+ fn test_range_step() {
+ assert_eq!(range_step(0i, 20, 5).collect::<~[int]>(), ~[0, 5, 10, 15]);
+ assert_eq!(range_step(20i, 0, -5).collect::<~[int]>(), ~[20, 15, 10, 5]);
+ assert_eq!(range_step(20i, 0, -6).collect::<~[int]>(), ~[20, 14, 8, 2]);
+ assert_eq!(range_step(200u8, 255, 50).collect::<~[u8]>(), ~[200u8, 250]);
+ assert_eq!(range_step(200, -5, 1).collect::<~[int]>(), ~[]);
+ assert_eq!(range_step(200, 200, 1).collect::<~[int]>(), ~[]);
+ }
+
+ #[test]
+ fn test_range_step_inclusive() {
+ assert_eq!(range_step_inclusive(0i, 20, 5).collect::<~[int]>(), ~[0, 5, 10, 15, 20]);
+ assert_eq!(range_step_inclusive(20i, 0, -5).collect::<~[int]>(), ~[20, 15, 10, 5, 0]);
+ assert_eq!(range_step_inclusive(20i, 0, -6).collect::<~[int]>(), ~[20, 14, 8, 2]);
+ assert_eq!(range_step_inclusive(200u8, 255, 50).collect::<~[u8]>(), ~[200u8, 250]);
+ assert_eq!(range_step_inclusive(200, -5, 1).collect::<~[int]>(), ~[]);
+ assert_eq!(range_step_inclusive(200, 200, 1).collect::<~[int]>(), ~[200]);
}
#[test]
the TLS slot. Useful for dynamic variables, singletons, and interfacing with
foreign code with bad callback interfaces.
-To use, declare a static variable of the type you wish to store. The
-initialization should be `&local_data::Key`. This is then the key to what you
-wish to store.
+To declare a new key for storing local data of a particular type, use the
+`local_data_key!` macro. This macro will expand to a `static` item apppriately
+named and annotated. This name is then passed to the functions in this module to
+modify/read the slot specified by the key.
~~~{.rust}
use std::local_data;
local_data::get(key_int, |opt| assert_eq!(opt, Some(&3)));
local_data::set(key_vector, ~[4]);
-local_data::get(key_int, |opt| assert_eq!(opt, Some(&~[4])));
+local_data::get(key_vector, |opt| assert_eq!(opt, Some(&~[4])));
~~~
-Casting 'Arcane Sight' reveals an overwhelming aura of Transmutation
-magic.
-
*/
+// Casting 'Arcane Sight' reveals an overwhelming aura of Transmutation
+// magic.
+
use cast;
use libc;
use prelude::*;
use option::*;
use os;
-use either::*;
use rt;
-use rt::logging::{Logger, StdErrLogger};
+use rt::logging::{Logger, StdErrLogger, OwnedString};
/// Turns on logging to stdout globally
pub fn console_on() {
match optional_task {
Some(local) => {
// Use the available logger
- (*local).logger.log(Left(msg));
+ (*local).logger.log(OwnedString(msg));
}
None => {
// There is no logger anywhere, just write to stderr
let mut logger = StdErrLogger;
- logger.log(Left(msg));
+ logger.log(OwnedString(msg));
}
}
}
#[allow(missing_doc)];
#[allow(non_uppercase_statics)];
+use default::Default;
use libc::c_int;
use num::{Zero, One, strconv};
use num::{FPCategory, FPNaN, FPInfinite , FPZero, FPSubnormal, FPNormal};
}
}
+impl Default for f32 {
+ #[inline]
+ fn default() -> f32 { 0.0 }
+}
+
impl Zero for f32 {
#[inline]
fn zero() -> f32 { 0.0 }
#[allow(missing_doc)];
#[allow(non_uppercase_statics)];
+use default::Default;
use libc::c_int;
use num::{Zero, One, strconv};
use num::{FPCategory, FPNaN, FPInfinite , FPZero, FPSubnormal, FPNormal};
}
}
+impl Default for f64 {
+ #[inline]
+ fn default() -> f64 { 0.0 }
+}
+
impl Zero for f64 {
#[inline]
fn zero() -> f64 { 0.0 }
#[allow(missing_doc)];
#[allow(non_uppercase_statics)];
+use default::Default;
use num::{Zero, One, strconv};
use num::FPCategory;
use num;
}
}
+impl Default for float {
+ #[inline]
+ fn default() -> float { 0.0 }
+}
+
impl Zero for float {
#[inline]
fn zero() -> float { 0.0 }
#[allow(non_uppercase_statics)];
+use default::Default;
use num::{ToStrRadix, FromStrRadix};
use num::{CheckedDiv, Zero, One, strconv};
use prelude::*;
}
}
-enum Range { Closed, HalfOpen }
-
-#[inline]
-///
-/// Iterate through a range with a given step value.
-///
-/// Let `term` denote the closed interval `[stop-step,stop]` if `r` is Closed;
-/// otherwise `term` denotes the half-open interval `[stop-step,stop)`.
-/// Iterates through the range `[x_0, x_1, ..., x_n]` where
-/// `x_j == start + step*j`, and `x_n` lies in the interval `term`.
-///
-/// If no such nonnegative integer `n` exists, then the iteration range
-/// is empty.
-///
-fn range_step_core(start: $T, stop: $T, step: $T, r: Range, it: &fn($T) -> bool) -> bool {
- let mut i = start;
- if step == 0 {
- fail!(~"range_step called with step == 0");
- } else if step == (1 as $T) { // elide bounds check to tighten loop
- while i < stop {
- if !it(i) { return false; }
- // no need for overflow check;
- // cannot have i + 1 > max_value because i < stop <= max_value
- i += (1 as $T);
- }
- } else if step == (-1 as $T) { // elide bounds check to tighten loop
- while i > stop {
- if !it(i) { return false; }
- // no need for underflow check;
- // cannot have i - 1 < min_value because i > stop >= min_value
- i -= (1 as $T);
- }
- } else if step > 0 { // ascending
- while i < stop {
- if !it(i) { return false; }
- // avoiding overflow. break if i + step > max_value
- if i > max_value - step { return true; }
- i += step;
- }
- } else { // descending
- while i > stop {
- if !it(i) { return false; }
- // avoiding underflow. break if i + step < min_value
- if i < min_value - step { return true; }
- i += step;
- }
- }
- match r {
- HalfOpen => return true,
- Closed => return (i != stop || it(i))
- }
-}
-
-#[inline]
-///
-/// Iterate through the range [`start`..`stop`) with a given step value.
-///
-/// Iterates through the range `[x_0, x_1, ..., x_n]` where
-/// * `x_i == start + step*i`, and
-/// * `n` is the greatest nonnegative integer such that `x_n < stop`
-///
-/// (If no such `n` exists, then the iteration range is empty.)
-///
-/// # Arguments
-///
-/// * `start` - lower bound, inclusive
-/// * `stop` - higher bound, exclusive
-///
-/// # Examples
-/// ~~~
-/// let mut sum = 0;
-/// for int::range(1, 5) |i| {
-/// sum += i;
-/// }
-/// assert!(sum == 10);
-/// ~~~
-///
-pub fn range_step(start: $T, stop: $T, step: $T, it: &fn($T) -> bool) -> bool {
- range_step_core(start, stop, step, HalfOpen, it)
-}
-
-#[inline]
-///
-/// Iterate through a range with a given step value.
-///
-/// Iterates through the range `[x_0, x_1, ..., x_n]` where
-/// `x_i == start + step*i` and `x_n <= last < step + x_n`.
-///
-/// (If no such nonnegative integer `n` exists, then the iteration
-/// range is empty.)
-///
-pub fn range_step_inclusive(start: $T, last: $T, step: $T, it: &fn($T) -> bool) -> bool {
- range_step_core(start, last, step, Closed, it)
-}
-
impl Num for $T {}
#[cfg(not(test))]
}
}
+impl Default for $T {
+ #[inline]
+ fn default() -> $T { 0 }
+}
+
impl Zero for $T {
#[inline]
fn zero() -> $T { 0 }
// String conversion functions and impl str -> num
-/// Parse a string as a number in base 10.
-#[inline]
-pub fn from_str(s: &str) -> Option<$T> {
- strconv::from_str_common(s, 10u, true, false, false,
- strconv::ExpNone, false, false)
-}
-
-/// Parse a string as a number in the given base.
-#[inline]
-pub fn from_str_radix(s: &str, radix: uint) -> Option<$T> {
- strconv::from_str_common(s, radix, true, false, false,
- strconv::ExpNone, false, false)
-}
-
/// Parse a byte slice as a number in the given base.
#[inline]
pub fn parse_bytes(buf: &[u8], radix: uint) -> Option<$T> {
impl FromStr for $T {
#[inline]
fn from_str(s: &str) -> Option<$T> {
- from_str(s)
+ strconv::from_str_common(s, 10u, true, false, false,
+ strconv::ExpNone, false, false)
}
}
impl FromStrRadix for $T {
#[inline]
fn from_str_radix(s: &str, radix: uint) -> Option<$T> {
- from_str_radix(s, radix)
+ strconv::from_str_common(s, radix, true, false, false,
+ strconv::ExpNone, false, false)
}
}
use super::*;
use int;
- use i16;
use i32;
- use i64;
- use i8;
use num;
use sys;
#[test]
fn test_from_str() {
- assert_eq!(from_str("0"), Some(0 as $T));
- assert_eq!(from_str("3"), Some(3 as $T));
- assert_eq!(from_str("10"), Some(10 as $T));
- assert_eq!(i32::from_str("123456789"), Some(123456789 as i32));
- assert_eq!(from_str("00100"), Some(100 as $T));
+ assert_eq!(from_str::<$T>("0"), Some(0 as $T));
+ assert_eq!(from_str::<$T>("3"), Some(3 as $T));
+ assert_eq!(from_str::<$T>("10"), Some(10 as $T));
+ assert_eq!(from_str::<i32>("123456789"), Some(123456789 as i32));
+ assert_eq!(from_str::<$T>("00100"), Some(100 as $T));
- assert_eq!(from_str("-1"), Some(-1 as $T));
- assert_eq!(from_str("-3"), Some(-3 as $T));
- assert_eq!(from_str("-10"), Some(-10 as $T));
- assert_eq!(i32::from_str("-123456789"), Some(-123456789 as i32));
- assert_eq!(from_str("-00100"), Some(-100 as $T));
+ assert_eq!(from_str::<$T>("-1"), Some(-1 as $T));
+ assert_eq!(from_str::<$T>("-3"), Some(-3 as $T));
+ assert_eq!(from_str::<$T>("-10"), Some(-10 as $T));
+ assert_eq!(from_str::<i32>("-123456789"), Some(-123456789 as i32));
+ assert_eq!(from_str::<$T>("-00100"), Some(-100 as $T));
- assert!(from_str(" ").is_none());
- assert!(from_str("x").is_none());
+ assert!(from_str::<$T>(" ").is_none());
+ assert!(from_str::<$T>("x").is_none());
}
#[test]
#[test]
fn test_int_from_str_overflow() {
let mut i8_val: i8 = 127_i8;
- assert_eq!(i8::from_str("127"), Some(i8_val));
- assert!(i8::from_str("128").is_none());
+ assert_eq!(from_str::<i8>("127"), Some(i8_val));
+ assert!(from_str::<i8>("128").is_none());
i8_val += 1 as i8;
- assert_eq!(i8::from_str("-128"), Some(i8_val));
- assert!(i8::from_str("-129").is_none());
+ assert_eq!(from_str::<i8>("-128"), Some(i8_val));
+ assert!(from_str::<i8>("-129").is_none());
let mut i16_val: i16 = 32_767_i16;
- assert_eq!(i16::from_str("32767"), Some(i16_val));
- assert!(i16::from_str("32768").is_none());
+ assert_eq!(from_str::<i16>("32767"), Some(i16_val));
+ assert!(from_str::<i16>("32768").is_none());
i16_val += 1 as i16;
- assert_eq!(i16::from_str("-32768"), Some(i16_val));
- assert!(i16::from_str("-32769").is_none());
+ assert_eq!(from_str::<i16>("-32768"), Some(i16_val));
+ assert!(from_str::<i16>("-32769").is_none());
let mut i32_val: i32 = 2_147_483_647_i32;
- assert_eq!(i32::from_str("2147483647"), Some(i32_val));
- assert!(i32::from_str("2147483648").is_none());
+ assert_eq!(from_str::<i32>("2147483647"), Some(i32_val));
+ assert!(from_str::<i32>("2147483648").is_none());
i32_val += 1 as i32;
- assert_eq!(i32::from_str("-2147483648"), Some(i32_val));
- assert!(i32::from_str("-2147483649").is_none());
+ assert_eq!(from_str::<i32>("-2147483648"), Some(i32_val));
+ assert!(from_str::<i32>("-2147483649").is_none());
let mut i64_val: i64 = 9_223_372_036_854_775_807_i64;
- assert_eq!(i64::from_str("9223372036854775807"), Some(i64_val));
- assert!(i64::from_str("9223372036854775808").is_none());
+ assert_eq!(from_str::<i64>("9223372036854775807"), Some(i64_val));
+ assert!(from_str::<i64>("9223372036854775808").is_none());
i64_val += 1 as i64;
- assert_eq!(i64::from_str("-9223372036854775808"), Some(i64_val));
- assert!(i64::from_str("-9223372036854775809").is_none());
- }
-
- #[test]
- fn test_ranges() {
- let mut l = ~[];
-
- do range_step(20,26,2) |i| {
- l.push(i);
- true
- };
- do range_step(36,30,-2) |i| {
- l.push(i);
- true
- };
- do range_step(max_value - 2, max_value, 2) |i| {
- l.push(i);
- true
- };
- do range_step(max_value - 3, max_value, 2) |i| {
- l.push(i);
- true
- };
- do range_step(min_value + 2, min_value, -2) |i| {
- l.push(i);
- true
- };
- do range_step(min_value + 3, min_value, -2) |i| {
- l.push(i);
- true
- };
- assert_eq!(l, ~[20,22,24,
- 36,34,32,
- max_value-2,
- max_value-3,max_value-1,
- min_value+2,
- min_value+3,min_value+1]);
-
- // None of the `fail`s should execute.
- do range_step(10,0,1) |_i| {
- fail!(~"unreachable");
- };
- do range_step(0,10,-1) |_i| {
- fail!(~"unreachable");
- };
- }
-
- #[test]
- #[should_fail]
- fn test_range_step_zero_step() {
- do range_step(0,10,0) |_i| { true };
+ assert_eq!(from_str::<i64>("-9223372036854775808"), Some(i64_val));
+ assert!(from_str::<i64>("-9223372036854775809").is_none());
}
#[test]
+ DeepClone
+ Num
+ NumCast
+ + Orderable
+ Bounded
+ Neg<Self>
+ Add<Self,Self>
fn from_str_radix(str: &str, radix: uint) -> Option<Self>;
}
+/// A utility function that just calls FromStrRadix::from_str_radix
+pub fn from_str_radix<T: FromStrRadix>(str: &str, radix: uint) -> Option<T> {
+ FromStrRadix::from_str_radix(str, radix)
+}
+
/// Calculates a power to a given radix, optimized for uint `pow` and `radix`.
///
/// Returns `radix^pow` as `T`.
#[allow(non_uppercase_statics)];
+use default::Default;
use num::BitCount;
use num::{ToStrRadix, FromStrRadix};
use num::{CheckedDiv, Zero, One, strconv};
}
}
-enum Range { Closed, HalfOpen }
-
-#[inline]
-///
-/// Iterate through a range with a given step value.
-///
-/// Let `term` denote the closed interval `[stop-step,stop]` if `r` is Closed;
-/// otherwise `term` denotes the half-open interval `[stop-step,stop)`.
-/// Iterates through the range `[x_0, x_1, ..., x_n]` where
-/// `x_j == start + step*j`, and `x_n` lies in the interval `term`.
-///
-/// If no such nonnegative integer `n` exists, then the iteration range
-/// is empty.
-///
-fn range_step_core(start: $T, stop: $T, step: $T_SIGNED, r: Range, it: &fn($T) -> bool) -> bool {
- let mut i = start;
- if step == 0 {
- fail!("range_step called with step == 0");
- } else if step == (1 as $T_SIGNED) { // elide bounds check to tighten loop
- while i < stop {
- if !it(i) { return false; }
- // no need for overflow check;
- // cannot have i + 1 > max_value because i < stop <= max_value
- i += (1 as $T);
- }
- } else if step == (-1 as $T_SIGNED) { // elide bounds check to tighten loop
- while i > stop {
- if !it(i) { return false; }
- // no need for underflow check;
- // cannot have i - 1 < min_value because i > stop >= min_value
- i -= (1 as $T);
- }
- } else if step > 0 { // ascending
- while i < stop {
- if !it(i) { return false; }
- // avoiding overflow. break if i + step > max_value
- if i > max_value - (step as $T) { return true; }
- i += step as $T;
- }
- } else { // descending
- while i > stop {
- if !it(i) { return false; }
- // avoiding underflow. break if i + step < min_value
- if i < min_value + ((-step) as $T) { return true; }
- i -= -step as $T;
- }
- }
- match r {
- HalfOpen => return true,
- Closed => return (i != stop || it(i))
- }
-}
-
-#[inline]
-///
-/// Iterate through the range [`start`..`stop`) with a given step value.
-///
-/// Iterates through the range `[x_0, x_1, ..., x_n]` where
-/// - `x_i == start + step*i`, and
-/// - `n` is the greatest nonnegative integer such that `x_n < stop`
-///
-/// (If no such `n` exists, then the iteration range is empty.)
-///
-/// # Arguments
-///
-/// * `start` - lower bound, inclusive
-/// * `stop` - higher bound, exclusive
-///
-/// # Examples
-/// ~~~ {.rust}
-/// let nums = [1,2,3,4,5,6,7];
-///
-/// for uint::range_step(0, nums.len() - 1, 2) |i| {
-/// printfln!("%d & %d", nums[i], nums[i+1]);
-/// }
-/// ~~~
-///
-pub fn range_step(start: $T, stop: $T, step: $T_SIGNED, it: &fn($T) -> bool) -> bool {
- range_step_core(start, stop, step, HalfOpen, it)
-}
-
-#[inline]
-///
-/// Iterate through a range with a given step value.
-///
-/// Iterates through the range `[x_0, x_1, ..., x_n]` where
-/// `x_i == start + step*i` and `x_n <= last < step + x_n`.
-///
-/// (If no such nonnegative integer `n` exists, then the iteration
-/// range is empty.)
-///
-pub fn range_step_inclusive(start: $T, last: $T, step: $T_SIGNED, it: &fn($T) -> bool) -> bool {
- range_step_core(start, last, step, Closed, it)
-}
-
impl Num for $T {}
#[cfg(not(test))]
}
}
+impl Default for $T {
+ #[inline]
+ fn default() -> $T { 0 }
+}
+
impl Zero for $T {
#[inline]
fn zero() -> $T { 0 }
// String conversion functions and impl str -> num
-/// Parse a string as a number in base 10.
-#[inline]
-pub fn from_str(s: &str) -> Option<$T> {
- strconv::from_str_common(s, 10u, false, false, false,
- strconv::ExpNone, false, false)
-}
-
-/// Parse a string as a number in the given base.
-#[inline]
-pub fn from_str_radix(s: &str, radix: uint) -> Option<$T> {
- strconv::from_str_common(s, radix, false, false, false,
- strconv::ExpNone, false, false)
-}
-
/// Parse a byte slice as a number in the given base.
#[inline]
pub fn parse_bytes(buf: &[u8], radix: uint) -> Option<$T> {
impl FromStr for $T {
#[inline]
fn from_str(s: &str) -> Option<$T> {
- from_str(s)
+ strconv::from_str_common(s, 10u, false, false, false,
+ strconv::ExpNone, false, false)
}
}
impl FromStrRadix for $T {
#[inline]
fn from_str_radix(s: &str, radix: uint) -> Option<$T> {
- from_str_radix(s, radix)
+ strconv::from_str_common(s, radix, false, false, false,
+ strconv::ExpNone, false, false)
}
}
use num;
use sys;
use u16;
- use u32;
- use u64;
- use u8;
#[test]
fn test_num() {
#[test]
pub fn test_from_str() {
- assert_eq!(from_str("0"), Some(0u as $T));
- assert_eq!(from_str("3"), Some(3u as $T));
- assert_eq!(from_str("10"), Some(10u as $T));
- assert_eq!(u32::from_str("123456789"), Some(123456789 as u32));
- assert_eq!(from_str("00100"), Some(100u as $T));
+ assert_eq!(from_str::<$T>("0"), Some(0u as $T));
+ assert_eq!(from_str::<$T>("3"), Some(3u as $T));
+ assert_eq!(from_str::<$T>("10"), Some(10u as $T));
+ assert_eq!(from_str::<u32>("123456789"), Some(123456789 as u32));
+ assert_eq!(from_str::<$T>("00100"), Some(100u as $T));
- assert!(from_str("").is_none());
- assert!(from_str(" ").is_none());
- assert!(from_str("x").is_none());
+ assert!(from_str::<$T>("").is_none());
+ assert!(from_str::<$T>(" ").is_none());
+ assert!(from_str::<$T>("x").is_none());
}
#[test]
#[test]
fn test_uint_from_str_overflow() {
let mut u8_val: u8 = 255_u8;
- assert_eq!(u8::from_str("255"), Some(u8_val));
- assert!(u8::from_str("256").is_none());
+ assert_eq!(from_str::<u8>("255"), Some(u8_val));
+ assert!(from_str::<u8>("256").is_none());
u8_val += 1 as u8;
- assert_eq!(u8::from_str("0"), Some(u8_val));
- assert!(u8::from_str("-1").is_none());
+ assert_eq!(from_str::<u8>("0"), Some(u8_val));
+ assert!(from_str::<u8>("-1").is_none());
let mut u16_val: u16 = 65_535_u16;
- assert_eq!(u16::from_str("65535"), Some(u16_val));
- assert!(u16::from_str("65536").is_none());
+ assert_eq!(from_str::<u16>("65535"), Some(u16_val));
+ assert!(from_str::<u16>("65536").is_none());
u16_val += 1 as u16;
- assert_eq!(u16::from_str("0"), Some(u16_val));
- assert!(u16::from_str("-1").is_none());
+ assert_eq!(from_str::<u16>("0"), Some(u16_val));
+ assert!(from_str::<u16>("-1").is_none());
let mut u32_val: u32 = 4_294_967_295_u32;
- assert_eq!(u32::from_str("4294967295"), Some(u32_val));
- assert!(u32::from_str("4294967296").is_none());
+ assert_eq!(from_str::<u32>("4294967295"), Some(u32_val));
+ assert!(from_str::<u32>("4294967296").is_none());
u32_val += 1 as u32;
- assert_eq!(u32::from_str("0"), Some(u32_val));
- assert!(u32::from_str("-1").is_none());
+ assert_eq!(from_str::<u32>("0"), Some(u32_val));
+ assert!(from_str::<u32>("-1").is_none());
let mut u64_val: u64 = 18_446_744_073_709_551_615_u64;
- assert_eq!(u64::from_str("18446744073709551615"), Some(u64_val));
- assert!(u64::from_str("18446744073709551616").is_none());
+ assert_eq!(from_str::<u64>("18446744073709551615"), Some(u64_val));
+ assert!(from_str::<u64>("18446744073709551616").is_none());
u64_val += 1 as u64;
- assert_eq!(u64::from_str("0"), Some(u64_val));
- assert!(u64::from_str("-1").is_none());
+ assert_eq!(from_str::<u64>("0"), Some(u64_val));
+ assert!(from_str::<u64>("-1").is_none());
}
#[test]
100u.to_str_radix(37u);
}
- #[test]
- pub fn test_ranges() {
- let mut l = ~[];
-
- do range_step(20,26,2) |i| {
- l.push(i);
- true
- };
- do range_step(36,30,-2) |i| {
- l.push(i);
- true
- };
- do range_step(max_value - 2, max_value, 2) |i| {
- l.push(i);
- true
- };
- do range_step(max_value - 3, max_value, 2) |i| {
- l.push(i);
- true
- };
- do range_step(min_value + 2, min_value, -2) |i| {
- l.push(i);
- true
- };
- do range_step(min_value + 3, min_value, -2) |i| {
- l.push(i);
- true
- };
-
- assert_eq!(l, ~[20,22,24,
- 36,34,32,
- max_value-2,
- max_value-3,max_value-1,
- min_value+2,
- min_value+3,min_value+1]);
-
- // None of the `fail`s should execute.
- do range_step(10,0,1) |_i| {
- fail!("unreachable");
- };
- do range_step(0,1,-10) |_i| {
- fail!("unreachable");
- };
- }
-
- #[test]
- #[should_fail]
- fn test_range_step_zero_step_up() {
- do range_step(0,10,0) |_i| { true };
- }
- #[test]
- #[should_fail]
- fn test_range_step_zero_step_down() {
- do range_step(0,-10,0) |_i| { true };
- }
-
#[test]
fn test_unsigned_checked_div() {
assert_eq!(10u.checked_div(&2), Some(5));
use clone::Clone;
use cmp::{Eq,Ord};
+use default::Default;
+use either;
use util;
use num::Zero;
use iter;
use iter::{Iterator, DoubleEndedIterator, ExactSize};
+use result;
use str::{StrSlice, OwnedStr};
use to_str::ToStr;
use clone::DeepClone;
#[inline]
pub fn is_some(&self) -> bool { !self.is_none() }
- /// Update an optional value by optionally running its content through a
- /// function that returns an option.
+ /// Returns `None` if the option is `None`, otherwise returns `optb`.
#[inline]
- pub fn chain<U>(self, f: &fn(t: T) -> Option<U>) -> Option<U> {
+ pub fn and(self, optb: Option<T>) -> Option<T> {
match self {
- Some(t) => f(t),
- None => None
+ Some(_) => optb,
+ None => None,
}
}
- /// Returns the leftmost Some() value, or None if both are None.
+ /// Returns `None` if the option is `None`, otherwise calls `f` with the
+ /// wrapped value and returns the result.
#[inline]
- pub fn or(self, optb: Option<T>) -> Option<T> {
+ pub fn and_then<U>(self, f: &fn(T) -> Option<U>) -> Option<U> {
match self {
- Some(opta) => Some(opta),
- _ => optb
+ Some(x) => f(x),
+ None => None,
}
}
- /// Update an optional value by optionally running its content by reference
- /// through a function that returns an option.
+ /// Returns `None` if the option is `None`, otherwise calls `f` with a
+ /// reference to the wrapped value and returns the result.
#[inline]
- pub fn chain_ref<'a, U>(&'a self, f: &fn(x: &'a T) -> Option<U>) -> Option<U> {
+ pub fn and_then_ref<'a, U>(&'a self, f: &fn(&'a T) -> Option<U>) -> Option<U> {
match *self {
Some(ref x) => f(x),
None => None
}
}
- /// Update an optional value by optionally running its content by mut reference
- /// through a function that returns an option.
+ /// Returns `None` if the option is `None`, otherwise calls `f` with a
+ /// mutable reference to the wrapped value and returns the result.
#[inline]
- pub fn chain_mut_ref<'a, U>(&'a mut self, f: &fn(x: &'a mut T) -> Option<U>) -> Option<U> {
+ pub fn and_then_mut_ref<'a, U>(&'a mut self, f: &fn(&'a mut T) -> Option<U>) -> Option<U> {
match *self {
Some(ref mut x) => f(x),
None => None
}
}
+ /// Returns the option if it contains a value, otherwise returns `optb`.
+ #[inline]
+ pub fn or(self, optb: Option<T>) -> Option<T> {
+ match self {
+ Some(_) => self,
+ None => optb
+ }
+ }
+
+ /// Returns the option if it contains a value, otherwise calls `f` and
+ /// returns the result.
+ #[inline]
+ pub fn or_else(self, f: &fn() -> Option<T>) -> Option<T> {
+ match self {
+ Some(_) => self,
+ None => f(),
+ }
+ }
+
/// Filters an optional value using given function.
#[inline(always)]
pub fn filtered(self, f: &fn(t: &T) -> bool) -> Option<T> {
/// Returns the contained value or a default
#[inline]
- pub fn unwrap_or_default(self, def: T) -> T {
+ pub fn unwrap_or(self, def: T) -> T {
match self {
Some(x) => x,
None => def
}
}
+ /// Returns the contained value or computes it from a closure
+ #[inline]
+ pub fn unwrap_or_else(self, f: &fn() -> T) -> T {
+ match self {
+ Some(x) => x,
+ None => f()
+ }
+ }
+
/// Applies a function zero or more times until the result is `None`.
#[inline]
pub fn while_some(self, blk: &fn(v: T) -> Option<T>) {
}
}
+/// A generic trait for converting a value to a `Option`
+pub trait ToOption<T> {
+ /// Convert to the `option` type
+ fn to_option(&self) -> Option<T>;
+}
+
+/// A generic trait for converting a value to a `Option`
+pub trait IntoOption<T> {
+ /// Convert to the `option` type
+ fn into_option(self) -> Option<T>;
+}
+
+/// A generic trait for converting a value to a `Option`
+pub trait AsOption<T> {
+ /// Convert to the `option` type
+ fn as_option<'a>(&'a self) -> Option<&'a T>;
+}
+
+impl<T: Clone> ToOption<T> for Option<T> {
+ #[inline]
+ fn to_option(&self) -> Option<T> { self.clone() }
+}
+
+impl<T> IntoOption<T> for Option<T> {
+ #[inline]
+ fn into_option(self) -> Option<T> { self }
+}
+
+impl<T> AsOption<T> for Option<T> {
+ #[inline]
+ fn as_option<'a>(&'a self) -> Option<&'a T> {
+ match *self {
+ Some(ref x) => Some(x),
+ None => None,
+ }
+ }
+}
+
+impl<T: Clone> result::ToResult<T, ()> for Option<T> {
+ #[inline]
+ fn to_result(&self) -> result::Result<T, ()> {
+ match *self {
+ Some(ref x) => result::Ok(x.clone()),
+ None => result::Err(()),
+ }
+ }
+}
+
+impl<T> result::IntoResult<T, ()> for Option<T> {
+ #[inline]
+ fn into_result(self) -> result::Result<T, ()> {
+ match self {
+ Some(x) => result::Ok(x),
+ None => result::Err(()),
+ }
+ }
+}
+
+impl<T: Clone> either::ToEither<(), T> for Option<T> {
+ #[inline]
+ fn to_either(&self) -> either::Either<(), T> {
+ match *self {
+ Some(ref x) => either::Right(x.clone()),
+ None => either::Left(()),
+ }
+ }
+}
+
+impl<T> either::IntoEither<(), T> for Option<T> {
+ #[inline]
+ fn into_either(self) -> either::Either<(), T> {
+ match self {
+ Some(x) => either::Right(x),
+ None => either::Left(()),
+ }
+ }
+}
+
+impl<T: Default> Option<T> {
+ /// Returns the contained value or default (for this type)
+ #[inline]
+ pub fn unwrap_or_default(self) -> T {
+ match self {
+ Some(x) => x,
+ None => Default::default()
+ }
+ }
+
+ /// Returns self or `Some`-wrapped default value
+ #[inline]
+ pub fn or_default(self) -> Option<T> {
+ match self {
+ None => Some(Default::default()),
+ x => x,
+ }
+ }
+}
+
+impl<T> Default for Option<T> {
+ #[inline]
+ fn default() -> Option<T> { None }
+}
+
impl<T:Zero> Option<T> {
/// Returns the contained value or zero (for this type)
#[inline]
}
}
-impl<T> Zero for Option<T> {
- fn zero() -> Option<T> { None }
- fn is_zero(&self) -> bool { self.is_none() }
-}
-
/// An iterator that yields either one or zero elements
#[deriving(Clone, DeepClone)]
pub struct OptionIterator<A> {
#[cfg(test)]
mod tests {
use super::*;
+
+ use either::{IntoEither, ToEither};
+ use either;
+ use result::{IntoResult, ToResult};
+ use result;
use util;
#[test]
let _y3 = y.take_unwrap();
}
+ #[test]
+ fn test_and() {
+ let x: Option<int> = Some(1);
+ assert_eq!(x.and(Some(2)), Some(2));
+ assert_eq!(x.and(None), None);
+
+ let x: Option<int> = None;
+ assert_eq!(x.and(Some(2)), None);
+ assert_eq!(x.and(None), None);
+ }
+
+ #[test]
+ fn test_and_then() {
+ let x: Option<int> = Some(1);
+ assert_eq!(x.and_then(|x| Some(x + 1)), Some(2));
+ assert_eq!(x.and_then(|_| None::<int>), None);
+
+ let x: Option<int> = None;
+ assert_eq!(x.and_then(|x| Some(x + 1)), None);
+ assert_eq!(x.and_then(|_| None::<int>), None);
+ }
+
+ #[test]
+ fn test_or() {
+ let x: Option<int> = Some(1);
+ assert_eq!(x.or(Some(2)), Some(1));
+ assert_eq!(x.or(None), Some(1));
+
+ let x: Option<int> = None;
+ assert_eq!(x.or(Some(2)), Some(2));
+ assert_eq!(x.or(None), None);
+ }
+
+ #[test]
+ fn test_or_else() {
+ let x: Option<int> = Some(1);
+ assert_eq!(x.or_else(|| Some(2)), Some(1));
+ assert_eq!(x.or_else(|| None), Some(1));
+
+ let x: Option<int> = None;
+ assert_eq!(x.or_else(|| Some(2)), Some(2));
+ assert_eq!(x.or_else(|| None), None);
+ }
+
#[test]
fn test_option_while_some() {
let mut i = 0;
assert_eq!(i, 11);
}
+ #[test]
+ fn test_unwrap() {
+ assert_eq!(Some(1).unwrap(), 1);
+ assert_eq!(Some(~"hello").unwrap(), ~"hello");
+ }
+
+ #[test]
+ #[should_fail]
+ fn test_unwrap_fail1() {
+ let x: Option<int> = None;
+ x.unwrap();
+ }
+
+ #[test]
+ #[should_fail]
+ fn test_unwrap_fail2() {
+ let x: Option<~str> = None;
+ x.unwrap();
+ }
+
+ #[test]
+ fn test_unwrap_or() {
+ let x: Option<int> = Some(1);
+ assert_eq!(x.unwrap_or(2), 1);
+
+ let x: Option<int> = None;
+ assert_eq!(x.unwrap_or(2), 2);
+ }
+
+ #[test]
+ fn test_unwrap_or_else() {
+ let x: Option<int> = Some(1);
+ assert_eq!(x.unwrap_or_else(|| 2), 1);
+
+ let x: Option<int> = None;
+ assert_eq!(x.unwrap_or_else(|| 2), 2);
+ }
+
#[test]
fn test_unwrap_or_zero() {
let some_stuff = Some(42);
assert!(!x.mutate_default(0i, |i| i+1));
assert_eq!(x, Some(0i));
}
+
+ #[test]
+ pub fn test_to_option() {
+ let some: Option<int> = Some(100);
+ let none: Option<int> = None;
+
+ assert_eq!(some.to_option(), Some(100));
+ assert_eq!(none.to_option(), None);
+ }
+
+ #[test]
+ pub fn test_into_option() {
+ let some: Option<int> = Some(100);
+ let none: Option<int> = None;
+
+ assert_eq!(some.into_option(), Some(100));
+ assert_eq!(none.into_option(), None);
+ }
+
+ #[test]
+ pub fn test_as_option() {
+ let some: Option<int> = Some(100);
+ let none: Option<int> = None;
+
+ assert_eq!(some.as_option().unwrap(), &100);
+ assert_eq!(none.as_option(), None);
+ }
+
+ #[test]
+ pub fn test_to_result() {
+ let some: Option<int> = Some(100);
+ let none: Option<int> = None;
+
+ assert_eq!(some.to_result(), result::Ok(100));
+ assert_eq!(none.to_result(), result::Err(()));
+ }
+
+ #[test]
+ pub fn test_into_result() {
+ let some: Option<int> = Some(100);
+ let none: Option<int> = None;
+
+ assert_eq!(some.into_result(), result::Ok(100));
+ assert_eq!(none.into_result(), result::Err(()));
+ }
+
+ #[test]
+ pub fn test_to_either() {
+ let some: Option<int> = Some(100);
+ let none: Option<int> = None;
+
+ assert_eq!(some.to_either(), either::Right(100));
+ assert_eq!(none.to_either(), either::Left(()));
+ }
+
+ #[test]
+ pub fn test_into_either() {
+ let some: Option<int> = Some(100);
+ let none: Option<int> = None;
+
+ assert_eq!(some.into_either(), either::Right(100));
+ assert_eq!(none.into_either(), either::Left(()));
+ }
}
#[cfg(windows)]
fn secondary() -> Option<Path> {
- do getenv("USERPROFILE").chain |p| {
+ do getenv("USERPROFILE").and_then |p| {
if !p.is_empty() {
Some(Path(p))
} else {
if cfg!(target_os = "android") {
Path("/data/tmp")
} else {
- getenv_nonempty("TMPDIR").unwrap_or_default(Path("/tmp"))
+ getenv_nonempty("TMPDIR").unwrap_or(Path("/tmp"))
}
}
getenv_nonempty("TMP").or(
getenv_nonempty("TEMP").or(
getenv_nonempty("USERPROFILE").or(
- getenv_nonempty("WINDIR")))).unwrap_or_default(Path("C:\\Windows"))
+ getenv_nonempty("WINDIR")))).unwrap_or(Path("C:\\Windows"))
}
}
setenv("USERPROFILE", "/home/PaloAlto");
assert_eq!(os::homedir(), Some(Path("/home/MountainView")));
- oldhome.iter().advance(|s| { setenv("HOME", *s); true });
- olduserprofile.iter().advance(|s| { setenv("USERPROFILE", *s); true });
+ for s in oldhome.iter() { setenv("HOME", *s) }
+ for s in olduserprofile.iter() { setenv("USERPROFILE", *s) }
}
#[test]
}
// Equality for pointers
-#[cfg(not(test))]
+#[cfg(stage0, not(test))]
impl<T> Eq for *T {
#[inline]
fn eq(&self, other: &*T) -> bool {
fn ne(&self, other: &*T) -> bool { !self.eq(other) }
}
-#[cfg(not(test))]
+#[cfg(not(stage0), not(test))]
+impl<T> Eq for *T {
+ #[inline]
+ fn eq(&self, other: &*T) -> bool {
+ *self == *other
+ }
+ #[inline]
+ fn ne(&self, other: &*T) -> bool { !self.eq(other) }
+}
+
+#[cfg(stage0, not(test))]
impl<T> Eq for *mut T {
#[inline]
fn eq(&self, other: &*mut T) -> bool {
fn ne(&self, other: &*mut T) -> bool { !self.eq(other) }
}
+#[cfg(not(stage0), not(test))]
+impl<T> Eq for *mut T {
+ #[inline]
+ fn eq(&self, other: &*mut T) -> bool {
+ *self == *other
+ }
+ #[inline]
+ fn ne(&self, other: &*mut T) -> bool { !self.eq(other) }
+}
+
// Equivalence for pointers
#[cfg(not(test))]
impl<T> Equiv<*mut T> for *T {
}
// Comparison for pointers
-#[cfg(not(test))]
+#[cfg(stage0, not(test))]
impl<T> Ord for *T {
#[inline]
fn lt(&self, other: &*T) -> bool {
}
}
-#[cfg(not(test))]
+#[cfg(not(stage0), not(test))]
+impl<T> Ord for *T {
+ #[inline]
+ fn lt(&self, other: &*T) -> bool {
+ *self < *other
+ }
+ #[inline]
+ fn le(&self, other: &*T) -> bool {
+ *self <= *other
+ }
+ #[inline]
+ fn ge(&self, other: &*T) -> bool {
+ *self >= *other
+ }
+ #[inline]
+ fn gt(&self, other: &*T) -> bool {
+ *self > *other
+ }
+}
+
+#[cfg(stage0, not(test))]
impl<T> Ord for *mut T {
#[inline]
fn lt(&self, other: &*mut T) -> bool {
}
}
+#[cfg(not(stage0), not(test))]
+impl<T> Ord for *mut T {
+ #[inline]
+ fn lt(&self, other: &*mut T) -> bool {
+ *self < *other
+ }
+ #[inline]
+ fn le(&self, other: &*mut T) -> bool {
+ *self <= *other
+ }
+ #[inline]
+ fn ge(&self, other: &*mut T) -> bool {
+ *self >= *other
+ }
+ #[inline]
+ fn gt(&self, other: &*mut T) -> bool {
+ *self > *other
+ }
+}
+
#[cfg(test)]
pub mod ptr_tests {
use super::*;
use cmp;
use container::Container;
use int;
-use iter::{Iterator, range};
+use iter::{Iterator, range, range_step};
use local_data;
use num;
use prelude::*;
if use_rsl {
macro_rules! memloop (
($arr:expr) => {{
- do u32::range_step(0, RAND_SIZE, 8) |i| {
+ for i in range_step(0u32, RAND_SIZE, 8) {
a+=$arr[i ]; b+=$arr[i+1];
c+=$arr[i+2]; d+=$arr[i+3];
e+=$arr[i+4]; f+=$arr[i+5];
self.mem[i+2]=c; self.mem[i+3]=d;
self.mem[i+4]=e; self.mem[i+5]=f;
self.mem[i+6]=g; self.mem[i+7]=h;
- true
- };
+ }
}}
);
memloop!(self.rsl);
memloop!(self.mem);
} else {
- do u32::range_step(0, RAND_SIZE, 8) |i| {
+ for i in range_step(0u32, RAND_SIZE, 8) {
mix!();
self.mem[i ]=a; self.mem[i+1]=b;
self.mem[i+2]=c; self.mem[i+3]=d;
self.mem[i+4]=e; self.mem[i+5]=f;
self.mem[i+6]=g; self.mem[i+7]=h;
- true
- };
+ }
}
self.isaac();
});
macro_rules! rngstep(
($j:expr, $shift:expr) => {{
- let base = base + $j;
+ let base = $j;
let mix = if $shift < 0 {
a >> -$shift as uint
} else {
let r = [(0, MIDPOINT), (MIDPOINT, 0)];
for &(mr_offset, m2_offset) in r.iter() {
- do uint::range_step(0, MIDPOINT, 4) |base| {
- rngstep!(0, 13);
- rngstep!(1, -6);
- rngstep!(2, 2);
- rngstep!(3, -16);
- true
- };
+ for i in range_step(0u, MIDPOINT, 4) {
+ rngstep!(i + 0, 13);
+ rngstep!(i + 1, -6);
+ rngstep!(i + 2, 2);
+ rngstep!(i + 3, -16);
+ }
}
self.a = a;
use either;
use iter::Iterator;
use option::{None, Option, Some, OptionIterator};
+use option;
use vec;
use vec::OwnedVector;
use to_str::ToStr;
}
impl<T, E: ToStr> Result<T, E> {
- /// Convert to the `either` type
- ///
- /// `Ok` result variants are converted to `either::Right` variants, `Err`
- /// result variants are converted to `either::Left`.
- #[inline]
- pub fn to_either(self)-> either::Either<E, T>{
- match self {
- Ok(t) => either::Right(t),
- Err(e) => either::Left(e),
- }
- }
-
/// Get a reference to the value out of a successful result
///
/// # Failure
}
}
+ /// Call a method based on a previous result
+ ///
+ /// If `self` is `Ok`, then `res` it is returned. If `self` is `Err`,
+ /// then `self` is returned.
+ #[inline]
+ pub fn and(self, res: Result<T, E>) -> Result<T, E> {
+ match self {
+ Ok(_) => res,
+ Err(_) => self,
+ }
+ }
+
/// Call a method based on a previous result
///
/// If `self` is `Ok` then the value is extracted and passed to `op`
- /// whereupon `op`s result is returned. if `self` is `Err` then it is
+ /// whereupon `op`s result is returned. If `self` is `Err` then it is
/// immediately returned. This function can be used to compose the results
/// of two functions.
///
/// Ok(parse_bytes(buf))
/// };
#[inline]
- pub fn chain<U>(self, op: &fn(T) -> Result<U, E>) -> Result<U, E> {
+ pub fn and_then<U>(self, op: &fn(T) -> Result<U, E>) -> Result<U, E> {
match self {
Ok(t) => op(t),
Err(e) => Err(e),
}
}
+ /// Call a method based on a previous result
+ ///
+ /// If `self` is `Ok`, then `self` is returned. If `self` is `Err`
+ /// then `res` is returned.
+ #[inline]
+ pub fn or(self, res: Result<T, E>) -> Result<T, E> {
+ match self {
+ Ok(_) => self,
+ Err(_) => res,
+ }
+ }
+
/// Call a function based on a previous result
///
/// If `self` is `Err` then the value is extracted and passed to `op`
/// immediately returned. This function can be used to pass through a
/// successful result while handling an error.
#[inline]
- pub fn chain_err<F>(self, op: &fn(E) -> Result<T, F>) -> Result<T, F> {
+ pub fn or_else<F>(self, op: &fn(E) -> Result<T, F>) -> Result<T, F> {
match self {
Ok(t) => Ok(t),
Err(e) => op(e),
}
}
+/// A generic trait for converting a value to a `Result`
+pub trait ToResult<T, E> {
+ /// Convert to the `result` type
+ fn to_result(&self) -> Result<T, E>;
+}
+
+/// A generic trait for converting a value to a `Result`
+pub trait IntoResult<T, E> {
+ /// Convert to the `result` type
+ fn into_result(self) -> Result<T, E>;
+}
+
+/// A generic trait for converting a value to a `Result`
+pub trait AsResult<T, E> {
+ /// Convert to the `result` type
+ fn as_result<'a>(&'a self) -> Result<&'a T, &'a E>;
+}
+
+impl<T: Clone, E> option::ToOption<T> for Result<T, E> {
+ #[inline]
+ fn to_option(&self)-> Option<T> {
+ match *self {
+ Ok(ref t) => Some(t.clone()),
+ Err(_) => None,
+ }
+ }
+}
+
+impl<T, E> option::IntoOption<T> for Result<T, E> {
+ #[inline]
+ fn into_option(self)-> Option<T> {
+ match self {
+ Ok(t) => Some(t),
+ Err(_) => None,
+ }
+ }
+}
+
+impl<T, E> option::AsOption<T> for Result<T, E> {
+ #[inline]
+ fn as_option<'a>(&'a self)-> Option<&'a T> {
+ match *self {
+ Ok(ref t) => Some(t),
+ Err(_) => None,
+ }
+ }
+}
+
+impl<T: Clone, E: Clone> ToResult<T, E> for Result<T, E> {
+ #[inline]
+ fn to_result(&self) -> Result<T, E> { self.clone() }
+}
+
+impl<T, E> IntoResult<T, E> for Result<T, E> {
+ #[inline]
+ fn into_result(self) -> Result<T, E> { self }
+}
+
+impl<T, E> AsResult<T, E> for Result<T, E> {
+ #[inline]
+ fn as_result<'a>(&'a self) -> Result<&'a T, &'a E> {
+ match *self {
+ Ok(ref t) => Ok(t),
+ Err(ref e) => Err(e),
+ }
+ }
+}
+
+impl<T: Clone, E: Clone> either::ToEither<E, T> for Result<T, E> {
+ #[inline]
+ fn to_either(&self)-> either::Either<E, T> {
+ match *self {
+ Ok(ref t) => either::Right(t.clone()),
+ Err(ref e) => either::Left(e.clone()),
+ }
+ }
+}
+
+impl<T, E> either::IntoEither<E, T> for Result<T, E> {
+ #[inline]
+ fn into_either(self)-> either::Either<E, T> {
+ match self {
+ Ok(t) => either::Right(t),
+ Err(e) => either::Left(e),
+ }
+ }
+}
+
+impl<T, E> either::AsEither<E, T> for Result<T, E> {
+ #[inline]
+ fn as_either<'a>(&'a self)-> either::Either<&'a E, &'a T> {
+ match *self {
+ Ok(ref t) => either::Right(t),
+ Err(ref e) => either::Left(e),
+ }
+ }
+}
+
#[inline]
#[allow(missing_doc)]
pub fn map_opt<T, U: ToStr, V>(o_t: &Option<T>,
mod tests {
use super::*;
+ use either::{IntoEither, ToEither, AsEither};
use either;
use iter::range;
+ use option::{IntoOption, ToOption, AsOption};
+ use option;
use str::OwnedStr;
use vec::ImmutableVector;
pub fn op1() -> Result<int, ~str> { Ok(666) }
+ pub fn op2() -> Result<int, ~str> { Err(~"sadface") }
+
+ #[test]
+ pub fn test_and() {
+ assert_eq!(op1().and(Ok(667)).unwrap(), 667);
+ assert_eq!(op1().and(Err(~"bad")).unwrap_err(), ~"bad");
- pub fn op2(i: int) -> Result<uint, ~str> {
- Ok(i as uint + 1u)
+ assert_eq!(op2().and(Ok(667)).unwrap_err(), ~"sadface");
+ assert_eq!(op2().and(Err(~"bad")).unwrap_err(), ~"sadface");
}
- pub fn op3() -> Result<int, ~str> { Err(~"sadface") }
+ #[test]
+ pub fn test_and_then() {
+ assert_eq!(op1().and_then(|i| Ok::<int, ~str>(i + 1)).unwrap(), 667);
+ assert_eq!(op1().and_then(|_| Err::<int, ~str>(~"bad")).unwrap_err(), ~"bad");
+
+ assert_eq!(op2().and_then(|i| Ok::<int, ~str>(i + 1)).unwrap_err(), ~"sadface");
+ assert_eq!(op2().and_then(|_| Err::<int, ~str>(~"bad")).unwrap_err(), ~"sadface");
+ }
#[test]
- pub fn chain_success() {
- assert_eq!(op1().chain(op2).unwrap(), 667u);
+ pub fn test_or() {
+ assert_eq!(op1().or(Ok(667)).unwrap(), 666);
+ assert_eq!(op1().or(Err(~"bad")).unwrap(), 666);
+
+ assert_eq!(op2().or(Ok(667)).unwrap(), 667);
+ assert_eq!(op2().or(Err(~"bad")).unwrap_err(), ~"bad");
}
#[test]
- pub fn chain_failure() {
- assert_eq!(op3().chain( op2).unwrap_err(), ~"sadface");
+ pub fn test_or_else() {
+ assert_eq!(op1().or_else(|_| Ok::<int, ~str>(667)).unwrap(), 666);
+ assert_eq!(op1().or_else(|e| Err::<int, ~str>(e + "!")).unwrap(), 666);
+
+ assert_eq!(op2().or_else(|_| Ok::<int, ~str>(667)).unwrap(), 667);
+ assert_eq!(op2().or_else(|e| Err::<int, ~str>(e + "!")).unwrap_err(), ~"sadface!");
}
#[test]
assert_eq!(*foo.get_ref(), 100);
}
- #[test]
- pub fn test_to_either() {
- let r: Result<int, ()> = Ok(100);
- let err: Result<(), int> = Err(404);
-
- assert_eq!(r.to_either(), either::Right(100));
- assert_eq!(err.to_either(), either::Left(404));
- }
-
#[test]
fn test_collect() {
assert_eq!(collect(range(0, 0)
.map(|f| (*f)())),
Err(1));
}
+
+ #[test]
+ pub fn test_to_option() {
+ let ok: Result<int, int> = Ok(100);
+ let err: Result<int, int> = Err(404);
+
+ assert_eq!(ok.to_option(), option::Some(100));
+ assert_eq!(err.to_option(), option::None);
+ }
+
+ #[test]
+ pub fn test_into_option() {
+ let ok: Result<int, int> = Ok(100);
+ let err: Result<int, int> = Err(404);
+
+ assert_eq!(ok.into_option(), option::Some(100));
+ assert_eq!(err.into_option(), option::None);
+ }
+
+ #[test]
+ pub fn test_as_option() {
+ let ok: Result<int, int> = Ok(100);
+ let err: Result<int, int> = Err(404);
+
+ assert_eq!(ok.as_option().unwrap(), &100);
+ assert_eq!(err.as_option(), option::None);
+ }
+
+ #[test]
+ pub fn test_to_result() {
+ let ok: Result<int, int> = Ok(100);
+ let err: Result<int, int> = Err(404);
+
+ assert_eq!(ok.to_result(), Ok(100));
+ assert_eq!(err.to_result(), Err(404));
+ }
+
+ #[test]
+ pub fn test_into_result() {
+ let ok: Result<int, int> = Ok(100);
+ let err: Result<int, int> = Err(404);
+
+ assert_eq!(ok.into_result(), Ok(100));
+ assert_eq!(err.into_result(), Err(404));
+ }
+
+ #[test]
+ pub fn test_as_result() {
+ let ok: Result<int, int> = Ok(100);
+ let err: Result<int, int> = Err(404);
+
+ let x = 100;
+ assert_eq!(ok.as_result(), Ok(&x));
+
+ let x = 404;
+ assert_eq!(err.as_result(), Err(&x));
+ }
+
+ #[test]
+ pub fn test_to_either() {
+ let ok: Result<int, int> = Ok(100);
+ let err: Result<int, int> = Err(404);
+
+ assert_eq!(ok.to_either(), either::Right(100));
+ assert_eq!(err.to_either(), either::Left(404));
+ }
+
+ #[test]
+ pub fn test_into_either() {
+ let ok: Result<int, int> = Ok(100);
+ let err: Result<int, int> = Err(404);
+
+ assert_eq!(ok.into_either(), either::Right(100));
+ assert_eq!(err.into_either(), either::Left(404));
+ }
+
+ #[test]
+ pub fn test_as_either() {
+ let ok: Result<int, int> = Ok(100);
+ let err: Result<int, int> = Err(404);
+
+ assert_eq!(ok.as_either().unwrap_right(), &100);
+ assert_eq!(err.as_either().unwrap_left(), &404);
+ }
}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+
+use libc::{c_void, c_char};
+use ptr;
+use ptr::RawPtr;
+use vec;
+use hashmap::HashSet;
+use container::MutableSet;
+
+pub struct ModEntry{
+ name: *c_char,
+ log_level: *mut u32
+}
+struct CrateMapV0 {
+ entries: *ModEntry,
+ children: [*CrateMap, ..1]
+}
+
+struct CrateMap {
+ version: i32,
+ annihilate_fn: *c_void,
+ entries: *ModEntry,
+ /// a dynamically sized struct, where all pointers to children are listed adjacent
+ /// to the struct, terminated with NULL
+ children: [*CrateMap, ..1]
+}
+
+unsafe fn version(crate_map: *CrateMap) -> i32 {
+ match (*crate_map).version {
+ 1 => return 1,
+ _ => return 0
+ }
+}
+
+/// Returns a pointer to the annihilate function of the CrateMap
+pub unsafe fn annihilate_fn(crate_map: *CrateMap) -> *c_void {
+ match version(crate_map) {
+ 0 => return ptr::null(),
+ 1 => return (*crate_map).annihilate_fn,
+ _ => fail!("Unknown crate map version!")
+ }
+}
+
+unsafe fn entries(crate_map: *CrateMap) -> *ModEntry {
+ match version(crate_map) {
+ 0 => {
+ let v0 = crate_map as (*CrateMapV0);
+ return (*v0).entries;
+ }
+ 1 => return (*crate_map).entries,
+ _ => fail!("Unknown crate map version!")
+ }
+}
+
+unsafe fn iterator(crate_map: *CrateMap) -> **CrateMap {
+ match version(crate_map) {
+ 0 => {
+ let v0 = crate_map as (*CrateMapV0);
+ return vec::raw::to_ptr((*v0).children);
+ }
+ 1 => return vec::raw::to_ptr((*crate_map).children),
+ _ => fail!("Unknown crate map version!")
+ }
+}
+
+unsafe fn iter_module_map(mod_entries: *ModEntry, f: &fn(*mut ModEntry)) {
+ let mut curr = mod_entries;
+
+ while !(*curr).name.is_null() {
+ f(curr as *mut ModEntry);
+ curr = curr.offset(1);
+ }
+}
+
+unsafe fn do_iter_crate_map(crate_map: *CrateMap, f: &fn(*mut ModEntry),
+ visited: &mut HashSet<*CrateMap>) {
+ if visited.insert(crate_map) {
+ iter_module_map(entries(crate_map), |x| f(x));
+ let child_crates = iterator(crate_map);
+ do ptr::array_each(child_crates) |child| {
+ do_iter_crate_map(child, |x| f(x), visited);
+ }
+ }
+}
+
+/// Iterates recursively over `crate_map` and all child crate maps
+pub unsafe fn iter_crate_map(crate_map: *CrateMap, f: &fn(*mut ModEntry)) {
+ // XXX: use random numbers as keys from the OS-level RNG when there is a nice
+ // way to do this
+ let mut v: HashSet<*CrateMap> = HashSet::with_capacity_and_keys(0, 0, 32);
+ do_iter_crate_map(crate_map, f, &mut v);
+}
+
+#[test]
+fn iter_crate_map_duplicates() {
+ use c_str::ToCStr;
+ use cast::transmute;
+
+ struct CrateMapT3 {
+ version: i32,
+ annihilate_fn: *c_void,
+ entries: *ModEntry,
+ children: [*CrateMap, ..3]
+ }
+
+ unsafe {
+ let mod_name1 = "c::m1".to_c_str();
+ let mut level3: u32 = 3;
+
+ let entries: ~[ModEntry] = ~[
+ ModEntry { name: mod_name1.with_ref(|buf| buf), log_level: &mut level3},
+ ModEntry { name: ptr::null(), log_level: ptr::mut_null()}
+ ];
+ let child_crate = CrateMap {
+ version: 1,
+ annihilate_fn: ptr::null(),
+ entries: vec::raw::to_ptr(entries),
+ children: [ptr::null()]
+ };
+
+ let root_crate = CrateMapT3 {
+ version: 1, annihilate_fn: ptr::null(),
+ entries: vec::raw::to_ptr([ModEntry { name: ptr::null(), log_level: ptr::mut_null()}]),
+ children: [&child_crate as *CrateMap, &child_crate as *CrateMap, ptr::null()]
+ };
+
+ let mut cnt = 0;
+ do iter_crate_map(transmute(&root_crate)) |entry| {
+ assert!(*(*entry).log_level == 3);
+ cnt += 1;
+ }
+ assert!(cnt == 1);
+ }
+}
+
+#[test]
+fn iter_crate_map_follow_children() {
+ use c_str::ToCStr;
+ use cast::transmute;
+
+ struct CrateMapT2 {
+ version: i32,
+ annihilate_fn: *c_void,
+ entries: *ModEntry,
+ children: [*CrateMap, ..2]
+ }
+
+ unsafe {
+ let mod_name1 = "c::m1".to_c_str();
+ let mod_name2 = "c::m2".to_c_str();
+ let mut level2: u32 = 2;
+ let mut level3: u32 = 3;
+ let child_crate2 = CrateMap {
+ version: 1,
+ annihilate_fn: ptr::null(),
+ entries: vec::raw::to_ptr([
+ ModEntry { name: mod_name1.with_ref(|buf| buf), log_level: &mut level2},
+ ModEntry { name: mod_name2.with_ref(|buf| buf), log_level: &mut level3},
+ ModEntry { name: ptr::null(), log_level: ptr::mut_null()}
+ ]),
+ children: [ptr::null()]
+ };
+
+ let child_crate1 = CrateMapT2 {
+ version: 1,
+ annihilate_fn: ptr::null(),
+ entries: vec::raw::to_ptr([
+ ModEntry { name: "t::f1".to_c_str().with_ref(|buf| buf), log_level: &mut 1},
+ ModEntry { name: ptr::null(), log_level: ptr::mut_null()}
+ ]),
+ children: [&child_crate2 as *CrateMap, ptr::null()]
+ };
+
+ let child_crate1_ptr: *CrateMap = transmute(&child_crate1);
+ let root_crate = CrateMapT2 {
+ version: 1, annihilate_fn: ptr::null(),
+ entries: vec::raw::to_ptr([
+ ModEntry { name: "t::f1".to_c_str().with_ref(|buf| buf), log_level: &mut 0},
+ ModEntry { name: ptr::null(), log_level: ptr::mut_null()}
+ ]),
+ children: [child_crate1_ptr, ptr::null()]
+ };
+
+ let mut cnt = 0;
+ do iter_crate_map(transmute(&root_crate)) |entry| {
+ assert!(*(*entry).log_level == cnt);
+ cnt += 1;
+ }
+ assert!(cnt == 4);
+ }
+}
}
}
-struct InternalBufferedWriter<W>(BufferedWriter<W>);
+// FIXME #9155 this should be a newtype struct
+struct InternalBufferedWriter<W> {
+ inner: BufferedWriter<W>
+}
impl<W: Reader> Reader for InternalBufferedWriter<W> {
fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
- self.inner.read(buf)
+ self.inner.inner.read(buf)
}
fn eof(&mut self) -> bool {
- self.inner.eof()
+ self.inner.inner.eof()
}
}
/// Wraps a Stream and buffers input and output to and from it
///
/// NOTE: `BufferedStream` will NOT flush its output buffer when dropped.
-pub struct BufferedStream<S>(BufferedReader<InternalBufferedWriter<S>>);
+// FIXME #9155 this should be a newtype struct
+pub struct BufferedStream<S> {
+ priv inner: BufferedReader<InternalBufferedWriter<S>>
+}
impl<S: Stream> BufferedStream<S> {
pub fn with_capacities(reader_cap: uint, writer_cap: uint, inner: S)
-> BufferedStream<S> {
let writer = BufferedWriter::with_capacity(writer_cap, inner);
- let internal_writer = InternalBufferedWriter(writer);
+ let internal_writer = InternalBufferedWriter { inner: writer };
let reader = BufferedReader::with_capacity(reader_cap,
internal_writer);
- BufferedStream(reader)
+ BufferedStream { inner: reader }
}
pub fn new(inner: S) -> BufferedStream<S> {
impl<S: Stream> Reader for BufferedStream<S> {
fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
- (**self).read(buf)
+ self.inner.read(buf)
}
fn eof(&mut self) -> bool {
- (**self).eof()
+ self.inner.eof()
}
}
impl<S: Stream> Writer for BufferedStream<S> {
fn write(&mut self, buf: &[u8]) {
- self.inner.write(buf)
+ self.inner.inner.inner.write(buf)
}
fn flush(&mut self) {
- self.inner.flush()
+ self.inner.inner.inner.flush()
}
}
impl<S: Stream> Decorator<S> for BufferedStream<S> {
fn inner(self) -> S {
- self.inner.inner()
+ self.inner.inner.inner.inner()
}
fn inner_ref<'a>(&'a self) -> &'a S {
- self.inner.inner_ref()
+ self.inner.inner.inner.inner_ref()
}
fn inner_mut_ref<'a>(&'a mut self) -> &'a mut S {
- self.inner.inner_mut_ref()
+ self.inner.inner.inner.inner_mut_ref()
}
}
}
fn file_test_smoke_test_impl() {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
let message = "it's alright. have a good time";
let filename = &Path("./tmp/file_rt_io_file_test.txt");
{
}
fn file_test_invalid_path_opened_without_create_should_raise_condition_impl() {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
let filename = &Path("./tmp/file_that_does_not_exist.txt");
let mut called = false;
do io_error::cond.trap(|_| {
}
fn file_test_unlinking_invalid_path_should_raise_condition_impl() {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
let filename = &Path("./tmp/file_another_file_that_does_not_exist.txt");
let mut called = false;
do io_error::cond.trap(|_| {
}
fn file_test_io_non_positional_read_impl() {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
use str;
let message = "ten-four";
let mut read_mem = [0, .. 8];
}
fn file_test_io_seeking_impl() {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
use str;
let message = "ten-four";
let mut read_mem = [0, .. 4];
fn file_test_io_seek_and_write_impl() {
use io;
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
use str;
let initial_msg = "food-is-yummy";
let overwrite_msg = "-the-bar!!";
}
fn file_test_io_seek_shakedown_impl() {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
use str; // 01234567890123
let initial_msg = "qwer-asdf-zxcv";
let chunk_one = "qwer";
fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() }
}
+///Calls a function with a MemWriter and returns
+///the writer's stored vector.
+pub fn with_mem_writer(writeFn:&fn(&mut MemWriter)) -> ~[u8] {
+ let mut writer = MemWriter::new();
+ writeFn(&mut writer);
+ writer.inner()
+}
+
#[cfg(test)]
mod test {
use prelude::*;
assert_eq!(reader.read(buf), None);
assert!(reader.eof());
}
+
+ #[test]
+ fn test_with_mem_writer() {
+ let buf = with_mem_writer(|wr| wr.write([1,2,3,4,5,6,7]));
+ assert_eq!(buf, ~[1,2,3,4,5,6,7]);
+ }
}
}
do self.read_atomically |p| {
- p.read_char().chain(|c| parse_digit(c, radix))
+ p.read_char().and_then(|c| parse_digit(c, radix))
}
}
}
}
- fn flush(&mut self) { fail!() }
+ fn flush(&mut self) { /* no-op */ }
}
pub struct TcpListener(~RtioTcpListenerObject);
use rt::io::net::ip::{Ipv4Addr, SocketAddr};
use rt::io::*;
use prelude::*;
+ use rt::comm::oneshot;
#[test] #[ignore]
fn bind_error() {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
let mut called = false;
do io_error::cond.trap(|e| {
assert!(e.kind == PermissionDenied);
#[test]
#[ignore(cfg(windows))] // FIXME #8811
fn connect_error() {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
let mut called = false;
do io_error::cond.trap(|e| {
assert_eq!(e.kind, ConnectionRefused);
#[test]
fn smoke_test_ip4() {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
let addr = next_test_ip4();
+ let (port, chan) = oneshot();
+ let port = Cell::new(port);
+ let chan = Cell::new(chan);
do spawntask {
let mut acceptor = TcpListener::bind(addr).listen();
+ chan.take().send(());
let mut stream = acceptor.accept();
let mut buf = [0];
stream.read(buf);
}
do spawntask {
+ port.take().recv();
let mut stream = TcpStream::connect(addr);
stream.write([99]);
}
#[test]
fn smoke_test_ip6() {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
let addr = next_test_ip6();
+ let (port, chan) = oneshot();
+ let port = Cell::new(port);
+ let chan = Cell::new(chan);
do spawntask {
let mut acceptor = TcpListener::bind(addr).listen();
+ chan.take().send(());
let mut stream = acceptor.accept();
let mut buf = [0];
stream.read(buf);
}
do spawntask {
+ port.take().recv();
let mut stream = TcpStream::connect(addr);
stream.write([99]);
}
#[test]
fn read_eof_ip4() {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
let addr = next_test_ip4();
+ let (port, chan) = oneshot();
+ let port = Cell::new(port);
+ let chan = Cell::new(chan);
do spawntask {
let mut acceptor = TcpListener::bind(addr).listen();
+ chan.take().send(());
let mut stream = acceptor.accept();
let mut buf = [0];
let nread = stream.read(buf);
}
do spawntask {
+ port.take().recv();
let _stream = TcpStream::connect(addr);
// Close
}
#[test]
fn read_eof_ip6() {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
let addr = next_test_ip6();
+ let (port, chan) = oneshot();
+ let port = Cell::new(port);
+ let chan = Cell::new(chan);
do spawntask {
let mut acceptor = TcpListener::bind(addr).listen();
+ chan.take().send(());
let mut stream = acceptor.accept();
let mut buf = [0];
let nread = stream.read(buf);
}
do spawntask {
+ port.take().recv();
let _stream = TcpStream::connect(addr);
// Close
}
#[test]
#[ignore(cfg(windows))] // FIXME #8811
fn read_eof_twice_ip4() {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
let addr = next_test_ip4();
+ let (port, chan) = oneshot();
+ let port = Cell::new(port);
+ let chan = Cell::new(chan);
do spawntask {
let mut acceptor = TcpListener::bind(addr).listen();
+ chan.take().send(());
let mut stream = acceptor.accept();
let mut buf = [0];
let nread = stream.read(buf);
}
do spawntask {
+ port.take().recv();
let _stream = TcpStream::connect(addr);
// Close
}
#[test]
#[ignore(cfg(windows))] // FIXME #8811
fn read_eof_twice_ip6() {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
let addr = next_test_ip6();
+ let (port, chan) = oneshot();
+ let port = Cell::new(port);
+ let chan = Cell::new(chan);
do spawntask {
let mut acceptor = TcpListener::bind(addr).listen();
+ chan.take().send(());
let mut stream = acceptor.accept();
let mut buf = [0];
let nread = stream.read(buf);
}
do spawntask {
+ port.take().recv();
let _stream = TcpStream::connect(addr);
// Close
}
#[test]
#[ignore(cfg(windows))] // FIXME #8811
fn write_close_ip4() {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
let addr = next_test_ip4();
+ let (port, chan) = oneshot();
+ let port = Cell::new(port);
+ let chan = Cell::new(chan);
do spawntask {
let mut acceptor = TcpListener::bind(addr).listen();
+ chan.take().send(());
let mut stream = acceptor.accept();
let buf = [0];
loop {
}
do spawntask {
+ port.take().recv();
let _stream = TcpStream::connect(addr);
// Close
}
#[test]
#[ignore(cfg(windows))] // FIXME #8811
fn write_close_ip6() {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
let addr = next_test_ip6();
+ let (port, chan) = oneshot();
+ let port = Cell::new(port);
+ let chan = Cell::new(chan);
do spawntask {
let mut acceptor = TcpListener::bind(addr).listen();
+ chan.take().send(());
let mut stream = acceptor.accept();
let buf = [0];
loop {
}
do spawntask {
+ port.take().recv();
let _stream = TcpStream::connect(addr);
// Close
}
#[test]
fn multiple_connect_serial_ip4() {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
let addr = next_test_ip4();
let max = 10;
+ let (port, chan) = oneshot();
+ let port = Cell::new(port);
+ let chan = Cell::new(chan);
do spawntask {
let mut acceptor = TcpListener::bind(addr).listen();
+ chan.take().send(());
for ref mut stream in acceptor.incoming().take(max) {
let mut buf = [0];
stream.read(buf);
}
do spawntask {
+ port.take().recv();
do max.times {
let mut stream = TcpStream::connect(addr);
stream.write([99]);
#[test]
fn multiple_connect_serial_ip6() {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
let addr = next_test_ip6();
let max = 10;
+ let (port, chan) = oneshot();
+ let port = Cell::new(port);
+ let chan = Cell::new(chan);
do spawntask {
let mut acceptor = TcpListener::bind(addr).listen();
+ chan.take().send(());
for ref mut stream in acceptor.incoming().take(max) {
let mut buf = [0];
stream.read(buf);
}
do spawntask {
+ port.take().recv();
do max.times {
let mut stream = TcpStream::connect(addr);
stream.write([99]);
#[test]
fn multiple_connect_interleaved_greedy_schedule_ip4() {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
let addr = next_test_ip4();
static MAX: int = 10;
+ let (port, chan) = oneshot();
+ let chan = Cell::new(chan);
do spawntask {
let mut acceptor = TcpListener::bind(addr).listen();
+ chan.take().send(());
for (i, stream) in acceptor.incoming().enumerate().take(MAX as uint) {
let stream = Cell::new(stream);
// Start another task to handle the connection
}
}
+ port.recv();
connect(0, addr);
fn connect(i: int, addr: SocketAddr) {
#[test]
fn multiple_connect_interleaved_greedy_schedule_ip6() {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
let addr = next_test_ip6();
static MAX: int = 10;
+ let (port, chan) = oneshot();
+ let chan = Cell::new(chan);
do spawntask {
let mut acceptor = TcpListener::bind(addr).listen();
+ chan.take().send(());
for (i, stream) in acceptor.incoming().enumerate().take(MAX as uint) {
let stream = Cell::new(stream);
// Start another task to handle the connection
}
}
+ port.recv();
connect(0, addr);
fn connect(i: int, addr: SocketAddr) {
#[test]
fn multiple_connect_interleaved_lazy_schedule_ip4() {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
let addr = next_test_ip4();
static MAX: int = 10;
+ let (port, chan) = oneshot();
+ let chan = Cell::new(chan);
do spawntask {
let mut acceptor = TcpListener::bind(addr).listen();
+ chan.take().send(());
for stream in acceptor.incoming().take(MAX as uint) {
let stream = Cell::new(stream);
// Start another task to handle the connection
}
}
+ port.recv();
connect(0, addr);
fn connect(i: int, addr: SocketAddr) {
}
#[test]
fn multiple_connect_interleaved_lazy_schedule_ip6() {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
let addr = next_test_ip6();
static MAX: int = 10;
+ let (port, chan) = oneshot();
+ let chan = Cell::new(chan);
do spawntask {
let mut acceptor = TcpListener::bind(addr).listen();
+ chan.take().send(());
for stream in acceptor.incoming().take(MAX as uint) {
let stream = Cell::new(stream);
// Start another task to handle the connection
}
}
+ port.recv();
connect(0, addr);
fn connect(i: int, addr: SocketAddr) {
#[cfg(test)]
fn socket_name(addr: SocketAddr) {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
do spawntask {
let mut listener = TcpListener::bind(addr).unwrap();
#[cfg(test)]
fn peer_name(addr: SocketAddr) {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
+ let (port, chan) = oneshot();
+ let port = Cell::new(port);
+ let chan = Cell::new(chan);
+
do spawntask {
let mut acceptor = TcpListener::bind(addr).listen();
+ chan.take().send(());
acceptor.accept();
}
do spawntask {
+ port.take().recv();
let stream = TcpStream::connect(addr);
assert!(stream.is_some());
use rt::io::net::ip::{Ipv4Addr, SocketAddr};
use rt::io::*;
use option::{Some, None};
+ use rt::comm::oneshot;
+ use cell::Cell;
#[test] #[ignore]
fn bind_error() {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
let mut called = false;
do io_error::cond.trap(|e| {
assert!(e.kind == PermissionDenied);
#[test]
fn socket_smoke_test_ip4() {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
let server_ip = next_test_ip4();
let client_ip = next_test_ip4();
+ let (port, chan) = oneshot();
+ let port = Cell::new(port);
+ let chan = Cell::new(chan);
do spawntask {
match UdpSocket::bind(server_ip) {
Some(ref mut server) => {
+ chan.take().send(());
let mut buf = [0];
match server.recvfrom(buf) {
Some((nread, src)) => {
do spawntask {
match UdpSocket::bind(client_ip) {
- Some(ref mut client) => client.sendto([99], server_ip),
+ Some(ref mut client) => {
+ port.take().recv();
+ client.sendto([99], server_ip)
+ }
None => fail!()
}
}
#[test]
fn socket_smoke_test_ip6() {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
let server_ip = next_test_ip6();
let client_ip = next_test_ip6();
+ let (port, chan) = oneshot();
+ let port = Cell::new(port);
+ let chan = Cell::new(chan);
do spawntask {
match UdpSocket::bind(server_ip) {
Some(ref mut server) => {
+ chan.take().send(());
let mut buf = [0];
match server.recvfrom(buf) {
Some((nread, src)) => {
do spawntask {
match UdpSocket::bind(client_ip) {
- Some(ref mut client) => client.sendto([99], server_ip),
+ Some(ref mut client) => {
+ port.take().recv();
+ client.sendto([99], server_ip)
+ }
None => fail!()
}
}
#[test]
fn stream_smoke_test_ip4() {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
let server_ip = next_test_ip4();
let client_ip = next_test_ip4();
+ let (port, chan) = oneshot();
+ let port = Cell::new(port);
+ let chan = Cell::new(chan);
do spawntask {
match UdpSocket::bind(server_ip) {
Some(server) => {
let server = ~server;
let mut stream = server.connect(client_ip);
+ chan.take().send(());
let mut buf = [0];
match stream.read(buf) {
Some(nread) => {
Some(client) => {
let client = ~client;
let mut stream = client.connect(server_ip);
+ port.take().recv();
stream.write([99]);
}
None => fail!()
#[test]
fn stream_smoke_test_ip6() {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
let server_ip = next_test_ip6();
let client_ip = next_test_ip6();
+ let (port, chan) = oneshot();
+ let port = Cell::new(port);
+ let chan = Cell::new(chan);
do spawntask {
match UdpSocket::bind(server_ip) {
Some(server) => {
let server = ~server;
let mut stream = server.connect(client_ip);
+ chan.take().send(());
let mut buf = [0];
match stream.read(buf) {
Some(nread) => {
Some(client) => {
let client = ~client;
let mut stream = client.connect(server_ip);
+ port.take().recv();
stream.write([99]);
}
None => fail!()
#[cfg(test)]
fn socket_name(addr: SocketAddr) {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
do spawntask {
let server = UdpSocket::bind(addr);
#[test]
fn test_option_writer() {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
let mut writer: Option<MemWriter> = Some(MemWriter::new());
writer.write([0, 1, 2]);
writer.flush();
#[test]
fn test_option_writer_error() {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
let mut writer: Option<MemWriter> = None;
let mut called = false;
#[test]
fn test_option_reader() {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
let mut reader: Option<MemReader> = Some(MemReader::new(~[0, 1, 2, 3]));
let mut buf = [0, 0];
reader.read(buf);
pub struct Timer(~RtioTimerObject);
+/// Sleep the current task for `msecs` milliseconds.
+pub fn sleep(msecs: u64) {
+ let mut timer = Timer::new().expect("timer::sleep: could not create a Timer");
+
+ timer.sleep(msecs)
+}
+
impl Timer {
pub fn new() -> Option<Timer> {
use rt::test::*;
#[test]
fn test_io_timer_sleep_simple() {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
let timer = Timer::new();
do timer.map_move |mut t| { t.sleep(1) };
}
}
+
+ #[test]
+ fn test_io_timer_sleep_standalone() {
+ do run_in_mt_newsched_task {
+ sleep(1)
+ }
+ }
}
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use cast::transmute;
-use either::*;
-use libc::{c_void, uintptr_t, c_char, exit, STDERR_FILENO};
+use from_str::from_str;
+use libc::{uintptr_t, exit, STDERR_FILENO};
use option::{Some, None, Option};
use rt::util::dumb_println;
+use rt::crate_map::{ModEntry, iter_crate_map};
use str::StrSlice;
use str::raw::from_c_str;
use u32;
-use unstable::raw::Closure;
use vec::ImmutableVector;
-
+use cast::transmute;
struct LogDirective {
name: Option<~str>,
level: u32
}
-// This is the Rust representation of the mod_entry struct in src/rt/rust_crate_map.h
-struct ModEntry{
- name: *c_char,
- log_level: *mut u32
-}
-
static MAX_LOG_LEVEL: u32 = 255;
static DEFAULT_LOG_LEVEL: u32 = 1;
-
-fn iter_crate_map(map: *u8, f: &fn(*mut ModEntry)) {
- unsafe {
- let closure : Closure = transmute(f);
- let code = transmute(closure.code);
- let env = transmute(closure.env);
- rust_iter_crate_map(transmute(map), iter_cb, code, env);
- }
-
- extern fn iter_cb(code: *c_void, env: *c_void, entry: *ModEntry){
- unsafe {
- let closure: Closure = Closure {
- code: transmute(code),
- env: transmute(env),
- };
- let closure: &fn(*ModEntry) = transmute(closure);
- return closure(entry);
- }
- }
- extern {
- #[cfg(not(stage0))]
- #[rust_stack]
- fn rust_iter_crate_map(map: *c_void,
- f: extern "C" fn(*c_void, *c_void, entry: *ModEntry),
- code: *c_void,
- data: *c_void);
-
- #[cfg(stage0)]
- #[rust_stack]
- fn rust_iter_crate_map(map: *c_void,
- f: *u8,
- code: *c_void,
- data: *c_void);
- }
-}
static log_level_names : &'static[&'static str] = &'static["error", "warn", "info", "debug"];
/// Parse an individual log level that is either a number or a symbolic log level
fn parse_log_level(level: &str) -> Option<u32> {
- let num = u32::from_str(level);
+ let num = from_str::<u32>(level);
let mut log_level;
match num {
Some(num) => {
log_level
}
-
/// Parse a logging specification string (e.g: "crate1,crate2::mod3,crate3::x=1")
/// and return a vector with log directives.
/// Valid log levels are 0-255, with the most likely ones being 1-4 (defined in std::).
/// Also supports string log levels of error, warn, info, and debug
-
fn parse_logging_spec(spec: ~str) -> ~[LogDirective]{
let mut dirs = ~[];
for s in spec.split_iter(',') {
if settings.len() > 0 {
if settings == ~"::help" || settings == ~"?" {
dumb_println("\nCrate log map:\n");
- do iter_crate_map(crate_map) |entry: *mut ModEntry| {
- unsafe {
+ unsafe {
+ do iter_crate_map(transmute(crate_map)) |entry: *mut ModEntry| {
dumb_println(" "+from_c_str((*entry).name));
}
- }
- unsafe {
exit(1);
}
}
}
let mut n_matches: u32 = 0;
- do iter_crate_map(crate_map) |entry: *mut ModEntry| {
- let m = update_entry(dirs, entry);
- n_matches += m;
+ unsafe {
+ do iter_crate_map(transmute(crate_map)) |entry: *mut ModEntry| {
+ let m = update_entry(dirs, entry);
+ n_matches += m;
+ }
}
if n_matches < (dirs.len() as u32) {
}
}
+/// Represent a string with `Send` bound.
+pub enum SendableString {
+ OwnedString(~str),
+ StaticString(&'static str)
+}
+
pub trait Logger {
- fn log(&mut self, msg: Either<~str, &'static str>);
+ fn log(&mut self, msg: SendableString);
}
pub struct StdErrLogger;
impl Logger for StdErrLogger {
- fn log(&mut self, msg: Either<~str, &'static str>) {
+ fn log(&mut self, msg: SendableString) {
use io::{Writer, WriterUtil};
if !should_log_console() {
}
let s: &str = match msg {
- Left(ref s) => {
- let s: &str = *s;
- s
- }
- Right(ref s) => {
- let s: &str = *s;
- s
- }
+ OwnedString(ref s) => {
+ let slc: &str = *s;
+ slc
+ },
+ StaticString(s) => s,
};
// Truncate the string
/// The Logger trait and implementations
pub mod logging;
+/// Crate map
+pub mod crate_map;
+
/// Tools for testing the runtime
pub mod test;
// except according to those terms.
use libc;
-use uint;
use option::{Some, None};
use cell::Cell;
use clone::Clone;
/// stress tests. Default 1.
pub fn stress_factor() -> uint {
use os::getenv;
+ use from_str::from_str;
match getenv("RUST_RT_STRESS") {
- Some(val) => uint::from_str(val).unwrap(),
+ Some(val) => from_str::<uint>(val).unwrap(),
None => 1
}
}
#[cfg(test)] use unstable::run_in_bare_thread;
#[cfg(test)] use rt::test::{spawntask,
next_test_ip4,
- run_in_newsched_task};
+ run_in_mt_newsched_task};
#[cfg(test)] use iter::{Iterator, range};
+#[cfg(test)] use rt::comm::oneshot;
// XXX we should not be calling uvll functions in here.
#[test]
fn test_uv_remote() {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
let mut tube = Tube::new();
let tube_clone = tube.clone();
let remote_cell = Cell::new_empty();
impl RtioTcpAcceptor for UvTcpAcceptor {
fn accept(&mut self) -> Result<~RtioTcpStreamObject, IoError> {
- self.incoming.recv()
+ do self.home_for_io |self_| {
+ self_.incoming.recv()
+ }
}
fn accept_simultaneously(&mut self) -> Result<(), IoError> {
#[test]
fn test_simple_io_no_connect() {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
unsafe {
let io: *mut IoFactoryObject = Local::unsafe_borrow();
let addr = next_test_ip4();
#[test]
fn test_simple_udp_io_bind_only() {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
unsafe {
let io: *mut IoFactoryObject = Local::unsafe_borrow();
let addr = next_test_ip4();
#[test]
fn test_simple_tcp_server_and_client() {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
let addr = next_test_ip4();
+ let (port, chan) = oneshot();
+ let port = Cell::new(port);
+ let chan = Cell::new(chan);
// Start the server first so it's listening when we connect
do spawntask {
let io: *mut IoFactoryObject = Local::unsafe_borrow();
let listener = (*io).tcp_bind(addr).unwrap();
let mut acceptor = listener.listen().unwrap();
+ chan.take().send(());
let mut stream = acceptor.accept().unwrap();
let mut buf = [0, .. 2048];
let nread = stream.read(buf).unwrap();
do spawntask {
unsafe {
+ port.take().recv();
let io: *mut IoFactoryObject = Local::unsafe_borrow();
let mut stream = (*io).tcp_connect(addr).unwrap();
stream.write([0, 1, 2, 3, 4, 5, 6, 7]);
#[test]
fn test_simple_udp_server_and_client() {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
let server_addr = next_test_ip4();
let client_addr = next_test_ip4();
+ let (port, chan) = oneshot();
+ let port = Cell::new(port);
+ let chan = Cell::new(chan);
do spawntask {
unsafe {
let io: *mut IoFactoryObject = Local::unsafe_borrow();
let mut server_socket = (*io).udp_bind(server_addr).unwrap();
+ chan.take().send(());
let mut buf = [0, .. 2048];
let (nread,src) = server_socket.recvfrom(buf).unwrap();
assert_eq!(nread, 8);
unsafe {
let io: *mut IoFactoryObject = Local::unsafe_borrow();
let mut client_socket = (*io).udp_bind(client_addr).unwrap();
+ port.take().recv();
client_socket.sendto([0, 1, 2, 3, 4, 5, 6, 7], server_addr);
}
}
#[test] #[ignore(reason = "busted")]
fn test_read_and_block() {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
let addr = next_test_ip4();
+ let (port, chan) = oneshot();
+ let port = Cell::new(port);
+ let chan = Cell::new(chan);
do spawntask {
let io: *mut IoFactoryObject = unsafe { Local::unsafe_borrow() };
let listener = unsafe { (*io).tcp_bind(addr).unwrap() };
let mut acceptor = listener.listen().unwrap();
+ chan.take().send(());
let mut stream = acceptor.accept().unwrap();
let mut buf = [0, .. 2048];
do spawntask {
unsafe {
+ port.take().recv();
let io: *mut IoFactoryObject = Local::unsafe_borrow();
let mut stream = (*io).tcp_connect(addr).unwrap();
stream.write([0, 1, 2, 3, 4, 5, 6, 7]);
#[test]
fn test_read_read_read() {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
let addr = next_test_ip4();
static MAX: uint = 500000;
+ let (port, chan) = oneshot();
+ let port = Cell::new(port);
+ let chan = Cell::new(chan);
do spawntask {
unsafe {
let io: *mut IoFactoryObject = Local::unsafe_borrow();
let listener = (*io).tcp_bind(addr).unwrap();
let mut acceptor = listener.listen().unwrap();
+ chan.take().send(());
let mut stream = acceptor.accept().unwrap();
let buf = [1, .. 2048];
let mut total_bytes_written = 0;
do spawntask {
unsafe {
+ port.take().recv();
let io: *mut IoFactoryObject = Local::unsafe_borrow();
let mut stream = (*io).tcp_connect(addr).unwrap();
let mut buf = [0, .. 2048];
#[test]
#[ignore(cfg(windows))] // FIXME #8816
fn test_udp_twice() {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
let server_addr = next_test_ip4();
let client_addr = next_test_ip4();
+ let (port, chan) = oneshot();
+ let port = Cell::new(port);
+ let chan = Cell::new(chan);
do spawntask {
unsafe {
let io: *mut IoFactoryObject = Local::unsafe_borrow();
let mut client = (*io).udp_bind(client_addr).unwrap();
+ port.take().recv();
assert!(client.sendto([1], server_addr).is_ok());
assert!(client.sendto([2], server_addr).is_ok());
}
unsafe {
let io: *mut IoFactoryObject = Local::unsafe_borrow();
let mut server = (*io).udp_bind(server_addr).unwrap();
+ chan.take().send(());
let mut buf1 = [0];
let mut buf2 = [0];
let (nread1, src1) = server.recvfrom(buf1).unwrap();
#[test]
fn test_udp_many_read() {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
let server_out_addr = next_test_ip4();
let server_in_addr = next_test_ip4();
let client_out_addr = next_test_ip4();
let client_in_addr = next_test_ip4();
static MAX: uint = 500_000;
+ let (p1, c1) = oneshot();
+ let (p2, c2) = oneshot();
+
+ let first = Cell::new((p1, c2));
+ let second = Cell::new((p2, c1));
+
do spawntask {
unsafe {
let io: *mut IoFactoryObject = Local::unsafe_borrow();
let mut server_out = (*io).udp_bind(server_out_addr).unwrap();
let mut server_in = (*io).udp_bind(server_in_addr).unwrap();
+ let (port, chan) = first.take();
+ chan.send(());
+ port.recv();
let msg = [1, .. 2048];
let mut total_bytes_sent = 0;
let mut buf = [1];
let io: *mut IoFactoryObject = Local::unsafe_borrow();
let mut client_out = (*io).udp_bind(client_out_addr).unwrap();
let mut client_in = (*io).udp_bind(client_in_addr).unwrap();
+ let (port, chan) = second.take();
+ port.recv();
+ chan.send(());
let mut total_bytes_recv = 0;
let mut buf = [0, .. 2048];
while total_bytes_recv < MAX {
#[test]
fn test_timer_sleep_simple() {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
unsafe {
let io: *mut IoFactoryObject = Local::unsafe_borrow();
let timer = (*io).timer_init();
#[test]
#[ignore(cfg(windows))] // FIXME #8816
fn file_test_uvio_full_simple() {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
file_test_uvio_full_simple_impl();
}
}
#[test]
fn file_test_uvio_write_to_stdout() {
- do run_in_newsched_task {
+ do run_in_mt_newsched_task {
uvio_naive_print("jubilation\n");
}
}
pub static EPIPE: c_int = -libc::EPIPE;
}
+// see libuv/include/uv-unix.h
+#[cfg(unix)]
pub struct uv_buf_t {
base: *u8,
len: libc::size_t,
}
+// see libuv/include/uv-win.h
+#[cfg(windows)]
+pub struct uv_buf_t {
+ len: u32,
+ base: *u8,
+}
+
pub type uv_handle_t = c_void;
pub type uv_loop_t = c_void;
pub type uv_idle_t = c_void;
// FIXME #4427: Temporary until rt::rt_fail_ goes away
pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! {
- use either::Left;
use option::{Some, None};
use rt::in_green_task_context;
use rt::task::Task;
use rt::local::Local;
- use rt::logging::Logger;
+ use rt::logging::{Logger, OwnedString};
use str::Str;
unsafe {
msg, file, line as int)
};
- task.logger.log(Left(msg));
+ task.logger.log(OwnedString(msg));
}
} else {
rterrln!("failed in non-task context at '%s', %s:%i",
#[test] fn iterbytes_compiles () {
takes_iterbytes((3,4,5,false));
}
- fn takes_iterbytes<T : IterBytes>(x : T) {}
+ fn takes_iterbytes<T : IterBytes>(_x : T) {}
}
mod test_map {
use super::*;
use prelude::*;
+ use iter::range_step;
use uint;
#[test]
#[test]
fn test_step() {
let mut trie = TrieMap::new();
- let n = 300;
+ let n = 300u;
- do uint::range_step(1, n, 2) |x| {
+ for x in range_step(1u, n, 2) {
assert!(trie.insert(x, x + 1));
assert!(trie.contains_key(&x));
check_integrity(&trie.root);
- true
- };
+ }
- do uint::range_step(0, n, 2) |x| {
+ for x in range_step(0u, n, 2) {
assert!(!trie.contains_key(&x));
assert!(trie.insert(x, x + 1));
check_integrity(&trie.root);
- true
- };
+ }
for x in range(0u, n) {
assert!(trie.contains_key(&x));
check_integrity(&trie.root);
}
- do uint::range_step(1, n, 2) |x| {
+ for x in range_step(1u, n, 2) {
assert!(trie.remove(&x));
assert!(!trie.contains_key(&x));
check_integrity(&trie.root);
- true
- };
+ }
- do uint::range_step(0, n, 2) |x| {
+ for x in range_step(0u, n, 2) {
assert!(trie.contains_key(&x));
assert!(!trie.insert(x, x + 1));
check_integrity(&trie.root);
- true
- };
+ }
}
#[test]
let value = 42u;
let mut map : TrieMap<uint> = TrieMap::new();
- do uint::range_step(0u, last, step as int) |x| {
+ for x in range_step(0u, last, step) {
assert!(x % step == 0);
map.insert(x, value);
- true
- };
+ }
for i in range(0u, last - step) {
let mut lb = map.lower_bound_iter(i);
pub mod inner {
use clone::Clone;
#[cfg(not(test))] use cmp::*;
+ #[cfg(not(test))] use default::Default;
#[cfg(not(test))] use num::Zero;
$(
}
}
+ #[cfg(not(test))]
+ impl<$($T:Default),+> Default for ($($T,)+) {
+ #[inline]
+ fn default() -> ($($T,)+) {
+ ($({ let x: $T = Default::default(); x},)+)
+ }
+ }
+
#[cfg(not(test))]
impl<$($T:Zero),+> Zero for ($($T,)+) {
#[inline]
fn equals(&self, _other: &()) -> bool { true }
}
+#[cfg(not(test))]
+impl Default for () {
+ #[inline]
+ fn default() -> () { () }
+}
+
#[cfg(not(test))]
impl Zero for () {
#[inline]
#[inline]
fn is_zero(&self) -> bool { true }
}
-
-#[cfg(not(test))]
-impl Default for () {
- fn default() -> () { () }
-}
use libc;
#[test]
- #[ignore(cfg(windows))] // FIXME #8818
+ // #[ignore(cfg(windows))] // FIXME #8818
+ #[ignore] // FIXME #9137 this library isn't thread-safe
fn test_loading_cosine() {
// The math library does not need to be loaded since it is already
// statically linked in
#[cfg(target_os = "linux")]
#[cfg(target_os = "macos")]
#[cfg(target_os = "freebsd")]
+ #[ignore] // FIXME #9137 this library isn't thread-safe
fn test_errors_do_not_crash() {
// Open /dev/null as a library to get an error, and make sure
// that only causes an error, and not a crash.
}
}
-
-/// Changes the current working directory to the specified
-/// path while acquiring a global lock, then calls `action`.
-/// If the change is successful, releases the lock and restores the
-/// CWD to what it was before, returning true.
-/// Returns false if the directory doesn't exist or if the directory change
-/// is otherwise unsuccessful.
-///
-/// This is used by test cases to avoid cwd races.
-///
-/// # Safety Note
-///
-/// This uses a pthread mutex so descheduling in the action callback
-/// can lead to deadlock. Calling change_dir_locked recursively will
-/// also deadlock.
-pub fn change_dir_locked(p: &Path, action: &fn()) -> bool {
- #[fixed_stack_segment]; #[inline(never)];
-
- use os;
- use os::change_dir;
- use unstable::sync::atomically;
- use unstable::finally::Finally;
-
- unsafe {
- // This is really sketchy. Using a pthread mutex so descheduling
- // in the `action` callback can cause deadlock. Doing it in
- // `task::atomically` to try to avoid that, but ... I don't know
- // this is all bogus.
- return do atomically {
- rust_take_change_dir_lock();
-
- do (||{
- let old_dir = os::getcwd();
- if change_dir(p) {
- action();
- change_dir(&old_dir)
- }
- else {
- false
- }
- }).finally {
- rust_drop_change_dir_lock();
- }
- }
- }
-
- extern {
- fn rust_take_change_dir_lock();
- fn rust_drop_change_dir_lock();
- }
-}
-
-
/// Dynamically inquire about whether we're running under V.
/// You should usually not use this unless your test definitely
/// can't run correctly un-altered. Valgrind is there to help
use container::{Container, Mutable};
use cmp::{Eq, TotalOrd, Ordering, Less, Equal, Greater};
use cmp;
+use default::Default;
use iter::*;
use libc::c_void;
-use num::{Integer, Zero, CheckedAdd, Saturating};
+use num::{Integer, CheckedAdd, Saturating};
use option::{None, Option, Some};
use ptr::to_unsafe_ptr;
use ptr;
*/
#[inline]
pub fn build<A>(size: Option<uint>, builder: &fn(push: &fn(v: A))) -> ~[A] {
- let mut vec = with_capacity(size.unwrap_or_default(4));
+ let mut vec = with_capacity(size.unwrap_or(4));
builder(|x| vec.push(x));
vec
}
}
// This works because every lifetime is a sub-lifetime of 'static
-impl<'self, A> Zero for &'self [A] {
- fn zero() -> &'self [A] { &'self [] }
- fn is_zero(&self) -> bool { self.is_empty() }
+impl<'self, A> Default for &'self [A] {
+ fn default() -> &'self [A] { &'self [] }
}
-impl<A> Zero for ~[A] {
- fn zero() -> ~[A] { ~[] }
- fn is_zero(&self) -> bool { self.len() == 0 }
+impl<A> Default for ~[A] {
+ fn default() -> ~[A] { ~[] }
}
-impl<A> Zero for @[A] {
- fn zero() -> @[A] { @[] }
- fn is_zero(&self) -> bool { self.len() == 0 }
+impl<A> Default for @[A] {
+ fn default() -> @[A] { @[] }
}
macro_rules! iterator {
}
#[test]
- fn test_vec_zero() {
- use num::Zero;
+ fn test_vec_default() {
+ use default::Default;
macro_rules! t (
($ty:ty) => {{
- let v: $ty = Zero::zero();
+ let v: $ty = Default::default();
assert!(v.is_empty());
- assert!(v.is_zero());
}}
);
// if it should be non-hygienic (most things are), just compare the
// 'name' fields of the idents. Or, even better, replace the idents
// with Name's.
- fail!(fmt!("not allowed to compare these idents: %?, %?", self, other));
+ fail!(fmt!("not allowed to compare these idents: %?, %?. Probably \
+ related to issue #6993", self, other));
}
}
fn ne(&self, other: &Ident) -> bool {
DefStatic(DefId, bool /* is_mutbl */),
DefArg(NodeId, bool /* is_mutbl */),
DefLocal(NodeId, bool /* is_mutbl */),
- DefVariant(DefId /* enum */, DefId /* variant */),
+ DefVariant(DefId /* enum */, DefId /* variant */, bool /* is_structure */),
DefTy(DefId),
DefTrait(DefId),
DefPrimTy(prim_ty),
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
pub enum BlockCheckMode {
DefaultBlock,
- UnsafeBlock,
+ UnsafeBlock(UnsafeSource),
+}
+
+#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
+pub enum UnsafeSource {
+ CompilerGenerated,
+ UserProvided,
}
#[deriving(Clone, Eq, Encodable, Decodable,IterBytes)]
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
path_pretty_name(Ident, u64),
}
+impl path_elt {
+ pub fn ident(&self) -> Ident {
+ match *self {
+ path_mod(ident) |
+ path_name(ident) |
+ path_pretty_name(ident, _) => ident
+ }
+ }
+}
+
pub type path = ~[path_elt];
pub fn path_to_str_with_sep(p: &[path_elt], sep: &str, itr: @ident_interner)
self.map_block(block)
}
- // XXX: Methods below can become default methods.
-
- fn visit_mod(&mut self, module: &_mod, _: Span, _: NodeId, _: ()) {
- visit::walk_mod(self, module, ())
- }
-
- fn visit_view_item(&mut self, view_item: &view_item, _: ()) {
- visit::walk_view_item(self, view_item, ())
- }
-
- fn visit_foreign_item(&mut self, foreign_item: @foreign_item, _: ()) {
- visit::walk_foreign_item(self, foreign_item, ())
- }
-
- fn visit_local(&mut self, local: @Local, _: ()) {
- visit::walk_local(self, local, ())
- }
-
- fn visit_arm(&mut self, arm: &Arm, _: ()) {
- visit::walk_arm(self, arm, ())
- }
-
- fn visit_decl(&mut self, decl: @Decl, _: ()) {
- visit::walk_decl(self, decl, ())
- }
-
- fn visit_expr_post(&mut self, _: @Expr, _: ()) {
- // Empty!
- }
-
fn visit_ty(&mut self, typ: &Ty, _: ()) {
visit::walk_ty(self, typ, ())
}
-
- fn visit_generics(&mut self, generics: &Generics, _: ()) {
- visit::walk_generics(self, generics, ())
- }
-
- fn visit_fn(&mut self,
- function_kind: &fn_kind,
- function_declaration: &fn_decl,
- block: &Block,
- span: Span,
- node_id: NodeId,
- _: ()) {
- visit::walk_fn(self,
- function_kind,
- function_declaration,
- block,
- span,
- node_id,
- ())
- }
-
- fn visit_ty_method(&mut self, ty_method: &TypeMethod, _: ()) {
- visit::walk_ty_method(self, ty_method, ())
- }
-
- fn visit_trait_method(&mut self, trait_method: &trait_method, _: ()) {
- visit::walk_trait_method(self, trait_method, ())
- }
-
- fn visit_struct_def(&mut self,
- struct_def: @struct_def,
- ident: Ident,
- generics: &Generics,
- node_id: NodeId,
- _: ()) {
- visit::walk_struct_def(self,
- struct_def,
- ident,
- generics,
- node_id,
- ())
- }
-
- fn visit_struct_field(&mut self, struct_field: @struct_field, _: ()) {
- visit::walk_struct_field(self, struct_field, ())
- }
}
pub fn map_crate(diag: @mut span_handler, c: &Crate) -> map {
pub fn variant_def_ids(d: Def) -> Option<(DefId, DefId)> {
match d {
- DefVariant(enum_id, var_id) => {
+ DefVariant(enum_id, var_id, _) => {
Some((enum_id, var_id))
}
_ => None
match d {
DefFn(id, _) | DefStaticMethod(id, _, _) | DefMod(id) |
DefForeignMod(id) | DefStatic(id, _) |
- DefVariant(_, id) | DefTy(id) | DefTyParam(id, _) |
+ DefVariant(_, id, _) | DefTy(id) | DefTyParam(id, _) |
DefUse(id) | DefStruct(id) | DefTrait(id) | DefMethod(id, _) => {
id
}
visit::walk_stmt(self, statement, env)
}
- // XXX: Default
- fn visit_arm(&mut self, arm: &Arm, env: ()) {
- visit::walk_arm(self, arm, env)
- }
-
fn visit_pat(&mut self, pattern: @Pat, env: ()) {
(self.visit_callback)(pattern.id);
visit::walk_pat(self, pattern, env)
}
- // XXX: Default
- fn visit_decl(&mut self, declaration: @Decl, env: ()) {
- visit::walk_decl(self, declaration, env)
- }
fn visit_expr(&mut self, expression: @Expr, env: ()) {
{
visit::walk_expr(self, expression, env)
}
- // XXX: Default
- fn visit_expr_post(&mut self, _: @Expr, _: ()) {
- // Empty!
- }
-
fn visit_ty(&mut self, typ: &Ty, env: ()) {
(self.visit_callback)(typ.id);
match typ.node {
}
}
- // XXX: Default
- fn visit_ty_method(&mut self, type_method: &TypeMethod, env: ()) {
- visit::walk_ty_method(self, type_method, env)
- }
-
- // XXX: Default
- fn visit_trait_method(&mut self, trait_method: &trait_method, env: ()) {
- visit::walk_trait_method(self, trait_method, env)
- }
-
- // XXX: Default
- fn visit_struct_def(&mut self,
- struct_definition: @struct_def,
- identifier: Ident,
- generics: &Generics,
- node_id: NodeId,
- env: ()) {
- visit::walk_struct_def(self,
- struct_definition,
- identifier,
- generics,
- node_id,
- env)
- }
-
fn visit_struct_field(&mut self, struct_field: @struct_field, env: ()) {
(self.visit_callback)(struct_field.node.id);
visit::walk_struct_field(self, struct_field, env)
-> Option<@str> {
attrs.iter()
.find(|at| name == at.name())
- .chain(|at| at.value_str())
+ .and_then(|at| at.value_str())
}
pub fn last_meta_item_value_str_by_name(items: &[@MetaItem], name: &str)
-> Option<@str> {
- items.rev_iter().find(|mi| name == mi.name()).chain(|i| i.value_str())
+ items.rev_iter().find(|mi| name == mi.name()).and_then(|i| i.value_str())
}
/* Higher-level applications */
}
/// A byte offset
-#[deriving(Clone, Eq, IterBytes)]
+#[deriving(Clone, Eq, IterBytes, Ord)]
pub struct BytePos(uint);
/// A character offset. Because of multibyte utf8 characters, a byte offset
/// is not equivalent to a character offset. The CodeMap will convert BytePos
/// values to CharPos values as necessary.
-#[deriving(Eq,IterBytes)]
+#[deriving(Eq,IterBytes, Ord)]
pub struct CharPos(uint);
// XXX: Lots of boilerplate in these impls, but so far my attempts to fix
fn to_uint(&self) -> uint { **self }
}
-impl cmp::Ord for BytePos {
- fn lt(&self, other: &BytePos) -> bool { **self < **other }
- fn le(&self, other: &BytePos) -> bool { **self <= **other }
- fn ge(&self, other: &BytePos) -> bool { **self >= **other }
- fn gt(&self, other: &BytePos) -> bool { **self > **other }
-}
-
impl Add<BytePos, BytePos> for BytePos {
fn add(&self, rhs: &BytePos) -> BytePos {
BytePos(**self + **rhs)
fn to_uint(&self) -> uint { **self }
}
-impl cmp::Ord for CharPos {
- fn lt(&self, other: &CharPos) -> bool { **self < **other }
- fn le(&self, other: &CharPos) -> bool { **self <= **other }
- fn ge(&self, other: &CharPos) -> bool { **self >= **other }
- fn gt(&self, other: &CharPos) -> bool { **self > **other }
-}
-
impl Add<CharPos,CharPos> for CharPos {
fn add(&self, rhs: &CharPos) -> CharPos {
CharPos(**self + **rhs)
@SE(IdentTT(ext::tt::macro_rules::add_new_extension, None)));
syntax_expanders.insert(intern(&"fmt"),
builtin_normal_tt_no_ctxt(ext::fmt::expand_syntax_ext));
- syntax_expanders.insert(intern(&"format"),
- builtin_normal_tt_no_ctxt(ext::ifmt::expand_format));
- syntax_expanders.insert(intern(&"write"),
- builtin_normal_tt_no_ctxt(ext::ifmt::expand_write));
- syntax_expanders.insert(intern(&"writeln"),
- builtin_normal_tt_no_ctxt(ext::ifmt::expand_writeln));
+ syntax_expanders.insert(intern(&"format_args"),
+ builtin_normal_tt_no_ctxt(ext::format::expand_args));
syntax_expanders.insert(
intern(&"auto_encode"),
@SE(ItemDecorator(ext::auto_encode::expand_auto_encode)));
--- /dev/null
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use ast::{MetaItem, item, Expr};
+use codemap::Span;
+use ext::base::ExtCtxt;
+use ext::build::AstBuilder;
+use ext::deriving::generic::*;
+
+use std::vec;
+
+pub fn expand_deriving_default(cx: @ExtCtxt,
+ span: Span,
+ mitem: @MetaItem,
+ in_items: ~[@item])
+ -> ~[@item] {
+ let trait_def = TraitDef {
+ path: Path::new(~["std", "default", "Default"]),
+ additional_bounds: ~[],
+ generics: LifetimeBounds::empty(),
+ methods: ~[
+ MethodDef {
+ name: "default",
+ generics: LifetimeBounds::empty(),
+ explicit_self: None,
+ args: ~[],
+ ret_ty: Self,
+ const_nonmatching: false,
+ combine_substructure: default_substructure
+ },
+ ]
+ };
+ trait_def.expand(cx, span, mitem, in_items)
+}
+
+fn default_substructure(cx: @ExtCtxt, span: Span, substr: &Substructure) -> @Expr {
+ let default_ident = ~[
+ cx.ident_of("std"),
+ cx.ident_of("default"),
+ cx.ident_of("Default"),
+ cx.ident_of("default")
+ ];
+ let default_call = || {
+ cx.expr_call_global(span, default_ident.clone(), ~[])
+ };
+
+ return match *substr.fields {
+ StaticStruct(_, ref summary) => {
+ match *summary {
+ Left(count) => {
+ if count == 0 {
+ cx.expr_ident(span, substr.type_ident)
+ } else {
+ let exprs = vec::from_fn(count, |_| default_call());
+ cx.expr_call_ident(span, substr.type_ident, exprs)
+ }
+ }
+ Right(ref fields) => {
+ let default_fields = do fields.map |ident| {
+ cx.field_imm(span, *ident, default_call())
+ };
+ cx.expr_struct_ident(span, substr.type_ident, default_fields)
+ }
+ }
+ }
+ StaticEnum(*) => {
+ cx.span_fatal(span, "`Default` cannot be derived for enums, \
+ only structs")
+ }
+ _ => cx.bug("Non-static method in `deriving(Default)`")
+ };
+}
pub mod rand;
pub mod to_str;
pub mod zero;
+pub mod default;
#[path="cmp/eq.rs"]
pub mod eq;
"ToStr" => expand!(to_str::expand_deriving_to_str),
"Zero" => expand!(zero::expand_deriving_zero),
+ "Default" => expand!(default::expand_deriving_default),
ref tname => {
cx.span_err(titem.span, fmt!("unknown \
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use ast::{Block, Crate, NodeId, DeclLocal, Expr_, ExprMac, SyntaxContext};
+use ast::{Block, Crate, DeclLocal, Expr_, ExprMac, SyntaxContext};
use ast::{Local, Ident, mac_invoc_tt};
use ast::{item_mac, Mrk, Stmt_, StmtDecl, StmtMac, StmtExpr, StmtSemi};
use ast::{token_tree};
// mark before:
let marked_before = mark_tts(*tts,fm);
let marked_ctxt = new_mark(fm, ctxt);
+
+ // The span that we pass to the expanders we want to
+ // be the root of the call stack. That's the most
+ // relevant span and it's the actual invocation of
+ // the macro.
+ let mac_span = original_span(cx);
+
let expanded =
- match expandfun(cx, mac.span, marked_before, marked_ctxt) {
+ match expandfun(cx, mac_span.call_site,
+ marked_before, marked_ctxt) {
MRExpr(e) => e,
MRAny(expr_maker,_,_) => expr_maker(),
_ => {
};
let maybe_it = match expanded {
- MRItem(it) => mark_item(it,fm).chain(|i| {fld.fold_item(i)}),
- MRExpr(_) => cx.span_fatal(pth.span,
- fmt!("expr macro in item position: %s", extnamestr)),
- MRAny(_, item_maker, _) => item_maker().chain(|i| {mark_item(i,fm)})
- .chain(|i| {fld.fold_item(i)}),
+ MRItem(it) => {
+ mark_item(it,fm)
+ .and_then(|i| fld.fold_item(i))
+ }
+ MRExpr(_) => {
+ cx.span_fatal(pth.span, fmt!("expr macro in item position: %s", extnamestr))
+ }
+ MRAny(_, item_maker, _) => {
+ item_maker()
+ .and_then(|i| mark_item(i,fm))
+ .and_then(|i| fld.fold_item(i))
+ }
MRDef(ref mdef) => {
// yikes... no idea how to apply the mark to this. I'm afraid
// we're going to have to wait-and-see on this one.
-> (Option<Stmt_>, Span) {
// why the copying here and not in expand_expr?
// looks like classic changed-in-only-one-place
- let (mac, pth, tts, semi, ctxt) = match *s {
+ let (pth, tts, semi, ctxt) = match *s {
StmtMac(ref mac, semi) => {
match mac.node {
mac_invoc_tt(ref pth, ref tts, ctxt) => {
- ((*mac).clone(), pth, (*tts).clone(), semi, ctxt)
+ (pth, (*tts).clone(), semi, ctxt)
}
}
}
// mark before expansion:
let marked_tts = mark_tts(tts,fm);
let marked_ctxt = new_mark(fm,ctxt);
- let expanded = match expandfun(cx, mac.span, marked_tts, marked_ctxt) {
+
+ // See the comment in expand_expr for why we want the original span,
+ // not the current mac.span.
+ let mac_span = original_span(cx);
+
+ let expanded = match expandfun(cx, mac_span.call_site,
+ marked_tts, marked_ctxt) {
MRExpr(e) =>
@codemap::Spanned { node: StmtExpr(e, ast::DUMMY_NODE_ID),
span: e.span},
}
}
- // XXX: Methods below can become default methods.
-
- fn visit_mod(&mut self, module: &ast::_mod, _: Span, _: NodeId, _: ()) {
- visit::walk_mod(self, module, ())
- }
-
- fn visit_view_item(&mut self, view_item: &ast::view_item, _: ()) {
- visit::walk_view_item(self, view_item, ())
- }
-
- fn visit_item(&mut self, item: @ast::item, _: ()) {
- visit::walk_item(self, item, ())
- }
-
- fn visit_foreign_item(&mut self,
- foreign_item: @ast::foreign_item,
- _: ()) {
- visit::walk_foreign_item(self, foreign_item, ())
- }
-
- fn visit_local(&mut self, local: @ast::Local, _: ()) {
- visit::walk_local(self, local, ())
- }
-
- fn visit_block(&mut self, block: &ast::Block, _: ()) {
- visit::walk_block(self, block, ())
- }
-
- fn visit_stmt(&mut self, stmt: @ast::Stmt, _: ()) {
- visit::walk_stmt(self, stmt, ())
- }
-
- fn visit_arm(&mut self, arm: &ast::Arm, _: ()) {
- visit::walk_arm(self, arm, ())
- }
-
- fn visit_decl(&mut self, decl: @ast::Decl, _: ()) {
- visit::walk_decl(self, decl, ())
- }
-
- fn visit_expr(&mut self, expr: @ast::Expr, _: ()) {
- visit::walk_expr(self, expr, ())
- }
-
- fn visit_expr_post(&mut self, _: @ast::Expr, _: ()) {
- // Empty!
- }
-
fn visit_ty(&mut self, typ: &ast::Ty, _: ()) {
visit::walk_ty(self, typ, ())
}
- fn visit_generics(&mut self, generics: &ast::Generics, _: ()) {
- visit::walk_generics(self, generics, ())
- }
-
- fn visit_fn(&mut self,
- function_kind: &visit::fn_kind,
- function_declaration: &ast::fn_decl,
- block: &ast::Block,
- span: Span,
- node_id: NodeId,
- _: ()) {
- visit::walk_fn(self,
- function_kind,
- function_declaration,
- block,
- span,
- node_id,
- ())
- }
-
- fn visit_ty_method(&mut self, ty_method: &ast::TypeMethod, _: ()) {
- visit::walk_ty_method(self, ty_method, ())
- }
-
- fn visit_trait_method(&mut self,
- trait_method: &ast::trait_method,
- _: ()) {
- visit::walk_trait_method(self, trait_method, ())
- }
-
- fn visit_struct_def(&mut self,
- struct_def: @ast::struct_def,
- ident: Ident,
- generics: &ast::Generics,
- node_id: NodeId,
- _: ()) {
- visit::walk_struct_def(self,
- struct_def,
- ident,
- generics,
- node_id,
- ())
- }
-
- fn visit_struct_field(&mut self,
- struct_field: @ast::struct_field,
- _: ()) {
- visit::walk_struct_field(self, struct_field, ())
- }
}
// a visitor that extracts the paths
path_accumulator: @mut ~[ast::Path],
}
-// XXX : YIKES a lot of boilerplate again....
impl Visitor<()> for NewPathExprFinderContext {
fn visit_expr(&mut self, expr: @ast::Expr, _: ()) {
}
}
-
- // XXX: Methods below can become default methods.
-
- fn visit_pat(&mut self, pattern: @ast::Pat, _: ()) {
- visit::walk_pat(self,pattern,())
- }
-
- fn visit_mod(&mut self, module: &ast::_mod, _: Span, _: NodeId, _: ()) {
- visit::walk_mod(self, module, ())
- }
-
- fn visit_view_item(&mut self, view_item: &ast::view_item, _: ()) {
- visit::walk_view_item(self, view_item, ())
- }
-
- fn visit_item(&mut self, item: @ast::item, _: ()) {
- visit::walk_item(self, item, ())
- }
-
- fn visit_foreign_item(&mut self,
- foreign_item: @ast::foreign_item,
- _: ()) {
- visit::walk_foreign_item(self, foreign_item, ())
- }
-
- fn visit_local(&mut self, local: @ast::Local, _: ()) {
- visit::walk_local(self, local, ())
- }
-
- fn visit_block(&mut self, block: &ast::Block, _: ()) {
- visit::walk_block(self, block, ())
- }
-
- fn visit_stmt(&mut self, stmt: @ast::Stmt, _: ()) {
- visit::walk_stmt(self, stmt, ())
- }
-
- fn visit_arm(&mut self, arm: &ast::Arm, _: ()) {
- visit::walk_arm(self, arm, ())
- }
-
- fn visit_decl(&mut self, decl: @ast::Decl, _: ()) {
- visit::walk_decl(self, decl, ())
- }
-
- fn visit_expr_post(&mut self, _: @ast::Expr, _: ()) {
- // Empty!
- }
-
fn visit_ty(&mut self, typ: &ast::Ty, _: ()) {
visit::walk_ty(self, typ, ())
}
- fn visit_generics(&mut self, generics: &ast::Generics, _: ()) {
- visit::walk_generics(self, generics, ())
- }
-
- fn visit_fn(&mut self,
- function_kind: &visit::fn_kind,
- function_declaration: &ast::fn_decl,
- block: &ast::Block,
- span: Span,
- node_id: NodeId,
- _: ()) {
- visit::walk_fn(self,
- function_kind,
- function_declaration,
- block,
- span,
- node_id,
- ())
- }
-
- fn visit_ty_method(&mut self, ty_method: &ast::TypeMethod, _: ()) {
- visit::walk_ty_method(self, ty_method, ())
- }
-
- fn visit_trait_method(&mut self,
- trait_method: &ast::trait_method,
- _: ()) {
- visit::walk_trait_method(self, trait_method, ())
- }
-
- fn visit_struct_def(&mut self,
- struct_def: @ast::struct_def,
- ident: Ident,
- generics: &ast::Generics,
- node_id: NodeId,
- _: ()) {
- visit::walk_struct_def(self,
- struct_def,
- ident,
- generics,
- node_id,
- ())
- }
-
- fn visit_struct_field(&mut self,
- struct_field: @ast::struct_field,
- _: ()) {
- visit::walk_struct_field(self, struct_field, ())
- }
}
// return a visitor that extracts the pat_ident paths
}
})
)
- macro_rules! error( ($($arg:tt)+) => (log!(1u32, $($arg)+)) )
- macro_rules! warn ( ($($arg:tt)+) => (log!(2u32, $($arg)+)) )
- macro_rules! info ( ($($arg:tt)+) => (log!(3u32, $($arg)+)) )
- macro_rules! debug( ($($arg:tt)+) => (
- if cfg!(debug) { log!(4u32, $($arg)+) }
+ macro_rules! error( ($($arg:tt)*) => (log!(1u32, $($arg)*)) )
+ macro_rules! warn ( ($($arg:tt)*) => (log!(2u32, $($arg)*)) )
+ macro_rules! info ( ($($arg:tt)*) => (log!(3u32, $($arg)*)) )
+ macro_rules! debug( ($($arg:tt)*) => (
+ if cfg!(debug) { log!(4u32, $($arg)*) }
))
macro_rules! log2(
}
})
)
- macro_rules! error2( ($($arg:tt)+) => (log2!(1u32, $($arg)+)) )
- macro_rules! warn2 ( ($($arg:tt)+) => (log2!(2u32, $($arg)+)) )
- macro_rules! info2 ( ($($arg:tt)+) => (log2!(3u32, $($arg)+)) )
- macro_rules! debug2( ($($arg:tt)+) => (
- if cfg!(debug) { log2!(4u32, $($arg)+) }
+ macro_rules! error2( ($($arg:tt)*) => (log2!(1u32, $($arg)*)) )
+ macro_rules! warn2 ( ($($arg:tt)*) => (log2!(2u32, $($arg)*)) )
+ macro_rules! info2 ( ($($arg:tt)*) => (log2!(3u32, $($arg)*)) )
+ macro_rules! debug2( ($($arg:tt)*) => (
+ if cfg!(debug) { log2!(4u32, $($arg)*) }
))
macro_rules! fail(
() => (
fail!(\"explicit failure\")
);
- ($($arg:tt)+) => (
- ::std::sys::FailWithCause::fail_with(format!($($arg)+), file!(), line!())
+ ($($arg:tt)*) => (
+ ::std::sys::FailWithCause::fail_with(format!($($arg)*), file!(), line!())
)
)
)
)
+ macro_rules! format(($($arg:tt)*) => (
+ format_args!(::std::fmt::format, $($arg)*)
+ ))
+ macro_rules! write(($dst:expr, $($arg:tt)*) => (
+ format_args!(|args| { ::std::fmt::write($dst, args) }, $($arg)*)
+ ))
+ macro_rules! writeln(($dst:expr, $($arg:tt)*) => (
+ format_args!(|args| { ::std::fmt::writeln($dst, args) }, $($arg)*)
+ ))
// FIXME(#6846) once stdio is redesigned, this shouldn't perform an
// allocation but should rather delegate to an invocation of
// write! instead of format!
macro_rules! print (
- ($($arg:tt)+) => (::std::io::print(format!($($arg)+)))
+ ($($arg:tt)*) => (::std::io::print(format!($($arg)*)))
)
-
// FIXME(#6846) once stdio is redesigned, this shouldn't perform an
// allocation but should rather delegate to an io::Writer
macro_rules! println (
- ($($arg:tt)+) => (::std::io::println(format!($($arg)+)))
+ ($($arg:tt)*) => (::std::io::println(format!($($arg)*)))
)
// NOTE: use this after a snapshot lands to abstract the details
mark_tts(tts,outer_mark)
}
+fn original_span(cx: @ExtCtxt) -> @codemap::ExpnInfo {
+ let mut relevant_info = cx.backtrace();
+ let mut einfo = relevant_info.unwrap();
+ loop {
+ match relevant_info {
+ None => { break }
+ Some(e) => {
+ einfo = e;
+ relevant_info = einfo.call_site.expn_info;
+ }
+ }
+ }
+ return einfo;
+}
#[cfg(test)]
mod test {
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use ast;
+use codemap::{Span, respan};
+use ext::base::*;
+use ext::base;
+use ext::build::AstBuilder;
+use rsparse = parse;
+use parse::token;
+
+use std::fmt::parse;
+use std::hashmap::{HashMap, HashSet};
+use std::vec;
+
+#[deriving(Eq)]
+enum ArgumentType {
+ Unknown,
+ Known(@str),
+ Unsigned,
+ String,
+}
+
+struct Context {
+ ecx: @ExtCtxt,
+ fmtsp: Span,
+
+ // Parsed argument expressions and the types that we've found so far for
+ // them.
+ args: ~[@ast::Expr],
+ arg_types: ~[Option<ArgumentType>],
+ // Parsed named expressions and the types that we've found for them so far
+ names: HashMap<@str, @ast::Expr>,
+ name_types: HashMap<@str, ArgumentType>,
+
+ // Collection of the compiled `rt::Piece` structures
+ pieces: ~[@ast::Expr],
+ name_positions: HashMap<@str, uint>,
+ method_statics: ~[@ast::item],
+
+ // Updated as arguments are consumed or methods are entered
+ nest_level: uint,
+ next_arg: uint,
+}
+
+impl Context {
+ /// Parses the arguments from the given list of tokens, returning None if
+ /// there's a parse error so we can continue parsing other fmt! expressions.
+ fn parse_args(&mut self, sp: Span,
+ tts: &[ast::token_tree]) -> (@ast::Expr, Option<@ast::Expr>) {
+ let p = rsparse::new_parser_from_tts(self.ecx.parse_sess(),
+ self.ecx.cfg(),
+ tts.to_owned());
+ // Parse the leading function expression (maybe a block, maybe a path)
+ let extra = p.parse_expr();
+ if !p.eat(&token::COMMA) {
+ self.ecx.span_err(sp, "expected token: `,`");
+ return (extra, None);
+ }
+
+ if *p.token == token::EOF {
+ self.ecx.span_err(sp, "requires at least a format string argument");
+ return (extra, None);
+ }
+ let fmtstr = p.parse_expr();
+ let mut named = false;
+ while *p.token != token::EOF {
+ if !p.eat(&token::COMMA) {
+ self.ecx.span_err(sp, "expected token: `,`");
+ return (extra, None);
+ }
+ if named || (token::is_ident(p.token) &&
+ p.look_ahead(1, |t| *t == token::EQ)) {
+ named = true;
+ let ident = match *p.token {
+ token::IDENT(i, _) => {
+ p.bump();
+ i
+ }
+ _ if named => {
+ self.ecx.span_err(*p.span,
+ "expected ident, positional arguments \
+ cannot follow named arguments");
+ return (extra, None);
+ }
+ _ => {
+ self.ecx.span_err(*p.span,
+ fmt!("expected ident for named \
+ argument, but found `%s`",
+ p.this_token_to_str()));
+ return (extra, None);
+ }
+ };
+ let name = self.ecx.str_of(ident);
+ p.expect(&token::EQ);
+ let e = p.parse_expr();
+ match self.names.find(&name) {
+ None => {}
+ Some(prev) => {
+ self.ecx.span_err(e.span, fmt!("duplicate argument \
+ named `%s`", name));
+ self.ecx.parse_sess.span_diagnostic.span_note(
+ prev.span, "previously here");
+ loop
+ }
+ }
+ self.names.insert(name, e);
+ } else {
+ self.args.push(p.parse_expr());
+ self.arg_types.push(None);
+ }
+ }
+ return (extra, Some(fmtstr));
+ }
+
+ /// Verifies one piece of a parse string. All errors are not emitted as
+ /// fatal so we can continue giving errors about this and possibly other
+ /// format strings.
+ fn verify_piece(&mut self, p: &parse::Piece) {
+ match *p {
+ parse::String(*) => {}
+ parse::CurrentArgument => {
+ if self.nest_level == 0 {
+ self.ecx.span_err(self.fmtsp,
+ "`#` reference used with nothing to \
+ reference back to");
+ }
+ }
+ parse::Argument(ref arg) => {
+ // width/precision first, if they have implicit positional
+ // parameters it makes more sense to consume them first.
+ self.verify_count(arg.format.width);
+ self.verify_count(arg.format.precision);
+
+ // argument second, if it's an implicit positional parameter
+ // it's written second, so it should come after width/precision.
+ let pos = match arg.position {
+ parse::ArgumentNext => {
+ let i = self.next_arg;
+ if self.check_positional_ok() {
+ self.next_arg += 1;
+ }
+ Left(i)
+ }
+ parse::ArgumentIs(i) => Left(i),
+ parse::ArgumentNamed(s) => Right(s.to_managed()),
+ };
+ let ty = if arg.format.ty == "" {
+ Unknown
+ } else { Known(arg.format.ty.to_managed()) };
+ self.verify_arg_type(pos, ty);
+
+ // and finally the method being applied
+ match arg.method {
+ None => {}
+ Some(ref method) => { self.verify_method(pos, *method); }
+ }
+ }
+ }
+ }
+
+ fn verify_pieces(&mut self, pieces: &[parse::Piece]) {
+ for piece in pieces.iter() {
+ self.verify_piece(piece);
+ }
+ }
+
+ fn verify_count(&mut self, c: parse::Count) {
+ match c {
+ parse::CountImplied | parse::CountIs(*) => {}
+ parse::CountIsParam(i) => {
+ self.verify_arg_type(Left(i), Unsigned);
+ }
+ parse::CountIsNextParam => {
+ if self.check_positional_ok() {
+ self.verify_arg_type(Left(self.next_arg), Unsigned);
+ self.next_arg += 1;
+ }
+ }
+ }
+ }
+
+ fn check_positional_ok(&mut self) -> bool {
+ if self.nest_level != 0 {
+ self.ecx.span_err(self.fmtsp, "cannot use implicit positional \
+ arguments nested inside methods");
+ false
+ } else {
+ true
+ }
+ }
+
+ fn verify_method(&mut self, pos: Either<uint, @str>, m: &parse::Method) {
+ self.nest_level += 1;
+ match *m {
+ parse::Plural(_, ref arms, ref default) => {
+ let mut seen_cases = HashSet::new();
+ self.verify_arg_type(pos, Unsigned);
+ for arm in arms.iter() {
+ if !seen_cases.insert(arm.selector) {
+ match arm.selector {
+ Left(name) => {
+ self.ecx.span_err(self.fmtsp,
+ fmt!("duplicate selector \
+ `%?`", name));
+ }
+ Right(idx) => {
+ self.ecx.span_err(self.fmtsp,
+ fmt!("duplicate selector \
+ `=%u`", idx));
+ }
+ }
+ }
+ self.verify_pieces(arm.result);
+ }
+ self.verify_pieces(*default);
+ }
+ parse::Select(ref arms, ref default) => {
+ self.verify_arg_type(pos, String);
+ let mut seen_cases = HashSet::new();
+ for arm in arms.iter() {
+ if !seen_cases.insert(arm.selector) {
+ self.ecx.span_err(self.fmtsp,
+ fmt!("duplicate selector `%s`",
+ arm.selector));
+ } else if arm.selector == "" {
+ self.ecx.span_err(self.fmtsp,
+ "empty selector in `select`");
+ }
+ self.verify_pieces(arm.result);
+ }
+ self.verify_pieces(*default);
+ }
+ }
+ self.nest_level -= 1;
+ }
+
+ fn verify_arg_type(&mut self, arg: Either<uint, @str>, ty: ArgumentType) {
+ match arg {
+ Left(arg) => {
+ if arg < 0 || self.args.len() <= arg {
+ let msg = fmt!("invalid reference to argument `%u` (there \
+ are %u arguments)", arg, self.args.len());
+ self.ecx.span_err(self.fmtsp, msg);
+ return;
+ }
+ self.verify_same(self.args[arg].span, ty, self.arg_types[arg]);
+ if ty != Unknown || self.arg_types[arg].is_none() {
+ self.arg_types[arg] = Some(ty);
+ }
+ }
+
+ Right(name) => {
+ let span = match self.names.find(&name) {
+ Some(e) => e.span,
+ None => {
+ let msg = fmt!("There is no argument named `%s`", name);
+ self.ecx.span_err(self.fmtsp, msg);
+ return;
+ }
+ };
+ self.verify_same(span, ty,
+ self.name_types.find(&name).map(|&x| *x));
+ if ty != Unknown || !self.name_types.contains_key(&name) {
+ self.name_types.insert(name, ty);
+ }
+ // Assign this named argument a slot in the arguments array if
+ // it hasn't already been assigned a slot.
+ if !self.name_positions.contains_key(&name) {
+ let slot = self.name_positions.len();
+ self.name_positions.insert(name, slot);
+ }
+ }
+ }
+ }
+
+ /// When we're keeping track of the types that are declared for certain
+ /// arguments, we assume that `None` means we haven't seen this argument
+ /// yet, `Some(None)` means that we've seen the argument, but no format was
+ /// specified, and `Some(Some(x))` means that the argument was declared to
+ /// have type `x`.
+ ///
+ /// Obviously `Some(Some(x)) != Some(Some(y))`, but we consider it true
+ /// that: `Some(None) == Some(Some(x))`
+ fn verify_same(&self, sp: Span, ty: ArgumentType,
+ before: Option<ArgumentType>) {
+ if ty == Unknown { return }
+ let cur = match before {
+ Some(Unknown) | None => return,
+ Some(t) => t,
+ };
+ if ty == cur { return }
+ match (cur, ty) {
+ (Known(cur), Known(ty)) => {
+ self.ecx.span_err(sp,
+ fmt!("argument redeclared with type `%s` when \
+ it was previously `%s`", ty, cur));
+ }
+ (Known(cur), _) => {
+ self.ecx.span_err(sp,
+ fmt!("argument used to format with `%s` was \
+ attempted to not be used for formatting",
+ cur));
+ }
+ (_, Known(ty)) => {
+ self.ecx.span_err(sp,
+ fmt!("argument previously used as a format \
+ argument attempted to be used as `%s`",
+ ty));
+ }
+ (_, _) => {
+ self.ecx.span_err(sp, "argument declared with multiple formats");
+ }
+ }
+ }
+
+ /// Translate a `parse::Piece` to a static `rt::Piece`
+ fn trans_piece(&mut self, piece: &parse::Piece) -> @ast::Expr {
+ let sp = self.fmtsp;
+ let parsepath = |s: &str| {
+ ~[self.ecx.ident_of("std"), self.ecx.ident_of("fmt"),
+ self.ecx.ident_of("parse"), self.ecx.ident_of(s)]
+ };
+ let rtpath = |s: &str| {
+ ~[self.ecx.ident_of("std"), self.ecx.ident_of("fmt"),
+ self.ecx.ident_of("rt"), self.ecx.ident_of(s)]
+ };
+ let ctpath = |s: &str| {
+ ~[self.ecx.ident_of("std"), self.ecx.ident_of("fmt"),
+ self.ecx.ident_of("parse"), self.ecx.ident_of(s)]
+ };
+ let none = self.ecx.path_global(sp, ~[
+ self.ecx.ident_of("std"),
+ self.ecx.ident_of("option"),
+ self.ecx.ident_of("None")]);
+ let none = self.ecx.expr_path(none);
+ let some = |e: @ast::Expr| {
+ let p = self.ecx.path_global(sp, ~[
+ self.ecx.ident_of("std"),
+ self.ecx.ident_of("option"),
+ self.ecx.ident_of("Some")]);
+ let p = self.ecx.expr_path(p);
+ self.ecx.expr_call(sp, p, ~[e])
+ };
+ let trans_count = |c: parse::Count| {
+ match c {
+ parse::CountIs(i) => {
+ self.ecx.expr_call_global(sp, ctpath("CountIs"),
+ ~[self.ecx.expr_uint(sp, i)])
+ }
+ parse::CountIsParam(i) => {
+ self.ecx.expr_call_global(sp, ctpath("CountIsParam"),
+ ~[self.ecx.expr_uint(sp, i)])
+ }
+ parse::CountImplied => {
+ let path = self.ecx.path_global(sp, ctpath("CountImplied"));
+ self.ecx.expr_path(path)
+ }
+ parse::CountIsNextParam => {
+ let path = self.ecx.path_global(sp, ctpath("CountIsNextParam"));
+ self.ecx.expr_path(path)
+ }
+ }
+ };
+ let trans_method = |method: &parse::Method| {
+ let method = match *method {
+ parse::Select(ref arms, ref default) => {
+ let arms = arms.iter().map(|arm| {
+ let p = self.ecx.path_global(sp, rtpath("SelectArm"));
+ let result = arm.result.iter().map(|p| {
+ self.trans_piece(p)
+ }).collect();
+ let s = arm.selector.to_managed();
+ let selector = self.ecx.expr_str(sp, s);
+ self.ecx.expr_struct(sp, p, ~[
+ self.ecx.field_imm(sp,
+ self.ecx.ident_of("selector"),
+ selector),
+ self.ecx.field_imm(sp, self.ecx.ident_of("result"),
+ self.ecx.expr_vec_slice(sp, result)),
+ ])
+ }).collect();
+ let default = default.iter().map(|p| {
+ self.trans_piece(p)
+ }).collect();
+ self.ecx.expr_call_global(sp, rtpath("Select"), ~[
+ self.ecx.expr_vec_slice(sp, arms),
+ self.ecx.expr_vec_slice(sp, default),
+ ])
+ }
+ parse::Plural(offset, ref arms, ref default) => {
+ let offset = match offset {
+ Some(i) => { some(self.ecx.expr_uint(sp, i)) }
+ None => { none.clone() }
+ };
+ let arms = arms.iter().map(|arm| {
+ let p = self.ecx.path_global(sp, rtpath("PluralArm"));
+ let result = arm.result.iter().map(|p| {
+ self.trans_piece(p)
+ }).collect();
+ let (lr, selarg) = match arm.selector {
+ Left(t) => {
+ let p = ctpath(fmt!("%?", t));
+ let p = self.ecx.path_global(sp, p);
+ (self.ecx.ident_of("Left"),
+ self.ecx.expr_path(p))
+ }
+ Right(i) => {
+ (self.ecx.ident_of("Right"),
+ self.ecx.expr_uint(sp, i))
+ }
+ };
+ let selector = self.ecx.expr_call_ident(sp,
+ lr, ~[selarg]);
+ self.ecx.expr_struct(sp, p, ~[
+ self.ecx.field_imm(sp,
+ self.ecx.ident_of("selector"),
+ selector),
+ self.ecx.field_imm(sp, self.ecx.ident_of("result"),
+ self.ecx.expr_vec_slice(sp, result)),
+ ])
+ }).collect();
+ let default = default.iter().map(|p| {
+ self.trans_piece(p)
+ }).collect();
+ self.ecx.expr_call_global(sp, rtpath("Plural"), ~[
+ offset,
+ self.ecx.expr_vec_slice(sp, arms),
+ self.ecx.expr_vec_slice(sp, default),
+ ])
+ }
+ };
+ let life = self.ecx.lifetime(sp, self.ecx.ident_of("static"));
+ let ty = self.ecx.ty_path(self.ecx.path_all(
+ sp,
+ true,
+ rtpath("Method"),
+ Some(life),
+ ~[]
+ ), None);
+ let st = ast::item_static(ty, ast::MutImmutable, method);
+ let static_name = self.ecx.ident_of(fmt!("__static_method_%u",
+ self.method_statics.len()));
+ // Flag these statics as `address_insignificant` so LLVM can
+ // merge duplicate globals as much as possible (which we're
+ // generating a whole lot of).
+ let unnamed = self.ecx.meta_word(self.fmtsp, @"address_insignificant");
+ let unnamed = self.ecx.attribute(self.fmtsp, unnamed);
+ let item = self.ecx.item(sp, static_name, ~[unnamed], st);
+ self.method_statics.push(item);
+ self.ecx.expr_ident(sp, static_name)
+ };
+
+ match *piece {
+ parse::String(s) => {
+ self.ecx.expr_call_global(sp, rtpath("String"),
+ ~[self.ecx.expr_str(sp, s.to_managed())])
+ }
+ parse::CurrentArgument => {
+ let nil = self.ecx.expr_lit(sp, ast::lit_nil);
+ self.ecx.expr_call_global(sp, rtpath("CurrentArgument"), ~[nil])
+ }
+ parse::Argument(ref arg) => {
+ // Translate the position
+ let pos = match arg.position {
+ // These two have a direct mapping
+ parse::ArgumentNext => {
+ let path = self.ecx.path_global(sp,
+ rtpath("ArgumentNext"));
+ self.ecx.expr_path(path)
+ }
+ parse::ArgumentIs(i) => {
+ self.ecx.expr_call_global(sp, rtpath("ArgumentIs"),
+ ~[self.ecx.expr_uint(sp, i)])
+ }
+ // Named arguments are converted to positional arguments at
+ // the end of the list of arguments
+ parse::ArgumentNamed(n) => {
+ let n = n.to_managed();
+ let i = match self.name_positions.find_copy(&n) {
+ Some(i) => i,
+ None => 0, // error already emitted elsewhere
+ };
+ let i = i + self.args.len();
+ self.ecx.expr_call_global(sp, rtpath("ArgumentIs"),
+ ~[self.ecx.expr_uint(sp, i)])
+ }
+ };
+
+ // Translate the format
+ let fill = match arg.format.fill { Some(c) => c, None => ' ' };
+ let fill = self.ecx.expr_lit(sp, ast::lit_char(fill as u32));
+ let align = match arg.format.align {
+ parse::AlignLeft => {
+ self.ecx.path_global(sp, parsepath("AlignLeft"))
+ }
+ parse::AlignRight => {
+ self.ecx.path_global(sp, parsepath("AlignRight"))
+ }
+ parse::AlignUnknown => {
+ self.ecx.path_global(sp, parsepath("AlignUnknown"))
+ }
+ };
+ let align = self.ecx.expr_path(align);
+ let flags = self.ecx.expr_uint(sp, arg.format.flags);
+ let prec = trans_count(arg.format.precision);
+ let width = trans_count(arg.format.width);
+ let path = self.ecx.path_global(sp, rtpath("FormatSpec"));
+ let fmt = self.ecx.expr_struct(sp, path, ~[
+ self.ecx.field_imm(sp, self.ecx.ident_of("fill"), fill),
+ self.ecx.field_imm(sp, self.ecx.ident_of("align"), align),
+ self.ecx.field_imm(sp, self.ecx.ident_of("flags"), flags),
+ self.ecx.field_imm(sp, self.ecx.ident_of("precision"), prec),
+ self.ecx.field_imm(sp, self.ecx.ident_of("width"), width),
+ ]);
+
+ // Translate the method (if any)
+ let method = match arg.method {
+ None => { none.clone() }
+ Some(ref m) => {
+ let m = trans_method(*m);
+ some(self.ecx.expr_addr_of(sp, m))
+ }
+ };
+ let path = self.ecx.path_global(sp, rtpath("Argument"));
+ let s = self.ecx.expr_struct(sp, path, ~[
+ self.ecx.field_imm(sp, self.ecx.ident_of("position"), pos),
+ self.ecx.field_imm(sp, self.ecx.ident_of("format"), fmt),
+ self.ecx.field_imm(sp, self.ecx.ident_of("method"), method),
+ ]);
+ self.ecx.expr_call_global(sp, rtpath("Argument"), ~[s])
+ }
+ }
+ }
+
+ /// Actually builds the expression which the ifmt! block will be expanded
+ /// to
+ fn to_expr(&self, extra: @ast::Expr) -> @ast::Expr {
+ let mut lets = ~[];
+ let mut locals = ~[];
+ let mut names = vec::from_fn(self.name_positions.len(), |_| None);
+
+ // First, declare all of our methods that are statics
+ for &method in self.method_statics.iter() {
+ let decl = respan(self.fmtsp, ast::DeclItem(method));
+ lets.push(@respan(self.fmtsp,
+ ast::StmtDecl(@decl, ast::DUMMY_NODE_ID)));
+ }
+
+ // Next, build up the static array which will become our precompiled
+ // format "string"
+ let fmt = self.ecx.expr_vec(self.fmtsp, self.pieces.clone());
+ let piece_ty = self.ecx.ty_path(self.ecx.path_all(
+ self.fmtsp,
+ true, ~[
+ self.ecx.ident_of("std"),
+ self.ecx.ident_of("fmt"),
+ self.ecx.ident_of("rt"),
+ self.ecx.ident_of("Piece"),
+ ],
+ Some(self.ecx.lifetime(self.fmtsp, self.ecx.ident_of("static"))),
+ ~[]
+ ), None);
+ let ty = ast::ty_fixed_length_vec(
+ self.ecx.ty_mt(piece_ty.clone(), ast::MutImmutable),
+ self.ecx.expr_uint(self.fmtsp, self.pieces.len())
+ );
+ let ty = self.ecx.ty(self.fmtsp, ty);
+ let st = ast::item_static(ty, ast::MutImmutable, fmt);
+ let static_name = self.ecx.ident_of("__static_fmtstr");
+ // see above comment for `address_insignificant` and why we do it
+ let unnamed = self.ecx.meta_word(self.fmtsp, @"address_insignificant");
+ let unnamed = self.ecx.attribute(self.fmtsp, unnamed);
+ let item = self.ecx.item(self.fmtsp, static_name, ~[unnamed], st);
+ let decl = respan(self.fmtsp, ast::DeclItem(item));
+ lets.push(@respan(self.fmtsp, ast::StmtDecl(@decl, ast::DUMMY_NODE_ID)));
+
+ // Right now there is a bug such that for the expression:
+ // foo(bar(&1))
+ // the lifetime of `1` doesn't outlast the call to `bar`, so it's not
+ // vald for the call to `foo`. To work around this all arguments to the
+ // fmt! string are shoved into locals. Furthermore, we shove the address
+ // of each variable because we don't want to move out of the arguments
+ // passed to this function.
+ for (i, &e) in self.args.iter().enumerate() {
+ if self.arg_types[i].is_none() { loop } // error already generated
+
+ let name = self.ecx.ident_of(fmt!("__arg%u", i));
+ let e = self.ecx.expr_addr_of(e.span, e);
+ lets.push(self.ecx.stmt_let(e.span, false, name, e));
+ locals.push(self.format_arg(e.span, Left(i),
+ self.ecx.expr_ident(e.span, name)));
+ }
+ for (&name, &e) in self.names.iter() {
+ if !self.name_types.contains_key(&name) { loop }
+
+ let lname = self.ecx.ident_of(fmt!("__arg%s", name));
+ let e = self.ecx.expr_addr_of(e.span, e);
+ lets.push(self.ecx.stmt_let(e.span, false, lname, e));
+ names[*self.name_positions.get(&name)] =
+ Some(self.format_arg(e.span, Right(name),
+ self.ecx.expr_ident(e.span, lname)));
+ }
+
+ // Now create the fmt::Arguments struct with all our locals we created.
+ let args = names.move_iter().map(|a| a.unwrap());
+ let mut args = locals.move_iter().chain(args);
+ let fmt = self.ecx.expr_ident(self.fmtsp, static_name);
+ let args = self.ecx.expr_vec_slice(self.fmtsp, args.collect());
+ let result = self.ecx.expr_call_global(self.fmtsp, ~[
+ self.ecx.ident_of("std"),
+ self.ecx.ident_of("fmt"),
+ self.ecx.ident_of("Arguments"),
+ self.ecx.ident_of("new"),
+ ], ~[fmt, args]);
+
+ // We did all the work of making sure that the arguments
+ // structure is safe, so we can safely have an unsafe block.
+ let result = self.ecx.expr_block(ast::Block {
+ view_items: ~[],
+ stmts: ~[],
+ expr: Some(result),
+ id: ast::DUMMY_NODE_ID,
+ rules: ast::UnsafeBlock(ast::CompilerGenerated),
+ span: self.fmtsp,
+ });
+ let resname = self.ecx.ident_of("__args");
+ lets.push(self.ecx.stmt_let(self.fmtsp, false, resname, result));
+ let res = self.ecx.expr_ident(self.fmtsp, resname);
+ let result = self.ecx.expr_call(extra.span, extra, ~[
+ self.ecx.expr_addr_of(extra.span, res)]);
+ self.ecx.expr_block(self.ecx.block(self.fmtsp, lets,
+ Some(result)))
+ }
+
+ fn format_arg(&self, sp: Span, argno: Either<uint, @str>,
+ arg: @ast::Expr) -> @ast::Expr {
+ let ty = match argno {
+ Left(i) => self.arg_types[i].unwrap(),
+ Right(s) => *self.name_types.get(&s)
+ };
+
+ let fmt_trait = match ty {
+ Unknown => "Default",
+ Known(tyname) => {
+ match tyname.as_slice() {
+ "?" => "Poly",
+ "b" => "Bool",
+ "c" => "Char",
+ "d" | "i" => "Signed",
+ "f" => "Float",
+ "o" => "Octal",
+ "p" => "Pointer",
+ "s" => "String",
+ "t" => "Binary",
+ "u" => "Unsigned",
+ "x" => "LowerHex",
+ "X" => "UpperHex",
+ _ => {
+ self.ecx.span_err(sp, fmt!("unknown format trait \
+ `%s`", tyname));
+ "Dummy"
+ }
+ }
+ }
+ String => {
+ return self.ecx.expr_call_global(sp, ~[
+ self.ecx.ident_of("std"),
+ self.ecx.ident_of("fmt"),
+ self.ecx.ident_of("argumentstr"),
+ ], ~[arg])
+ }
+ Unsigned => {
+ return self.ecx.expr_call_global(sp, ~[
+ self.ecx.ident_of("std"),
+ self.ecx.ident_of("fmt"),
+ self.ecx.ident_of("argumentuint"),
+ ], ~[arg])
+ }
+ };
+
+ let format_fn = self.ecx.path_global(sp, ~[
+ self.ecx.ident_of("std"),
+ self.ecx.ident_of("fmt"),
+ self.ecx.ident_of(fmt_trait),
+ self.ecx.ident_of("fmt"),
+ ]);
+ self.ecx.expr_call_global(sp, ~[
+ self.ecx.ident_of("std"),
+ self.ecx.ident_of("fmt"),
+ self.ecx.ident_of("argument"),
+ ], ~[self.ecx.expr_path(format_fn), arg])
+ }
+}
+
+pub fn expand_args(ecx: @ExtCtxt, sp: Span,
+ tts: &[ast::token_tree]) -> base::MacResult {
+ let mut cx = Context {
+ ecx: ecx,
+ args: ~[],
+ arg_types: ~[],
+ names: HashMap::new(),
+ name_positions: HashMap::new(),
+ name_types: HashMap::new(),
+ nest_level: 0,
+ next_arg: 0,
+ pieces: ~[],
+ method_statics: ~[],
+ fmtsp: sp,
+ };
+ let (extra, efmt) = match cx.parse_args(sp, tts) {
+ (extra, Some(e)) => (extra, e),
+ (_, None) => { return MRExpr(ecx.expr_uint(sp, 2)); }
+ };
+ cx.fmtsp = efmt.span;
+ let fmt = expr_to_str(ecx, efmt,
+ "format argument must be a string literal.");
+
+ let mut err = false;
+ do parse::parse_error::cond.trap(|m| {
+ if !err {
+ err = true;
+ ecx.span_err(efmt.span, m);
+ }
+ }).inside {
+ for piece in parse::Parser::new(fmt) {
+ if !err {
+ cx.verify_piece(&piece);
+ let piece = cx.trans_piece(&piece);
+ cx.pieces.push(piece);
+ }
+ }
+ }
+ if err { return MRExpr(efmt) }
+
+ // Make sure that all arguments were used and all arguments have types.
+ for (i, ty) in cx.arg_types.iter().enumerate() {
+ if ty.is_none() {
+ ecx.span_err(cx.args[i].span, "argument never used");
+ }
+ }
+ for (name, e) in cx.names.iter() {
+ if !cx.name_types.contains_key(name) {
+ ecx.span_err(e.span, "named argument never used");
+ }
+ }
+
+ MRExpr(cx.to_expr(extra))
+}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use ast;
-use codemap::{Span, respan};
-use ext::base::*;
-use ext::base;
-use ext::build::AstBuilder;
-use rsparse = parse;
-use parse::token;
-
-use std::fmt::parse;
-use std::hashmap::{HashMap, HashSet};
-use std::vec;
-
-#[deriving(Eq)]
-enum ArgumentType {
- Unknown,
- Known(@str),
- Unsigned,
- String,
-}
-
-struct Context {
- ecx: @ExtCtxt,
- fmtsp: Span,
-
- // Parsed argument expressions and the types that we've found so far for
- // them.
- args: ~[@ast::Expr],
- arg_types: ~[Option<ArgumentType>],
- // Parsed named expressions and the types that we've found for them so far
- names: HashMap<@str, @ast::Expr>,
- name_types: HashMap<@str, ArgumentType>,
-
- // Collection of the compiled `rt::Piece` structures
- pieces: ~[@ast::Expr],
- name_positions: HashMap<@str, uint>,
- method_statics: ~[@ast::item],
-
- // Updated as arguments are consumed or methods are entered
- nest_level: uint,
- next_arg: uint,
-}
-
-impl Context {
- /// Parses the arguments from the given list of tokens, returning None if
- /// there's a parse error so we can continue parsing other fmt! expressions.
- fn parse_args(&mut self, sp: Span,
- leading_expr: bool,
- tts: &[ast::token_tree]) -> (Option<@ast::Expr>,
- Option<@ast::Expr>) {
- let p = rsparse::new_parser_from_tts(self.ecx.parse_sess(),
- self.ecx.cfg(),
- tts.to_owned());
- // If we want a leading expression (for ifmtf), parse it here
- let extra = if leading_expr {
- let e = Some(p.parse_expr());
- if !p.eat(&token::COMMA) {
- self.ecx.span_err(sp, "expected token: `,`");
- return (e, None);
- }
- e
- } else { None };
-
- if *p.token == token::EOF {
- self.ecx.span_err(sp, "requires at least a format string argument");
- return (extra, None);
- }
- let fmtstr = p.parse_expr();
- let mut named = false;
- while *p.token != token::EOF {
- if !p.eat(&token::COMMA) {
- self.ecx.span_err(sp, "expected token: `,`");
- return (extra, None);
- }
- if named || (token::is_ident(p.token) &&
- p.look_ahead(1, |t| *t == token::EQ)) {
- named = true;
- let ident = match *p.token {
- token::IDENT(i, _) => {
- p.bump();
- i
- }
- _ if named => {
- self.ecx.span_err(*p.span,
- "expected ident, positional arguments \
- cannot follow named arguments");
- return (extra, None);
- }
- _ => {
- self.ecx.span_err(*p.span,
- fmt!("expected ident for named \
- argument, but found `%s`",
- p.this_token_to_str()));
- return (extra, None);
- }
- };
- let name = self.ecx.str_of(ident);
- p.expect(&token::EQ);
- let e = p.parse_expr();
- match self.names.find(&name) {
- None => {}
- Some(prev) => {
- self.ecx.span_err(e.span, fmt!("duplicate argument \
- named `%s`", name));
- self.ecx.parse_sess.span_diagnostic.span_note(
- prev.span, "previously here");
- loop
- }
- }
- self.names.insert(name, e);
- } else {
- self.args.push(p.parse_expr());
- self.arg_types.push(None);
- }
- }
- return (extra, Some(fmtstr));
- }
-
- /// Verifies one piece of a parse string. All errors are not emitted as
- /// fatal so we can continue giving errors about this and possibly other
- /// format strings.
- fn verify_piece(&mut self, p: &parse::Piece) {
- match *p {
- parse::String(*) => {}
- parse::CurrentArgument => {
- if self.nest_level == 0 {
- self.ecx.span_err(self.fmtsp,
- "`#` reference used with nothing to \
- reference back to");
- }
- }
- parse::Argument(ref arg) => {
- // width/precision first, if they have implicit positional
- // parameters it makes more sense to consume them first.
- self.verify_count(arg.format.width);
- self.verify_count(arg.format.precision);
-
- // argument second, if it's an implicit positional parameter
- // it's written second, so it should come after width/precision.
- let pos = match arg.position {
- parse::ArgumentNext => {
- let i = self.next_arg;
- if self.check_positional_ok() {
- self.next_arg += 1;
- }
- Left(i)
- }
- parse::ArgumentIs(i) => Left(i),
- parse::ArgumentNamed(s) => Right(s.to_managed()),
- };
- let ty = if arg.format.ty == "" {
- Unknown
- } else { Known(arg.format.ty.to_managed()) };
- self.verify_arg_type(pos, ty);
-
- // and finally the method being applied
- match arg.method {
- None => {}
- Some(ref method) => { self.verify_method(pos, *method); }
- }
- }
- }
- }
-
- fn verify_pieces(&mut self, pieces: &[parse::Piece]) {
- for piece in pieces.iter() {
- self.verify_piece(piece);
- }
- }
-
- fn verify_count(&mut self, c: parse::Count) {
- match c {
- parse::CountImplied | parse::CountIs(*) => {}
- parse::CountIsParam(i) => {
- self.verify_arg_type(Left(i), Unsigned);
- }
- parse::CountIsNextParam => {
- if self.check_positional_ok() {
- self.verify_arg_type(Left(self.next_arg), Unsigned);
- self.next_arg += 1;
- }
- }
- }
- }
-
- fn check_positional_ok(&mut self) -> bool {
- if self.nest_level != 0 {
- self.ecx.span_err(self.fmtsp, "cannot use implicit positional \
- arguments nested inside methods");
- false
- } else {
- true
- }
- }
-
- fn verify_method(&mut self, pos: Either<uint, @str>, m: &parse::Method) {
- self.nest_level += 1;
- match *m {
- parse::Plural(_, ref arms, ref default) => {
- let mut seen_cases = HashSet::new();
- self.verify_arg_type(pos, Unsigned);
- for arm in arms.iter() {
- if !seen_cases.insert(arm.selector) {
- match arm.selector {
- Left(name) => {
- self.ecx.span_err(self.fmtsp,
- fmt!("duplicate selector \
- `%?`", name));
- }
- Right(idx) => {
- self.ecx.span_err(self.fmtsp,
- fmt!("duplicate selector \
- `=%u`", idx));
- }
- }
- }
- self.verify_pieces(arm.result);
- }
- self.verify_pieces(*default);
- }
- parse::Select(ref arms, ref default) => {
- self.verify_arg_type(pos, String);
- let mut seen_cases = HashSet::new();
- for arm in arms.iter() {
- if !seen_cases.insert(arm.selector) {
- self.ecx.span_err(self.fmtsp,
- fmt!("duplicate selector `%s`",
- arm.selector));
- } else if arm.selector == "" {
- self.ecx.span_err(self.fmtsp,
- "empty selector in `select`");
- }
- self.verify_pieces(arm.result);
- }
- self.verify_pieces(*default);
- }
- }
- self.nest_level -= 1;
- }
-
- fn verify_arg_type(&mut self, arg: Either<uint, @str>, ty: ArgumentType) {
- match arg {
- Left(arg) => {
- if arg < 0 || self.args.len() <= arg {
- let msg = fmt!("invalid reference to argument `%u` (there \
- are %u arguments)", arg, self.args.len());
- self.ecx.span_err(self.fmtsp, msg);
- return;
- }
- self.verify_same(self.args[arg].span, ty, self.arg_types[arg]);
- if ty != Unknown || self.arg_types[arg].is_none() {
- self.arg_types[arg] = Some(ty);
- }
- }
-
- Right(name) => {
- let span = match self.names.find(&name) {
- Some(e) => e.span,
- None => {
- let msg = fmt!("There is no argument named `%s`", name);
- self.ecx.span_err(self.fmtsp, msg);
- return;
- }
- };
- self.verify_same(span, ty,
- self.name_types.find(&name).map(|&x| *x));
- if ty != Unknown || !self.name_types.contains_key(&name) {
- self.name_types.insert(name, ty);
- }
- // Assign this named argument a slot in the arguments array if
- // it hasn't already been assigned a slot.
- if !self.name_positions.contains_key(&name) {
- let slot = self.name_positions.len();
- self.name_positions.insert(name, slot);
- }
- }
- }
- }
-
- /// When we're keeping track of the types that are declared for certain
- /// arguments, we assume that `None` means we haven't seen this argument
- /// yet, `Some(None)` means that we've seen the argument, but no format was
- /// specified, and `Some(Some(x))` means that the argument was declared to
- /// have type `x`.
- ///
- /// Obviously `Some(Some(x)) != Some(Some(y))`, but we consider it true
- /// that: `Some(None) == Some(Some(x))`
- fn verify_same(&self, sp: Span, ty: ArgumentType,
- before: Option<ArgumentType>) {
- if ty == Unknown { return }
- let cur = match before {
- Some(Unknown) | None => return,
- Some(t) => t,
- };
- if ty == cur { return }
- match (cur, ty) {
- (Known(cur), Known(ty)) => {
- self.ecx.span_err(sp,
- fmt!("argument redeclared with type `%s` when \
- it was previously `%s`", ty, cur));
- }
- (Known(cur), _) => {
- self.ecx.span_err(sp,
- fmt!("argument used to format with `%s` was \
- attempted to not be used for formatting",
- cur));
- }
- (_, Known(ty)) => {
- self.ecx.span_err(sp,
- fmt!("argument previously used as a format \
- argument attempted to be used as `%s`",
- ty));
- }
- (_, _) => {
- self.ecx.span_err(sp, "argument declared with multiple formats");
- }
- }
- }
-
- /// Translate a `parse::Piece` to a static `rt::Piece`
- fn trans_piece(&mut self, piece: &parse::Piece) -> @ast::Expr {
- let sp = self.fmtsp;
- let parsepath = |s: &str| {
- ~[self.ecx.ident_of("std"), self.ecx.ident_of("fmt"),
- self.ecx.ident_of("parse"), self.ecx.ident_of(s)]
- };
- let rtpath = |s: &str| {
- ~[self.ecx.ident_of("std"), self.ecx.ident_of("fmt"),
- self.ecx.ident_of("rt"), self.ecx.ident_of(s)]
- };
- let ctpath = |s: &str| {
- ~[self.ecx.ident_of("std"), self.ecx.ident_of("fmt"),
- self.ecx.ident_of("parse"), self.ecx.ident_of(s)]
- };
- let none = || {
- let p = self.ecx.path(sp, ~[self.ecx.ident_of("None")]);
- self.ecx.expr_path(p)
- };
- let some = |e: @ast::Expr| {
- self.ecx.expr_call_ident(sp, self.ecx.ident_of("Some"), ~[e])
- };
- let trans_count = |c: parse::Count| {
- match c {
- parse::CountIs(i) => {
- self.ecx.expr_call_global(sp, ctpath("CountIs"),
- ~[self.ecx.expr_uint(sp, i)])
- }
- parse::CountIsParam(i) => {
- self.ecx.expr_call_global(sp, ctpath("CountIsParam"),
- ~[self.ecx.expr_uint(sp, i)])
- }
- parse::CountImplied => {
- let path = self.ecx.path_global(sp, ctpath("CountImplied"));
- self.ecx.expr_path(path)
- }
- parse::CountIsNextParam => {
- let path = self.ecx.path_global(sp, ctpath("CountIsNextParam"));
- self.ecx.expr_path(path)
- }
- }
- };
- let trans_method = |method: &parse::Method| {
- let method = match *method {
- parse::Select(ref arms, ref default) => {
- let arms = arms.iter().map(|arm| {
- let p = self.ecx.path_global(sp, rtpath("SelectArm"));
- let result = arm.result.iter().map(|p| {
- self.trans_piece(p)
- }).collect();
- let s = arm.selector.to_managed();
- let selector = self.ecx.expr_str(sp, s);
- self.ecx.expr_struct(sp, p, ~[
- self.ecx.field_imm(sp,
- self.ecx.ident_of("selector"),
- selector),
- self.ecx.field_imm(sp, self.ecx.ident_of("result"),
- self.ecx.expr_vec_slice(sp, result)),
- ])
- }).collect();
- let default = default.iter().map(|p| {
- self.trans_piece(p)
- }).collect();
- self.ecx.expr_call_global(sp, rtpath("Select"), ~[
- self.ecx.expr_vec_slice(sp, arms),
- self.ecx.expr_vec_slice(sp, default),
- ])
- }
- parse::Plural(offset, ref arms, ref default) => {
- let offset = match offset {
- Some(i) => { some(self.ecx.expr_uint(sp, i)) }
- None => { none() }
- };
- let arms = arms.iter().map(|arm| {
- let p = self.ecx.path_global(sp, rtpath("PluralArm"));
- let result = arm.result.iter().map(|p| {
- self.trans_piece(p)
- }).collect();
- let (lr, selarg) = match arm.selector {
- Left(t) => {
- let p = ctpath(fmt!("%?", t));
- let p = self.ecx.path_global(sp, p);
- (self.ecx.ident_of("Left"),
- self.ecx.expr_path(p))
- }
- Right(i) => {
- (self.ecx.ident_of("Right"),
- self.ecx.expr_uint(sp, i))
- }
- };
- let selector = self.ecx.expr_call_ident(sp,
- lr, ~[selarg]);
- self.ecx.expr_struct(sp, p, ~[
- self.ecx.field_imm(sp,
- self.ecx.ident_of("selector"),
- selector),
- self.ecx.field_imm(sp, self.ecx.ident_of("result"),
- self.ecx.expr_vec_slice(sp, result)),
- ])
- }).collect();
- let default = default.iter().map(|p| {
- self.trans_piece(p)
- }).collect();
- self.ecx.expr_call_global(sp, rtpath("Plural"), ~[
- offset,
- self.ecx.expr_vec_slice(sp, arms),
- self.ecx.expr_vec_slice(sp, default),
- ])
- }
- };
- let life = self.ecx.lifetime(sp, self.ecx.ident_of("static"));
- let ty = self.ecx.ty_path(self.ecx.path_all(
- sp,
- true,
- rtpath("Method"),
- Some(life),
- ~[]
- ), None);
- let st = ast::item_static(ty, ast::MutImmutable, method);
- let static_name = self.ecx.ident_of(fmt!("__static_method_%u",
- self.method_statics.len()));
- // Flag these statics as `address_insignificant` so LLVM can
- // merge duplicate globals as much as possible (which we're
- // generating a whole lot of).
- let unnamed = self.ecx.meta_word(self.fmtsp, @"address_insignificant");
- let unnamed = self.ecx.attribute(self.fmtsp, unnamed);
- let item = self.ecx.item(sp, static_name, ~[unnamed], st);
- self.method_statics.push(item);
- self.ecx.expr_ident(sp, static_name)
- };
-
- match *piece {
- parse::String(s) => {
- self.ecx.expr_call_global(sp, rtpath("String"),
- ~[self.ecx.expr_str(sp, s.to_managed())])
- }
- parse::CurrentArgument => {
- let nil = self.ecx.expr_lit(sp, ast::lit_nil);
- self.ecx.expr_call_global(sp, rtpath("CurrentArgument"), ~[nil])
- }
- parse::Argument(ref arg) => {
- // Translate the position
- let pos = match arg.position {
- // These two have a direct mapping
- parse::ArgumentNext => {
- let path = self.ecx.path_global(sp,
- rtpath("ArgumentNext"));
- self.ecx.expr_path(path)
- }
- parse::ArgumentIs(i) => {
- self.ecx.expr_call_global(sp, rtpath("ArgumentIs"),
- ~[self.ecx.expr_uint(sp, i)])
- }
- // Named arguments are converted to positional arguments at
- // the end of the list of arguments
- parse::ArgumentNamed(n) => {
- let n = n.to_managed();
- let i = match self.name_positions.find_copy(&n) {
- Some(i) => i,
- None => 0, // error already emitted elsewhere
- };
- let i = i + self.args.len();
- self.ecx.expr_call_global(sp, rtpath("ArgumentIs"),
- ~[self.ecx.expr_uint(sp, i)])
- }
- };
-
- // Translate the format
- let fill = match arg.format.fill { Some(c) => c, None => ' ' };
- let fill = self.ecx.expr_lit(sp, ast::lit_char(fill as u32));
- let align = match arg.format.align {
- parse::AlignLeft => {
- self.ecx.path_global(sp, parsepath("AlignLeft"))
- }
- parse::AlignRight => {
- self.ecx.path_global(sp, parsepath("AlignRight"))
- }
- parse::AlignUnknown => {
- self.ecx.path_global(sp, parsepath("AlignUnknown"))
- }
- };
- let align = self.ecx.expr_path(align);
- let flags = self.ecx.expr_uint(sp, arg.format.flags);
- let prec = trans_count(arg.format.precision);
- let width = trans_count(arg.format.width);
- let path = self.ecx.path_global(sp, rtpath("FormatSpec"));
- let fmt = self.ecx.expr_struct(sp, path, ~[
- self.ecx.field_imm(sp, self.ecx.ident_of("fill"), fill),
- self.ecx.field_imm(sp, self.ecx.ident_of("align"), align),
- self.ecx.field_imm(sp, self.ecx.ident_of("flags"), flags),
- self.ecx.field_imm(sp, self.ecx.ident_of("precision"), prec),
- self.ecx.field_imm(sp, self.ecx.ident_of("width"), width),
- ]);
-
- // Translate the method (if any)
- let method = match arg.method {
- None => { none() }
- Some(ref m) => {
- let m = trans_method(*m);
- some(self.ecx.expr_addr_of(sp, m))
- }
- };
- let path = self.ecx.path_global(sp, rtpath("Argument"));
- let s = self.ecx.expr_struct(sp, path, ~[
- self.ecx.field_imm(sp, self.ecx.ident_of("position"), pos),
- self.ecx.field_imm(sp, self.ecx.ident_of("format"), fmt),
- self.ecx.field_imm(sp, self.ecx.ident_of("method"), method),
- ]);
- self.ecx.expr_call_global(sp, rtpath("Argument"), ~[s])
- }
- }
- }
-
- /// Actually builds the expression which the ifmt! block will be expanded
- /// to
- fn to_expr(&self, extra: Option<@ast::Expr>, f: &str) -> @ast::Expr {
- let mut lets = ~[];
- let mut locals = ~[];
- let mut names = vec::from_fn(self.name_positions.len(), |_| None);
-
- // First, declare all of our methods that are statics
- for &method in self.method_statics.iter() {
- let decl = respan(self.fmtsp, ast::DeclItem(method));
- lets.push(@respan(self.fmtsp,
- ast::StmtDecl(@decl, ast::DUMMY_NODE_ID)));
- }
-
- // Next, build up the static array which will become our precompiled
- // format "string"
- let fmt = self.ecx.expr_vec(self.fmtsp, self.pieces.clone());
- let ty = ast::ty_fixed_length_vec(
- self.ecx.ty_mt(
- self.ecx.ty_path(self.ecx.path_all(
- self.fmtsp,
- true, ~[
- self.ecx.ident_of("std"),
- self.ecx.ident_of("fmt"),
- self.ecx.ident_of("rt"),
- self.ecx.ident_of("Piece"),
- ],
- Some(self.ecx.lifetime(self.fmtsp, self.ecx.ident_of("static"))),
- ~[]
- ), None),
- ast::MutImmutable
- ),
- self.ecx.expr_uint(self.fmtsp, self.pieces.len())
- );
- let ty = self.ecx.ty(self.fmtsp, ty);
- let st = ast::item_static(ty, ast::MutImmutable, fmt);
- let static_name = self.ecx.ident_of("__static_fmtstr");
- // see above comment for `address_insignificant` and why we do it
- let unnamed = self.ecx.meta_word(self.fmtsp, @"address_insignificant");
- let unnamed = self.ecx.attribute(self.fmtsp, unnamed);
- let item = self.ecx.item(self.fmtsp, static_name, ~[unnamed], st);
- let decl = respan(self.fmtsp, ast::DeclItem(item));
- lets.push(@respan(self.fmtsp, ast::StmtDecl(@decl, ast::DUMMY_NODE_ID)));
-
- // Right now there is a bug such that for the expression:
- // foo(bar(&1))
- // the lifetime of `1` doesn't outlast the call to `bar`, so it's not
- // vald for the call to `foo`. To work around this all arguments to the
- // fmt! string are shoved into locals. Furthermore, we shove the address
- // of each variable because we don't want to move out of the arguments
- // passed to this function.
- for (i, &e) in self.args.iter().enumerate() {
- if self.arg_types[i].is_none() { loop } // error already generated
-
- let name = self.ecx.ident_of(fmt!("__arg%u", i));
- let e = self.ecx.expr_addr_of(e.span, e);
- lets.push(self.ecx.stmt_let(e.span, false, name, e));
- locals.push(self.format_arg(e.span, Left(i), name));
- }
- for (&name, &e) in self.names.iter() {
- if !self.name_types.contains_key(&name) { loop }
-
- let lname = self.ecx.ident_of(fmt!("__arg%s", name));
- let e = self.ecx.expr_addr_of(e.span, e);
- lets.push(self.ecx.stmt_let(e.span, false, lname, e));
- names[*self.name_positions.get(&name)] =
- Some(self.format_arg(e.span, Right(name), lname));
- }
-
- let args = names.move_iter().map(|a| a.unwrap());
- let mut args = locals.move_iter().chain(args);
-
- let mut fmt_args = match extra {
- Some(e) => ~[e], None => ~[]
- };
- fmt_args.push(self.ecx.expr_ident(self.fmtsp, static_name));
- fmt_args.push(self.ecx.expr_vec(self.fmtsp, args.collect()));
-
- // Next, build up the actual call to the {s,f}printf function.
- let result = self.ecx.expr_call_global(self.fmtsp, ~[
- self.ecx.ident_of("std"),
- self.ecx.ident_of("fmt"),
- self.ecx.ident_of(f),
- ], fmt_args);
-
- // sprintf is unsafe, but we just went through a lot of work to
- // validate that our call is save, so inject the unsafe block for the
- // user.
- let result = self.ecx.expr_block(ast::Block {
- view_items: ~[],
- stmts: ~[],
- expr: Some(result),
- id: ast::DUMMY_NODE_ID,
- rules: ast::UnsafeBlock,
- span: self.fmtsp,
- });
-
- self.ecx.expr_block(self.ecx.block(self.fmtsp, lets, Some(result)))
- }
-
- fn format_arg(&self, sp: Span, arg: Either<uint, @str>,
- ident: ast::Ident) -> @ast::Expr {
- let ty = match arg {
- Left(i) => self.arg_types[i].unwrap(),
- Right(s) => *self.name_types.get(&s)
- };
-
- let argptr = self.ecx.expr_ident(sp, ident);
- let fmt_trait = match ty {
- Unknown => "Default",
- Known(tyname) => {
- match tyname.as_slice() {
- "?" => "Poly",
- "b" => "Bool",
- "c" => "Char",
- "d" | "i" => "Signed",
- "f" => "Float",
- "o" => "Octal",
- "p" => "Pointer",
- "s" => "String",
- "t" => "Binary",
- "u" => "Unsigned",
- "x" => "LowerHex",
- "X" => "UpperHex",
- _ => {
- self.ecx.span_err(sp, fmt!("unknown format trait \
- `%s`", tyname));
- "Dummy"
- }
- }
- }
- String => {
- return self.ecx.expr_call_global(sp, ~[
- self.ecx.ident_of("std"),
- self.ecx.ident_of("fmt"),
- self.ecx.ident_of("argumentstr"),
- ], ~[argptr])
- }
- Unsigned => {
- return self.ecx.expr_call_global(sp, ~[
- self.ecx.ident_of("std"),
- self.ecx.ident_of("fmt"),
- self.ecx.ident_of("argumentuint"),
- ], ~[argptr])
- }
- };
-
- let format_fn = self.ecx.path_global(sp, ~[
- self.ecx.ident_of("std"),
- self.ecx.ident_of("fmt"),
- self.ecx.ident_of(fmt_trait),
- self.ecx.ident_of("fmt"),
- ]);
- self.ecx.expr_call_global(sp, ~[
- self.ecx.ident_of("std"),
- self.ecx.ident_of("fmt"),
- self.ecx.ident_of("argument"),
- ], ~[self.ecx.expr_path(format_fn), argptr])
- }
-}
-
-pub fn expand_format(ecx: @ExtCtxt, sp: Span,
- tts: &[ast::token_tree]) -> base::MacResult {
- expand_ifmt(ecx, sp, tts, false, false, "format")
-}
-
-pub fn expand_write(ecx: @ExtCtxt, sp: Span,
- tts: &[ast::token_tree]) -> base::MacResult {
- expand_ifmt(ecx, sp, tts, true, false, "write")
-}
-
-pub fn expand_writeln(ecx: @ExtCtxt, sp: Span,
- tts: &[ast::token_tree]) -> base::MacResult {
- expand_ifmt(ecx, sp, tts, true, true, "write")
-}
-
-fn expand_ifmt(ecx: @ExtCtxt, sp: Span, tts: &[ast::token_tree],
- leading_arg: bool, append_newline: bool,
- function: &str) -> base::MacResult {
- let mut cx = Context {
- ecx: ecx,
- args: ~[],
- arg_types: ~[],
- names: HashMap::new(),
- name_positions: HashMap::new(),
- name_types: HashMap::new(),
- nest_level: 0,
- next_arg: 0,
- pieces: ~[],
- method_statics: ~[],
- fmtsp: sp,
- };
- let (extra, efmt) = match cx.parse_args(sp, leading_arg, tts) {
- (extra, Some(e)) => (extra, e),
- (_, None) => { return MRExpr(ecx.expr_uint(sp, 2)); }
- };
- cx.fmtsp = efmt.span;
- let fmt = expr_to_str(ecx, efmt,
- "format argument must be a string literal.");
- let fmt = if append_newline { fmt + "\n" } else { fmt.to_owned() };
-
- let mut err = false;
- do parse::parse_error::cond.trap(|m| {
- if !err {
- err = true;
- ecx.span_err(efmt.span, m);
- }
- }).inside {
- for piece in parse::Parser::new(fmt) {
- if !err {
- cx.verify_piece(&piece);
- let piece = cx.trans_piece(&piece);
- cx.pieces.push(piece);
- }
- }
- }
- if err { return MRExpr(efmt) }
-
- // Make sure that all arguments were used and all arguments have types.
- for (i, ty) in cx.arg_types.iter().enumerate() {
- if ty.is_none() {
- ecx.span_err(cx.args[i].span, "argument never used");
- }
- }
- for (name, e) in cx.names.iter() {
- if !cx.name_types.contains_key(name) {
- ecx.span_err(e.span, "named argument never used");
- }
- }
-
- MRExpr(cx.to_expr(extra, function))
-}
ExprBreak(ref opt_ident) => {
// FIXME #6993: add fold_name to fold.... then cut out the
// bogus Name->Ident->Name conversion.
- ExprBreak(opt_ident.map_move(|x| fld.fold_ident(Ident::new(x)).name))
+ ExprBreak(opt_ident.map_move(|x| {
+ // FIXME #9129: Assigning the new ident to a temporary to work around codegen bug
+ let newx = Ident::new(x);
+ fld.fold_ident(newx).name
+ }))
}
ExprAgain(ref opt_ident) => {
// FIXME #6993: add fold_name to fold....
- ExprAgain(opt_ident.map_move(|x| fld.fold_ident(Ident::new(x)).name))
+ ExprAgain(opt_ident.map_move(|x| {
+ // FIXME #9129: Assigning the new ident to a temporary to work around codegen bug
+ let newx = Ident::new(x);
+ fld.fold_ident(newx).name
+ }))
}
ExprRet(ref e) => {
ExprRet(e.map_move(|x| fld.fold_expr(x)))
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use abi::AbiSet;
-use ast::*;
-use ast;
-use codemap::Span;
-use parse;
-use opt_vec;
-use opt_vec::OptVec;
-
-// Context-passing AST walker. Each overridden visit method has full control
-// over what happens with its node, it can do its own traversal of the node's
-// children (potentially passing in different contexts to each), call
-// visit::visit_* to apply the default traversal algorithm (again, it can
-// override the context), or prevent deeper traversal by doing nothing.
-//
-// Note: it is an important invariant that the default visitor walks the body
-// of a function in "execution order" (more concretely, reverse post-order
-// with respect to the CFG implied by the AST), meaning that if AST node A may
-// execute before AST node B, then A is visited first. The borrow checker in
-// particular relies on this property.
-
-// Our typesystem doesn't do circular types, so the visitor record can not
-// hold functions that take visitors. A vt enum is used to break the cycle.
-pub enum vt<E> { mk_vt(visitor<E>), }
-
-pub enum fn_kind<'self> {
- // fn foo() or extern "Abi" fn foo()
- fk_item_fn(Ident, &'self Generics, purity, AbiSet),
-
- // fn foo(&self)
- fk_method(Ident, &'self Generics, &'self method),
-
- // @fn(x, y) { ... }
- fk_anon(ast::Sigil),
-
- // |x, y| ...
- fk_fn_block,
-}
-
-pub fn name_of_fn(fk: &fn_kind) -> Ident {
- match *fk {
- fk_item_fn(name, _, _, _) | fk_method(name, _, _) => {
- name
- }
- fk_anon(*) | fk_fn_block(*) => parse::token::special_idents::anon,
- }
-}
-
-pub fn generics_of_fn(fk: &fn_kind) -> Generics {
- match *fk {
- fk_item_fn(_, generics, _, _) |
- fk_method(_, generics, _) => {
- (*generics).clone()
- }
- fk_anon(*) | fk_fn_block(*) => {
- Generics {
- lifetimes: opt_vec::Empty,
- ty_params: opt_vec::Empty,
- }
- }
- }
-}
-
-pub struct Visitor<E> {
- visit_mod: @fn(&_mod, Span, NodeId, (E, vt<E>)),
- visit_view_item: @fn(&view_item, (E, vt<E>)),
- visit_foreign_item: @fn(@foreign_item, (E, vt<E>)),
- visit_item: @fn(@item, (E, vt<E>)),
- visit_local: @fn(@Local, (E, vt<E>)),
- visit_block: @fn(&Block, (E, vt<E>)),
- visit_stmt: @fn(@Stmt, (E, vt<E>)),
- visit_arm: @fn(&Arm, (E, vt<E>)),
- visit_pat: @fn(@Pat, (E, vt<E>)),
- visit_decl: @fn(@Decl, (E, vt<E>)),
- visit_expr: @fn(@Expr, (E, vt<E>)),
- visit_expr_post: @fn(@Expr, (E, vt<E>)),
- visit_ty: @fn(&Ty, (E, vt<E>)),
- visit_generics: @fn(&Generics, (E, vt<E>)),
- visit_fn: @fn(&fn_kind, &fn_decl, &Block, Span, NodeId, (E, vt<E>)),
- visit_ty_method: @fn(&TypeMethod, (E, vt<E>)),
- visit_trait_method: @fn(&trait_method, (E, vt<E>)),
- visit_struct_def: @fn(@struct_def, Ident, &Generics, NodeId, (E, vt<E>)),
- visit_struct_field: @fn(@struct_field, (E, vt<E>)),
-}
-
-pub type visitor<E> = @Visitor<E>;
-
-pub fn default_visitor<E:Clone>() -> visitor<E> {
- return @Visitor {
- visit_mod: |a,b,c,d|visit_mod::<E>(a, b, c, d),
- visit_view_item: |a,b|visit_view_item::<E>(a, b),
- visit_foreign_item: |a,b|visit_foreign_item::<E>(a, b),
- visit_item: |a,b|visit_item::<E>(a, b),
- visit_local: |a,b|visit_local::<E>(a, b),
- visit_block: |a,b|visit_block::<E>(a, b),
- visit_stmt: |a,b|visit_stmt::<E>(a, b),
- visit_arm: |a,b|visit_arm::<E>(a, b),
- visit_pat: |a,b|visit_pat::<E>(a, b),
- visit_decl: |a,b|visit_decl::<E>(a, b),
- visit_expr: |a,b|visit_expr::<E>(a, b),
- visit_expr_post: |_a,_b| (),
- visit_ty: |a,b|skip_ty::<E>(a, b),
- visit_generics: |a,b|visit_generics::<E>(a, b),
- visit_fn: |a,b,c,d,e,f|visit_fn::<E>(a, b, c, d, e, f),
- visit_ty_method: |a,b|visit_ty_method::<E>(a, b),
- visit_trait_method: |a,b|visit_trait_method::<E>(a, b),
- visit_struct_def: |a,b,c,d,e|visit_struct_def::<E>(a, b, c, d, e),
- visit_struct_field: |a,b|visit_struct_field::<E>(a, b),
- };
-}
-
-pub fn visit_crate<E:Clone>(c: &Crate, (e, v): (E, vt<E>)) {
- (v.visit_mod)(&c.module, c.span, CRATE_NODE_ID, (e, v));
-}
-
-pub fn visit_mod<E:Clone>(m: &_mod,
- _sp: Span,
- _id: NodeId,
- (e, v): (E, vt<E>)) {
- for vi in m.view_items.iter() {
- (v.visit_view_item)(vi, (e.clone(), v));
- }
- for i in m.items.iter() {
- (v.visit_item)(*i, (e.clone(), v));
- }
-}
-
-pub fn visit_view_item<E>(_vi: &view_item, (_e, _v): (E, vt<E>)) { }
-
-pub fn visit_local<E:Clone>(loc: &Local, (e, v): (E, vt<E>)) {
- (v.visit_pat)(loc.pat, (e.clone(), v));
- (v.visit_ty)(&loc.ty, (e.clone(), v));
- match loc.init {
- None => (),
- Some(ex) => (v.visit_expr)(ex, (e, v))
- }
-}
-
-fn visit_trait_ref<E:Clone>(tref: &ast::trait_ref, (e, v): (E, vt<E>)) {
- visit_path(&tref.path, (e, v));
-}
-
-pub fn visit_item<E:Clone>(i: &item, (e, v): (E, vt<E>)) {
- match i.node {
- item_static(ref t, _, ex) => {
- (v.visit_ty)(t, (e.clone(), v));
- (v.visit_expr)(ex, (e.clone(), v));
- }
- item_fn(ref decl, purity, abi, ref generics, ref body) => {
- (v.visit_fn)(
- &fk_item_fn(
- i.ident,
- generics,
- purity,
- abi
- ),
- decl,
- body,
- i.span,
- i.id,
- (e,
- v)
- );
- }
- item_mod(ref m) => (v.visit_mod)(m, i.span, i.id, (e, v)),
- item_foreign_mod(ref nm) => {
- for vi in nm.view_items.iter() {
- (v.visit_view_item)(vi, (e.clone(), v));
- }
- for ni in nm.items.iter() {
- (v.visit_foreign_item)(*ni, (e.clone(), v));
- }
- }
- item_ty(ref t, ref tps) => {
- (v.visit_ty)(t, (e.clone(), v));
- (v.visit_generics)(tps, (e, v));
- }
- item_enum(ref enum_definition, ref tps) => {
- (v.visit_generics)(tps, (e.clone(), v));
- visit_enum_def(
- enum_definition,
- tps,
- (e, v)
- );
- }
- item_impl(ref tps, ref traits, ref ty, ref methods) => {
- (v.visit_generics)(tps, (e.clone(), v));
- for p in traits.iter() {
- visit_trait_ref(p, (e.clone(), v));
- }
- (v.visit_ty)(ty, (e.clone(), v));
- for m in methods.iter() {
- visit_method_helper(*m, (e.clone(), v))
- }
- }
- item_struct(struct_def, ref generics) => {
- (v.visit_generics)(generics, (e.clone(), v));
- (v.visit_struct_def)(struct_def, i.ident, generics, i.id, (e, v));
- }
- item_trait(ref generics, ref traits, ref methods) => {
- (v.visit_generics)(generics, (e.clone(), v));
- for p in traits.iter() {
- visit_path(&p.path, (e.clone(), v));
- }
- for m in methods.iter() {
- (v.visit_trait_method)(m, (e.clone(), v));
- }
- }
- item_mac(ref m) => visit_mac(m, (e, v))
- }
-}
-
-pub fn visit_enum_def<E:Clone>(enum_definition: &ast::enum_def,
- tps: &Generics,
- (e, v): (E, vt<E>)) {
- for vr in enum_definition.variants.iter() {
- match vr.node.kind {
- tuple_variant_kind(ref variant_args) => {
- for va in variant_args.iter() {
- (v.visit_ty)(&va.ty, (e.clone(), v));
- }
- }
- struct_variant_kind(struct_def) => {
- (v.visit_struct_def)(struct_def, vr.node.name, tps,
- vr.node.id, (e.clone(), v));
- }
- }
- // Visit the disr expr if it exists
- for ex in vr.node.disr_expr.iter() {
- (v.visit_expr)(*ex, (e.clone(), v))
- }
- }
-}
-
-pub fn skip_ty<E>(_t: &Ty, (_e,_v): (E, vt<E>)) {}
-
-pub fn visit_ty<E:Clone>(t: &Ty, (e, v): (E, vt<E>)) {
- match t.node {
- ty_box(ref mt) | ty_uniq(ref mt) |
- ty_vec(ref mt) | ty_ptr(ref mt) | ty_rptr(_, ref mt) => {
- (v.visit_ty)(mt.ty, (e, v));
- },
- ty_tup(ref ts) => {
- for tt in ts.iter() {
- (v.visit_ty)(tt, (e.clone(), v));
- }
- },
- ty_closure(ref f) => {
- for a in f.decl.inputs.iter() {
- (v.visit_ty)(&a.ty, (e.clone(), v));
- }
- (v.visit_ty)(&f.decl.output, (e.clone(), v));
- do f.bounds.map |bounds| {
- visit_ty_param_bounds(bounds, (e.clone(), v));
- };
- },
- ty_bare_fn(ref f) => {
- for a in f.decl.inputs.iter() {
- (v.visit_ty)(&a.ty, (e.clone(), v));
- }
- (v.visit_ty)(&f.decl.output, (e, v));
- },
- ty_path(ref p, ref bounds, _) => {
- visit_path(p, (e.clone(), v));
- do bounds.map |bounds| {
- visit_ty_param_bounds(bounds, (e.clone(), v));
- };
- },
- ty_fixed_length_vec(ref mt, ex) => {
- (v.visit_ty)(mt.ty, (e.clone(), v));
- (v.visit_expr)(ex, (e.clone(), v));
- },
- ty_typeof(ex) => {
- (v.visit_expr)(ex, (e.clone(), v));
- }
- ty_nil | ty_bot | ty_mac(_) | ty_infer => ()
- }
-}
-
-pub fn visit_path<E:Clone>(p: &Path, (e, v): (E, vt<E>)) {
- for segment in p.segments.iter() {
- for typ in segment.types.iter() {
- (v.visit_ty)(typ, (e.clone(), v))
- }
- }
-}
-
-pub fn visit_pat<E:Clone>(p: &Pat, (e, v): (E, vt<E>)) {
- match p.node {
- PatEnum(ref path, ref children) => {
- visit_path(path, (e.clone(), v));
- for children in children.iter() {
- for child in children.iter() {
- (v.visit_pat)(*child, (e.clone(), v));
- }
- }
- }
- PatStruct(ref path, ref fields, _) => {
- visit_path(path, (e.clone(), v));
- for f in fields.iter() {
- (v.visit_pat)(f.pat, (e.clone(), v));
- }
- }
- PatTup(ref elts) => {
- for elt in elts.iter() {
- (v.visit_pat)(*elt, (e.clone(), v))
- }
- },
- PatBox(inner) | PatUniq(inner) | PatRegion(inner) => {
- (v.visit_pat)(inner, (e, v))
- },
- PatIdent(_, ref path, ref inner) => {
- visit_path(path, (e.clone(), v));
- for subpat in inner.iter() {
- (v.visit_pat)(*subpat, (e.clone(), v))
- }
- }
- PatLit(ex) => (v.visit_expr)(ex, (e, v)),
- PatRange(e1, e2) => {
- (v.visit_expr)(e1, (e.clone(), v));
- (v.visit_expr)(e2, (e, v));
- }
- PatWild => (),
- PatVec(ref before, ref slice, ref after) => {
- for elt in before.iter() {
- (v.visit_pat)(*elt, (e.clone(), v));
- }
- for elt in slice.iter() {
- (v.visit_pat)(*elt, (e.clone(), v));
- }
- for tail in after.iter() {
- (v.visit_pat)(*tail, (e.clone(), v));
- }
- }
- }
-}
-
-pub fn visit_foreign_item<E:Clone>(ni: &foreign_item, (e, v): (E, vt<E>)) {
- match ni.node {
- foreign_item_fn(ref fd, ref generics) => {
- visit_fn_decl(fd, (e.clone(), v));
- (v.visit_generics)(generics, (e, v));
- }
- foreign_item_static(ref t, _) => {
- (v.visit_ty)(t, (e, v));
- }
- }
-}
-
-pub fn visit_ty_param_bounds<E:Clone>(bounds: &OptVec<TyParamBound>,
- (e, v): (E, vt<E>)) {
- for bound in bounds.iter() {
- match *bound {
- TraitTyParamBound(ref ty) => visit_trait_ref(ty, (e.clone(), v)),
- RegionTyParamBound => {}
- }
- }
-}
-
-pub fn visit_generics<E:Clone>(generics: &Generics, (e, v): (E, vt<E>)) {
- for tp in generics.ty_params.iter() {
- visit_ty_param_bounds(&tp.bounds, (e.clone(), v));
- }
-}
-
-pub fn visit_fn_decl<E:Clone>(fd: &fn_decl, (e, v): (E, vt<E>)) {
- for a in fd.inputs.iter() {
- (v.visit_pat)(a.pat, (e.clone(), v));
- (v.visit_ty)(&a.ty, (e.clone(), v));
- }
- (v.visit_ty)(&fd.output, (e, v));
-}
-
-// Note: there is no visit_method() method in the visitor, instead override
-// visit_fn() and check for fk_method(). I named this visit_method_helper()
-// because it is not a default impl of any method, though I doubt that really
-// clarifies anything. - Niko
-pub fn visit_method_helper<E:Clone>(m: &method, (e, v): (E, vt<E>)) {
- (v.visit_fn)(&fk_method(m.ident, &m.generics, m),
- &m.decl,
- &m.body,
- m.span,
- m.id,
- (e, v));
-}
-
-pub fn visit_fn<E:Clone>(fk: &fn_kind,
- decl: &fn_decl,
- body: &Block,
- _sp: Span,
- _id: NodeId,
- (e, v): (E, vt<E>)) {
- visit_fn_decl(decl, (e.clone(), v));
- let generics = generics_of_fn(fk);
- (v.visit_generics)(&generics, (e.clone(), v));
- (v.visit_block)(body, (e, v));
-}
-
-pub fn visit_ty_method<E:Clone>(m: &TypeMethod, (e, v): (E, vt<E>)) {
- for a in m.decl.inputs.iter() {
- (v.visit_ty)(&a.ty, (e.clone(), v));
- }
- (v.visit_generics)(&m.generics, (e.clone(), v));
- (v.visit_ty)(&m.decl.output, (e, v));
-}
-
-pub fn visit_trait_method<E:Clone>(m: &trait_method, (e, v): (E, vt<E>)) {
- match *m {
- required(ref ty_m) => (v.visit_ty_method)(ty_m, (e, v)),
- provided(m) => visit_method_helper(m, (e, v))
- }
-}
-
-pub fn visit_struct_def<E:Clone>(
- sd: @struct_def,
- _nm: ast::Ident,
- _generics: &Generics,
- _id: NodeId,
- (e, v): (E, vt<E>)
-) {
- for f in sd.fields.iter() {
- (v.visit_struct_field)(*f, (e.clone(), v));
- }
-}
-
-pub fn visit_struct_field<E:Clone>(sf: &struct_field, (e, v): (E, vt<E>)) {
- (v.visit_ty)(&sf.node.ty, (e, v));
-}
-
-pub fn visit_block<E:Clone>(b: &Block, (e, v): (E, vt<E>)) {
- for vi in b.view_items.iter() {
- (v.visit_view_item)(vi, (e.clone(), v));
- }
- for s in b.stmts.iter() {
- (v.visit_stmt)(*s, (e.clone(), v));
- }
- visit_expr_opt(b.expr, (e, v));
-}
-
-pub fn visit_stmt<E>(s: &Stmt, (e, v): (E, vt<E>)) {
- match s.node {
- StmtDecl(d, _) => (v.visit_decl)(d, (e, v)),
- StmtExpr(ex, _) => (v.visit_expr)(ex, (e, v)),
- StmtSemi(ex, _) => (v.visit_expr)(ex, (e, v)),
- StmtMac(ref mac, _) => visit_mac(mac, (e, v))
- }
-}
-
-pub fn visit_decl<E:Clone>(d: &Decl, (e, v): (E, vt<E>)) {
- match d.node {
- DeclLocal(ref loc) => (v.visit_local)(*loc, (e, v)),
- DeclItem(it) => (v.visit_item)(it, (e, v))
- }
-}
-
-pub fn visit_expr_opt<E>(eo: Option<@Expr>, (e, v): (E, vt<E>)) {
- match eo { None => (), Some(ex) => (v.visit_expr)(ex, (e, v)) }
-}
-
-pub fn visit_exprs<E:Clone>(exprs: &[@Expr], (e, v): (E, vt<E>)) {
- for ex in exprs.iter() { (v.visit_expr)(*ex, (e.clone(), v)); }
-}
-
-pub fn visit_mac<E>(_m: &mac, (_e, _v): (E, vt<E>)) {
- /* no user-serviceable parts inside */
-}
-
-pub fn visit_expr<E:Clone>(ex: @Expr, (e, v): (E, vt<E>)) {
- match ex.node {
- ExprVstore(x, _) => (v.visit_expr)(x, (e.clone(), v)),
- ExprVec(ref es, _) => visit_exprs(*es, (e.clone(), v)),
- ExprRepeat(element, count, _) => {
- (v.visit_expr)(element, (e.clone(), v));
- (v.visit_expr)(count, (e.clone(), v));
- }
- ExprStruct(ref p, ref flds, base) => {
- visit_path(p, (e.clone(), v));
- for f in flds.iter() {
- (v.visit_expr)(f.expr, (e.clone(), v));
- }
- visit_expr_opt(base, (e.clone(), v));
- }
- ExprTup(ref elts) => {
- for el in elts.iter() { (v.visit_expr)(*el, (e.clone(), v)) }
- }
- ExprCall(callee, ref args, _) => {
- visit_exprs(*args, (e.clone(), v));
- (v.visit_expr)(callee, (e.clone(), v));
- }
- ExprMethodCall(_, callee, _, ref tys, ref args, _) => {
- visit_exprs(*args, (e.clone(), v));
- for tp in tys.iter() {
- (v.visit_ty)(tp, (e.clone(), v));
- }
- (v.visit_expr)(callee, (e.clone(), v));
- }
- ExprBinary(_, _, a, b) => {
- (v.visit_expr)(a, (e.clone(), v));
- (v.visit_expr)(b, (e.clone(), v));
- }
- ExprAddrOf(_, x) | ExprUnary(_, _, x) |
- ExprDoBody(x) => (v.visit_expr)(x, (e.clone(), v)),
- ExprLit(_) => (),
- ExprCast(x, ref t) => {
- (v.visit_expr)(x, (e.clone(), v));
- (v.visit_ty)(t, (e.clone(), v));
- }
- ExprIf(x, ref b, eo) => {
- (v.visit_expr)(x, (e.clone(), v));
- (v.visit_block)(b, (e.clone(), v));
- visit_expr_opt(eo, (e.clone(), v));
- }
- ExprWhile(x, ref b) => {
- (v.visit_expr)(x, (e.clone(), v));
- (v.visit_block)(b, (e.clone(), v));
- }
- ExprForLoop(pattern, subexpression, ref block, _) => {
- (v.visit_pat)(pattern, (e.clone(), v));
- (v.visit_expr)(subexpression, (e.clone(), v));
- (v.visit_block)(block, (e.clone(), v))
- }
- ExprLoop(ref b, _) => (v.visit_block)(b, (e.clone(), v)),
- ExprMatch(x, ref arms) => {
- (v.visit_expr)(x, (e.clone(), v));
- for a in arms.iter() { (v.visit_arm)(a, (e.clone(), v)); }
- }
- ExprFnBlock(ref decl, ref body) => {
- (v.visit_fn)(
- &fk_fn_block,
- decl,
- body,
- ex.span,
- ex.id,
- (e.clone(), v)
- );
- }
- ExprBlock(ref b) => (v.visit_block)(b, (e.clone(), v)),
- ExprAssign(a, b) => {
- (v.visit_expr)(b, (e.clone(), v));
- (v.visit_expr)(a, (e.clone(), v));
- }
- ExprAssignOp(_, _, a, b) => {
- (v.visit_expr)(b, (e.clone(), v));
- (v.visit_expr)(a, (e.clone(), v));
- }
- ExprField(x, _, ref tys) => {
- (v.visit_expr)(x, (e.clone(), v));
- for tp in tys.iter() {
- (v.visit_ty)(tp, (e.clone(), v));
- }
- }
- ExprIndex(_, a, b) => {
- (v.visit_expr)(a, (e.clone(), v));
- (v.visit_expr)(b, (e.clone(), v));
- }
- ExprPath(ref p) => visit_path(p, (e.clone(), v)),
- ExprSelf => (),
- ExprBreak(_) => (),
- ExprAgain(_) => (),
- ExprRet(eo) => visit_expr_opt(eo, (e.clone(), v)),
- ExprLogLevel => (),
- ExprMac(ref mac) => visit_mac(mac, (e.clone(), v)),
- ExprParen(x) => (v.visit_expr)(x, (e.clone(), v)),
- ExprInlineAsm(ref a) => {
- for &(_, input) in a.inputs.iter() {
- (v.visit_expr)(input, (e.clone(), v));
- }
- for &(_, out) in a.outputs.iter() {
- (v.visit_expr)(out, (e.clone(), v));
- }
- }
- }
- (v.visit_expr_post)(ex, (e, v));
-}
-
-pub fn visit_arm<E:Clone>(a: &Arm, (e, v): (E, vt<E>)) {
- for p in a.pats.iter() { (v.visit_pat)(*p, (e.clone(), v)); }
- visit_expr_opt(a.guard, (e.clone(), v));
- (v.visit_block)(&a.body, (e.clone(), v));
-}
-
-// Simpler, non-context passing interface. Always walks the whole tree, simply
-// calls the given functions on the nodes.
-
-pub struct SimpleVisitor {
- visit_mod: @fn(&_mod, Span, NodeId),
- visit_view_item: @fn(&view_item),
- visit_foreign_item: @fn(@foreign_item),
- visit_item: @fn(@item),
- visit_local: @fn(@Local),
- visit_block: @fn(&Block),
- visit_stmt: @fn(@Stmt),
- visit_arm: @fn(&Arm),
- visit_pat: @fn(@Pat),
- visit_decl: @fn(@Decl),
- visit_expr: @fn(@Expr),
- visit_expr_post: @fn(@Expr),
- visit_ty: @fn(&Ty),
- visit_generics: @fn(&Generics),
- visit_fn: @fn(&fn_kind, &fn_decl, &Block, Span, NodeId),
- visit_ty_method: @fn(&TypeMethod),
- visit_trait_method: @fn(&trait_method),
- visit_struct_def: @fn(@struct_def, Ident, &Generics, NodeId),
- visit_struct_field: @fn(@struct_field),
- visit_struct_method: @fn(@method)
-}
-
-pub type simple_visitor = @SimpleVisitor;
-
-pub fn simple_ignore_ty(_t: &Ty) {}
-
-pub fn default_simple_visitor() -> @SimpleVisitor {
- @SimpleVisitor {
- visit_mod: |_m, _sp, _id| { },
- visit_view_item: |_vi| { },
- visit_foreign_item: |_ni| { },
- visit_item: |_i| { },
- visit_local: |_l| { },
- visit_block: |_b| { },
- visit_stmt: |_s| { },
- visit_arm: |_a| { },
- visit_pat: |_p| { },
- visit_decl: |_d| { },
- visit_expr: |_e| { },
- visit_expr_post: |_e| { },
- visit_ty: simple_ignore_ty,
- visit_generics: |_| {},
- visit_fn: |_, _, _, _, _| {},
- visit_ty_method: |_| {},
- visit_trait_method: |_| {},
- visit_struct_def: |_, _, _, _| {},
- visit_struct_field: |_| {},
- visit_struct_method: |_| {},
- }
-}
-
-pub fn mk_simple_visitor(v: simple_visitor) -> vt<()> {
- fn v_mod(
- f: @fn(&_mod, Span, NodeId),
- m: &_mod,
- sp: Span,
- id: NodeId,
- (e, v): ((), vt<()>)
- ) {
- f(m, sp, id);
- visit_mod(m, sp, id, (e, v));
- }
- fn v_view_item(f: @fn(&view_item), vi: &view_item, (e, v): ((), vt<()>)) {
- f(vi);
- visit_view_item(vi, (e, v));
- }
- fn v_foreign_item(f: @fn(@foreign_item), ni: @foreign_item, (e, v): ((), vt<()>)) {
- f(ni);
- visit_foreign_item(ni, (e, v));
- }
- fn v_item(f: @fn(@item), i: @item, (e, v): ((), vt<()>)) {
- f(i);
- visit_item(i, (e, v));
- }
- fn v_local(f: @fn(@Local), l: @Local, (e, v): ((), vt<()>)) {
- f(l);
- visit_local(l, (e, v));
- }
- fn v_block(f: @fn(&ast::Block), bl: &ast::Block, (e, v): ((), vt<()>)) {
- f(bl);
- visit_block(bl, (e, v));
- }
- fn v_stmt(f: @fn(@Stmt), st: @Stmt, (e, v): ((), vt<()>)) {
- f(st);
- visit_stmt(st, (e, v));
- }
- fn v_arm(f: @fn(&Arm), a: &Arm, (e, v): ((), vt<()>)) {
- f(a);
- visit_arm(a, (e, v));
- }
- fn v_pat(f: @fn(@Pat), p: @Pat, (e, v): ((), vt<()>)) {
- f(p);
- visit_pat(p, (e, v));
- }
- fn v_decl(f: @fn(@Decl), d: @Decl, (e, v): ((), vt<()>)) {
- f(d);
- visit_decl(d, (e, v));
- }
- fn v_expr(f: @fn(@Expr), ex: @Expr, (e, v): ((), vt<()>)) {
- f(ex);
- visit_expr(ex, (e, v));
- }
- fn v_expr_post(f: @fn(@Expr), ex: @Expr, (_e, _v): ((), vt<()>)) {
- f(ex);
- }
- fn v_ty(f: @fn(&Ty), ty: &Ty, (e, v): ((), vt<()>)) {
- f(ty);
- visit_ty(ty, (e, v));
- }
- fn v_ty_method(f: @fn(&TypeMethod), ty: &TypeMethod, (e, v): ((), vt<()>)) {
- f(ty);
- visit_ty_method(ty, (e, v));
- }
- fn v_trait_method(f: @fn(&trait_method),
- m: &trait_method,
- (e, v): ((), vt<()>)) {
- f(m);
- visit_trait_method(m, (e, v));
- }
- fn v_struct_def(
- f: @fn(@struct_def, Ident, &Generics, NodeId),
- sd: @struct_def,
- nm: Ident,
- generics: &Generics,
- id: NodeId,
- (e, v): ((), vt<()>)
- ) {
- f(sd, nm, generics, id);
- visit_struct_def(sd, nm, generics, id, (e, v));
- }
- fn v_generics(
- f: @fn(&Generics),
- ps: &Generics,
- (e, v): ((), vt<()>)
- ) {
- f(ps);
- visit_generics(ps, (e, v));
- }
- fn v_fn(
- f: @fn(&fn_kind, &fn_decl, &Block, Span, NodeId),
- fk: &fn_kind,
- decl: &fn_decl,
- body: &Block,
- sp: Span,
- id: NodeId,
- (e, v): ((), vt<()>)
- ) {
- f(fk, decl, body, sp, id);
- visit_fn(fk, decl, body, sp, id, (e, v));
- }
- let visit_ty: @fn(&Ty, ((), vt<()>)) =
- |a,b| v_ty(v.visit_ty, a, b);
- fn v_struct_field(f: @fn(@struct_field), sf: @struct_field, (e, v): ((), vt<()>)) {
- f(sf);
- visit_struct_field(sf, (e, v));
- }
- return mk_vt(@Visitor {
- visit_mod: |a,b,c,d|v_mod(v.visit_mod, a, b, c, d),
- visit_view_item: |a,b| v_view_item(v.visit_view_item, a, b),
- visit_foreign_item:
- |a,b|v_foreign_item(v.visit_foreign_item, a, b),
- visit_item: |a,b|v_item(v.visit_item, a, b),
- visit_local: |a,b|v_local(v.visit_local, a, b),
- visit_block: |a,b|v_block(v.visit_block, a, b),
- visit_stmt: |a,b|v_stmt(v.visit_stmt, a, b),
- visit_arm: |a,b|v_arm(v.visit_arm, a, b),
- visit_pat: |a,b|v_pat(v.visit_pat, a, b),
- visit_decl: |a,b|v_decl(v.visit_decl, a, b),
- visit_expr: |a,b|v_expr(v.visit_expr, a, b),
- visit_expr_post: |a,b| v_expr_post(v.visit_expr_post, a, b),
- visit_ty: visit_ty,
- visit_generics: |a,b|
- v_generics(v.visit_generics, a, b),
- visit_fn: |a,b,c,d,e,f|
- v_fn(v.visit_fn, a, b, c, d, e, f),
- visit_ty_method: |a,b|
- v_ty_method(v.visit_ty_method, a, b),
- visit_trait_method: |a,b|
- v_trait_method(v.visit_trait_method, a, b),
- visit_struct_def: |a,b,c,d,e|
- v_struct_def(v.visit_struct_def, a, b, c, d, e),
- visit_struct_field: |a,b|
- v_struct_field(v.visit_struct_field, a, b),
- });
-}
}
}
+impl<T> Default for OptVec<T> {
+ fn default() -> OptVec<T> { Empty }
+}
+
pub struct OptVecIterator<'self, T> {
priv iter: Option<VecIterator<'self, T>>
}
use std::cast::transmute;
use std::char;
use std::either;
-use std::u64;
+use std::num::from_str_radix;
use std::util;
pub use ext::tt::transcribe::{TtReader, new_tt_reader};
if num_str.len() == 0u {
rdr.fatal(~"no valid digits found for number");
}
- let parsed = match u64::from_str_radix(num_str, base as uint) {
+ let parsed = match from_str_radix::<u64>(num_str, base as uint) {
Some(p) => p,
None => rdr.fatal(~"int literal is too large")
};
if num_str.len() == 0u {
rdr.fatal(~"no valid digits found for number");
}
- let parsed = match u64::from_str_radix(num_str, base as uint) {
+ let parsed = match from_str_radix::<u64>(num_str, base as uint) {
Some(p) => p,
None => rdr.fatal(~"int literal is too large")
};
use opt_vec;
use opt_vec::OptVec;
-use std::either::Either;
-use std::either;
use std::hashmap::HashSet;
use std::util;
use std::vec;
RESTRICT_NO_BAR_OR_DOUBLEBAR_OP,
}
-type arg_or_capture_item = Either<arg, ()>;
type item_info = (Ident, item_, Option<~[Attribute]>);
/// How to parse a path. There are four different kinds of paths, all of which
*/
let opt_abis = self.parse_opt_abis();
- let abis = opt_abis.unwrap_or_default(AbiSet::Rust());
+ let abis = opt_abis.unwrap_or(AbiSet::Rust());
let purity = self.parse_unsafety();
self.expect_keyword(keywords::Fn);
let (decl, lifetimes) = self.parse_ty_fn_decl();
let (explicit_self, d) = do self.parse_fn_decl_with_self() |p| {
// This is somewhat dubious; We don't want to allow argument
// names to be left off if there is a definition...
- either::Left(p.parse_arg_general(false))
+ p.parse_arg_general(false)
};
let hi = p.last_span.hi;
}
// parse a single function argument
- pub fn parse_arg(&self) -> arg_or_capture_item {
- either::Left(self.parse_arg_general(true))
+ pub fn parse_arg(&self) -> arg {
+ self.parse_arg_general(true)
}
// parse an argument in a lambda header e.g. |arg, arg|
- pub fn parse_fn_block_arg(&self) -> arg_or_capture_item {
+ pub fn parse_fn_block_arg(&self) -> arg {
self.parse_arg_mode();
let is_mutbl = self.eat_keyword(keywords::Mut);
let pat = self.parse_pat();
span: mk_sp(self.span.lo, self.span.hi),
}
};
- either::Left(ast::arg {
+ ast::arg {
is_mutbl: is_mutbl,
ty: t,
pat: pat,
id: ast::DUMMY_NODE_ID
- })
+ }
}
pub fn maybe_parse_fixed_vstore(&self) -> Option<@ast::Expr> {
} else if self.eat_keyword(keywords::Match) {
return self.parse_match_expr();
} else if self.eat_keyword(keywords::Unsafe) {
- return self.parse_block_expr(lo, UnsafeBlock);
+ return self.parse_block_expr(lo, UnsafeBlock(ast::UserProvided));
} else if *self.token == token::LBRACKET {
self.bump();
let mutbl = self.parse_mutability();
let ident = self.parse_ident();
let opt_bounds = self.parse_optional_ty_param_bounds();
// For typarams we don't care about the difference b/w "<T>" and "<T:>".
- let bounds = opt_bounds.unwrap_or_default(opt_vec::Empty);
+ let bounds = opt_bounds.unwrap_or_default();
ast::TyParam { ident: ident, id: ast::DUMMY_NODE_ID, bounds: bounds }
}
// parse the argument list and result type of a function declaration
pub fn parse_fn_decl(&self) -> fn_decl {
- let args_or_capture_items: ~[arg_or_capture_item] =
+ let args: ~[arg] =
self.parse_unspanned_seq(
&token::LPAREN,
&token::RPAREN,
|p| p.parse_arg()
);
- let inputs = either::lefts(args_or_capture_items.move_iter()).collect();
-
let (ret_style, ret_ty) = self.parse_ret_ty();
ast::fn_decl {
- inputs: inputs,
+ inputs: args,
output: ret_ty,
cf: ret_style,
}
fn parse_fn_decl_with_self(
&self,
parse_arg_fn:
- &fn(&Parser) -> arg_or_capture_item
+ &fn(&Parser) -> arg
) -> (explicit_self, fn_decl) {
fn maybe_parse_explicit_self(
cnstr: &fn(v: Mutability) -> ast::explicit_self_,
};
// If we parsed a self type, expect a comma before the argument list.
- let args_or_capture_items;
+ let fn_inputs;
if explicit_self != sty_static {
match *self.token {
token::COMMA => {
self.bump();
let sep = seq_sep_trailing_disallowed(token::COMMA);
- args_or_capture_items = self.parse_seq_to_before_end(
+ fn_inputs = self.parse_seq_to_before_end(
&token::RPAREN,
sep,
parse_arg_fn
);
}
token::RPAREN => {
- args_or_capture_items = ~[];
+ fn_inputs = ~[];
}
_ => {
self.fatal(
}
} else {
let sep = seq_sep_trailing_disallowed(token::COMMA);
- args_or_capture_items = self.parse_seq_to_before_end(
+ fn_inputs = self.parse_seq_to_before_end(
&token::RPAREN,
sep,
parse_arg_fn
let hi = self.span.hi;
- let inputs = either::lefts(args_or_capture_items.move_iter()).collect();
let (ret_style, ret_ty) = self.parse_ret_ty();
let fn_decl = ast::fn_decl {
- inputs: inputs,
+ inputs: fn_inputs,
output: ret_ty,
cf: ret_style
};
};
ast::fn_decl {
- inputs: either::lefts(inputs_captures.move_iter()).collect(),
+ inputs: inputs_captures,
output: output,
cf: return_val,
}
self.obsolete(*self.last_span, ObsoleteExternVisibility);
}
- let abis = opt_abis.unwrap_or_default(AbiSet::C());
+ let abis = opt_abis.unwrap_or(AbiSet::C());
let (inner, next) = self.parse_inner_attrs_and_next();
let m = self.parse_foreign_mod_items(sort, abis, next);
if self.eat_keyword(keywords::Fn) {
// EXTERN FUNCTION ITEM
- let abis = opt_abis.unwrap_or_default(AbiSet::C());
+ let abis = opt_abis.unwrap_or(AbiSet::C());
let (ident, item_, extra_attrs) =
self.parse_item_fn(extern_fn, abis);
return iovi_item(self.mk_item(lo, self.last_span.hi, ident,
};
print_type(s, ty);
- space(s.s);
if methods.len() == 0 {
word(s.s, ";");
+ end(s); // end the head-ibox
+ end(s); // end the outer cbox
} else {
+ space(s.s);
bopen(s);
for meth in methods.iter() {
print_method(s, *meth);
attrs: &[ast::Attribute],
close_box: bool) {
match blk.rules {
- ast::UnsafeBlock => word_space(s, "unsafe"),
+ ast::UnsafeBlock(*) => word_space(s, "unsafe"),
ast::DefaultBlock => ()
}
maybe_print_comment(s, blk.span.lo);
pub mod ast_map;
pub mod visit;
pub mod fold;
-pub mod oldvisit;
pub mod parse;
pub mod cfg;
pub mod fmt;
- pub mod ifmt;
+ pub mod format;
pub mod env;
pub mod bytes;
pub mod concat_idents;
return &global_args_ptr;
}
-static lock_and_signal change_dir_lock;
-
-extern "C" CDECL void
-rust_take_change_dir_lock() {
- change_dir_lock.lock();
-}
-
-extern "C" CDECL void
-rust_drop_change_dir_lock() {
- change_dir_lock.unlock();
-}
-
// Used by i386 __morestack
extern "C" CDECL uintptr_t
rust_get_task() {
env_lock.unlock();
}
+static lock_and_signal linenoise_lock;
+
+extern "C" CDECL void
+rust_take_linenoise_lock() {
+ linenoise_lock.lock();
+}
+
+extern "C" CDECL void
+rust_drop_linenoise_lock() {
+ linenoise_lock.unlock();
+}
+
extern "C" CDECL unsigned int
rust_valgrind_stack_register(void *start, void *end) {
return VALGRIND_STACK_REGISTER(start, end);
+++ /dev/null
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#include "rust_crate_map.h"
-#include <set>
-
-void iter_module_map(const mod_entry* map,
- void (*fn)(void* fptr, void* env, const mod_entry *entry),
- void* fptr,
- void* env
- ) {
- for (const mod_entry* cur = map; cur->name; cur++) {
- fn(fptr, env, cur);
- }
-}
-
-void iter_crate_map(const cratemap* map,
- void (*fn)(void* fptr, void* env, const mod_entry *entry),
- void *fptr,
- void *env,
- std::set<const cratemap*>& visited) {
- if (visited.find(map) == visited.end()) {
- // Mark this crate visited
- visited.insert(map);
- // First iterate this crate
- iter_module_map(map->entries(), fn, fptr, env);
- // Then recurse on linked crates
- for (cratemap::iterator i = map->begin(),
- e = map->end(); i != e; ++i) {
- iter_crate_map(*i, fn, fptr, env, visited);
- }
- }
-}
-
-void iter_crate_map(const cratemap* map,
- void (*fn)(void* fptr, void* env, const mod_entry *entry),
- void *fptr,
- void *env
- ) {
- std::set<const cratemap*> visited;
- iter_crate_map(map, fn, fptr, env, visited);
-}
-
-extern "C" CDECL void
-rust_iter_crate_map(const cratemap* map,
- void (*fn)(void* fptr, void* env, const mod_entry *entry),
- void *fptr,
- void *env
- ) {
- return iter_crate_map(map, fn, fptr, env);
-}
-
-
-//
-// Local Variables:
-// mode: C++
-// fill-column: 78;
-// indent-tabs-mode: nil
-// c-basic-offset: 4
-// buffer-file-coding-system: utf-8-unix
-// End:
-//
+++ /dev/null
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#ifndef RUST_CRATE_MAP_H
-#define RUST_CRATE_MAP_H
-
-#include "rust_globals.h"
-#include <stdint.h>
-
-struct mod_entry {
- const char* name;
- uint32_t* log_level;
-};
-
-class cratemap;
-
-class cratemap_v0 {
- friend class cratemap;
- const mod_entry *m_entries;
- const cratemap* m_children[1];
-};
-
-class cratemap {
-private:
- int32_t m_version;
- const void *m_annihilate_fn;
- const mod_entry* m_entries;
- const cratemap* m_children[1];
-
- inline int32_t version() const {
- switch (m_version) {
- case 1: return 1;
- default: return 0;
- }
- }
-
-public:
- typedef const cratemap *const *iterator;
-
- inline const void *annihilate_fn() const {
- switch (version()) {
- case 0: return NULL;
- case 1: return m_annihilate_fn;
- default: assert(false && "Unknown crate map version!");
- return NULL; // Appease -Werror=return-type
- }
- }
-
- inline const mod_entry *entries() const {
- switch (version()) {
- case 0: return reinterpret_cast<const cratemap_v0 *>(this)->m_entries;
- case 1: return m_entries;
- default: assert(false && "Unknown crate map version!");
- return NULL; // Appease -Werror=return-type
- }
- }
-
- inline const iterator begin() const {
- switch (version()) {
- case 0:
- return &reinterpret_cast<const cratemap_v0 *>(this)->
- m_children[0];
- case 1:
- return &m_children[0];
- default: assert(false && "Unknown crate map version!");
- return NULL; // Appease -Werror=return-type
- }
- }
-
- inline const iterator end() const {
- iterator i = begin();
- while (*i)
- i++;
- return i;
- }
-};
-
-void iter_module_map(const mod_entry* map,
- void (*fn)(void* fptr, void* env, const mod_entry *entry),
- void *fptr,
- void *env);
-
-void iter_crate_map(const cratemap* map,
- void (*fn)(void* fptr, void* env, const mod_entry *entry),
- void *fptr,
- void *env);
-
-//
-// Local Variables:
-// mode: C++
-// fill-column: 78;
-// indent-tabs-mode: nil
-// c-basic-offset: 4
-// buffer-file-coding-system: utf-8-unix
-// End:
-//
-
-#endif /* RUST_CRATE_MAP_H */
rust_valgrind_stack_deregister
rust_take_env_lock
rust_drop_env_lock
-rust_iter_crate_map
rust_running_on_valgrind
rust_get_num_cpus
rust_get_global_args_ptr
rust_take_global_args_lock
rust_drop_global_args_lock
-rust_take_change_dir_lock
-rust_drop_change_dir_lock
+rust_take_linenoise_lock
+rust_drop_linenoise_lock
rust_get_test_int
rust_get_task
rust_uv_get_loop_from_getaddrinfo_req
LLVMValueRef Scope,
const char* Name,
LLVMValueRef Ty,
- LLVMValueRef File = 0,
- unsigned LineNo = 0,
- unsigned ColumnNo = 0)
+ LLVMValueRef File,
+ unsigned LineNo,
+ unsigned ColumnNo)
{
return wrap(Builder->createTemplateTypeParameter(
unwrapDI<DIDescriptor>(Scope),
ArgNo
));
}
+
+extern "C" LLVMValueRef LLVMDIBuilderCreateNameSpace(
+ DIBuilderRef Builder,
+ LLVMValueRef Scope,
+ const char* Name,
+ LLVMValueRef File,
+ unsigned LineNo)
+{
+ return wrap(Builder->createNameSpace(
+ unwrapDI<DIDescriptor>(Scope),
+ Name,
+ unwrapDI<DIFile>(File),
+ LineNo));
+}
+
+extern "C" void LLVMDICompositeTypeSetTypeArray(
+ LLVMValueRef CompositeType,
+ LLVMValueRef TypeArray)
+{
+ unwrapDI<DICompositeType>(CompositeType).setTypeArray(unwrapDI<DIArray>(TypeArray));
+}
LLVMDIBuilderCreateOpDeref
LLVMDIBuilderCreateOpPlus
LLVMDIBuilderCreateComplexVariable
+LLVMDIBuilderCreateNameSpace
+LLVMDICompositeTypeSetTypeArray
LLVMSetUnnamedAddr
LLVMRustAddPass
LLVMRustAddAnalysisPasses
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[crate_type = "lib"];
+
+pub trait X {
+ fn x() {
+ fn f() { }
+ f();
+ }
+}
+
impl read for int {
fn readMaybe(s: ~str) -> Option<int> {
- int::from_str(s)
+ from_str::<int>(s)
}
}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[link(name = "struct_variant_xc_aux",
+ vers = "0.1")];
+#[crate_type = "lib"];
+
+pub enum Enum {
+ Variant { arg: u8 }
+}
let args = os::args();
let n_keys = {
if args.len() == 2 {
- uint::from_str(args[1]).unwrap()
+ from_str::<uint>(args[1]).unwrap()
} else {
1000000
}
let args = os::args();
let num_keys = {
if args.len() == 2 {
- uint::from_str(args[1]).unwrap()
+ from_str::<uint>(args[1]).unwrap()
} else {
100 // woefully inadequate for any real measurement
}
args
};
- let n = uint::from_str(args[1]).unwrap();
+ let n = from_str::<uint>(args[1]).unwrap();
for i in range(0u, n) {
let x = i.to_str();
args
};
- let scale = uint::from_str(args[1]).unwrap();
- let num_keys = uint::from_str(args[2]).unwrap();
+ let scale = from_str::<uint>(args[1]).unwrap();
+ let num_keys = from_str::<uint>(args[2]).unwrap();
let do_validate = false;
let do_sequential = true;
let to_child = SharedChan::new(to_child);
- let size = uint::from_str(args[1]).unwrap();
- let workers = uint::from_str(args[2]).unwrap();
+ let size = from_str::<uint>(args[1]).unwrap();
+ let workers = from_str::<uint>(args[2]).unwrap();
let num_bytes = 100;
let start = extra::time::precise_time_s();
let mut worker_results = ~[];
let (from_parent, to_child) = stream();
let to_child = SharedChan::new(to_child);
- let size = uint::from_str(args[1]).unwrap();
- let workers = uint::from_str(args[2]).unwrap();
+ let size = from_str::<uint>(args[1]).unwrap();
+ let workers = from_str::<uint>(args[2]).unwrap();
let num_bytes = 100;
let start = extra::time::precise_time_s();
let mut worker_results = ~[];
args.clone()
};
- let num_tasks = uint::from_str(args[1]).unwrap();
- let msg_per_task = uint::from_str(args[2]).unwrap();
+ let num_tasks = from_str::<uint>(args[1]).unwrap();
+ let msg_per_task = from_str::<uint>(args[2]).unwrap();
let (num_chan, num_port) = init();
let num_chan = Cell::new(num_chan);
args.clone()
};
- let num_tasks = uint::from_str(args[1]).unwrap();
- let msg_per_task = uint::from_str(args[2]).unwrap();
+ let num_tasks = from_str::<uint>(args[1]).unwrap();
+ let msg_per_task = from_str::<uint>(args[2]).unwrap();
let (num_chan, num_port) = init();
let num_chan = Cell::new(num_chan);
let args = os::args();
let n = if args.len() == 3 {
- uint::from_str(args[1]).unwrap()
+ from_str::<uint>(args[1]).unwrap()
} else {
10000
};
let m = if args.len() == 3 {
- uint::from_str(args[2]).unwrap()
+ from_str::<uint>(args[2]).unwrap()
} else {
4
};
let args = os::args();
let n = if args.len() == 2 {
- uint::from_str(args[1]).unwrap()
+ from_str::<uint>(args[1]).unwrap()
} else {
10
};
let args = os::args();
let n = if args.len() == 2 {
- uint::from_str(args[1]).unwrap()
+ from_str::<uint>(args[1]).unwrap()
} else {
100000
};
} else {
args
};
- let n = int::from_str(args[1]).unwrap();
+ let n = from_str::<int>(args[1]).unwrap();
printfln!("Ack(3,%d): %d\n", n, ack(3, n));
}
args
};
- let n = int::from_str(args[1]).unwrap();
+ let n = from_str::<int>(args[1]).unwrap();
let min_depth = 4;
let mut max_depth;
if min_depth + 2 > n {
args
};
- let nn = uint::from_str(args[1]).unwrap();
+ let nn = from_str::<uint>(args[1]).unwrap();
print_complements();
io::println("");
io::stdout()
};
- let n = int::from_str(args[1]).unwrap();
+ let n = from_str::<int>(args[1]).unwrap();
let iub: ~[AminoAcids] =
make_cumulative(~[acid('a', 27u32), acid('c', 12u32), acid('g', 12u32),
} else {
args
};
- let n = int::from_str(args[1]).unwrap();
+ let n = from_str::<int>(args[1]).unwrap();
printfln!("%d\n", fib(n));
}
} else {
args
};
- let max = uint::from_str(args[1]).unwrap();
- let rep = uint::from_str(args[2]).unwrap();
+ let max = from_str::<uint>(args[1]).unwrap();
+ let rep = from_str::<uint>(args[2]).unwrap();
let mut checkf = 0.0;
let mut appendf = 0.0;
let comps: ~[&str] = line.trim().split_iter(',').collect();
if comps.len() == 3u {
- let row = uint::from_str(comps[0]).unwrap() as u8;
- let col = uint::from_str(comps[1]).unwrap() as u8;
- g[row][col] = uint::from_str(comps[2]).unwrap() as u8;
+ let row = from_str::<uint>(comps[0]).unwrap() as u8;
+ let col = from_str::<uint>(comps[1]).unwrap() as u8;
+ g[row][col] = from_str::<uint>(comps[2]).unwrap() as u8;
}
else {
fail!("Invalid sudoku file");
};
let (p,c) = comm::stream();
- child_generation(uint::from_str(args[1]).unwrap(), c);
+ child_generation(from_str::<uint>(args[1]).unwrap(), c);
if p.try_recv().is_none() {
fail!("it happened when we slumbered");
}
args.clone()
};
- let num_tasks = uint::from_str(args[1]).unwrap();
+ let num_tasks = from_str::<uint>(args[1]).unwrap();
// Main group #0 waits for unsupervised group #1.
// Grandparent group #1 waits for middle group #2, then fails, killing #3.
args
};
- let children = uint::from_str(args[1]).get();
+ let children = from_str::<uint>(args[1]).get();
let (wait_port, wait_chan) = stream();
do task::spawn {
calc(children, &wait_chan);
} else {
args
};
- let n = uint::from_str(args[1]).unwrap();
+ let n = from_str::<uint>(args[1]).unwrap();
let mut i = 0u;
while i < n { task::spawn(|| f(n) ); i += 1u; }
}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ debug!("%s %s", 3); //~ ERROR: not enough arguments
+}
fn main() {
// bad arguments to the format! call
- format!(); //~ ERROR: requires at least a format string
format!("{}"); //~ ERROR: invalid reference to argument
format!("{1}", 1); //~ ERROR: invalid reference to argument `1`
format!("{foo}", foo=1, foo=2); //~ ERROR: duplicate argument
format!("#"); //~ ERROR: `#` reference used
format!("", foo=1, 2); //~ ERROR: positional arguments cannot follow
- format!("" 1); //~ ERROR: expected token: `,`
- format!("", 1 1); //~ ERROR: expected token: `,`
format!("{0, select, a{} a{} other{}}", "a"); //~ ERROR: duplicate selector
format!("{0, plural, =1{} =1{} other{}}", 1u); //~ ERROR: duplicate selector
format!("foo } bar"); //~ ERROR: unmatched `}` found
format!("foo }"); //~ ERROR: unmatched `}` found
+
+ format!(); //~ ERROR: requires at least a format string argument
+ format!("" 1); //~ ERROR: expected token: `,`
+ format!("", 1 1); //~ ERROR: expected token: `,`
}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ format_args!("test"); //~ ERROR: expected token
+ format_args!("", || {}); //~ ERROR: must be a string literal
+}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ format_args!("{}", ""); //~ ERROR: expected function
+}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+extern {
+ fn rust_get_test_int() -> std::libc::intptr_t;
+}
+
+trait A {
+ fn foo() {
+ unsafe {
+ rust_get_test_int(); //~ ERROR invoking non-Rust fn
+ }
+ }
+}
+
+fn main() {
+}
// its numerical value.
// compile-flags:-Z extra-debug-info
-// debugger:break _zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// debugger:print b
// its numerical value.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// debugger:print *bool_ref
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// its numerical value.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// debugger:print *bool_ref
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// its numerical value.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// debugger:print *bool_ref
// compile-flags:-Z extra-debug-info
// debugger:set print pretty off
-// debugger:break _zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// debugger:print *a
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// compile-flags:-Z extra-debug-info
// debugger:set print pretty off
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
(x, y)
}
-fn zzz() {()}
\ No newline at end of file
+fn zzz() {()}
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// STACK BY REF
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// STRUCT
// compile-flags:-Z extra-debug-info
// debugger:set print union on
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// compile-flags:-Z extra-debug-info
// debugger:set print union on
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// xfail-win32
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// FIRST ITERATION
// xfail-win32
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// BEFORE if
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// xfail-win32
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// FIRST ITERATION
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// FIRST ITERATION
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// xfail-win32
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// STRUCT EXPRESSION
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// compile-flags:-Z extra-debug-info
// debugger:set print pretty off
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// STACK BY REF
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// STACK BY REF
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// STACK BY REF
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// STACK BY REF
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// STACK BY REF
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// compile-flags:-Z extra-debug-info
// debugger:set print pretty off
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// compile-flags:-Z extra-debug-info
// debugger:set print pretty off
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags:-Z extra-debug-info
+// debugger:set print pretty off
+// debugger:rbreak zzz
+// debugger:run
+// debugger:finish
+
+// debugger:print stack_unique.value
+// check:$1 = 0
+// debugger:print stack_unique.next.val->value
+// check:$2 = 1
+
+// debugger:print unique_unique->value
+// check:$3 = 2
+// debugger:print unique_unique->next.val->value
+// check:$4 = 3
+
+// debugger:print box_unique->val.value
+// check:$5 = 4
+// debugger:print box_unique->val.next.val->value
+// check:$6 = 5
+
+// debugger:print vec_unique[0].value
+// check:$7 = 6.5
+// debugger:print vec_unique[0].next.val->value
+// check:$8 = 7.5
+
+// debugger:print borrowed_unique->value
+// check:$9 = 8.5
+// debugger:print borrowed_unique->next.val->value
+// check:$10 = 9.5
+
+// MANAGED
+// debugger:print stack_managed.value
+// check:$11 = 10
+// debugger:print stack_managed.next.val->val.value
+// check:$12 = 11
+
+// debugger:print unique_managed->val.value
+// check:$13 = 12
+// debugger:print unique_managed->val.next.val->val.value
+// check:$14 = 13
+
+// debugger:print box_managed->val.value
+// check:$15 = 14
+// debugger:print box_managed->val.next.val->val.value
+// check:$16 = 15
+
+// debugger:print vec_managed[0].value
+// check:$17 = 16.5
+// debugger:print vec_managed[0].next.val->val.value
+// check:$18 = 17.5
+
+// debugger:print borrowed_managed->value
+// check:$19 = 18.5
+// debugger:print borrowed_managed->next.val->val.value
+// check:$20 = 19.5
+
+// LONG CYCLE
+// debugger:print long_cycle1.value
+// check:$21 = 20
+// debugger:print long_cycle1.next->value
+// check:$22 = 21
+// debugger:print long_cycle1.next->next->value
+// check:$23 = 22
+// debugger:print long_cycle1.next->next->next->value
+// check:$24 = 23
+
+// debugger:print long_cycle2.value
+// check:$25 = 24
+// debugger:print long_cycle2.next->value
+// check:$26 = 25
+// debugger:print long_cycle2.next->next->value
+// check:$27 = 26
+
+// debugger:print long_cycle3.value
+// check:$28 = 27
+// debugger:print long_cycle3.next->value
+// check:$29 = 28
+
+// debugger:print long_cycle4.value
+// check:$30 = 29.5
+
+// debugger:print (*****long_cycle_w_anonymous_types).value
+// check:$31 = 30
+
+// debugger:print (*****((*****long_cycle_w_anonymous_types).next.val)).value
+// check:$32 = 31
+
+// debugger:continue
+
+#[allow(unused_variable)];
+
+enum Opt<T> {
+ Empty,
+ Val { val: T }
+}
+
+struct UniqueNode<T> {
+ next: Opt<~UniqueNode<T>>,
+ value: T
+}
+
+struct ManagedNode<T> {
+ next: Opt<@ManagedNode<T>>,
+ value: T
+}
+
+struct LongCycle1<T> {
+ next: ~LongCycle2<T>,
+ value: T,
+}
+
+struct LongCycle2<T> {
+ next: ~LongCycle3<T>,
+ value: T,
+}
+
+struct LongCycle3<T> {
+ next: ~LongCycle4<T>,
+ value: T,
+}
+
+struct LongCycle4<T> {
+ next: Option<~LongCycle1<T>>,
+ value: T,
+}
+
+struct LongCycleWithAnonymousTypes {
+ next: Opt<~~~~~LongCycleWithAnonymousTypes>,
+ value: uint,
+}
+
+// This test case makes sure that recursive structs are properly described. The Node structs are
+// generic so that we can have a new type (that newly needs to be described) for the different
+// cases. The potential problem with recursive types is that the DI generation algorithm gets
+// trapped in an endless loop. To make sure, we actually test this in the different cases, we have
+// to operate on a new type each time, otherwise we would just hit the DI cache for all but the
+// first case.
+
+// The different cases below (stack_*, unique_*, box_*, etc) are set up so that the type description
+// algorithm will enter the type reference cycle that is created by a recursive definition from a
+// different context each time.
+
+// The "long cycle" cases are constructed to span a longer, indirect recursion cycle between types.
+// The different locals will cause the DI algorithm to enter the type reference cycle at different
+// points.
+
+fn main() {
+ let stack_unique: UniqueNode<u16> = UniqueNode {
+ next: Val {
+ val: ~UniqueNode {
+ next: Empty,
+ value: 1_u16,
+ }
+ },
+ value: 0_u16,
+ };
+
+ let unique_unique: ~UniqueNode<u32> = ~UniqueNode {
+ next: Val {
+ val: ~UniqueNode {
+ next: Empty,
+ value: 3,
+ }
+ },
+ value: 2,
+ };
+
+ let box_unique: @UniqueNode<u64> = @UniqueNode {
+ next: Val {
+ val: ~UniqueNode {
+ next: Empty,
+ value: 5,
+ }
+ },
+ value: 4,
+ };
+
+ let vec_unique: [UniqueNode<f32>, ..1] = [UniqueNode {
+ next: Val {
+ val: ~UniqueNode {
+ next: Empty,
+ value: 7.5,
+ }
+ },
+ value: 6.5,
+ }];
+
+ let borrowed_unique: &UniqueNode<f64> = &UniqueNode {
+ next: Val {
+ val: ~UniqueNode {
+ next: Empty,
+ value: 9.5,
+ }
+ },
+ value: 8.5,
+ };
+
+ let stack_managed: ManagedNode<u16> = ManagedNode {
+ next: Val {
+ val: @ManagedNode {
+ next: Empty,
+ value: 11,
+ }
+ },
+ value: 10,
+ };
+
+ let unique_managed: ~ManagedNode<u32> = ~ManagedNode {
+ next: Val {
+ val: @ManagedNode {
+ next: Empty,
+ value: 13,
+ }
+ },
+ value: 12,
+ };
+
+ let box_managed: @ManagedNode<u64> = @ManagedNode {
+ next: Val {
+ val: @ManagedNode {
+ next: Empty,
+ value: 15,
+ }
+ },
+ value: 14,
+ };
+
+ let vec_managed: [ManagedNode<f32>, ..1] = [ManagedNode {
+ next: Val {
+ val: @ManagedNode {
+ next: Empty,
+ value: 17.5,
+ }
+ },
+ value: 16.5,
+ }];
+
+ let borrowed_managed: &ManagedNode<f64> = &ManagedNode {
+ next: Val {
+ val: @ManagedNode {
+ next: Empty,
+ value: 19.5,
+ }
+ },
+ value: 18.5,
+ };
+
+ // LONG CYCLE
+ let long_cycle1: LongCycle1<u16> = LongCycle1 {
+ next: ~LongCycle2 {
+ next: ~LongCycle3 {
+ next: ~LongCycle4 {
+ next: None,
+ value: 23,
+ },
+ value: 22,
+ },
+ value: 21
+ },
+ value: 20
+ };
+
+ let long_cycle2: LongCycle2<u32> = LongCycle2 {
+ next: ~LongCycle3 {
+ next: ~LongCycle4 {
+ next: None,
+ value: 26,
+ },
+ value: 25,
+ },
+ value: 24
+ };
+
+ let long_cycle3: LongCycle3<u64> = LongCycle3 {
+ next: ~LongCycle4 {
+ next: None,
+ value: 28,
+ },
+ value: 27,
+ };
+
+ let long_cycle4: LongCycle4<f32> = LongCycle4 {
+ next: None,
+ value: 29.5,
+ };
+
+ // It's important that LongCycleWithAnonymousTypes is encountered only at the end of the
+ // `~` chain.
+ let long_cycle_w_anonymous_types = ~~~~~LongCycleWithAnonymousTypes {
+ next: Val {
+ val: ~~~~~LongCycleWithAnonymousTypes {
+ next: Empty,
+ value: 31,
+ }
+ },
+ value: 30
+ };
+
+ zzz();
+}
+
+fn zzz() {()}
+
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// STACK BY REF
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// STACK BY REF
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// compile-flags:-Z extra-debug-info
// debugger:set print pretty off
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// compile-flags:-Z extra-debug-info
// debugger:set print pretty off
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// STRUCT
// compile-flags:-Z extra-debug-info
// debugger:set print union on
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// compile-flags:-Z extra-debug-info
// debugger:set print pretty off
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// compile-flags:-Z extra-debug-info
// debugger:set print union on
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// debugger:print simple
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags:-Z extra-debug-info
+// debugger:run
+
+#[allow(unused_variable)];
+
+trait Trait {
+ fn method(&self) -> int { 0 }
+}
+
+struct Struct {
+ a: int,
+ b: float
+}
+
+impl Trait for Struct {}
+
+// There is no real test here yet. Just make sure that it compiles without crashing.
+fn main() {
+ let stack_struct = Struct { a:0, b: 1.0 };
+ let reference: &Trait = &stack_struct as &Trait;
+ let managed: @Trait = @Struct { a:2, b: 3.0 } as @Trait;
+ let unique: ~Trait = ~Struct { a:2, b: 3.0 } as ~Trait;
+}
// compile-flags:-Z extra-debug-info
// debugger:set print pretty off
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// compile-flags:-Z extra-debug-info
// debugger:set print pretty off
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// compile-flags:-Z extra-debug-info
// debugger:set print pretty off
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// compile-flags:-Z extra-debug-info
// debugger:set print union on
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// except according to those terms.
// compile-flags:-Z extra-debug-info
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// compile-flags:-Z extra-debug-info
// debugger:set print pretty off
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// debugger:print empty.size_in_bytes
// compile-flags:-Z extra-debug-info
// debugger:set print pretty off
-// debugger:break zzz
+// debugger:rbreak zzz
// debugger:run
// debugger:finish
// debugger:print a
--- /dev/null
+trait X { }
+impl X for uint;
+
+trait Y { }
+impl Y for uint;
--- /dev/null
+trait X { }
+impl X for uint;
+
+trait Y { }
+impl Y for uint;
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// error-pattern:quux
+fn foo() -> ! { fail!("quux"); }
+fn main() { foo() == foo(); }
#[deriving(Zero)]
struct Lots {
- c: Option<util::NonCopyable>,
d: u8,
e: char,
f: float,
g: (f32, char),
- h: ~[util::NonCopyable],
- i: @mut (int, int),
- j: bool,
- k: (),
+ h: @mut (int, int),
+ i: bool,
+ j: (),
}
fn main() {
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// xfail-fast windows doesn't like 'extern mod extra'
+
+extern mod extra;
+
+use extra::glob::*;
+use extra::tempfile;
+use std::unstable::finally::Finally;
+use std::{io, os, unstable};
+
+pub fn main() {
+ fn change_then_remove(p: &Path, f: &fn()) {
+ assert!(os::change_dir(p));
+
+ do f.finally {
+ os::remove_dir_recursive(p);
+ }
+ }
+
+ fn mk_file(path: &str, directory: bool) {
+ if directory {
+ os::make_dir(&Path(path), 0xFFFF);
+ } else {
+ io::mk_file_writer(&Path(path), [io::Create]);
+ }
+ }
+
+ fn abs_path(path: &str) -> Path {
+ os::getcwd().push_many(Path(path).components)
+ }
+
+ fn glob_vec(pattern: &str) -> ~[Path] {
+ glob(pattern).collect()
+ }
+
+ let root = tempfile::mkdtemp(&os::tmpdir(), "glob-tests");
+ let root = root.expect("Should have created a temp directory");
+
+ do change_then_remove(&root) {
+ mk_file("aaa", true);
+ mk_file("aaa/apple", true);
+ mk_file("aaa/orange", true);
+ mk_file("aaa/tomato", true);
+ mk_file("aaa/tomato/tomato.txt", false);
+ mk_file("aaa/tomato/tomoto.txt", false);
+ mk_file("bbb", true);
+ mk_file("bbb/specials", true);
+ mk_file("bbb/specials/!", false);
+
+ // windows does not allow `*` or `?` characters to exist in filenames
+ if os::consts::FAMILY != os::consts::windows::FAMILY {
+ mk_file("bbb/specials/*", false);
+ mk_file("bbb/specials/?", false);
+ }
+
+ mk_file("bbb/specials/[", false);
+ mk_file("bbb/specials/]", false);
+ mk_file("ccc", true);
+ mk_file("xyz", true);
+ mk_file("xyz/x", false);
+ mk_file("xyz/y", false);
+ mk_file("xyz/z", false);
+
+ assert_eq!(glob_vec(""), ~[]);
+ assert_eq!(glob_vec("."), ~[]);
+ assert_eq!(glob_vec(".."), ~[]);
+
+ assert_eq!(glob_vec("aaa"), ~[abs_path("aaa")]);
+ assert_eq!(glob_vec("aaa/"), ~[abs_path("aaa")]);
+ assert_eq!(glob_vec("a"), ~[]);
+ assert_eq!(glob_vec("aa"), ~[]);
+ assert_eq!(glob_vec("aaaa"), ~[]);
+
+ assert_eq!(glob_vec("aaa/apple"), ~[abs_path("aaa/apple")]);
+ assert_eq!(glob_vec("aaa/apple/nope"), ~[]);
+
+ // windows should support both / and \ as directory separators
+ if os::consts::FAMILY == os::consts::windows::FAMILY {
+ assert_eq!(glob_vec("aaa\\apple"), ~[abs_path("aaa/apple")]);
+ }
+
+ assert_eq!(glob_vec("???/"), ~[
+ abs_path("aaa"),
+ abs_path("bbb"),
+ abs_path("ccc"),
+ abs_path("xyz")]);
+
+ assert_eq!(glob_vec("aaa/tomato/tom?to.txt"), ~[
+ abs_path("aaa/tomato/tomato.txt"),
+ abs_path("aaa/tomato/tomoto.txt")]);
+
+ assert_eq!(glob_vec("xyz/?"), ~[
+ abs_path("xyz/x"),
+ abs_path("xyz/y"),
+ abs_path("xyz/z")]);
+
+ assert_eq!(glob_vec("a*"), ~[abs_path("aaa")]);
+ assert_eq!(glob_vec("*a*"), ~[abs_path("aaa")]);
+ assert_eq!(glob_vec("a*a"), ~[abs_path("aaa")]);
+ assert_eq!(glob_vec("aaa*"), ~[abs_path("aaa")]);
+ assert_eq!(glob_vec("*aaa"), ~[abs_path("aaa")]);
+ assert_eq!(glob_vec("*aaa*"), ~[abs_path("aaa")]);
+ assert_eq!(glob_vec("*a*a*a*"), ~[abs_path("aaa")]);
+ assert_eq!(glob_vec("aaa*/"), ~[abs_path("aaa")]);
+
+ assert_eq!(glob_vec("aaa/*"), ~[
+ abs_path("aaa/apple"),
+ abs_path("aaa/orange"),
+ abs_path("aaa/tomato")]);
+
+ assert_eq!(glob_vec("aaa/*a*"), ~[
+ abs_path("aaa/apple"),
+ abs_path("aaa/orange"),
+ abs_path("aaa/tomato")]);
+
+ assert_eq!(glob_vec("*/*/*.txt"), ~[
+ abs_path("aaa/tomato/tomato.txt"),
+ abs_path("aaa/tomato/tomoto.txt")]);
+
+ assert_eq!(glob_vec("*/*/t[aob]m?to[.]t[!y]t"), ~[
+ abs_path("aaa/tomato/tomato.txt"),
+ abs_path("aaa/tomato/tomoto.txt")]);
+
+ assert_eq!(glob_vec("aa[a]"), ~[abs_path("aaa")]);
+ assert_eq!(glob_vec("aa[abc]"), ~[abs_path("aaa")]);
+ assert_eq!(glob_vec("a[bca]a"), ~[abs_path("aaa")]);
+ assert_eq!(glob_vec("aa[b]"), ~[]);
+ assert_eq!(glob_vec("aa[xyz]"), ~[]);
+ assert_eq!(glob_vec("aa[]]"), ~[]);
+
+ assert_eq!(glob_vec("aa[!b]"), ~[abs_path("aaa")]);
+ assert_eq!(glob_vec("aa[!bcd]"), ~[abs_path("aaa")]);
+ assert_eq!(glob_vec("a[!bcd]a"), ~[abs_path("aaa")]);
+ assert_eq!(glob_vec("aa[!a]"), ~[]);
+ assert_eq!(glob_vec("aa[!abc]"), ~[]);
+
+ assert_eq!(glob_vec("bbb/specials/[[]"), ~[abs_path("bbb/specials/[")]);
+ assert_eq!(glob_vec("bbb/specials/!"), ~[abs_path("bbb/specials/!")]);
+ assert_eq!(glob_vec("bbb/specials/[]]"), ~[abs_path("bbb/specials/]")]);
+
+ if os::consts::FAMILY != os::consts::windows::FAMILY {
+ assert_eq!(glob_vec("bbb/specials/[*]"), ~[abs_path("bbb/specials/*")]);
+ assert_eq!(glob_vec("bbb/specials/[?]"), ~[abs_path("bbb/specials/?")]);
+ }
+
+ if os::consts::FAMILY == os::consts::windows::FAMILY {
+
+ assert_eq!(glob_vec("bbb/specials/[![]"), ~[
+ abs_path("bbb/specials/!"),
+ abs_path("bbb/specials/]")]);
+
+ assert_eq!(glob_vec("bbb/specials/[!]]"), ~[
+ abs_path("bbb/specials/!"),
+ abs_path("bbb/specials/[")]);
+
+ assert_eq!(glob_vec("bbb/specials/[!!]"), ~[
+ abs_path("bbb/specials/["),
+ abs_path("bbb/specials/]")]);
+
+ } else {
+
+ assert_eq!(glob_vec("bbb/specials/[![]"), ~[
+ abs_path("bbb/specials/!"),
+ abs_path("bbb/specials/*"),
+ abs_path("bbb/specials/?"),
+ abs_path("bbb/specials/]")]);
+
+ assert_eq!(glob_vec("bbb/specials/[!]]"), ~[
+ abs_path("bbb/specials/!"),
+ abs_path("bbb/specials/*"),
+ abs_path("bbb/specials/?"),
+ abs_path("bbb/specials/[")]);
+
+ assert_eq!(glob_vec("bbb/specials/[!!]"), ~[
+ abs_path("bbb/specials/*"),
+ abs_path("bbb/specials/?"),
+ abs_path("bbb/specials/["),
+ abs_path("bbb/specials/]")]);
+
+ assert_eq!(glob_vec("bbb/specials/[!*]"), ~[
+ abs_path("bbb/specials/!"),
+ abs_path("bbb/specials/?"),
+ abs_path("bbb/specials/["),
+ abs_path("bbb/specials/]")]);
+
+ assert_eq!(glob_vec("bbb/specials/[!?]"), ~[
+ abs_path("bbb/specials/!"),
+ abs_path("bbb/specials/*"),
+ abs_path("bbb/specials/["),
+ abs_path("bbb/specials/]")]);
+
+ }
+ };
+}
// xfail-fast: check-fast screws up repr paths
+#[deny(warnings)];
+
use std::fmt;
+use std::rt::io::Decorator;
+use std::rt::io::mem::MemWriter;
+use std::rt::io;
+use std::rt::io::Writer;
+use std::str;
struct A;
struct B;
t!(format!("{foo} {1} {bar} {0}", 0, 1, foo=2, bar=3), "2 1 3 0");
t!(format!("{} {0:s}", "a"), "a a");
t!(format!("{} {0}", "a"), "a a");
+ t!(format!("{foo_bar}", foo_bar=1), "1");
// Methods should probably work
t!(format!("{0, plural, =1{a#} =2{b#} zero{c#} other{d#}}", 0u), "c0");
let a = ~3;
format!("{:?}", a);
format!("{:?}", a);
+
+ // make sure that format! doesn't cause spurious unused-unsafe warnings when
+ // it's inside of an outer unsafe block
+ unsafe {
+ let a: int = ::std::cast::transmute(3u);
+ format!("{}", a);
+ }
+
+ test_format_args();
}
// Basic test to make sure that we can invoke the `write!` macro with an
// io::Writer instance.
fn test_write() {
- use std::rt::io::Decorator;
- use std::rt::io::mem::MemWriter;
- use std::rt::io;
- use std::str;
-
let mut buf = MemWriter::new();
write!(&mut buf as &mut io::Writer, "{}", 3);
{
println!("this is a {}", "test");
println!("{foo}", foo="bar");
}
+
+// Just make sure that the macros are defined, there's not really a lot that we
+// can do with them just yet (to test the output)
+fn test_format_args() {
+ let mut buf = MemWriter::new();
+ {
+ let w = &mut buf as &mut io::Writer;
+ format_args!(|args| { fmt::write(w, args) }, "{}", 1);
+ format_args!(|args| { fmt::write(w, args) }, "test");
+ format_args!(|args| { fmt::write(w, args) }, "{test}", test=3);
+ }
+ let s = str::from_utf8_owned(buf.inner());
+ t!(s, "1test3");
+
+ let s = format_args!(fmt::format, "hello {}", "world");
+ t!(s, "hello world");
+}
}
priv fn parse_bulk(io: @io::Reader) -> Result {
- match int::from_str(chop(io.read_line())) {
+ match from_str::<int>(chop(io.read_line())) {
None => fail!(),
Some(-1) => Nil,
Some(len) if len >= 0 => parse_data(len as uint, io),
}
priv fn parse_multi(io: @io::Reader) -> Result {
- match int::from_str(chop(io.read_line())) {
+ match from_str::<int>(chop(io.read_line())) {
None => fail!(),
Some(-1) => Nil,
Some(0) => List(~[]),
}
priv fn parse_int(io: @io::Reader) -> Result {
- match int::from_str(chop(io.read_line())) {
+ match from_str::<int>(chop(io.read_line())) {
None => fail!(),
Some(i) => Int(i)
}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+macro_rules! silly_macro(
+ () => (
+ pub mod Qux {
+ pub struct Foo { x : u8 }
+ pub fn bar(_foo : Foo) {}
+ }
+ );
+)
+
+silly_macro!()
+
+fn main() {}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// xfail-fast windows doesn't like aux-build
+// aux-build:issue_9123.rs
+
+extern mod issue_9123;
+
+pub fn main() {}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::libc;
+
+extern {
+ fn rust_get_test_int() -> libc::intptr_t;
+}
+
+trait A {
+ #[fixed_stack_segment]
+ fn foo() {
+ unsafe {
+ rust_get_test_int();
+ }
+ }
+}
+
+fn main() {
+}
// sometimes we have had trouble finding
// the right type for f, as we unified
// bot and u32 here
- let f = match uint::from_str("1234") {
+ let f = match from_str::<uint>("1234") {
None => return (),
Some(num) => num as u32
};
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use std::int;
-use std::uint;
-
-fn uint_range(lo: uint, hi: uint, it: &fn(uint) -> bool) -> bool {
- range(lo, hi).advance(it)
-}
-
-fn int_range(lo: int, hi: int, it: &fn(int) -> bool) -> bool {
- range(lo, hi).advance(it)
-}
-
-fn uint_range_rev(hi: uint, lo: uint, it: &fn(uint) -> bool) -> bool {
- range(lo, hi).invert().advance(it)
-}
-
-fn int_range_rev(hi: int, lo: int, it: &fn(int) -> bool) -> bool {
- range(lo, hi).invert().advance(it)
-}
-
-fn int_range_step(a: int, b: int, step: int, it: &fn(int) -> bool) -> bool {
- int::range_step(a, b, step, it)
-}
-
-fn uint_range_step(a: uint, b: uint, step: int, it: &fn(uint) -> bool) -> bool {
- uint::range_step(a, b, step, it)
-}
-
-
-pub fn main() {
- // int and uint have same result for
- // Sum{100 > i >= 2} == (Sum{1 <= i <= 99} - 1) == n*(n+1)/2 - 1 for n=99
- let mut sum = 0u;
- do uint_range_rev(100, 2) |i| {
- sum += i;
- true
- };
- assert_eq!(sum, 4949);
-
- let mut sum = 0i;
- do int_range_rev(100, 2) |i| {
- sum += i;
- true
- };
- assert_eq!(sum, 4949);
-
-
- // elements are visited in correct order
- let primes = [2,3,5,7,11];
- let mut prod = 1i;
- do uint_range_rev(5, 0) |i| {
- printfln!("uint 4 downto 0: %u", i);
- prod *= int::pow(primes[i], i);
- true
- };
- assert_eq!(prod, 11*11*11*11*7*7*7*5*5*3*1);
- let mut prod = 1i;
- do int_range_rev(5, 0) |i| {
- printfln!("int 4 downto 0: %d", i);
- prod *= int::pow(primes[i], i as uint);
- true
- };
- assert_eq!(prod, 11*11*11*11*7*7*7*5*5*3*1);
-
-
- // range and range_rev are symmetric.
- let mut sum_up = 0u;
- do uint_range(10, 30) |i| {
- sum_up += i;
- true
- };
- let mut sum_down = 0u;
- do uint_range_rev(30, 10) |i| {
- sum_down += i;
- true
- };
- assert_eq!(sum_up, sum_down);
-
- let mut sum_up = 0;
- do int_range(-20, 10) |i| {
- sum_up += i;
- true
- };
- let mut sum_down = 0;
- do int_range_rev(10, -20) |i| {
- sum_down += i;
- true
- };
- assert_eq!(sum_up, sum_down);
-
-
- // empty ranges
- do int_range_rev(10, 10) |_| {
- fail!("range should be empty when start == stop");
- true
- };
-
- do uint_range_rev(0, 1) |_| {
- fail!("range should be empty when start-1 underflows");
- true
- };
-
- // range iterations do not wrap/underflow
- let mut uflo_loop_visited = ~[];
- do int_range_step(int::min_value+15, int::min_value, -4) |x| {
- uflo_loop_visited.push(x - int::min_value);
- true
- };
- assert_eq!(uflo_loop_visited, ~[15, 11, 7, 3]);
-
- let mut uflo_loop_visited = ~[];
- do uint_range_step(uint::min_value+15, uint::min_value, -4) |x| {
- uflo_loop_visited.push(x - uint::min_value);
- true
- };
- assert_eq!(uflo_loop_visited, ~[15, 11, 7, 3]);
-}
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use std::int;
-use std::uint;
-
-fn uint_range(lo: uint, hi: uint, it: &fn(uint) -> bool) -> bool {
- range(lo, hi).advance(it)
-}
-
-fn int_range(lo: int, hi: int, it: &fn(int) -> bool) -> bool {
- range(lo, hi).advance(it)
-}
-
-fn int_range_step(a: int, b: int, step: int, it: &fn(int) -> bool) -> bool {
- int::range_step(a, b, step, it)
-}
-
-fn uint_range_step(a: uint, b: uint, s: int, it: &fn(uint) -> bool) -> bool {
- uint::range_step(a, b, s, it)
-}
-
-pub fn main() {
- println("num-range start");
- // int and uint have same result for
- // Sum{2 <= i < 100} == (Sum{1 <= i <= 99} - 1) == n*(n+1)/2 - 1 for n=99
- let mut sum = 0u;
- do uint_range(2, 100) |i| {
- sum += i;
- true
- };
- assert_eq!(sum, 4949);
-
- let mut sum = 0i;
- do int_range(2, 100) |i| {
- sum += i;
- true
- };
- assert_eq!(sum, 4949);
-
-
- // elements are visited in correct order
- let primes = [2,3,5,7];
- let mut prod = 1i;
- do uint_range(0, 4) |i| {
- prod *= int::pow(primes[i], i);
- true
- };
- assert_eq!(prod, 1*3*5*5*7*7*7);
- let mut prod = 1i;
- do int_range(0, 4) |i| {
- prod *= int::pow(primes[i], i as uint);
- true
- };
- assert_eq!(prod, 1*3*5*5*7*7*7);
-
-
- // empty ranges
- do int_range(10, 10) |_| {
- fail!("range should be empty when start == stop");
- true
- };
-
- do uint_range(10, 10) |_| {
- fail!("range should be empty when start == stop");
- true
- };
-
-
- // range iterations do not wrap/overflow
- let mut oflo_loop_visited = ~[];
- do uint_range_step(uint::max_value-15, uint::max_value, 4) |x| {
- oflo_loop_visited.push(uint::max_value - x);
- true
- };
- assert_eq!(oflo_loop_visited, ~[15, 11, 7, 3]);
-
- let mut oflo_loop_visited = ~[];
- do int_range_step(int::max_value-15, int::max_value, 4) |x| {
- oflo_loop_visited.push(int::max_value - x);
- true
- };
- assert_eq!(oflo_loop_visited, ~[15, 11, 7, 3]);
-
-
- // range_step never passes nor visits the stop element
- do int_range_step(0, 21, 3) |x| {
- assert!(x < 21);
- true
- };
-
- // range_step_inclusive will never pass stop element, and may skip it.
- let mut saw21 = false;
- do uint::range_step_inclusive(0, 21, 4) |x| {
- assert!(x <= 21);
- if x == 21 { saw21 = true; }
- true
- };
- assert!(!saw21);
- let mut saw21 = false;
- do int::range_step_inclusive(0, 21, 4) |x| {
- assert!(x <= 21);
- if x == 21 { saw21 = true; }
- true
- };
- assert!(!saw21);
-
- // range_step_inclusive will never pass stop element, but may visit it.
- let mut saw21 = false;
- do uint::range_step_inclusive(0, 21, 3) |x| {
- assert!(x <= 21);
- printfln!("saw: %u", x);
- if x == 21 { saw21 = true; }
- true
- };
- assert!(saw21);
- let mut saw21 = false;
- do int::range_step_inclusive(0, 21, 3) |x| {
- assert!(x <= 21);
- if x == 21 { saw21 = true; }
- true
- };
- assert!(saw21);
-
-}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// xfail-fast no compile flags for check-fast
+
+// we want this to be compiled to avoid bitrot, but the actual test
+//has to be conducted by a human, i.e. someone (you?) compiling this
+//file with a plain rustc invocation and running it and checking it
+//works.
+
+// compile-flags: --cfg robot_mode
+
+extern mod extra;
+use extra::rl;
+
+static HISTORY_FILE: &'static str = "rl-human-test-history.txt";
+
+fn main() {
+ // don't run this in robot mode, but still typecheck it.
+ if !cfg!(robot_mode) {
+ println("~~ Welcome to the rl test \"suite\". ~~");
+ println!("Operations:
+ - restrict the history to 2 lines,
+ - set the tab-completion to suggest three copies of each of the last 3 letters (or 'empty'),
+ - add 'one' and 'two' to the history,
+ - save it to `{0}`,
+ - add 'three',
+ - prompt & save input (check the history & completion work and contains only 'two', 'three'),
+ - load from `{0}`
+ - prompt & save input (history should be 'one', 'two' again),
+ - prompt once more.
+
+The bool return values of each step are printed.",
+ HISTORY_FILE);
+
+ println!("restricting history length: {}", rl::set_history_max_len(3));
+
+ do rl::complete |line, suggest| {
+ if line.is_empty() {
+ suggest(~"empty")
+ } else {
+ for c in line.rev_iter().take(3) {
+ suggest(format!("{0}{1}{1}{1}", line, c))
+ }
+ }
+ }
+
+ println!("adding 'one': {}", rl::add_history("one"));
+ println!("adding 'two': {}", rl::add_history("two"));
+
+ println!("saving history: {}", rl::save_history(HISTORY_FILE));
+
+ println!("adding 'three': {}", rl::add_history("three"));
+
+ match rl::read("> ") {
+ Some(s) => println!("saving input: {}", rl::add_history(s)),
+ None => return
+ }
+ println!("loading history: {}", rl::load_history(HISTORY_FILE));
+
+ match rl::read("> ") {
+ Some(s) => println!("saving input: {}", rl::add_history(s)),
+ None => return
+ }
+
+ rl::read("> ");
+ }
+}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// xfail-fast - check-fast doesn't understand aux-build
+// aux-build:struct_variant_xc_aux.rs
+extern mod struct_variant_xc_aux;
+
+use struct_variant_xc_aux::Variant;
+
+fn main() {
+ let _ = Variant { arg: 1 };
+}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// xfail-fast windows doesn't like 'extern mod extra'
+
+// These tests are here to exercise the functionality of the `tempfile` module.
+// One might expect these tests to be located in that module, but sadly they
+// cannot. The tests need to invoke `os::change_dir` which cannot be done in the
+// normal test infrastructure. If the tests change the current working
+// directory, then *all* tests which require relative paths suddenly break b/c
+// they're in a different location than before. Hence, these tests are all run
+// serially here.
+
+extern mod extra;
+
+use extra::tempfile::mkdtemp;
+use std::os;
+use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
+
+fn test_mkdtemp() {
+ let p = mkdtemp(&Path("."), "foobar").unwrap();
+ os::remove_dir(&p);
+ assert!(p.to_str().ends_with("foobar"));
+}
+
+// Ideally these would be in std::os but then core would need
+// to depend on std
+fn recursive_mkdir_rel() {
+ let path = Path("frob");
+ debug!("recursive_mkdir_rel: Making: %s in cwd %s [%?]", path.to_str(),
+ os::getcwd().to_str(),
+ os::path_exists(&path));
+ assert!(os::mkdir_recursive(&path, (S_IRUSR | S_IWUSR | S_IXUSR) as i32));
+ assert!(os::path_is_dir(&path));
+ assert!(os::mkdir_recursive(&path, (S_IRUSR | S_IWUSR | S_IXUSR) as i32));
+ assert!(os::path_is_dir(&path));
+}
+
+fn recursive_mkdir_dot() {
+ let dot = Path(".");
+ assert!(os::mkdir_recursive(&dot, (S_IRUSR | S_IWUSR | S_IXUSR) as i32));
+ let dotdot = Path("..");
+ assert!(os::mkdir_recursive(&dotdot, (S_IRUSR | S_IWUSR | S_IXUSR) as i32));
+}
+
+fn recursive_mkdir_rel_2() {
+ let path = Path("./frob/baz");
+ debug!("recursive_mkdir_rel_2: Making: %s in cwd %s [%?]", path.to_str(),
+ os::getcwd().to_str(), os::path_exists(&path));
+ assert!(os::mkdir_recursive(&path, (S_IRUSR | S_IWUSR | S_IXUSR) as i32));
+ assert!(os::path_is_dir(&path));
+ assert!(os::path_is_dir(&path.pop()));
+ let path2 = Path("quux/blat");
+ debug!("recursive_mkdir_rel_2: Making: %s in cwd %s", path2.to_str(),
+ os::getcwd().to_str());
+ assert!(os::mkdir_recursive(&path2, (S_IRUSR | S_IWUSR | S_IXUSR) as i32));
+ assert!(os::path_is_dir(&path2));
+ assert!(os::path_is_dir(&path2.pop()));
+}
+
+// Ideally this would be in core, but needs mkdtemp
+pub fn test_rmdir_recursive_ok() {
+ let rwx = (S_IRUSR | S_IWUSR | S_IXUSR) as i32;
+
+ let tmpdir = mkdtemp(&os::tmpdir(), "test").expect("test_rmdir_recursive_ok: \
+ couldn't create temp dir");
+ let root = tmpdir.push("foo");
+
+ debug!("making %s", root.to_str());
+ assert!(os::make_dir(&root, rwx));
+ assert!(os::make_dir(&root.push("foo"), rwx));
+ assert!(os::make_dir(&root.push("foo").push("bar"), rwx));
+ assert!(os::make_dir(&root.push("foo").push("bar").push("blat"), rwx));
+ assert!(os::remove_dir_recursive(&root));
+ assert!(!os::path_exists(&root));
+ assert!(!os::path_exists(&root.push("bar")));
+ assert!(!os::path_exists(&root.push("bar").push("blat")));
+}
+
+fn in_tmpdir(f: &fn()) {
+ let tmpdir = mkdtemp(&os::tmpdir(), "test").expect("can't make tmpdir");
+ assert!(os::change_dir(&tmpdir));
+
+ f();
+}
+
+fn main() {
+ in_tmpdir(test_mkdtemp);
+ in_tmpdir(recursive_mkdir_rel);
+ in_tmpdir(recursive_mkdir_dot);
+ in_tmpdir(recursive_mkdir_rel_2);
+ in_tmpdir(test_rmdir_recursive_ok);
+}