Skip to content

Dedo #10581

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 12 commits into from
Closed

Dedo #10581

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion doc/po/ja/rust.md.po
Original file line number Diff line number Diff line change
Expand Up @@ -5383,7 +5383,7 @@ msgstr ""
#. type: Plain text
#: doc/rust.md:2849
msgid ""
"type Binop<'self> = &'self fn(int,int) -> int; let bo: Binop = add; x = "
"type Binop<'self> = 'self |int,int| -> int; let bo: Binop = add; x = "
"bo(5,7); ~~~~~~~~"
msgstr ""

Expand Down
2 changes: 1 addition & 1 deletion doc/po/rust.md.pot
Original file line number Diff line number Diff line change
Expand Up @@ -5370,7 +5370,7 @@ msgstr ""
#. type: Plain text
#: doc/rust.md:2849
msgid ""
"type Binop<'self> = &'self fn(int,int) -> int; let bo: Binop = add; x = "
"type Binop<'self> = 'self |int,int| -> int; let bo: Binop = add; x = "
"bo(5,7); ~~~~~~~~"
msgstr ""

Expand Down
32 changes: 13 additions & 19 deletions doc/rust.md
Original file line number Diff line number Diff line change
Expand Up @@ -2703,33 +2703,27 @@ A `loop` expression is only permitted in the body of a loop.
do_expr : "do" expr [ '|' ident_list '|' ] ? '{' block '}' ;
~~~~

A _do expression_ provides a more-familiar block-syntax for a [lambda expression](#lambda-expressions),
including a special translation of [return expressions](#return-expressions) inside the supplied block.

Any occurrence of a [return expression](#return-expressions)
inside this `block` expression is rewritten
as a reference to an (anonymous) flag set in the caller's environment,
which is checked on return from the `expr` and, if set,
causes a corresponding return from the caller.
In this way, the meaning of `return` statements in language built-in control blocks is preserved,
if they are rewritten using lambda functions and `do` expressions as abstractions.

The optional `ident_list` and `block` provided in a `do` expression are parsed as though they constitute a lambda expression;
A _do expression_ provides a more-familiar block syntax
for invoking a function and passing it a newly-created a procedure.

The optional `ident_list` and `block` provided in a `do` expression are parsed
as though they constitute a procedure expression;
if the `ident_list` is missing, an empty `ident_list` is implied.

The lambda expression is then provided as a _trailing argument_
to the outermost [call](#call-expressions) or [method call](#method-call-expressions) expression
The procedure expression is then provided as a _trailing argument_
to the outermost [call](#call-expressions) or
[method call](#method-call-expressions) expression
in the `expr` following `do`.
If the `expr` is a [path expression](#path-expressions), it is parsed as though it is a call expression.
If the `expr` is a [field expression](#field-expressions), it is parsed as though it is a method call expression.

In this example, both calls to `f` are equivalent:

~~~~
# fn f(f: |int|) { }
# fn f(f: proc(int)) { }
# fn g(i: int) { }

f(|j| g(j));
f(proc(j) { g(j) });

do f |j| {
g(j);
Expand All @@ -2739,10 +2733,10 @@ do f |j| {
In this example, both calls to the (binary) function `k` are equivalent:

~~~~
# fn k(x:int, f: |int|) { }
# fn k(x:int, f: proc(int)) { }
# fn l(i: int) { }

k(3, |j| l(j));
k(3, proc(j) { l(j) });

do k(3) |j| {
l(j);
Expand Down Expand Up @@ -3194,7 +3188,7 @@ fn add(x: int, y: int) -> int {

let mut x = add(5,7);

type Binop<'self> = &'self fn(int,int) -> int;
type Binop<'self> = 'self |int,int| -> int;
let bo: Binop = add;
x = bo(5,7);
~~~~
Expand Down
20 changes: 10 additions & 10 deletions doc/tutorial-conditions.md
Original file line number Diff line number Diff line change
Expand Up @@ -457,15 +457,15 @@ condition! {

fn main() {
// Trap the condition:
do malformed_line::cond.trap(|_| (-1,-1)).inside {
malformed_line::cond.trap(|_| (-1,-1)).inside(|| {

// The protected logic.
let pairs = read_int_pairs();
for &(a,b) in pairs.iter() {
println!("{:4.4d}, {:4.4d}", a, b);
}

}
})
}

fn read_int_pairs() -> ~[(int,int)] {
Expand Down Expand Up @@ -535,15 +535,15 @@ condition! {

fn main() {
// Trap the condition and return `None`
do malformed_line::cond.trap(|_| None).inside {
malformed_line::cond.trap(|_| None).inside(|| {

// The protected logic.
let pairs = read_int_pairs();
for &(a,b) in pairs.iter() {
println!("{:4.4d}, {:4.4d}", a, b);
}

}
})
}

fn read_int_pairs() -> ~[(int,int)] {
Expand Down Expand Up @@ -631,15 +631,15 @@ condition! {

fn main() {
// Trap the condition and return `UsePreviousLine`
do malformed_line::cond.trap(|_| UsePreviousLine).inside {
malformed_line::cond.trap(|_| UsePreviousLine).inside(|| {

// The protected logic.
let pairs = read_int_pairs();
for &(a,b) in pairs.iter() {
println!("{:4.4d}, {:4.4d}", a, b);
}

}
})
}

fn read_int_pairs() -> ~[(int,int)] {
Expand Down Expand Up @@ -758,19 +758,19 @@ condition! {

fn main() {
// Trap the `malformed_int` condition and return -1
do malformed_int::cond.trap(|_| -1).inside {
malformed_int::cond.trap(|_| -1).inside(|| {

// Trap the `malformed_line` condition and return `UsePreviousLine`
do malformed_line::cond.trap(|_| UsePreviousLine).inside {
malformed_line::cond.trap(|_| UsePreviousLine).inside(|| {

// The protected logic.
let pairs = read_int_pairs();
for &(a,b) in pairs.iter() {
println!("{:4.4d}, {:4.4d}", a, b);
}

}
}
})
})
}

// Parse an int; if parsing fails, call the condition handler and
Expand Down
8 changes: 4 additions & 4 deletions doc/tutorial-tasks.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ fn print_message() { println("I am running in a different task!"); }
spawn(print_message);

// Print something more profound in a different task using a lambda expression
spawn( || println("I am also running in a different task!") );
spawn(proc() println("I am also running in a different task!") );

// The canonical way to spawn is using `do` notation
do spawn {
Expand Down Expand Up @@ -253,13 +253,13 @@ might look like the example below.
# use std::vec;

// Create a vector of ports, one for each child task
let ports = do vec::from_fn(3) |init_val| {
let ports = vec::from_fn(3, |init_val| {
let (port, chan) = stream();
do spawn {
chan.send(some_expensive_computation(init_val));
}
port
};
});

// Wait on each port, accumulating the results
let result = ports.iter().fold(0, |accum, port| accum + port.recv() );
Expand All @@ -278,7 +278,7 @@ fn fib(n: u64) -> u64 {
12586269025
}

let mut delayed_fib = extra::future::Future::spawn (|| fib(50) );
let mut delayed_fib = extra::future::Future::spawn(proc() fib(50));
make_a_sandwich();
println!("fib(50) = {:?}", delayed_fib.get())
~~~
Expand Down
33 changes: 13 additions & 20 deletions doc/tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -1439,19 +1439,14 @@ call_twice(function);

## Do syntax

The `do` expression provides a way to treat higher-order functions
(functions that take closures as arguments) as control structures.
The `do` expression makes it easier to call functions that take procedures
as arguments.

Consider this function that iterates over a vector of
integers, passing in a pointer to each integer in the vector:
Consider this function that takes a procedure:

~~~~
fn each(v: &[int], op: |v: &int|) {
let mut n = 0;
while n < v.len() {
op(&v[n]);
n += 1;
}
fn call_it(op: proc(v: int)) {
op(10)
}
~~~~

Expand All @@ -1460,26 +1455,24 @@ argument, we can write it in a way that has a pleasant, block-like
structure.

~~~~
# fn each(v: &[int], op: |v: &int|) { }
# fn do_some_work(i: &int) { }
each([1, 2, 3], |n| {
do_some_work(n);
# fn call_it(op: proc(v: int)) { }
call_it(proc(n) {
println(n.to_str());
});
~~~~

This is such a useful pattern that Rust has a special form of function
call that can be written more like a built-in control structure:
call for these functions.

~~~~
# fn each(v: &[int], op: |v: &int|) { }
# fn do_some_work(i: &int) { }
do each([1, 2, 3]) |n| {
do_some_work(n);
# fn call_it(op: proc(v: int)) { }
do call_it() |n| {
println(n.to_str());
}
~~~~

The call is prefixed with the keyword `do` and, instead of writing the
final closure inside the argument list, it appears outside of the
final procedure inside the argument list, it appears outside of the
parentheses, where it looks more like a typical block of
code.

Expand Down
14 changes: 8 additions & 6 deletions src/compiletest/compiletest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,12 +266,12 @@ pub fn make_tests(config: &config) -> ~[test::TestDescAndFn] {
let file = file.clone();
debug!("inspecting file {}", file.display());
if is_test(config, &file) {
let t = do make_test(config, &file) {
let t = make_test(config, &file, || {
match config.mode {
mode_codegen => make_metrics_test_closure(config, &file),
_ => make_test_closure(config, &file)
}
};
});
tests.push(t)
}
}
Expand Down Expand Up @@ -301,8 +301,8 @@ pub fn is_test(config: &config, testfile: &Path) -> bool {
return valid;
}

pub fn make_test(config: &config, testfile: &Path,
f: &fn()->test::TestFn) -> test::TestDescAndFn {
pub fn make_test(config: &config, testfile: &Path, f: || -> test::TestFn)
-> test::TestDescAndFn {
test::TestDescAndFn {
desc: test::TestDesc {
name: make_test_name(config, testfile),
Expand Down Expand Up @@ -333,13 +333,15 @@ pub fn make_test_closure(config: &config, testfile: &Path) -> test::TestFn {
let config = Cell::new((*config).clone());
// FIXME (#9639): This needs to handle non-utf8 paths
let testfile = Cell::new(testfile.as_str().unwrap().to_owned());
test::DynTestFn(|| { runtest::run(config.take(), testfile.take()) })
test::DynTestFn(proc() { runtest::run(config.take(), testfile.take()) })
}

pub fn make_metrics_test_closure(config: &config, testfile: &Path) -> test::TestFn {
use std::cell::Cell;
let config = Cell::new((*config).clone());
// FIXME (#9639): This needs to handle non-utf8 paths
let testfile = Cell::new(testfile.as_str().unwrap().to_owned());
test::DynMetricFn(|mm| { runtest::run_metrics(config.take(), testfile.take(), mm) })
test::DynMetricFn(proc(mm) {
runtest::run_metrics(config.take(), testfile.take(), mm)
})
}
14 changes: 7 additions & 7 deletions src/compiletest/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ pub fn load_props(testfile: &Path) -> TestProps {
let mut pp_exact = None;
let mut debugger_cmds = ~[];
let mut check_lines = ~[];
do iter_header(testfile) |ln| {
iter_header(testfile, |ln| {
match parse_error_pattern(ln) {
Some(ep) => error_patterns.push(ep),
None => ()
Expand Down Expand Up @@ -74,7 +74,7 @@ pub fn load_props(testfile: &Path) -> TestProps {
};

true
};
});
return TestProps {
error_patterns: error_patterns,
compile_flags: compile_flags,
Expand All @@ -91,18 +91,18 @@ pub fn is_test_ignored(config: &config, testfile: &Path) -> bool {
~"xfail-" + util::get_os(config.target)
}

let val = do iter_header(testfile) |ln| {
let val = iter_header(testfile, |ln| {
if parse_name_directive(ln, "xfail-test") { false }
else if parse_name_directive(ln, xfail_target(config)) { false }
else if config.mode == common::mode_pretty &&
parse_name_directive(ln, "xfail-pretty") { false }
else { true }
};
});

!val
}

fn iter_header(testfile: &Path, it: &fn(&str) -> bool) -> bool {
fn iter_header(testfile: &Path, it: |&str| -> bool) -> bool {
use std::io::buffered::BufferedReader;
use std::io::File;

Expand Down Expand Up @@ -143,7 +143,7 @@ fn parse_check_line(line: &str) -> Option<~str> {
}

fn parse_exec_env(line: &str) -> Option<(~str, ~str)> {
do parse_name_value_directive(line, ~"exec-env").map |nv| {
parse_name_value_directive(line, ~"exec-env").map(|nv| {
// nv is either FOO or FOO=BAR
let mut strs: ~[~str] = nv.splitn('=', 1).map(|s| s.to_owned()).collect();

Expand All @@ -155,7 +155,7 @@ fn parse_exec_env(line: &str) -> Option<(~str, ~str)> {
}
n => fail!("Expected 1 or 2 strings, not {}", n)
}
}
})
}

fn parse_pp_exact(line: &str, testfile: &Path) -> Option<Path> {
Expand Down
4 changes: 2 additions & 2 deletions src/compiletest/procsrv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ fn target_env(lib_path: &str, prog: &str) -> ~[(~str,~str)] {
assert!(prog.ends_with(".exe"));
let aux_path = prog.slice(0u, prog.len() - 4u).to_owned() + ".libaux";

env = do env.map() |pair| {
env = env.map(|pair| {
let (k,v) = (*pair).clone();
if k == ~"PATH" { (~"PATH", v + ";" + lib_path + ";" + aux_path) }
else { (k,v) }
};
});
if prog.ends_with("rustc.exe") {
env.push((~"RUST_THREADS", ~"1"));
}
Expand Down
13 changes: 8 additions & 5 deletions src/compiletest/runtest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -427,9 +427,9 @@ fn check_error_patterns(props: &TestProps,
testfile: &Path,
ProcRes: &ProcRes) {
if props.error_patterns.is_empty() {
do testfile.display().with_str |s| {
testfile.display().with_str(|s| {
fatal(~"no error pattern specified in " + s);
}
})
}

if ProcRes.status.success() {
Expand Down Expand Up @@ -730,9 +730,12 @@ fn compose_and_run(config: &config, testfile: &Path,
prog, args, procenv, input);
}

fn make_compile_args(config: &config, props: &TestProps, extras: ~[~str],
xform: &fn(&config, (&Path)) -> Path,
testfile: &Path) -> ProcArgs {
fn make_compile_args(config: &config,
props: &TestProps,
extras: ~[~str],
xform: |&config, &Path| -> Path,
testfile: &Path)
-> ProcArgs {
let xform_file = xform(config, testfile);
// FIXME (#9639): This needs to handle non-utf8 paths
let mut args = ~[testfile.as_str().unwrap().to_owned(),
Expand Down
Loading