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

@ -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);
}