Add 'do' expressions
This commit is contained in:
parent
ee9e5b9d20
commit
1ec5a5c635
18 changed files with 91 additions and 8 deletions
|
@ -318,6 +318,8 @@ enum expr_ {
|
||||||
// easily type this (a function returning nil on the inside but bool on
|
// easily type this (a function returning nil on the inside but bool on
|
||||||
// the outside).
|
// the outside).
|
||||||
expr_loop_body(@expr),
|
expr_loop_body(@expr),
|
||||||
|
// Like expr_loop_body but for 'do' blocks
|
||||||
|
expr_do_body(@expr),
|
||||||
expr_block(blk),
|
expr_block(blk),
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -415,6 +415,7 @@ fn noop_fold_expr(e: expr_, fld: ast_fold) -> expr_ {
|
||||||
}
|
}
|
||||||
expr_unary(binop, ohs) { expr_unary(binop, fld.fold_expr(ohs)) }
|
expr_unary(binop, ohs) { expr_unary(binop, fld.fold_expr(ohs)) }
|
||||||
expr_loop_body(f) { expr_loop_body(fld.fold_expr(f)) }
|
expr_loop_body(f) { expr_loop_body(fld.fold_expr(f)) }
|
||||||
|
expr_do_body(f) { expr_do_body(fld.fold_expr(f)) }
|
||||||
expr_lit(_) { copy e }
|
expr_lit(_) { copy e }
|
||||||
expr_cast(expr, ty) { expr_cast(fld.fold_expr(expr), ty) }
|
expr_cast(expr, ty) { expr_cast(fld.fold_expr(expr), ty) }
|
||||||
expr_addr_of(m, ohs) { expr_addr_of(m, fld.fold_expr(ohs)) }
|
expr_addr_of(m, ohs) { expr_addr_of(m, fld.fold_expr(ohs)) }
|
||||||
|
|
|
@ -772,6 +772,8 @@ class parser {
|
||||||
ret pexpr(self.parse_if_expr());
|
ret pexpr(self.parse_if_expr());
|
||||||
} else if self.eat_keyword("for") {
|
} else if self.eat_keyword("for") {
|
||||||
ret pexpr(self.parse_for_expr());
|
ret pexpr(self.parse_for_expr());
|
||||||
|
} else if self.eat_keyword("do") {
|
||||||
|
ret pexpr(self.parse_do_expr());
|
||||||
} else if self.eat_keyword("while") {
|
} else if self.eat_keyword("while") {
|
||||||
ret pexpr(self.parse_while_expr());
|
ret pexpr(self.parse_while_expr());
|
||||||
} else if self.eat_keyword("loop") {
|
} else if self.eat_keyword("loop") {
|
||||||
|
@ -1312,6 +1314,23 @@ class parser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_do_expr() -> @expr {
|
||||||
|
let lo = self.last_span;
|
||||||
|
let call = self.parse_expr_res(RESTRICT_STMT_EXPR);
|
||||||
|
alt call.node {
|
||||||
|
expr_call(f, args, true) {
|
||||||
|
let b_arg = vec::last(args);
|
||||||
|
let last = self.mk_expr(b_arg.span.lo, b_arg.span.hi,
|
||||||
|
expr_do_body(b_arg));
|
||||||
|
@{node: expr_call(f, vec::init(args) + [last], true)
|
||||||
|
with *call}
|
||||||
|
}
|
||||||
|
_ {
|
||||||
|
self.span_fatal(lo, "`do` must be followed by a block call");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_while_expr() -> @expr {
|
fn parse_while_expr() -> @expr {
|
||||||
let lo = self.last_span.lo;
|
let lo = self.last_span.lo;
|
||||||
let cond = self.parse_expr();
|
let cond = self.parse_expr();
|
||||||
|
|
|
@ -287,7 +287,7 @@ fn restricted_keyword_table() -> hashmap<str, ()> {
|
||||||
"assert",
|
"assert",
|
||||||
"be", "break",
|
"be", "break",
|
||||||
"check", "claim", "class", "const", "cont", "copy", "crust",
|
"check", "claim", "class", "const", "cont", "copy", "crust",
|
||||||
"drop",
|
"do", "drop",
|
||||||
"else", "enum", "export",
|
"else", "enum", "export",
|
||||||
"fail", "false", "fn", "for",
|
"fail", "false", "fn", "for",
|
||||||
"if", "iface", "impl", "import",
|
"if", "iface", "impl", "import",
|
||||||
|
|
|
@ -1048,6 +1048,9 @@ fn print_expr(s: ps, &&expr: @ast::expr) {
|
||||||
ast::expr_loop_body(body) {
|
ast::expr_loop_body(body) {
|
||||||
print_expr(s, body);
|
print_expr(s, body);
|
||||||
}
|
}
|
||||||
|
ast::expr_do_body(body) {
|
||||||
|
print_expr(s, body);
|
||||||
|
}
|
||||||
ast::expr_block(blk) {
|
ast::expr_block(blk) {
|
||||||
// containing cbox, will be closed by print-block at }
|
// containing cbox, will be closed by print-block at }
|
||||||
cbox(s, indent_unit);
|
cbox(s, indent_unit);
|
||||||
|
|
|
@ -382,7 +382,8 @@ fn visit_expr<E>(ex: @expr, e: E, v: vt<E>) {
|
||||||
for args.each {|eo| visit_expr_opt(eo, e, v); }
|
for args.each {|eo| visit_expr_opt(eo, e, v); }
|
||||||
}
|
}
|
||||||
expr_binary(_, a, b) { v.visit_expr(a, e, v); v.visit_expr(b, e, v); }
|
expr_binary(_, a, b) { v.visit_expr(a, e, v); v.visit_expr(b, e, v); }
|
||||||
expr_addr_of(_, x) | expr_unary(_, x) | expr_loop_body(x) |
|
expr_addr_of(_, x) | expr_unary(_, x) |
|
||||||
|
expr_loop_body(x) | expr_do_body(x) |
|
||||||
expr_check(_, x) | expr_assert(x) {
|
expr_check(_, x) | expr_assert(x) {
|
||||||
v.visit_expr(x, e, v);
|
v.visit_expr(x, e, v);
|
||||||
}
|
}
|
||||||
|
|
|
@ -174,7 +174,7 @@ impl public_methods for borrowck_ctxt {
|
||||||
ast::expr_swap(*) | ast::expr_move(*) | ast::expr_assign(*) |
|
ast::expr_swap(*) | ast::expr_move(*) | ast::expr_assign(*) |
|
||||||
ast::expr_assign_op(*) | ast::expr_fn(*) | ast::expr_fn_block(*) |
|
ast::expr_assign_op(*) | ast::expr_fn(*) | ast::expr_fn_block(*) |
|
||||||
ast::expr_assert(*) | ast::expr_check(*) | ast::expr_ret(*) |
|
ast::expr_assert(*) | ast::expr_check(*) | ast::expr_ret(*) |
|
||||||
ast::expr_loop_body(*) | ast::expr_unary(*) |
|
ast::expr_loop_body(*) | ast::expr_do_body(*) | ast::expr_unary(*) |
|
||||||
ast::expr_copy(*) | ast::expr_cast(*) | ast::expr_fail(*) |
|
ast::expr_copy(*) | ast::expr_cast(*) | ast::expr_fail(*) |
|
||||||
ast::expr_vstore(*) | ast::expr_vec(*) | ast::expr_tup(*) |
|
ast::expr_vstore(*) | ast::expr_vec(*) | ast::expr_tup(*) |
|
||||||
ast::expr_if_check(*) | ast::expr_if(*) | ast::expr_log(*) |
|
ast::expr_if_check(*) | ast::expr_if(*) | ast::expr_log(*) |
|
||||||
|
|
|
@ -412,7 +412,8 @@ fn visit_expr(expr: @expr, &&self: @ir_maps, vt: vt<@ir_maps>) {
|
||||||
expr_vec(*) | expr_rec(*) | expr_call(*) | expr_tup(*) |
|
expr_vec(*) | expr_rec(*) | expr_call(*) | expr_tup(*) |
|
||||||
expr_bind(*) | expr_new(*) | expr_log(*) | expr_binary(*) |
|
expr_bind(*) | expr_new(*) | expr_log(*) | expr_binary(*) |
|
||||||
expr_assert(*) | expr_check(*) | expr_addr_of(*) | expr_copy(*) |
|
expr_assert(*) | expr_check(*) | expr_addr_of(*) | expr_copy(*) |
|
||||||
expr_loop_body(*) | expr_cast(*) | expr_unary(*) | expr_fail(*) |
|
expr_loop_body(*) | expr_do_body(*) | expr_cast(*) |
|
||||||
|
expr_unary(*) | expr_fail(*) |
|
||||||
expr_break | expr_cont | expr_lit(_) | expr_ret(*) |
|
expr_break | expr_cont | expr_lit(_) | expr_ret(*) |
|
||||||
expr_block(*) | expr_move(*) | expr_assign(*) | expr_swap(*) |
|
expr_block(*) | expr_move(*) | expr_assign(*) | expr_swap(*) |
|
||||||
expr_assign_op(*) | expr_mac(*) {
|
expr_assign_op(*) | expr_mac(*) {
|
||||||
|
@ -1054,6 +1055,7 @@ class liveness {
|
||||||
expr_addr_of(_, e) |
|
expr_addr_of(_, e) |
|
||||||
expr_copy(e) |
|
expr_copy(e) |
|
||||||
expr_loop_body(e) |
|
expr_loop_body(e) |
|
||||||
|
expr_do_body(e) |
|
||||||
expr_cast(e, _) |
|
expr_cast(e, _) |
|
||||||
expr_unary(_, e) {
|
expr_unary(_, e) {
|
||||||
self.propagate_through_expr(e, succ)
|
self.propagate_through_expr(e, succ)
|
||||||
|
@ -1406,7 +1408,8 @@ fn check_expr(expr: @expr, &&self: @liveness, vt: vt<@liveness>) {
|
||||||
expr_vec(*) | expr_rec(*) | expr_tup(*) |
|
expr_vec(*) | expr_rec(*) | expr_tup(*) |
|
||||||
expr_bind(*) | expr_new(*) | expr_log(*) | expr_binary(*) |
|
expr_bind(*) | expr_new(*) | expr_log(*) | expr_binary(*) |
|
||||||
expr_assert(*) | expr_check(*) | expr_copy(*) |
|
expr_assert(*) | expr_check(*) | expr_copy(*) |
|
||||||
expr_loop_body(*) | expr_cast(*) | expr_unary(*) | expr_fail(*) |
|
expr_loop_body(*) | expr_do_body(*) |
|
||||||
|
expr_cast(*) | expr_unary(*) | expr_fail(*) |
|
||||||
expr_ret(*) | expr_break | expr_cont | expr_lit(_) |
|
expr_ret(*) | expr_break | expr_cont | expr_lit(_) |
|
||||||
expr_block(*) | expr_swap(*) | expr_mac(*) | expr_addr_of(*) {
|
expr_block(*) | expr_swap(*) | expr_mac(*) | expr_addr_of(*) {
|
||||||
visit::visit_expr(expr, self, vt);
|
visit::visit_expr(expr, self, vt);
|
||||||
|
|
|
@ -3622,6 +3622,9 @@ fn trans_expr(bcx: block, e: @ast::expr, dest: dest) -> block {
|
||||||
ast::expr_loop_body(blk) {
|
ast::expr_loop_body(blk) {
|
||||||
ret trans_loop_body(bcx, e, none, dest);
|
ret trans_loop_body(bcx, e, none, dest);
|
||||||
}
|
}
|
||||||
|
ast::expr_do_body(blk) {
|
||||||
|
ret trans_expr(bcx, blk, dest);
|
||||||
|
}
|
||||||
ast::expr_bind(f, args) {
|
ast::expr_bind(f, args) {
|
||||||
ret closure::trans_bind(
|
ret closure::trans_bind(
|
||||||
bcx, f, args, e.id, dest);
|
bcx, f, args, e.id, dest);
|
||||||
|
|
|
@ -223,7 +223,8 @@ fn mark_for_expr(cx: ctx, e: @expr) {
|
||||||
expr_while(_, _) | expr_fail(_) | expr_break | expr_cont |
|
expr_while(_, _) | expr_fail(_) | expr_break | expr_cont |
|
||||||
expr_unary(_, _) | expr_lit(_) | expr_assert(_) | expr_check(_, _) |
|
expr_unary(_, _) | expr_lit(_) | expr_assert(_) | expr_check(_, _) |
|
||||||
expr_if_check(_, _, _) | expr_mac(_) | expr_addr_of(_, _) |
|
expr_if_check(_, _, _) | expr_mac(_) | expr_addr_of(_, _) |
|
||||||
expr_ret(_) | expr_loop(_) | expr_bind(_, _) | expr_loop_body(_) {}
|
expr_ret(_) | expr_loop(_) | expr_bind(_, _) |
|
||||||
|
expr_loop_body(_) | expr_do_body(_) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -364,7 +364,7 @@ fn find_pre_post_expr(fcx: fn_ctxt, e: @expr) {
|
||||||
} else { find_pre_post_exprs(fcx, [l, r], e.id); }
|
} else { find_pre_post_exprs(fcx, [l, r], e.id); }
|
||||||
}
|
}
|
||||||
expr_addr_of(_, x) | expr_cast(x, _) | expr_unary(_, x) |
|
expr_addr_of(_, x) | expr_cast(x, _) | expr_unary(_, x) |
|
||||||
expr_loop_body(x) | expr_assert(x) | expr_copy(x) {
|
expr_loop_body(x) | expr_do_body(x) | expr_assert(x) | expr_copy(x) {
|
||||||
find_pre_post_expr(fcx, x);
|
find_pre_post_expr(fcx, x);
|
||||||
copy_pre_post(fcx.ccx, e.id, x);
|
copy_pre_post(fcx.ccx, e.id, x);
|
||||||
}
|
}
|
||||||
|
|
|
@ -486,7 +486,8 @@ fn find_pre_post_state_expr(fcx: fn_ctxt, pres: prestate, e: @expr) -> bool {
|
||||||
}
|
}
|
||||||
ret changed | set_poststate_ann(fcx.ccx, e.id, a_post);
|
ret changed | set_poststate_ann(fcx.ccx, e.id, a_post);
|
||||||
}
|
}
|
||||||
expr_field(x, _, _) | expr_loop_body(x) | expr_unary(_, x) |
|
expr_field(x, _, _) | expr_loop_body(x) | expr_do_body(x) |
|
||||||
|
expr_unary(_, x) |
|
||||||
expr_addr_of(_, x) | expr_assert(x) | expr_cast(x, _) |
|
expr_addr_of(_, x) | expr_assert(x) | expr_cast(x, _) |
|
||||||
expr_copy(x) {
|
expr_copy(x) {
|
||||||
ret find_pre_post_state_sub(fcx, pres, x, e.id, none);
|
ret find_pre_post_state_sub(fcx, pres, x, e.id, none);
|
||||||
|
|
|
@ -1364,6 +1364,32 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ast::expr_do_body(b) {
|
||||||
|
let expected_sty = unpack_expected(fcx, expected, {|x|some(x)}).get();
|
||||||
|
let (inner_ty, proto) = alt expected_sty {
|
||||||
|
ty::ty_fn(fty) {
|
||||||
|
(ty::mk_fn(tcx, fty), fty.proto)
|
||||||
|
}
|
||||||
|
_ {
|
||||||
|
tcx.sess.span_fatal(expr.span, "a do function's last argument \
|
||||||
|
should be of function type");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
alt check b.node {
|
||||||
|
ast::expr_fn_block(decl, body, cap_clause) {
|
||||||
|
check_expr_fn(fcx, b, proto, decl, body, true, some(inner_ty));
|
||||||
|
demand::suptype(fcx, b.span, inner_ty, fcx.expr_ty(b));
|
||||||
|
capture::check_capture_clause(tcx, b.id, cap_clause);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let block_ty = structurally_resolved_type(
|
||||||
|
fcx, expr.span, fcx.node_ty(b.id));
|
||||||
|
alt check ty::get(block_ty).struct {
|
||||||
|
ty::ty_fn(fty) {
|
||||||
|
fcx.write_ty(expr.id, ty::mk_fn(tcx, fty));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
ast::expr_block(b) {
|
ast::expr_block(b) {
|
||||||
// If this is an unchecked block, turn off purity-checking
|
// If this is an unchecked block, turn off purity-checking
|
||||||
bot = check_block(fcx, b);
|
bot = check_block(fcx, b);
|
||||||
|
|
3
src/test/compile-fail/do1.rs
Normal file
3
src/test/compile-fail/do1.rs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
fn main() {
|
||||||
|
let x = do y; //! ERROR: `do` must be followed by a block call
|
||||||
|
}
|
5
src/test/compile-fail/do2.rs
Normal file
5
src/test/compile-fail/do2.rs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
fn f(f: fn@(int) -> bool) -> bool { f(10) }
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
assert do f() { |i| i == 10 } == 10; //! ERROR: expected `bool` but found `int`
|
||||||
|
}
|
5
src/test/run-pass/do1.rs
Normal file
5
src/test/run-pass/do1.rs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
fn f(f: fn@(int)) { f(10) }
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
do f() { |i| assert i == 10 }
|
||||||
|
}
|
5
src/test/run-pass/do2.rs
Normal file
5
src/test/run-pass/do2.rs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
fn f(f: fn@(int) -> int) -> int { f(10) }
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
assert do f() { |i| i } == 10;
|
||||||
|
}
|
5
src/test/run-pass/do3.rs
Normal file
5
src/test/run-pass/do3.rs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
fn f(f: fn@(int) -> int) -> int { f(10) }
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
assert do f { |i| i } == 10;
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue