Change the way block calls are parsed, mark them as block-calls.

This makes it possible to omit the semicolon after the block, and will
cause the pretty-printer to properly print such calls (if
pretty-printing of blocks wasn't so broken). Block calls (with the
block outside of the parentheses) can now only occur at statement
level, and their value can not be used. When calling a block-style
function that returns a useful value, the block must be put insde the
parentheses.

Issue #1054
This commit is contained in:
Marijn Haverbeke 2011-10-21 14:11:24 +02:00
parent 0ce40f60e7
commit 7114702496
18 changed files with 56 additions and 46 deletions

View File

@ -302,7 +302,7 @@ fn mk_test_wrapper(cx: test_ctxt,
span: span) -> @ast::expr {
let call_expr: ast::expr = {
id: cx.next_node_id(),
node: ast::expr_call(@fn_path_expr, []),
node: ast::expr_call(@fn_path_expr, [], false),
span: span
};
@ -401,7 +401,7 @@ fn mk_test_main_call(cx: test_ctxt) -> @ast::expr {
let test_path_expr: ast::expr =
{id: cx.next_node_id(), node: test_path_expr_, span: dummy_sp()};
let test_call_expr_: ast::expr_ = ast::expr_call(@test_path_expr, []);
let test_call_expr_ = ast::expr_call(@test_path_expr, [], false);
let test_call_expr: ast::expr =
{id: cx.next_node_id(), node: test_call_expr_, span: dummy_sp()};
@ -419,7 +419,7 @@ fn mk_test_main_call(cx: test_ctxt) -> @ast::expr {
let test_main_call_expr_: ast::expr_ =
ast::expr_call(@test_main_path_expr,
[@args_path_expr, @test_call_expr]);
[@args_path_expr, @test_call_expr], false);
let test_main_call_expr: ast::expr =
{id: cx.next_node_id(), node: test_main_call_expr_, span: dummy_sp()};

View File

@ -93,7 +93,7 @@ fn visit_fn(cx: @ctx, f: ast::_fn, _tp: [ast::ty_param], sp: span,
fn visit_expr(cx: @ctx, ex: @ast::expr, sc: scope, v: vt<scope>) {
let handled = true;
alt ex.node {
ast::expr_call(f, args) {
ast::expr_call(f, args, _) {
check_call(*cx, f, args);
handled = false;
}
@ -667,7 +667,7 @@ fn expr_root(cx: ctx, ex: @ast::expr, autoderef: bool)
}
if is_none(path_def_id(cx, base_root.ex)) {
alt base_root.ex.node {
ast::expr_call(f, args) {
ast::expr_call(f, args, _) {
let fty = ty::expr_ty(cx.tcx, f);
alt ty::ty_fn_ret_style(cx.tcx, fty) {
ast::return_ref(mut, arg_n) {

View File

@ -42,7 +42,7 @@ fn fn_usage_expr(expr: @ast::expr,
}
}
ast::expr_call(f, args) {
ast::expr_call(f, args, _) {
let f_ctx = {unsafe_fn_legal: true,
generic_bare_fn_legal: true with ctx};
v.visit_expr(f, f_ctx, v);

View File

@ -174,7 +174,7 @@ fn need_shared_or_pinned_ctor(tcx: ty::ctxt, a: @ast::expr, descr: str) {
fn pinned_ctor(a: @ast::expr) -> bool {
// FIXME: Technically a lambda block is also a pinned ctor
alt a.node {
ast::expr_call(cexpr, _) {
ast::expr_call(cexpr, _, _) {
// Assuming that if it's a call that it's safe to move in, mostly
// because I don't know offhand how to ensure that it's a call
// specifically to a resource constructor
@ -224,7 +224,7 @@ fn check_expr(tcx: ty::ctxt, e: @ast::expr) {
ast::expr_fail(option::some(a)) {
need_expr_kind(tcx, a, ast::kind_shared, "'fail' operand");
}
ast::expr_call(callee, _) {
ast::expr_call(callee, _, _) {
let tpt = ty::expr_ty_params_and_ty(tcx, callee);
// If we have typarams, we're calling an item; we need to check

View File

@ -150,7 +150,7 @@ fn visit_decl(cx: @ctx, d: @decl, &&e: (), v: visit::vt<()>) {
fn visit_expr(cx: @ctx, ex: @expr, &&e: (), v: visit::vt<()>) {
alt ex.node {
expr_call(f, args) { check_call(cx, f, args); }
expr_call(f, args, _) { check_call(cx, f, args); }
expr_swap(lhs, rhs) {
check_lval(cx, lhs, msg_assign);
check_lval(cx, rhs, msg_assign);

View File

@ -3147,7 +3147,7 @@ fn expr_is_lval(tcx: ty::ctxt, e: @ast::expr) -> bool {
ty::ty_rec(_) { true }
}
}
ast::expr_call(f, _) {
ast::expr_call(f, _, _) {
let fty = ty::expr_ty(tcx, f);
ast_util::ret_by_ref(ty::ty_fn_ret_style(tcx, fty))
}
@ -3198,7 +3198,7 @@ fn trans_lval(cx: @block_ctxt, e: @ast::expr) -> lval_result {
ret lval_owned(sub.bcx, val);
}
// This is a by-ref returning call. Regular calls are not lval
ast::expr_call(f, args) {
ast::expr_call(f, args, _) {
let cell = empty_dest_cell();
let bcx = trans_call(cx, f, args, e.id, by_val(cell));
ret lval_owned(bcx, *cell);
@ -4175,7 +4175,7 @@ fn trans_expr(bcx: @block_ctxt, e: @ast::expr, dest: dest) -> @block_ctxt {
ast::expr_anon_obj(anon_obj) {
ret trans_anon_obj(bcx, e.span, anon_obj, e.id, dest);
}
ast::expr_call(f, args) {
ast::expr_call(f, args, _) {
ret trans_call(bcx, f, args, e.id, dest);
}
ast::expr_field(_, _) {

View File

@ -607,7 +607,7 @@ fn exprs_to_constr_args(tcx: ty::ctxt, args: [@expr]) -> [@constr_arg_use] {
fn expr_to_constr(tcx: ty::ctxt, e: @expr) -> sp_constr {
alt e.node {
expr_call(operator, args) {
expr_call(operator, args, _) {
alt operator.node {
expr_path(p) {
ret respan(e.span,

View File

@ -32,7 +32,7 @@ fn collect_pred(e: @expr, cx: ctxt, v: visit::vt<ctxt>) {
// If it's a call, generate appropriate instances of the
// call's constraints.
expr_call(operator, operands) {
expr_call(operator, operands, _) {
for c: @ty::constr in constraints_expr(cx.tcx, operator) {
let ct: sp_constr =
respan(c.span,

View File

@ -309,7 +309,7 @@ fn find_pre_post_expr(fcx: fn_ctxt, e: @expr) {
alt e.node {
expr_call(operator, operands) {
expr_call(operator, operands, _) {
/* copy */
let args = operands;

View File

@ -335,7 +335,7 @@ fn find_pre_post_state_expr(fcx: fn_ctxt, pres: prestate, e: @expr) -> bool {
vec::len(elts)), elts,
return_val);
}
expr_call(operator, operands) {
expr_call(operator, operands, _) {
ret find_pre_post_state_call(fcx, pres, operator, e.id,
callee_arg_init_ops(fcx, operator.id),
operands,

View File

@ -2072,7 +2072,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
out_args, rt, cf, constrs);
write::ty_only_fixup(fcx, id, ft);
}
ast::expr_call(f, args) {
ast::expr_call(f, args, _) {
bot = check_call_full(fcx, expr.span, f, args, expr.id);
}
ast::expr_self_method(ident) {
@ -2535,7 +2535,7 @@ fn check_pred_expr(fcx: @fn_ctxt, e: @ast::expr) -> bool {
/* e must be a call expr where all arguments are either
literals or slots */
alt e.node {
ast::expr_call(operator, operands) {
ast::expr_call(operator, operands, _) {
if !ty::is_pred_ty(fcx.ccx.tcx, expr_ty(fcx.ccx.tcx, operator)) {
fcx.ccx.tcx.sess.span_err
(operator.span,
@ -2632,7 +2632,7 @@ fn check_constraints(fcx: @fn_ctxt, cs: [@ast::constr], args: [ast::arg]) {
let call_expr_id = fcx.ccx.tcx.sess.next_node_id();
let call_expr =
@{id: call_expr_id,
node: ast::expr_call(oper, c_args),
node: ast::expr_call(oper, c_args, false),
span: c.span};
check_pred_expr(fcx, call_expr);
}

View File

@ -184,7 +184,7 @@ type expr = {id: node_id, node: expr_, span: span};
tag expr_ {
expr_vec([@expr], mutability);
expr_rec([field], option::t<@expr>);
expr_call(@expr, [@expr]);
expr_call(@expr, [@expr], bool);
expr_tup([@expr]);
expr_self_method(ident);
expr_bind(@expr, [option::t<@expr>]);

View File

@ -163,7 +163,7 @@ fn is_exported(i: ident, m: _mod) -> bool {
}
pure fn is_call_expr(e: @expr) -> bool {
alt e.node { expr_call(_, _) { true } _ { false } }
alt e.node { expr_call(_, _, _) { true } _ { false } }
}
fn is_constraint_arg(e: @expr) -> bool {

View File

@ -79,7 +79,7 @@ fn pieces_to_expr(cx: ext_ctxt, sp: span, pieces: [piece], args: [@ast::expr])
fn make_call(cx: ext_ctxt, sp: span, fn_path: [ast::ident],
args: [@ast::expr]) -> @ast::expr {
let pathexpr = make_path_expr(cx, sp, fn_path);
let callexpr = ast::expr_call(pathexpr, args);
let callexpr = ast::expr_call(pathexpr, args, false);
ret @{id: cx.next_id(), node: callexpr, span: sp};
}
fn make_rec_expr(cx: ext_ctxt, sp: span,

View File

@ -348,8 +348,9 @@ fn noop_fold_expr(e: expr_, fld: ast_fold) -> expr_ {
option::map(fld.fold_expr, maybe_expr))
}
expr_tup(elts) { expr_tup(vec::map(fld.fold_expr, elts)) }
expr_call(f, args) {
expr_call(fld.fold_expr(f), fld.map_exprs(fld.fold_expr, args))
expr_call(f, args, blk) {
expr_call(fld.fold_expr(f), fld.map_exprs(fld.fold_expr, args),
blk)
}
expr_self_method(id) { expr_self_method(fld.fold_ident(id)) }
expr_bind(f, args) {

View File

@ -977,7 +977,7 @@ fn parse_bottom_expr(p: parser) -> @ast::expr {
parse_seq(token::LPAREN, token::RPAREN, some(token::COMMA),
parse_expr, p);
hi = es.span.hi;
ex = ast::expr_call(f, es.node);
ex = ast::expr_call(f, es.node, false);
} else if p.peek() == token::MOD_SEP ||
is_ident(p.peek()) && !is_word(p, "true") &&
!is_word(p, "false") {
@ -1051,7 +1051,7 @@ fn parse_dot_or_call_expr_with(p: parser, e: @ast::expr) -> @ast::expr {
let es = parse_seq(token::LPAREN, token::RPAREN,
some(token::COMMA), parse_expr, p);
hi = es.span.hi;
let nd = ast::expr_call(e, es.node);
let nd = ast::expr_call(e, es.node, false);
e = mk_expr(p, lo, hi, nd);
}
}
@ -1073,19 +1073,6 @@ fn parse_dot_or_call_expr_with(p: parser, e: @ast::expr) -> @ast::expr {
t { unexpected(p, t); }
}
}
token::LBRACE. when is_bar(p.look_ahead(1u)) {
p.bump();
let blk = parse_fn_block_expr(p);
alt e.node {
ast::expr_call(f, args) {
e = @{node: ast::expr_call(f, args + [blk]) with *e};
}
_ {
e = mk_expr(p, lo, p.get_last_hi_pos(),
ast::expr_call(e, [blk]));
}
}
}
_ { ret e; }
}
}
@ -1569,7 +1556,6 @@ fn parse_source_stmt(p: parser) -> @ast::stmt {
let decl = parse_let(p);
ret @spanned(lo, decl.span.hi, ast::stmt_decl(decl, p.get_id()));
} else {
let item_attrs;
alt parse_outer_attrs_or_ext(p) {
none. { item_attrs = []; }
@ -1589,7 +1575,6 @@ fn parse_source_stmt(p: parser) -> @ast::stmt {
}
}
alt maybe_item {
some(i) {
let hi = i.span.hi;
@ -1599,6 +1584,21 @@ fn parse_source_stmt(p: parser) -> @ast::stmt {
none. {
// Remainder are line-expr stmts.
let e = parse_expr(p);
// See if it is a block call
if p.peek() == token::LBRACE && is_bar(p.look_ahead(1u)) {
p.bump();
let blk = parse_fn_block_expr(p);
alt e.node {
ast::expr_call(f, args, false) {
e = @{node: ast::expr_call(f, args + [blk], true)
with *e};
}
_ {
e = mk_expr(p, lo, p.get_last_hi_pos(),
ast::expr_call(e, [blk], true));
}
}
}
ret @spanned(lo, e.span.hi, ast::stmt_expr(e, p.get_id()));
}
_ { p.fatal("expected statement"); }
@ -1624,6 +1624,7 @@ fn expr_has_value(e: @ast::expr) -> bool {
ast::expr_for(_, _, blk) | ast::expr_do_while(blk, _) {
!option::is_none(blk.node.expr)
}
ast::expr_call(_, _, true) { false }
_ { true }
}
}

View File

@ -727,11 +727,19 @@ fn print_expr(s: ps, &&expr: @ast::expr) {
commasep_exprs(s, inconsistent, exprs);
pclose(s);
}
ast::expr_call(func, args) {
ast::expr_call(func, args, has_block) {
print_expr_parens_if_not_bot(s, func);
popen(s);
commasep_exprs(s, inconsistent, args);
pclose(s);
let base_args = args, blk = none;
if has_block { blk = some(vec::pop(base_args)); }
if !has_block || vec::len(base_args) > 0u {
popen(s);
commasep_exprs(s, inconsistent, base_args);
pclose(s);
}
if has_block {
nbsp(s);
print_expr(s, option::get(blk));
}
}
ast::expr_self_method(ident) {
word(s.s, "self.");

View File

@ -245,7 +245,7 @@ fn visit_expr<E>(ex: @expr, e: E, v: vt<E>) {
visit_expr_opt(base, e, v);
}
expr_tup(elts) { for el in elts { v.visit_expr(el, e, v); } }
expr_call(callee, args) {
expr_call(callee, args, _) {
visit_exprs(args, e, v);
v.visit_expr(callee, e, v);
}