librustc: Implement unboxed closures with mutable receivers

This commit is contained in:
Patrick Walton 2014-05-28 22:26:56 -07:00
parent 5ddc7b4a25
commit 02adaca4dc
77 changed files with 1905 additions and 384 deletions

View file

@ -25,7 +25,7 @@ use ast::{ExprBreak, ExprCall, ExprCast};
use ast::{ExprField, ExprFnBlock, ExprIf, ExprIndex};
use ast::{ExprLit, ExprLoop, ExprMac};
use ast::{ExprMethodCall, ExprParen, ExprPath, ExprProc};
use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary};
use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary, ExprUnboxedFn};
use ast::{ExprVec, ExprVstore, ExprVstoreSlice};
use ast::{ExprVstoreMutSlice, ExprWhile, ExprForLoop, Field, FnDecl};
use ast::{ExprVstoreUniq, Once, Many};
@ -59,6 +59,7 @@ use ast::Visibility;
use ast;
use ast_util::{as_prec, ident_to_path, lit_is_str, operator_prec};
use ast_util;
use attr;
use codemap::{Span, BytePos, Spanned, spanned, mk_sp};
use codemap;
use parse;
@ -1217,6 +1218,16 @@ impl<'a> Parser<'a> {
// NB: at the moment, trait methods are public by default; this
// could change.
let vis = p.parse_visibility();
let abi = if p.eat_keyword(keywords::Extern) {
p.parse_opt_abi().unwrap_or(abi::C)
} else if attr::contains_name(attrs.as_slice(),
"rust_call_abi_hack") {
// FIXME(stage0, pcwalton): Remove this awful hack after a
// snapshot, and change to `extern "rust-call" fn`.
abi::RustCall
} else {
abi::Rust
};
let style = p.parse_fn_style();
let ident = p.parse_ident();
@ -1239,6 +1250,7 @@ impl<'a> Parser<'a> {
fn_style: style,
decl: d,
generics: generics,
abi: abi,
explicit_self: explicit_self,
id: ast::DUMMY_NODE_ID,
span: mk_sp(lo, hi),
@ -1254,7 +1266,14 @@ impl<'a> Parser<'a> {
attrs: attrs,
id: ast::DUMMY_NODE_ID,
span: mk_sp(lo, hi),
node: ast::MethDecl(ident, generics, explicit_self, style, d, body, vis)
node: ast::MethDecl(ident,
generics,
abi,
explicit_self,
style,
d,
body,
vis)
})
}
@ -2620,51 +2639,11 @@ impl<'a> Parser<'a> {
self.mk_expr(lo, hi, ExprIf(cond, thn, els))
}
/// `|args| { ... }` or `{ ...}` like in `do` expressions
pub fn parse_lambda_block_expr(&mut self) -> Gc<Expr> {
self.parse_lambda_expr_(
|p| {
match p.token {
token::BINOP(token::OR) | token::OROR => {
p.parse_fn_block_decl()
}
_ => {
// No argument list - `do foo {`
P(FnDecl {
inputs: Vec::new(),
output: P(Ty {
id: ast::DUMMY_NODE_ID,
node: TyInfer,
span: p.span
}),
cf: Return,
variadic: false
})
}
}
},
|p| {
let blk = p.parse_block();
p.mk_expr(blk.span.lo, blk.span.hi, ExprBlock(blk))
})
}
/// `|args| expr`
// `|args| expr`
pub fn parse_lambda_expr(&mut self) -> Gc<Expr> {
self.parse_lambda_expr_(|p| p.parse_fn_block_decl(),
|p| p.parse_expr())
}
/// parse something of the form |args| expr
/// this is used both in parsing a lambda expr
/// and in parsing a block expr as e.g. in for...
pub fn parse_lambda_expr_(&mut self,
parse_decl: |&mut Parser| -> P<FnDecl>,
parse_body: |&mut Parser| -> Gc<Expr>)
-> Gc<Expr> {
let lo = self.span.lo;
let decl = parse_decl(self);
let body = parse_body(self);
let (decl, is_unboxed) = self.parse_fn_block_decl();
let body = self.parse_expr();
let fakeblock = P(ast::Block {
view_items: Vec::new(),
stmts: Vec::new(),
@ -2674,7 +2653,11 @@ impl<'a> Parser<'a> {
span: body.span,
});
return self.mk_expr(lo, body.span.hi, ExprFnBlock(decl, fakeblock));
if is_unboxed {
self.mk_expr(lo, body.span.hi, ExprUnboxedFn(decl, fakeblock))
} else {
self.mk_expr(lo, body.span.hi, ExprFnBlock(decl, fakeblock))
}
}
pub fn parse_else_expr(&mut self) -> Gc<Expr> {
@ -3955,18 +3938,30 @@ impl<'a> Parser<'a> {
(spanned(lo, hi, explicit_self), fn_decl)
}
/// Parse the |arg, arg| header on a lambda
fn parse_fn_block_decl(&mut self) -> P<FnDecl> {
let inputs_captures = {
// parse the |arg, arg| header on a lambda
fn parse_fn_block_decl(&mut self) -> (P<FnDecl>, bool) {
let (is_unboxed, inputs_captures) = {
if self.eat(&token::OROR) {
Vec::new()
(false, Vec::new())
} else {
self.parse_unspanned_seq(
&token::BINOP(token::OR),
self.expect(&token::BINOP(token::OR));
let is_unboxed = self.token == token::BINOP(token::AND) &&
self.look_ahead(1, |t| {
token::is_keyword(keywords::Mut, t)
}) &&
self.look_ahead(2, |t| *t == token::COLON);
if is_unboxed {
self.bump();
self.bump();
self.bump();
}
let args = self.parse_seq_to_before_end(
&token::BINOP(token::OR),
seq_sep_trailing_disallowed(token::COMMA),
|p| p.parse_fn_block_arg()
)
);
self.bump();
(is_unboxed, args)
}
};
let output = if self.eat(&token::RARROW) {
@ -3979,12 +3974,12 @@ impl<'a> Parser<'a> {
})
};
P(FnDecl {
(P(FnDecl {
inputs: inputs_captures,
output: output,
cf: Return,
variadic: false
})
}), is_unboxed)
}
/// Parses the `(arg, arg) -> return_type` header on a procedure.
@ -4079,6 +4074,11 @@ impl<'a> Parser<'a> {
(ast::MethMac(m), self.span.hi, attrs)
} else {
let visa = self.parse_visibility();
let abi = if self.eat_keyword(keywords::Extern) {
self.parse_opt_abi().unwrap_or(abi::C)
} else {
abi::Rust
};
let fn_style = self.parse_fn_style();
let ident = self.parse_ident();
let generics = self.parse_generics();
@ -4087,7 +4087,14 @@ impl<'a> Parser<'a> {
});
let (inner_attrs, body) = self.parse_inner_attrs_and_block();
let new_attrs = attrs.append(inner_attrs.as_slice());
(ast::MethDecl(ident, generics, explicit_self, fn_style, decl, body, visa),
(ast::MethDecl(ident,
generics,
abi,
explicit_self,
fn_style,
decl,
body,
visa),
body.span.hi, new_attrs)
}
};