Merge branch 'incoming' of github.com:mozilla/rust

This commit is contained in:
Paul Stansifer 2012-07-26 16:16:28 -07:00
commit 97422f0f0f
57 changed files with 829 additions and 467 deletions

View file

@ -3,10 +3,9 @@
* share immutable data between tasks.
*/
import comm::{port, chan, methods};
import sys::methods;
export arc, get, clone, shared_arc, get_arc;
export arc, get, clone;
export exclusive, methods;
@ -122,49 +121,6 @@ impl methods<T: send> for exclusive<T> {
}
}
// Convenience code for sharing arcs between tasks
type get_chan<T: const send> = chan<chan<arc<T>>>;
// (terminate, get)
type shared_arc<T: const send> = (shared_arc_res, get_chan<T>);
class shared_arc_res {
let c: comm::chan<()>;
new(c: comm::chan<()>) { self.c = c; }
drop { self.c.send(()); }
}
fn shared_arc<T: send const>(-data: T) -> shared_arc<T> {
let a = arc::arc(data);
let p = port();
let c = chan(p);
do task::spawn() |move a| {
let mut live = true;
let terminate = port();
let get = port();
c.send((chan(terminate), chan(get)));
while live {
alt comm::select2(terminate, get) {
either::left(()) { live = false; }
either::right(cc) {
comm::send(cc, arc::clone(&a));
}
}
}
};
let (terminate, get) = p.recv();
(shared_arc_res(terminate), get)
}
fn get_arc<T: send const>(c: get_chan<T>) -> arc::arc<T> {
let p = port();
c.send(chan(p));
p.recv()
}
#[cfg(test)]
mod tests {
import comm::*;
@ -196,25 +152,6 @@ mod tests {
log(info, arc_v);
}
#[test]
fn auto_share_arc() {
let v = ~[1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let (_res, arc_c) = shared_arc(v);
let p = port();
let c = chan(p);
do task::spawn() {
let arc_v = get_arc(arc_c);
let v = *get(&arc_v);
assert v[2] == 3;
c.send(());
};
assert p.recv() == ();
}
#[test]
#[ignore] // this can probably infinite loop too.
fn exclusive_arc() {

View file

@ -1,10 +1,10 @@
/// Interfaces used for comparison.
iface ord {
fn lt(&&other: self) -> bool;
trait ord {
pure fn lt(&&other: self) -> bool;
}
iface eq {
fn eq(&&other: self) -> bool;
trait eq {
pure fn eq(&&other: self) -> bool;
}

View file

@ -161,6 +161,7 @@ mod tuple;
// Ubiquitous-utility-type modules
mod ops;
mod cmp;
mod num;
mod hash;

View file

@ -30,6 +30,8 @@ import float::num;
import f32::num;
import f64::num;
import num::num;
import ops::{const, copy, send, owned};
import ops::{add, sub, mul, div, modulo, neg, bitops, index};
export path, option, some, none, unreachable;
export extensions;
@ -42,6 +44,9 @@ export immutable_copyable_vector, iter_trait_extensions, vec_concat;
export base_iter, copyable_iter, extended_iter;
export tuple_ops, extended_tuple_ops;
export ptr;
// The following exports are the core operators and kinds
export const, copy, send, owned;
export add, sub, mul, div, modulo, neg, bitops, index;
// Export the log levels as global constants. Higher levels mean
// more-verbosity. Error is the bottom level, default logging level is

View file

@ -18,12 +18,28 @@ enum dlist_node<T> = @{
mut next: dlist_link<T>
};
// Needs to be an @-box so nodes can back-reference it.
enum dlist<T> = @{
mut size: uint,
mut hd: dlist_link<T>,
mut tl: dlist_link<T>
};
class dlist_root<T> {
let mut size: uint;
let mut hd: dlist_link<T>;
let mut tl: dlist_link<T>;
new() {
self.size = 0; self.hd = none; self.tl = none;
}
drop {
/* FIXME (#????) This doesn't work during task failure - the box
* annihilator might have killed some of our nodes already. This will
* be safe to uncomment when the box annihilator is safer. As is,
* this makes test_dlist_cyclic_link below crash the runtime.
// Empty the list. Not doing this explicitly would leave cyclic links
// around, not to be freed until cycle collection at task exit.
while self.hd.is_some() {
self.unlink(self.hd.get());
}
*/
}
}
type dlist<T> = @dlist_root<T>;
impl private_methods<T> for dlist_node<T> {
pure fn assert_links() {
@ -91,7 +107,7 @@ pure fn new_dlist_node<T>(+data: T) -> dlist_node<T> {
/// Creates a new, empty dlist.
pure fn new_dlist<T>() -> dlist<T> {
dlist(@{mut size: 0, mut hd: none, mut tl: none})
@unchecked { dlist_root() }
}
/// Creates a new dlist with a single element
@ -118,7 +134,7 @@ fn concat<T>(lists: dlist<dlist<T>>) -> dlist<T> {
result
}
impl private_methods<T> for dlist<T> {
impl private_methods<T> for dlist_root<T> {
pure fn new_link(-data: T) -> dlist_link<T> {
some(dlist_node(@{data: data, mut linked: true,
mut prev: none, mut next: none}))
@ -288,20 +304,6 @@ impl extensions<T> for dlist<T> {
tl.map(|nobe| self.unlink(nobe));
tl
}
/// Remove data from the head of the list. O(1).
fn pop() -> option<T> {
do option::map_consume(self.pop_n()) |nobe| {
let dlist_node(@{ data: x, _ }) <- nobe;
x
}
}
/// Remove data from the tail of the list. O(1).
fn pop_tail() -> option<T> {
do option::map_consume(self.pop_tail_n()) |nobe| {
let dlist_node(@{ data: x, _ }) <- nobe;
x
}
}
/// Get the node at the list's head. O(1).
pure fn peek_n() -> option<dlist_node<T>> { self.hd }
/// Get the node at the list's tail. O(1).
@ -334,7 +336,7 @@ impl extensions<T> for dlist<T> {
* to the other list's head. O(1).
*/
fn append(them: dlist<T>) {
if box::ptr_eq(*self, *them) {
if box::ptr_eq(self, them) {
fail ~"Cannot append a dlist to itself!"
}
if them.len() > 0 {
@ -351,7 +353,7 @@ impl extensions<T> for dlist<T> {
* list's tail to this list's head. O(1).
*/
fn prepend(them: dlist<T>) {
if box::ptr_eq(*self, *them) {
if box::ptr_eq(self, them) {
fail ~"Cannot prepend a dlist to itself!"
}
if them.len() > 0 {
@ -366,15 +368,25 @@ impl extensions<T> for dlist<T> {
/// Reverse the list's elements in place. O(n).
fn reverse() {
let temp = new_dlist::<T>();
while !self.is_empty() {
let nobe = self.pop_n().get();
nobe.linked = true; // meh, kind of disorganised.
temp.add_head(some(nobe));
do option::while_some(self.hd) |nobe| {
let next_nobe = nobe.next;
self.remove(nobe);
self.make_mine(nobe);
self.add_head(some(nobe));
next_nobe
}
}
/**
* Remove everything from the list. This is important because the cyclic
* links won't otherwise be automatically refcounted-collected. O(n).
*/
fn clear() {
// Cute as it would be to simply detach the list and proclaim "O(1)!",
// the GC would still be a hidden O(n). Better to be honest about it.
while !self.is_empty() {
let _ = self.pop_n();
}
self.hd = temp.hd;
self.tl = temp.tl;
self.size = temp.size;
}
/// Iterate over nodes.
@ -431,6 +443,10 @@ impl extensions<T> for dlist<T> {
}
impl extensions<T: copy> for dlist<T> {
/// Remove data from the head of the list. O(1).
fn pop() -> option<T> { self.pop_n().map (|nobe| nobe.data) }
/// Remove data from the tail of the list. O(1).
fn pop_tail() -> option<T> { self.pop_tail_n().map (|nobe| nobe.data) }
/// Get data at the list's head. O(1).
pure fn peek() -> option<T> { self.peek_n().map (|nobe| nobe.data) }
/// Get data at the list's tail. O(1).
@ -596,6 +612,13 @@ mod tests {
a.assert_consistent(); assert a.is_empty();
}
#[test]
fn test_dlist_clear() {
let a = from_vec(~[5,4,3,2,1]);
a.clear();
assert a.len() == 0;
a.assert_consistent();
}
#[test]
fn test_dlist_is_empty() {
let empty = new_dlist::<int>();
let full1 = from_vec(~[1,2,3]);
@ -847,7 +870,7 @@ mod tests {
l.assert_consistent(); assert l.is_empty();
}
#[test] #[should_fail] #[ignore(cfg(windows))]
fn test_asymmetric_link() {
fn test_dlist_asymmetric_link() {
let l = new_dlist::<int>();
let _one = l.push_n(1);
let two = l.push_n(2);
@ -855,7 +878,7 @@ mod tests {
l.assert_consistent();
}
#[test] #[should_fail] #[ignore(cfg(windows))]
fn test_cyclic_list() {
fn test_dlist_cyclic_list() {
let l = new_dlist::<int>();
let one = l.push_n(1);
let _two = l.push_n(2);
@ -865,32 +888,32 @@ mod tests {
l.assert_consistent();
}
#[test] #[should_fail] #[ignore(cfg(windows))]
fn test_headless() {
fn test_dlist_headless() {
new_dlist::<int>().head();
}
#[test] #[should_fail] #[ignore(cfg(windows))]
fn test_insert_already_present_before() {
fn test_dlist_insert_already_present_before() {
let l = new_dlist::<int>();
let one = l.push_n(1);
let two = l.push_n(2);
l.insert_n_before(two, one);
}
#[test] #[should_fail] #[ignore(cfg(windows))]
fn test_insert_already_present_after() {
fn test_dlist_insert_already_present_after() {
let l = new_dlist::<int>();
let one = l.push_n(1);
let two = l.push_n(2);
l.insert_n_after(one, two);
}
#[test] #[should_fail] #[ignore(cfg(windows))]
fn test_insert_before_orphan() {
fn test_dlist_insert_before_orphan() {
let l = new_dlist::<int>();
let one = new_dlist_node(1);
let two = new_dlist_node(2);
l.insert_n_before(one, two);
}
#[test] #[should_fail] #[ignore(cfg(windows))]
fn test_insert_after_orphan() {
fn test_dlist_insert_after_orphan() {
let l = new_dlist::<int>();
let one = new_dlist_node(1);
let two = new_dlist_node(2);

View file

@ -168,15 +168,15 @@ pure fn log2(n: f32) -> f32 {
}
impl num of num::num for f32 {
fn add(&&other: f32) -> f32 { ret self + other; }
fn sub(&&other: f32) -> f32 { ret self - other; }
fn mul(&&other: f32) -> f32 { ret self * other; }
fn div(&&other: f32) -> f32 { ret self / other; }
fn modulo(&&other: f32) -> f32 { ret self % other; }
fn neg() -> f32 { ret -self; }
pure fn add(&&other: f32) -> f32 { ret self + other; }
pure fn sub(&&other: f32) -> f32 { ret self - other; }
pure fn mul(&&other: f32) -> f32 { ret self * other; }
pure fn div(&&other: f32) -> f32 { ret self / other; }
pure fn modulo(&&other: f32) -> f32 { ret self % other; }
pure fn neg() -> f32 { ret -self; }
fn to_int() -> int { ret self as int; }
fn from_int(n: int) -> f32 { ret n as f32; }
pure fn to_int() -> int { ret self as int; }
pure fn from_int(n: int) -> f32 { ret n as f32; }
}
//

View file

@ -195,15 +195,15 @@ pure fn log2(n: f64) -> f64 {
}
impl num of num::num for f64 {
fn add(&&other: f64) -> f64 { ret self + other; }
fn sub(&&other: f64) -> f64 { ret self - other; }
fn mul(&&other: f64) -> f64 { ret self * other; }
fn div(&&other: f64) -> f64 { ret self / other; }
fn modulo(&&other: f64) -> f64 { ret self % other; }
fn neg() -> f64 { ret -self; }
pure fn add(&&other: f64) -> f64 { ret self + other; }
pure fn sub(&&other: f64) -> f64 { ret self - other; }
pure fn mul(&&other: f64) -> f64 { ret self * other; }
pure fn div(&&other: f64) -> f64 { ret self / other; }
pure fn modulo(&&other: f64) -> f64 { ret self % other; }
pure fn neg() -> f64 { ret -self; }
fn to_int() -> int { ret self as int; }
fn from_int(n: int) -> f64 { ret n as f64; }
pure fn to_int() -> int { ret self as int; }
pure fn from_int(n: int) -> f64 { ret n as f64; }
}
//

View file

@ -403,32 +403,32 @@ fn pow_with_uint(base: uint, pow: uint) -> float {
ret total;
}
fn is_positive(x: float) -> bool { f64::is_positive(x as f64) }
fn is_negative(x: float) -> bool { f64::is_negative(x as f64) }
fn is_nonpositive(x: float) -> bool { f64::is_nonpositive(x as f64) }
fn is_nonnegative(x: float) -> bool { f64::is_nonnegative(x as f64) }
fn is_zero(x: float) -> bool { f64::is_zero(x as f64) }
fn is_infinite(x: float) -> bool { f64::is_infinite(x as f64) }
fn is_finite(x: float) -> bool { f64::is_finite(x as f64) }
fn is_NaN(x: float) -> bool { f64::is_NaN(x as f64) }
pure fn is_positive(x: float) -> bool { f64::is_positive(x as f64) }
pure fn is_negative(x: float) -> bool { f64::is_negative(x as f64) }
pure fn is_nonpositive(x: float) -> bool { f64::is_nonpositive(x as f64) }
pure fn is_nonnegative(x: float) -> bool { f64::is_nonnegative(x as f64) }
pure fn is_zero(x: float) -> bool { f64::is_zero(x as f64) }
pure fn is_infinite(x: float) -> bool { f64::is_infinite(x as f64) }
pure fn is_finite(x: float) -> bool { f64::is_finite(x as f64) }
pure fn is_NaN(x: float) -> bool { f64::is_NaN(x as f64) }
fn abs(x: float) -> float { f64::abs(x as f64) as float }
fn sqrt(x: float) -> float { f64::sqrt(x as f64) as float }
fn atan(x: float) -> float { f64::atan(x as f64) as float }
fn sin(x: float) -> float { f64::sin(x as f64) as float }
fn cos(x: float) -> float { f64::cos(x as f64) as float }
fn tan(x: float) -> float { f64::tan(x as f64) as float }
pure fn abs(x: float) -> float { f64::abs(x as f64) as float }
pure fn sqrt(x: float) -> float { f64::sqrt(x as f64) as float }
pure fn atan(x: float) -> float { f64::atan(x as f64) as float }
pure fn sin(x: float) -> float { f64::sin(x as f64) as float }
pure fn cos(x: float) -> float { f64::cos(x as f64) as float }
pure fn tan(x: float) -> float { f64::tan(x as f64) as float }
impl num of num::num for float {
fn add(&&other: float) -> float { ret self + other; }
fn sub(&&other: float) -> float { ret self - other; }
fn mul(&&other: float) -> float { ret self * other; }
fn div(&&other: float) -> float { ret self / other; }
fn modulo(&&other: float) -> float { ret self % other; }
fn neg() -> float { ret -self; }
pure fn add(&&other: float) -> float { ret self + other; }
pure fn sub(&&other: float) -> float { ret self - other; }
pure fn mul(&&other: float) -> float { ret self * other; }
pure fn div(&&other: float) -> float { ret self / other; }
pure fn modulo(&&other: float) -> float { ret self % other; }
pure fn neg() -> float { ret -self; }
fn to_int() -> int { ret self as int; }
fn from_int(n: int) -> float { ret n as float; }
pure fn to_int() -> int { ret self as int; }
pure fn from_int(n: int) -> float { ret n as float; }
}
#[test]

View file

@ -112,27 +112,27 @@ fn to_str_bytes<U>(n: T, radix: uint, f: fn(v: &[u8]) -> U) -> U {
fn str(i: T) -> ~str { ret to_str(i, 10u); }
impl ord of ord for T {
fn lt(&&other: T) -> bool {
pure fn lt(&&other: T) -> bool {
ret self < other;
}
}
impl eq of eq for T {
fn eq(&&other: T) -> bool {
pure fn eq(&&other: T) -> bool {
ret self == other;
}
}
impl num of num::num for T {
fn add(&&other: T) -> T { ret self + other; }
fn sub(&&other: T) -> T { ret self - other; }
fn mul(&&other: T) -> T { ret self * other; }
fn div(&&other: T) -> T { ret self / other; }
fn modulo(&&other: T) -> T { ret self % other; }
fn neg() -> T { ret -self; }
pure fn add(&&other: T) -> T { ret self + other; }
pure fn sub(&&other: T) -> T { ret self - other; }
pure fn mul(&&other: T) -> T { ret self * other; }
pure fn div(&&other: T) -> T { ret self / other; }
pure fn modulo(&&other: T) -> T { ret self % other; }
pure fn neg() -> T { ret -self; }
fn to_int() -> int { ret self as int; }
fn from_int(n: int) -> T { ret n as T; }
pure fn to_int() -> int { ret self as int; }
pure fn from_int(n: int) -> T { ret n as T; }
}
impl times of iter::times for T {

View file

@ -687,7 +687,11 @@ fn seek_in_buf(offset: int, pos: uint, len: uint, whence: seek_style) ->
fn read_whole_file_str(file: ~str) -> result<~str, ~str> {
result::chain(read_whole_file(file), |bytes| {
result::ok(str::from_bytes(bytes))
if str::is_utf8(bytes) {
result::ok(str::from_bytes(bytes))
} else {
result::err(file + ~" is not UTF-8")
}
})
}

View file

@ -1,17 +1,17 @@
/// An interface for numbers.
iface num {
trait num {
// FIXME: Cross-crate overloading doesn't work yet. (#2615)
// FIXME: Interface inheritance. (#2616)
fn add(&&other: self) -> self;
fn sub(&&other: self) -> self;
fn mul(&&other: self) -> self;
fn div(&&other: self) -> self;
fn modulo(&&other: self) -> self;
fn neg() -> self;
pure fn add(&&other: self) -> self;
pure fn sub(&&other: self) -> self;
pure fn mul(&&other: self) -> self;
pure fn div(&&other: self) -> self;
pure fn modulo(&&other: self) -> self;
pure fn neg() -> self;
fn to_int() -> int;
fn from_int(n: int) -> self; // FIXME (#2376) Static functions.
pure fn to_int() -> int;
pure fn from_int(n: int) -> self; // FIXME (#2376) Static functions.
// n.b. #2376 is for classes, not ifaces, but it could be generalized...
}

66
src/libcore/ops.rs Normal file
View file

@ -0,0 +1,66 @@
// Core operators and kinds.
#[lang="const"]
trait const {
// Empty.
}
#[lang="copy"]
trait copy {
// Empty.
}
#[lang="send"]
trait send {
// Empty.
}
#[lang="owned"]
trait owned {
// Empty.
}
#[lang="add"]
trait add<RHS,Result> {
pure fn add(rhs: RHS) -> Result;
}
#[lang="sub"]
trait sub<RHS,Result> {
pure fn sub(rhs: RHS) -> Result;
}
#[lang="mul"]
trait mul<RHS,Result> {
pure fn mul(rhs: RHS) -> Result;
}
#[lang="div"]
trait div<RHS,Result> {
pure fn div(rhs: RHS) -> Result;
}
#[lang="modulo"]
trait modulo<RHS,Result> {
pure fn modulo(rhs: RHS) -> Result;
}
#[lang="neg"]
trait neg<RHS,Result> {
pure fn neg(rhs: RHS) -> Result;
}
#[lang="bitops"]
trait bitops<RHS,BitCount,Result> {
pure fn and(rhs: RHS) -> Result;
pure fn or(rhs: RHS) -> Result;
pure fn xor(rhs: RHS) -> Result;
pure fn shl(n: BitCount) -> Result;
pure fn shr(n: BitCount) -> Result;
}
#[lang="index"]
trait index<Index,Result> {
pure fn index(index: Index) -> Result;
}

View file

@ -30,59 +30,6 @@ macro_rules! move {
// places. Once there is unary move, it can be removed.
fn move<T>(-x: T) -> T { x }
/**
Some thoughts about fixed buffers.
The idea is if a protocol is bounded, we will synthesize a record that
has a field for each state. Each of these states contains a packet for
the messages that are legal to be sent in that state. Then, instead of
allocating, the send code just finds a pointer to the right field and
uses that instead.
Unforunately, this makes things kind of tricky. We need to be able to
find the buffer, which means we need to pass it around. This could
either be associated with the (send|recv)_packet classes, or with the
packet itself. We will also need some form of reference counting so we
can track who has the responsibility of freeing the buffer.
We want to preserve the ability to do things like optimistic buffer
re-use, and skipping over to a new buffer when necessary. What I mean
is, suppose we had the typical stream protocol. It'd make sense to
amortize allocation costs by allocating a buffer with say 16
messages. When the sender gets to the end of the buffer, it could
check if the receiver is done with the packet in slot 0. If so, it can
just reuse that one, checking if the receiver is done with the next
one in each case. If it is ever not done, it just allocates a new
buffer and skips over to that.
Also, since protocols are in libcore, we have to do this in a way that
maintains backwards compatibility.
buffer header and buffer. Cast as c_void when necessary.
===
Okay, here are some new ideas.
It'd be nice to keep the bounded/unbounded case as uniform as
possible. It leads to less code duplication, and less things that can
go sublty wrong. For the bounded case, we could either have a struct
with a bunch of unique pointers to pre-allocated packets, or we could
lay them out inline. Inline layout is better, if for no other reason
than that we don't have to allocate each packet
individually. Currently we pass unique packets around as unsafe
pointers, but they are actually unique pointers. We should instead use
real unsafe pointers. This makes freeing data and running destructors
trickier though. Thus, we should allocate all packets in parter of a
higher level buffer structure. Packets can maintain a pointer to their
buffer, and this is the part that gets freed.
It might be helpful to have some idea of a semi-unique pointer (like
being partially pregnant, also like an ARC).
*/
enum state {
empty,
full,
@ -805,6 +752,12 @@ class port_set<T: send> : recv<T> {
vec::push(self.ports, port)
}
fn chan() -> chan<T> {
let (ch, po) = stream();
self.add(po);
ch
}
fn try_recv() -> option<T> {
let mut result = none;
while result == none && self.ports.len() > 0 {
@ -869,3 +822,52 @@ impl chan<T: send> of channel<T> for shared_chan<T> {
fn shared_chan<T:send>(+c: chan<T>) -> shared_chan<T> {
arc::exclusive(c)
}
trait select2<T: send, U: send> {
fn try_select() -> either<option<T>, option<U>>;
fn select() -> either<T, U>;
}
impl<T: send, U: send, Left: selectable recv<T>, Right: selectable recv<U>>
of select2<T, U> for (Left, Right) {
fn select() -> either<T, U> {
alt self {
(lp, rp) {
alt select2i(lp, rp) {
left(()) { left (lp.recv()) }
right(()) { right(rp.recv()) }
}
}
}
}
fn try_select() -> either<option<T>, option<U>> {
alt self {
(lp, rp) {
alt select2i(lp, rp) {
left(()) { left (lp.try_recv()) }
right(()) { right(rp.try_recv()) }
}
}
}
}
}
#[cfg(test)]
mod test {
#[test]
fn test_select2() {
let (c1, p1) = pipes::stream();
let (c2, p2) = pipes::stream();
c1.send("abc");
alt (p1, p2).select() {
right(_) { fail }
_ { }
}
c2.send(123);
}
}

View file

@ -53,27 +53,27 @@ pure fn compl(i: T) -> T {
}
impl ord of ord for T {
fn lt(&&other: T) -> bool {
pure fn lt(&&other: T) -> bool {
ret self < other;
}
}
impl eq of eq for T {
fn eq(&&other: T) -> bool {
pure fn eq(&&other: T) -> bool {
ret self == other;
}
}
impl num of num::num for T {
fn add(&&other: T) -> T { ret self + other; }
fn sub(&&other: T) -> T { ret self - other; }
fn mul(&&other: T) -> T { ret self * other; }
fn div(&&other: T) -> T { ret self / other; }
fn modulo(&&other: T) -> T { ret self % other; }
fn neg() -> T { ret -self; }
pure fn add(&&other: T) -> T { ret self + other; }
pure fn sub(&&other: T) -> T { ret self - other; }
pure fn mul(&&other: T) -> T { ret self * other; }
pure fn div(&&other: T) -> T { ret self / other; }
pure fn modulo(&&other: T) -> T { ret self % other; }
pure fn neg() -> T { ret -self; }
fn to_int() -> int { ret self as int; }
fn from_int(n: int) -> T { ret n as T; }
pure fn to_int() -> int { ret self as int; }
pure fn from_int(n: int) -> T { ret n as T; }
}
/**

View file

@ -2,24 +2,24 @@
const fuzzy_epsilon: float = 1.0e-6;
iface fuzzy_eq {
fn fuzzy_eq(&&other: self) -> bool;
trait fuzzy_eq {
pure fn fuzzy_eq(&&other: self) -> bool;
}
impl fuzzy_eq of fuzzy_eq for float {
fn fuzzy_eq(&&other: float) -> bool {
pure fn fuzzy_eq(&&other: float) -> bool {
ret float::abs(self - other) < fuzzy_epsilon;
}
}
impl fuzzy_eq of fuzzy_eq for f32 {
fn fuzzy_eq(&&other: f32) -> bool {
pure fn fuzzy_eq(&&other: f32) -> bool {
ret f32::abs(self - other) < (fuzzy_epsilon as f32);
}
}
impl fuzzy_eq of fuzzy_eq for f64 {
fn fuzzy_eq(&&other: f64) -> bool {
pure fn fuzzy_eq(&&other: f64) -> bool {
ret f64::abs(self - other) < (fuzzy_epsilon as f64);
}
}

View file

@ -87,7 +87,7 @@ enum def {
def_upvar(node_id /* local id of closed over var */,
@def /* closed over def */,
node_id /* expr node that creates the closure */),
def_class(def_id),
def_class(def_id, bool /* has constructor */),
def_region(node_id)
}

View file

@ -53,7 +53,7 @@ pure fn def_id_of_def(d: def) -> def_id {
def_fn(id, _) | def_mod(id) |
def_foreign_mod(id) | def_const(id) |
def_variant(_, id) | def_ty(id) | def_ty_param(id, _) |
def_use(id) | def_class(id) { id }
def_use(id) | def_class(id, _) { id }
def_arg(id, _) | def_local(id, _) | def_self(id) |
def_upvar(id, _, _) | def_binding(id) | def_region(id) {
local_def(id)

View file

@ -183,7 +183,6 @@ impl ast_builder of ext_ctxt_ast_builder for ext_ctxt {
{mode: ast::infer(self.next_id()),
ty: ty,
ident: name,
// FIXME #2886: should this be the same as the infer id?
id: self.next_id()}
}
@ -280,7 +279,6 @@ impl ast_builder of ext_ctxt_ast_builder for ext_ctxt {
}
fn ty_path_ast_builder(path: @ast::path) -> @ast::ty {
// FIXME #2886: make sure the node ids are legal.
@{id: self.next_id(),
node: ast::ty_path(path, self.next_id()),
span: self.empty_span()}

View file

@ -14,6 +14,7 @@ import io::{reader_util, writer_util};
import getopts::{optopt, optmulti, optflag, optflagopt, opt_present};
import back::{x86, x86_64};
import std::map::hashmap;
import lib::llvm::llvm;
enum pp_mode {ppm_normal, ppm_expanded, ppm_typed, ppm_identified,
ppm_expanded_identified }
@ -169,6 +170,9 @@ fn compile_upto(sess: session, cfg: ast::crate_cfg,
session::sess_os_to_meta_os(sess.targ_cfg.os),
sess.opts.static));
time(time_passes, ~"language item collection", ||
middle::lang_items::collect_language_items(crate, sess));
let { def_map: def_map,
exp_map: exp_map,
impl_map: impl_map,
@ -440,6 +444,9 @@ fn build_session_options(match: getopts::match,
}
debugging_opts |= this_bit;
}
if debugging_opts & session::debug_llvm != 0 {
llvm::LLVMSetDebug(1);
}
let output_type =
if parse_only || no_trans {

View file

@ -40,6 +40,7 @@ const borrowck_stats: uint = 1024u;
const borrowck_note_pure: uint = 2048;
const borrowck_note_loan: uint = 4096;
const no_landing_pads: uint = 8192;
const debug_llvm: uint = 16384;
fn debugging_opts_map() -> ~[(~str, ~str, uint)] {
~[(~"ppregions", ~"prettyprint regions with \
@ -61,7 +62,8 @@ fn debugging_opts_map() -> ~[(~str, ~str, uint)] {
(~"borrowck-note-loan", ~"note where loans are req'd",
borrowck_note_loan),
(~"no-landing-pads", ~"omit landing pads for unwinding",
no_landing_pads)
no_landing_pads),
(~"debug-llvm", ~"enable debug output from LLVM", debug_llvm)
]
}

View file

@ -969,6 +969,9 @@ extern mod llvm {
fn LLVMConstNamedStruct(S: TypeRef, ConstantVals: *ValueRef,
Count: c_uint) -> ValueRef;
/** Enables LLVM debug output. */
fn LLVMSetDebug(Enabled: c_int);
}
fn SetInstructionCallConv(Instr: ValueRef, CC: CallConv) {

View file

@ -25,6 +25,7 @@ export get_enum_variants;
export get_impls_for_mod;
export get_trait_methods;
export get_method_names_if_trait;
export get_item_attrs;
export each_path;
export get_type;
export get_impl_traits;
@ -149,6 +150,14 @@ fn get_method_names_if_trait(cstore: cstore::cstore, def: ast::def_id)
ret decoder::get_method_names_if_trait(cdata, def.node);
}
fn get_item_attrs(cstore: cstore::cstore,
def_id: ast::def_id,
f: fn(~[@ast::meta_item])) {
let cdata = cstore::get_crate_data(cstore, def_id.crate);
decoder::get_item_attrs(cdata, def_id.node, f)
}
fn get_class_fields(tcx: ty::ctxt, def: ast::def_id) -> ~[ty::field_ty] {
let cstore = tcx.cstore;
let cdata = cstore::get_crate_data(cstore, def.crate);

View file

@ -39,6 +39,7 @@ export get_crate_vers;
export get_impls_for_mod;
export get_trait_methods;
export get_method_names_if_trait;
export get_item_attrs;
export get_crate_module_paths;
export def_like;
export dl_def;
@ -282,7 +283,8 @@ fn item_to_def_like(item: ebml::doc, did: ast::def_id, cnum: ast::crate_num)
let fam_ch = item_family(item);
alt fam_ch {
'c' { dl_def(ast::def_const(did)) }
'C' { dl_def(ast::def_class(did)) }
'C' { dl_def(ast::def_class(did, true)) }
'S' { dl_def(ast::def_class(did, false)) }
'u' { dl_def(ast::def_fn(did, ast::unsafe_fn)) }
'f' { dl_def(ast::def_fn(did, ast::impure_fn)) }
'p' { dl_def(ast::def_fn(did, ast::pure_fn)) }
@ -659,6 +661,18 @@ fn get_method_names_if_trait(cdata: cmd, node_id: ast::node_id)
ret some(resulting_method_names);
}
fn get_item_attrs(cdata: cmd,
node_id: ast::node_id,
f: fn(~[@ast::meta_item])) {
let item = lookup_item(node_id, cdata.data);
do ebml::tagged_docs(item, tag_attributes) |attributes| {
do ebml::tagged_docs(attributes, tag_attribute) |attribute| {
f(get_meta_items(attribute));
}
}
}
// Helper function that gets either fields or methods
fn get_class_members(cdata: cmd, id: ast::node_id,
p: fn(char) -> bool) -> ~[ty::field_ty] {
@ -694,7 +708,7 @@ fn family_has_type_params(fam_ch: char) -> bool {
alt check fam_ch {
'c' | 'T' | 'm' | 'n' | 'g' | 'h' | 'j' { false }
'f' | 'u' | 'p' | 'F' | 'U' | 'P' | 'y' | 't' | 'v' | 'i' | 'I' | 'C'
| 'a'
| 'a' | 'S'
{ true }
}
}
@ -738,6 +752,7 @@ fn item_family_to_str(fam: char) -> ~str {
'i' { ret ~"impl"; }
'I' { ret ~"trait"; }
'C' { ret ~"class"; }
'S' { ret ~"struct"; }
'g' { ret ~"public field"; }
'j' { ret ~"private field"; }
}

View file

@ -663,7 +663,16 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item,
/* Now, make an item for the class itself */
ebml_w.start_tag(tag_items_data_item);
encode_def_id(ebml_w, local_def(item.id));
encode_family(ebml_w, 'C');
alt ctor {
none {
encode_family(ebml_w, 'S');
}
some(_) {
encode_family(ebml_w, 'C');
}
}
encode_type_param_bounds(ebml_w, ecx, tps);
encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
encode_name(ebml_w, item.ident);
@ -759,6 +768,7 @@ fn encode_info_for_item(ecx: @encode_ctxt, ebml_w: ebml::writer, item: @item,
encode_type_param_bounds(ebml_w, ecx, tps);
encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id));
encode_name(ebml_w, item.ident);
encode_attributes(ebml_w, item.attrs);
let mut i = 0u;
for vec::each(*ty::trait_methods(tcx, local_def(item.id))) |mty| {
alt ms[i] {

View file

@ -369,8 +369,8 @@ impl of tr for ast::def {
ast::def_upvar(nid1, def, nid2) {
ast::def_upvar(xcx.tr_id(nid1), @(*def).tr(xcx), xcx.tr_id(nid2))
}
ast::def_class(did) {
ast::def_class(did.tr(xcx))
ast::def_class(did, has_constructor) {
ast::def_class(did.tr(xcx), has_constructor)
}
ast::def_region(nid) { ast::def_region(xcx.tr_id(nid)) }
}

View file

@ -196,7 +196,7 @@ impl public_methods for borrowck_ctxt {
ast::def_foreign_mod(_) | ast::def_const(_) |
ast::def_use(_) | ast::def_variant(_, _) |
ast::def_ty(_) | ast::def_prim_ty(_) |
ast::def_ty_param(_, _) | ast::def_class(_) |
ast::def_ty_param(_, _) | ast::def_class(_, _) |
ast::def_region(_) {
@{id:id, span:span,
cat:cat_special(sk_static_item), lp:none,

View file

@ -0,0 +1,209 @@
// Detecting language items.
//
// Language items are items that represent concepts intrinsic to the language
// itself. Examples are:
//
// * Traits that specify "kinds"; e.g. "const", "copy", "send".
//
// * Traits that represent operators; e.g. "add", "sub", "index".
//
// * Functions called by the compiler itself.
import driver::session::session;
import metadata::csearch::{each_path, get_item_attrs};
import metadata::cstore::{iter_crate_data};
import metadata::decoder::{dl_def, dl_field, dl_impl};
import syntax::ast::{crate, def_id, def_ty, lit_str, meta_item, meta_list};
import syntax::ast::{meta_name_value, meta_word};
import syntax::ast_util::{local_def};
import syntax::visit::{default_simple_visitor, mk_simple_visitor};
import syntax::visit::{visit_crate, visit_item};
import std::map::{hashmap, str_hash};
import str_eq = str::eq;
class LanguageItems {
let mut const_trait: option<def_id>;
let mut copy_trait: option<def_id>;
let mut send_trait: option<def_id>;
let mut owned_trait: option<def_id>;
let mut add_trait: option<def_id>;
let mut sub_trait: option<def_id>;
let mut mul_trait: option<def_id>;
let mut div_trait: option<def_id>;
let mut modulo_trait: option<def_id>;
let mut neg_trait: option<def_id>;
let mut bitops_trait: option<def_id>;
let mut index_trait: option<def_id>;
new() {
self.const_trait = none;
self.copy_trait = none;
self.send_trait = none;
self.owned_trait = none;
self.add_trait = none;
self.sub_trait = none;
self.mul_trait = none;
self.div_trait = none;
self.modulo_trait = none;
self.neg_trait = none;
self.bitops_trait = none;
self.index_trait = none;
}
}
class LanguageItemCollector {
let items: LanguageItems;
let crate: @crate;
let session: session;
let item_refs: hashmap<~str,&mut option<def_id>>;
new(crate: @crate, session: session) {
self.crate = crate;
self.session = session;
self.items = LanguageItems();
self.item_refs = str_hash();
}
// XXX: Needed to work around an issue with constructors.
fn init() {
self.item_refs.insert(~"const", &mut self.items.const_trait);
self.item_refs.insert(~"copy", &mut self.items.copy_trait);
self.item_refs.insert(~"send", &mut self.items.send_trait);
self.item_refs.insert(~"owned", &mut self.items.owned_trait);
self.item_refs.insert(~"add", &mut self.items.add_trait);
self.item_refs.insert(~"sub", &mut self.items.sub_trait);
self.item_refs.insert(~"mul", &mut self.items.mul_trait);
self.item_refs.insert(~"div", &mut self.items.div_trait);
self.item_refs.insert(~"modulo", &mut self.items.modulo_trait);
self.item_refs.insert(~"neg", &mut self.items.neg_trait);
self.item_refs.insert(~"bitops", &mut self.items.bitops_trait);
self.item_refs.insert(~"index", &mut self.items.index_trait);
}
fn match_and_collect_meta_item(item_def_id: def_id,
meta_item: meta_item) {
alt meta_item.node {
meta_name_value(key, literal) => {
alt literal.node {
lit_str(value) => {
self.match_and_collect_item(item_def_id,
*key,
*value);
}
_ => {
// Skip.
}
}
}
meta_word(*) | meta_list(*) {
// Skip.
}
}
}
fn match_and_collect_item(item_def_id: def_id, key: ~str, value: ~str) {
if !str_eq(key, ~"lang") {
ret; // Didn't match.
}
alt self.item_refs.find(value) {
none => {
// Didn't match.
}
some(item_ref) => {
// Check for duplicates.
alt copy *item_ref {
some(original_def_id)
if original_def_id != item_def_id => {
self.session.warn(#fmt("duplicate entry for `%s`",
value));
}
some(_) | none => {
// OK.
}
}
// Matched.
*item_ref = some(item_def_id);
}
}
}
fn collect_local_language_items() {
let this = unsafe { ptr::addr_of(self) };
visit_crate(*self.crate, (), mk_simple_visitor(@{
visit_item: |item| {
for item.attrs.each |attribute| {
unsafe {
(*this).match_and_collect_meta_item(local_def(item
.id),
attribute.node
.value);
}
}
}
with *default_simple_visitor()
}));
}
fn collect_external_language_items() {
let crate_store = self.session.cstore;
do iter_crate_data(crate_store) |crate_number, _crate_metadata| {
for each_path(crate_store, crate_number) |path_entry| {
let def_id;
alt path_entry.def_like {
dl_def(def_ty(did)) => {
def_id = did;
}
dl_def(_) | dl_impl(_) | dl_field {
// Skip this.
again;
}
}
do get_item_attrs(crate_store, def_id) |meta_items| {
for meta_items.each |meta_item| {
self.match_and_collect_meta_item(def_id, *meta_item);
}
}
}
}
}
fn check_completeness() {
for self.item_refs.each |key, item_ref| {
alt copy *item_ref {
none => {
self.session.warn(#fmt("no item found for `%s`", key));
}
some(did) => {
// OK.
}
}
}
}
fn collect() {
self.init();
self.collect_local_language_items();
self.collect_external_language_items();
self.check_completeness();
}
}
fn collect_language_items(crate: @crate, session: session) -> LanguageItems {
let collector = LanguageItemCollector(crate, session);
collector.collect();
copy collector.items
}

View file

@ -467,7 +467,7 @@ fn determine_rp_in_ty(ty: @ast::ty,
alt ty.node {
ast::ty_path(_, id) {
alt cx.def_map.get(id) {
ast::def_ty(did) | ast::def_class(did) {
ast::def_ty(did) | ast::def_class(did, _) {
if did.crate == ast::local_crate {
cx.add_dep(did.node, cx.item_id);
} else {

View file

@ -41,7 +41,7 @@ import syntax::visit::{visit_mod, visit_ty, vt};
import box::ptr_eq;
import dvec::{dvec, extensions};
import option::get;
import option::{get, is_some};
import str::{connect, split_str};
import vec::pop;
@ -604,7 +604,7 @@ class Resolver {
let unused_import_lint_level: level;
let trait_info: hashmap<def_id,@hashmap<Atom,()>>;
let structs: hashmap<def_id,()>;
let structs: hashmap<def_id,bool>;
// The number of imports that are currently unresolved.
let mut unresolved_imports: uint;
@ -926,7 +926,8 @@ class Resolver {
(*name_bindings).define_impl(impl_info);
// Record the def ID of this struct.
self.structs.insert(local_def(item.id), ());
self.structs.insert(local_def(item.id),
is_some(optional_ctor));
visit_item(item, new_parent, visitor);
}
@ -1378,12 +1379,16 @@ class Resolver {
(*child_name_bindings).define_type(def);
}
def_class(def_id) {
def_class(def_id, has_constructor) {
#debug("(building reduced graph for external \
crate) building value and type %s",
final_ident);
(*child_name_bindings).define_value(def);
crate) building type %s (value? %d)",
final_ident,
if has_constructor { 1 } else { 0 });
(*child_name_bindings).define_type(def);
if has_constructor {
(*child_name_bindings).define_value(def);
}
}
def_self(*) | def_arg(*) | def_local(*) |
def_prim_ty(*) | def_ty_param(*) | def_binding(*) |
@ -4201,7 +4206,9 @@ class Resolver {
some(definition @ def_ty(class_id))
if self.structs.contains_key(class_id) {
self.record_def(expr.id, def_class(class_id));
let has_constructor = self.structs.get(class_id);
let class_def = def_class(class_id, has_constructor);
self.record_def(expr.id, class_def);
}
_ {
self.session.span_err(path.span,

View file

@ -2587,7 +2587,7 @@ fn type_err_to_str(cx: ctxt, err: type_err) -> ~str {
fn def_has_ty_params(def: ast::def) -> bool {
alt def {
ast::def_fn(_, _) | ast::def_variant(_, _) | ast::def_class(_)
ast::def_fn(_, _) | ast::def_variant(_, _) | ast::def_class(_, _)
{ true }
_ { false }
}

View file

@ -270,7 +270,7 @@ fn ast_ty_to_ty<AC: ast_conv, RS: region_scope copy owned>(
path_to_str(path))); }
some(d) { d }};
alt a_def {
ast::def_ty(did) | ast::def_class(did) {
ast::def_ty(did) | ast::def_class(did, _) {
ast_path_to_ty(self, rscope, did, path, id).ty
}
ast::def_prim_ty(nty) {

View file

@ -1649,7 +1649,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
// Resolve the path.
let class_id;
alt tcx.def_map.find(id) {
some(ast::def_class(type_def_id)) => {
some(ast::def_class(type_def_id, _)) => {
class_id = type_def_id;
}
_ => {
@ -2160,7 +2160,7 @@ fn ty_param_bounds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) ->
}
ast::def_fn(id, _) | ast::def_const(id) |
ast::def_variant(_, id) | ast::def_class(id) {
ast::def_variant(_, id) | ast::def_class(id, _) {
ret ty::lookup_item_type(fcx.ccx.tcx, id);
}
ast::def_binding(nid) {

View file

@ -200,7 +200,7 @@ fn region_of(fcx: @fn_ctxt, expr: @ast::expr) -> ty::region {
ast::def_foreign_mod(_) | ast::def_const(_) |
ast::def_use(_) | ast::def_variant(_, _) |
ast::def_ty(_) | ast::def_prim_ty(_) |
ast::def_ty_param(_, _) | ast::def_class(_) |
ast::def_ty_param(_, _) | ast::def_class(_, _) |
ast::def_region(_) {
ty::re_static
}

View file

@ -88,6 +88,7 @@ mod middle {
mod region;
mod const_eval;
mod astencode;
mod lang_items;
}
mod front {

View file

@ -27,6 +27,7 @@
#include "llvm/Support/SourceMgr.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/Debug.h"
#include "llvm-c/Core.h"
#include "llvm-c/BitReader.h"
#include "llvm-c/Object.h"
@ -185,3 +186,7 @@ extern "C" LLVMValueRef LLVMBuildAtomicRMW(LLVMBuilderRef B,
unwrap(target), unwrap(source),
order));
}
extern "C" void LLVMSetDebug(int Enabled) {
DebugFlag = Enabled;
}

View file

@ -528,6 +528,7 @@ LLVMSetAlignment
LLVMSetCleanup
LLVMSetCurrentDebugLocation
LLVMSetDataLayout
LLVMSetDebug
LLVMSetFunctionCallConv
LLVMSetGC
LLVMSetGlobalConstant

Binary file not shown.

View file

@ -0,0 +1,5 @@
// error-pattern: is not UTF-8
fn foo() {
#include("not-utf8.bin")
}

View file

@ -0,0 +1,8 @@
// xfail-test
fn fail_then_concat() {
let x = ~[], y = ~[3];
fail;
x += y;
~"good" + ~"bye";
}

View file

@ -0,0 +1,15 @@
fn f<T>(g: fn() -> T) -> T { g() }
fn main() {
let _x = f( | | { 10 });
// used to be: cannot determine a type for this expression
f(| | { });
// ditto
f( | | { ()});
// always worked
let _: () = f(| | { });
// empty block with no type info should compile too
let _ = f(||{});
let _ = (||{});
}

View file

@ -1,31 +1,29 @@
use std;
import comm;
import comm::chan;
import comm::send;
import pipes;
import pipes::chan;
import pipes::port;
import task;
fn main() { test05(); }
fn test05_start(ch : chan<int>) {
log(error, ch);
send(ch, 10);
ch.send(10);
#error("sent 10");
send(ch, 20);
ch.send(20);
#error("sent 20");
send(ch, 30);
ch.send(30);
#error("sent 30");
}
fn test05() {
let po = comm::port();
let ch = comm::chan(po);
let (ch, po) = pipes::stream();
task::spawn(|| test05_start(ch) );
let mut value = comm::recv(po);
let mut value = po.recv();
log(error, value);
value = comm::recv(po);
value = po.recv();
log(error, value);
value = comm::recv(po);
value = po.recv();
log(error, value);
assert (value == 30);
}

View file

@ -1,28 +1,27 @@
use std;
import task;
import comm;
import pipes;
fn start(c: comm::chan<comm::chan<~str>>) {
let p = comm::port();
comm::send(c, comm::chan(p));
fn start(c: pipes::chan<pipes::chan<~str>>) {
let (ch, p) = pipes::stream();
c.send(ch);
let mut a;
let mut b;
a = comm::recv(p);
a = p.recv();
assert a == ~"A";
log(error, a);
b = comm::recv(p);
b = p.recv();
assert b == ~"B";
log(error, b);
}
fn main() {
let p = comm::port();
let ch = comm::chan(p);
let (ch, p) = pipes::stream();
let child = task::spawn(|| start(ch) );
let c = comm::recv(p);
comm::send(c, ~"A");
comm::send(c, ~"B");
let c = p.recv();
c.send(~"A");
c.send(~"B");
task::yield();
}

View file

@ -1,15 +1,14 @@
use std;
import comm;
import pipes;
import task;
fn start(c: comm::chan<comm::chan<int>>) {
let p: comm::port<int> = comm::port();
comm::send(c, comm::chan(p));
fn start(c: pipes::chan<pipes::chan<int>>) {
let (ch, p) = pipes::stream();
c.send(ch);
}
fn main() {
let p = comm::port();
let ch = comm::chan(p);
let (ch, p) = pipes::stream();
let child = task::spawn(|| start(ch) );
let c = comm::recv(p);
let c = p.recv();
}

View file

@ -1,17 +1,16 @@
use std;
import task;
import comm;
import comm::send;
import pipes;
import pipes::send;
fn start(c: comm::chan<int>, start: int, number_of_messages: int) {
fn start(c: pipes::chan<int>, start: int, number_of_messages: int) {
let mut i: int = 0;
while i < number_of_messages { send(c, start + i); i += 1; }
while i < number_of_messages { c.send(start + i); i += 1; }
}
fn main() {
#debug("Check that we don't deadlock.");
let p = comm::port::<int>();
let ch = comm::chan(p);
let (ch, p) = pipes::stream();
task::try(|| start(ch, 0, 10) );
#debug("Joined task");
}

View file

@ -1,15 +1,14 @@
use std;
import comm;
import task;
fn main() {
let po = comm::port::<int>();
let ch = comm::chan(po);
let po = pipes::port_set();
// Spawn 10 tasks each sending us back one int.
let mut i = 10;
while (i > 0) {
log(debug, i);
let (ch, p) = pipes::stream();
po.add(p);
task::spawn(|copy i| child(i, ch) );
i = i - 1;
}
@ -18,17 +17,16 @@ fn main() {
// anything back, so we deadlock here.
i = 10;
let mut value = 0;
while (i > 0) {
log(debug, i);
value = comm::recv(po);
po.recv();
i = i - 1;
}
#debug("main thread exiting");
}
fn child(x: int, ch: comm::chan<int>) {
fn child(x: int, ch: pipes::chan<int>) {
log(debug, x);
comm::send(ch, copy x);
ch.send(x);
}

View file

@ -1,23 +1,21 @@
// xfail-win32
use std;
import comm;
import task;
fn start(c: comm::chan<int>, i0: int) {
fn start(c: pipes::chan<int>, i0: int) {
let mut i = i0;
while i > 0 {
comm::send(c, 0);
c.send(0);
i = i - 1;
}
}
fn main() {
let p = comm::port();
// Spawn a task that sends us back messages. The parent task
// is likely to terminate before the child completes, so from
// the child's point of view the receiver may die. We should
// drop messages on the floor in this case, and not crash!
let ch = comm::chan(p);
let child = task::spawn(|| start(ch, 10) );
let c = comm::recv(p);
let (ch, p) = pipes::stream();
task::spawn(|| start(ch, 10));
p.recv();
}

View file

@ -1,44 +1,41 @@
// -*- rust -*-
use std;
import comm;
import comm::send;
import comm::port;
import comm::recv;
import comm::chan;
import pipes;
import pipes::send;
import pipes::port;
import pipes::recv;
import pipes::chan;
// Tests of ports and channels on various types
fn test_rec() {
type r = {val0: int, val1: u8, val2: char};
let po = comm::port();
let ch = chan(po);
let (ch, po) = pipes::stream();
let r0: r = {val0: 0, val1: 1u8, val2: '2'};
send(ch, r0);
ch.send(r0);
let mut r1: r;
r1 = recv(po);
r1 = po.recv();
assert (r1.val0 == 0);
assert (r1.val1 == 1u8);
assert (r1.val2 == '2');
}
fn test_vec() {
let po = port();
let ch = chan(po);
let (ch, po) = pipes::stream();
let v0: ~[int] = ~[0, 1, 2];
send(ch, v0);
let v1 = recv(po);
ch.send(v0);
let v1 = po.recv();
assert (v1[0] == 0);
assert (v1[1] == 1);
assert (v1[2] == 2);
}
fn test_str() {
let po = port();
let ch = chan(po);
let s0 = ~"test";
send(ch, s0);
let s1 = recv(po);
let (ch, po) = pipes::stream();
let s0 = "test";
ch.send(s0);
let s1 = po.recv();
assert (s1[0] == 't' as u8);
assert (s1[1] == 'e' as u8);
assert (s1[2] == 's' as u8);
@ -47,33 +44,36 @@ fn test_str() {
fn test_tag() {
enum t { tag1, tag2(int), tag3(int, u8, char), }
let po = port();
let ch = chan(po);
send(ch, tag1);
send(ch, tag2(10));
send(ch, tag3(10, 11u8, 'A'));
let (ch, po) = pipes::stream();
ch.send(tag1);
ch.send(tag2(10));
ch.send(tag3(10, 11u8, 'A'));
let mut t1: t;
t1 = recv(po);
t1 = po.recv();
assert (t1 == tag1);
t1 = recv(po);
t1 = po.recv();
assert (t1 == tag2(10));
t1 = recv(po);
t1 = po.recv();
assert (t1 == tag3(10, 11u8, 'A'));
}
fn test_chan() {
let po = port();
let ch = chan(po);
let po0 = port();
let ch0 = chan(po0);
send(ch, ch0);
let ch1 = recv(po);
let (ch, po) = pipes::stream();
let (ch0, po0) = pipes::stream();
ch.send(ch0);
let ch1 = po.recv();
// Does the transmitted channel still work?
send(ch1, 10);
ch1.send(10);
let mut i: int;
i = recv(po0);
i = po0.recv();
assert (i == 10);
}
fn main() { test_rec(); test_vec(); test_str(); test_tag(); test_chan(); }
fn main() {
test_rec();
test_vec();
test_str();
test_tag();
test_chan();
}

View file

@ -1,9 +1,9 @@
use std;
import task;
import comm;
import comm::chan;
import comm::send;
import comm::recv;
import pipes;
import pipes::chan;
import pipes::send;
import pipes::recv;
fn main() { #debug("===== WITHOUT THREADS ====="); test00(); }
@ -12,7 +12,7 @@ fn test00_start(ch: chan<int>, message: int, count: int) {
let mut i: int = 0;
while i < count {
#debug("Sending Message");
send(ch, message + 0);
ch.send(message + 0);
i = i + 1;
}
#debug("Ending test00_start");
@ -24,14 +24,14 @@ fn test00() {
#debug("Creating tasks");
let po = comm::port();
let ch = chan(po);
let po = pipes::port_set();
let mut i: int = 0;
// Create and spawn tasks...
let mut results = ~[];
while i < number_of_tasks {
let ch = po.chan();
do task::task().future_result(|-r| {
results += ~[r];
}).spawn |copy i| {
@ -45,7 +45,7 @@ fn test00() {
for results.each |r| {
i = 0;
while i < number_of_messages {
let value = recv(po);
let value = po.recv();
sum += value;
i = i + 1;
}

View file

@ -1,44 +1,43 @@
use std;
import comm;
import comm::send;
import pipes;
import pipes::send;
fn main() { test00(); }
fn test00() {
let mut r: int = 0;
let mut sum: int = 0;
let p = comm::port();
let c = comm::chan(p);
send(c, 1);
send(c, 2);
send(c, 3);
send(c, 4);
r = comm::recv(p);
let (c, p) = pipes::stream();
c.send(1);
c.send(2);
c.send(3);
c.send(4);
r = p.recv();
sum += r;
log(debug, r);
r = comm::recv(p);
r = p.recv();
sum += r;
log(debug, r);
r = comm::recv(p);
r = p.recv();
sum += r;
log(debug, r);
r = comm::recv(p);
r = p.recv();
sum += r;
log(debug, r);
send(c, 5);
send(c, 6);
send(c, 7);
send(c, 8);
r = comm::recv(p);
c.send(5);
c.send(6);
c.send(7);
c.send(8);
r = p.recv();
sum += r;
log(debug, r);
r = comm::recv(p);
r = p.recv();
sum += r;
log(debug, r);
r = comm::recv(p);
r = p.recv();
sum += r;
log(debug, r);
r = comm::recv(p);
r = p.recv();
sum += r;
log(debug, r);
assert (sum == 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8);

View file

@ -1,17 +1,16 @@
use std;
import comm;
import pipes;
fn main() { test00(); }
fn test00() {
let r: int = 0;
let mut sum: int = 0;
let p = comm::port();
let c = comm::chan(p);
let (c, p) = pipes::stream();
let number_of_messages: int = 1000;
let mut i: int = 0;
while i < number_of_messages { comm::send(c, i + 0); i += 1; }
while i < number_of_messages { c.send(i + 0); i += 1; }
i = 0;
while i < number_of_messages { sum += comm::recv(p); i += 1; }
while i < number_of_messages { sum += p.recv(); i += 1; }
assert (sum == number_of_messages * (number_of_messages - 1) / 2);
}

View file

@ -1,37 +1,37 @@
use std;
import comm;
import comm::send;
import comm::chan;
import comm::recv;
import pipes;
import pipes::send;
import pipes::chan;
import pipes::recv;
fn main() { test00(); }
fn test00() {
let mut r: int = 0;
let mut sum: int = 0;
let p = comm::port();
let c0 = chan(p);
let c1 = chan(p);
let c2 = chan(p);
let c3 = chan(p);
let p = pipes::port_set();
let c0 = p.chan();
let c1 = p.chan();
let c2 = p.chan();
let c3 = p.chan();
let number_of_messages: int = 1000;
let mut i: int = 0;
while i < number_of_messages {
send(c0, i + 0);
send(c1, i + 0);
send(c2, i + 0);
send(c3, i + 0);
c0.send(i + 0);
c1.send(i + 0);
c2.send(i + 0);
c3.send(i + 0);
i += 1;
}
i = 0;
while i < number_of_messages {
r = recv(p);
r = p.recv();
sum += r;
r = recv(p);
r = p.recv();
sum += r;
r = recv(p);
r = p.recv();
sum += r;
r = recv(p);
r = p.recv();
sum += r;
i += 1;
}

View file

@ -1,43 +1,45 @@
use std;
import task;
import comm;
fn main() { test00(); }
fn test00_start(c: comm::chan<int>, start: int, number_of_messages: int) {
fn test00_start(c: pipes::chan<int>, start: int, number_of_messages: int) {
let mut i: int = 0;
while i < number_of_messages { comm::send(c, start + i); i += 1; }
while i < number_of_messages { c.send(start + i); i += 1; }
}
fn test00() {
let mut r: int = 0;
let mut sum: int = 0;
let p = comm::port();
let p = pipes::port_set();
let number_of_messages: int = 10;
let c = comm::chan(p);
let c = p.chan();
do task::spawn {
test00_start(c, number_of_messages * 0, number_of_messages);
}
let c = p.chan();
do task::spawn {
test00_start(c, number_of_messages * 1, number_of_messages);
}
let c = p.chan();
do task::spawn {
test00_start(c, number_of_messages * 2, number_of_messages);
}
let c = p.chan();
do task::spawn {
test00_start(c, number_of_messages * 3, number_of_messages);
}
let mut i: int = 0;
while i < number_of_messages {
r = comm::recv(p);
r = p.recv();
sum += r;
r = comm::recv(p);
r = p.recv();
sum += r;
r = comm::recv(p);
r = p.recv();
sum += r;
r = comm::recv(p);
r = p.recv();
sum += r;
i += 1;
}

View file

@ -1,20 +1,19 @@
use std;
import task;
import comm;
fn main() { test00(); }
fn test00_start(c: comm::chan<int>, number_of_messages: int) {
fn test00_start(c: pipes::chan<int>, number_of_messages: int) {
let mut i: int = 0;
while i < number_of_messages { comm::send(c, i + 0); i += 1; }
while i < number_of_messages { c.send(i + 0); i += 1; }
}
fn test00() {
let r: int = 0;
let mut sum: int = 0;
let p = comm::port();
let p = pipes::port_set();
let number_of_messages: int = 10;
let ch = comm::chan(p);
let ch = p.chan();
let mut result = none;
do task::task().future_result(|-r| { result = some(r); }).spawn {
@ -23,7 +22,7 @@ fn test00() {
let mut i: int = 0;
while i < number_of_messages {
sum += comm::recv(p);
sum += p.recv();
log(debug, r);
i += 1;
}

View file

@ -1,14 +1,12 @@
use std;
import comm::*;
import pipes::{port, chan};
/*
This is about the simplest program that can successfully send a
message.
*/
fn main() {
let po = port();
let ch = chan(po);
send(ch, 42);
let r = recv(po);
let (ch, po) = pipes::stream();
ch.send(42);
let r = po.recv();
log(error, r);
}

View file

@ -0,0 +1,31 @@
// xfail-pretty
fn id(x: bool) -> bool { x }
fn call_id() {
let c <- fail;
id(c);
}
fn call_id_2() { id(true) && id(ret); }
fn call_id_3() { id(ret) && id(ret); }
fn log_fail() { log(error, fail); }
fn log_ret() { log(error, ret); }
fn log_break() { loop { log(error, break); } }
fn log_again() { loop { log(error, again); } }
fn ret_ret() -> int { ret (ret 2) + 3; }
fn ret_guard() {
alt 2 {
x if (ret) { x; }
_ {}
}
}
fn main() {}