diff options
| author | Brian Anderson <banderson@mozilla.com> | 2012-06-29 18:09:56 -0700 |
|---|---|---|
| committer | Brian Anderson <banderson@mozilla.com> | 2012-06-30 16:01:52 -0700 |
| commit | ed834f062901d9db56f2430ad292d37c9e5c1812 (patch) | |
| tree | 9537c13611f662f344fcbbea9197614d69175dca /src/libsyntax/parse/parser.rs | |
| parent | 0293a31b689ff71cbe39112e226d151529f5a1cd (diff) | |
| download | rust-ed834f062901d9db56f2430ad292d37c9e5c1812.tar.gz rust-ed834f062901d9db56f2430ad292d37c9e5c1812.zip | |
syntax: Add support for new lambda syntax
Diffstat (limited to 'src/libsyntax/parse/parser.rs')
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 70 |
1 files changed, 61 insertions, 9 deletions
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 106fc26d88e..55058d337e9 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -30,6 +30,7 @@ enum restriction { RESTRICT_STMT_EXPR, RESTRICT_NO_CALL_EXPRS, RESTRICT_NO_BAR_OP, + RESTRICT_NO_BAR_OR_DOUBLEBAR_OP, } enum file_type { CRATE_FILE, SOURCE_FILE, } @@ -776,11 +777,13 @@ class parser { self.expect(token::RBRACE); ex = expr_rec(fields, base); } else if token::is_bar(self.token) { - ret pexpr(self.parse_fn_block_expr()); + ret pexpr(self.parse_fn_block_expr_old()); } else { let blk = self.parse_block_tail(lo, default_blk); ret self.mk_pexpr(blk.span.lo, blk.span.hi, expr_block(blk)); } + } else if token::is_bar(self.token) { + ret pexpr(self.parse_lambda_expr()); } else if self.eat_keyword("new") { self.expect(token::LPAREN); let r = self.parse_expr(); @@ -1234,7 +1237,14 @@ class parser { if self.expr_is_complete(plhs) { ret lhs; } let peeked = self.token; if peeked == token::BINOP(token::OR) && - self.restriction == RESTRICT_NO_BAR_OP { ret lhs; } + (self.restriction == RESTRICT_NO_BAR_OP || + self.restriction == RESTRICT_NO_BAR_OR_DOUBLEBAR_OP) { + ret lhs; + } + if peeked == token::OROR && + self.restriction == RESTRICT_NO_BAR_OR_DOUBLEBAR_OP { + ret lhs; + } let cur_opt = token_to_binop(peeked); alt cur_opt { some(cur_op) { @@ -1347,7 +1357,7 @@ class parser { expr_fn(proto, decl, body, capture_clause)); } - fn parse_fn_block_expr() -> @expr { + fn parse_fn_block_expr_old() -> @expr { let lo = self.last_span.lo; let (decl, captures) = self.parse_fn_block_decl(); let body = self.parse_block_tail(lo, default_blk); @@ -1355,6 +1365,38 @@ class parser { expr_fn_block(decl, body, captures)); } + // `|args| { ... }` like in `do` expressions + fn parse_lambda_block_expr() -> @expr { + self.parse_lambda_expr_({|| + let blk = self.parse_block(); + self.mk_expr(blk.span.lo, blk.span.hi, expr_block(blk)) + }) + } + + // `|args| expr` + fn parse_lambda_expr() -> @expr { + self.parse_lambda_expr_({|| self.parse_expr()}) + } + + fn parse_lambda_expr_(parse_body: fn&() -> @expr) -> @expr { + if self.token == token::LBRACE { + // Old style lambdas `{|args| ... }` + self.expect(token::LBRACE); + ret self.parse_fn_block_expr_old(); + } else { + let lo = self.last_span.lo; + // New style lambdas `|args| expr` + let (decl, captures) = self.parse_fn_block_decl(); + let body = parse_body(); + let fakeblock = {view_items: ~[], stmts: ~[], expr: some(body), + id: self.get_id(), rules: default_blk}; + let fakeblock = spanned(body.span.lo, body.span.hi, + fakeblock); + ret self.mk_expr(lo, body.span.hi, + expr_fn_block(decl, fakeblock, captures)); + } + } + fn parse_else_expr() -> @expr { if self.eat_keyword("if") { ret self.parse_if_expr(); @@ -1367,11 +1409,19 @@ class parser { fn parse_sugary_call_expr(keyword: str, ctor: fn(+@expr) -> expr_) -> @expr { let lo = self.last_span; - let e = self.parse_expr_res(RESTRICT_STMT_EXPR); + // Parse the callee `foo` in + // for foo || { + // for foo.bar || { + // etc, or the portion of the call expression before the lambda in + // for foo() || { + // or + // for foo.bar(a) || { + // Turn on the restriction to stop at | or || so we can parse + // them as the lambda arguments + let e = self.parse_expr_res(RESTRICT_NO_BAR_OR_DOUBLEBAR_OP); alt e.node { expr_call(f, args, false) { - self.expect(token::LBRACE); - let block = self.parse_fn_block_expr(); + let block = self.parse_lambda_block_expr(); let last_arg = self.mk_expr(block.span.lo, block.span.hi, ctor(block)); let args = vec::append(args, ~[last_arg]); @@ -1379,15 +1429,17 @@ class parser { with *e} } expr_path(*) | expr_field(*) | expr_call(*) { - self.expect(token::LBRACE); - let block = self.parse_fn_block_expr(); + let block = self.parse_lambda_block_expr(); let last_arg = self.mk_expr(block.span.lo, block.span.hi, ctor(block)); self.mk_expr(lo.lo, last_arg.span.hi, expr_call(e, ~[last_arg], true)) } _ { - self.warn(#fmt("unexpected sugary call %?", e.node)); + // There may be other types of expressions that can + // represent the callee in `for` and `do` expressions + // but they aren't represented by tests + #debug("sugary call on %?", e.node); self.span_fatal( lo, #fmt("`%s` must be followed by a block call", keyword)); } |
