diff options
| author | Patrick Walton <pcwalton@mimiga.net> | 2013-10-29 15:06:13 -0700 |
|---|---|---|
| committer | Patrick Walton <pcwalton@mimiga.net> | 2013-10-31 10:30:32 -0700 |
| commit | f27272d60f193c6d27cc283f48c5be0e41562814 (patch) | |
| tree | 6647a01e6d2a80a05213cedf75b651d7accc9828 /src/libsyntax/parse | |
| parent | e976de32dc590f759e6c0c72d286844ca373e775 (diff) | |
| download | rust-f27272d60f193c6d27cc283f48c5be0e41562814.tar.gz rust-f27272d60f193c6d27cc283f48c5be0e41562814.zip | |
librustc: Implement `|A| -> B` syntax for closures and make bare `fn`
work
Diffstat (limited to 'src/libsyntax/parse')
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 186 |
1 files changed, 155 insertions, 31 deletions
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 68796a39f1b..56254704e28 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -561,6 +561,45 @@ impl Parser { } } + // Expect and consume a `|`. If `||` is seen, replace it with a single + // `|` and continue. If a `|` is not seen, signal an error. + fn expect_or(&self) { + match *self.token { + token::BINOP(token::OR) => self.bump(), + token::OROR => { + self.replace_token(token::BINOP(token::OR), + self.span.lo + BytePos(1), + self.span.hi) + } + _ => { + let found_token = self.token_to_str(&token::BINOP(token::OR)); + self.fatal(format!("expected `{}`, found `{}`", + found_token, + self.this_token_to_str())) + } + } + } + + // Parse a sequence bracketed by `|` and `|`, stopping before the `|`. + fn parse_seq_to_before_or<T>(&self, + sep: &token::Token, + f: &fn(&Parser) -> T) + -> ~[T] { + let mut first = true; + let mut vector = ~[]; + while *self.token != token::BINOP(token::OR) && + *self.token != token::OROR { + if first { + first = false + } else { + self.expect(sep) + } + + vector.push(f(self)) + } + vector + } + // expect and consume a GT. if a >> is seen, replace it // with a single > and continue. If a GT is not seen, // signal an error. @@ -761,11 +800,33 @@ impl Parser { get_ident_interner().get(id.name) } - // is this one of the keywords that signals a closure type? - pub fn token_is_closure_keyword(&self, tok: &token::Token) -> bool { - token::is_keyword(keywords::Unsafe, tok) || - token::is_keyword(keywords::Once, tok) || - token::is_keyword(keywords::Fn, tok) + // Is the current token one of the keywords that signals a bare function + // type? + pub fn token_is_bare_fn_keyword(&self) -> bool { + if token::is_keyword(keywords::Fn, self.token) { + return true + } + + if token::is_keyword(keywords::Unsafe, self.token) || + token::is_keyword(keywords::Once, self.token) { + return self.look_ahead(1, |t| token::is_keyword(keywords::Fn, t)) + } + + false + } + + // Is the current token one of the keywords that signals a closure type? + pub fn token_is_closure_keyword(&self) -> bool { + token::is_keyword(keywords::Unsafe, self.token) || + token::is_keyword(keywords::Once, self.token) + } + + // Is the current token one of the keywords that signals an old-style + // closure type (with explicit sigil)? + pub fn token_is_old_style_closure_keyword(&self) -> bool { + token::is_keyword(keywords::Unsafe, self.token) || + token::is_keyword(keywords::Once, self.token) || + token::is_keyword(keywords::Fn, self.token) } pub fn token_is_lifetime(&self, tok: &token::Token) -> bool { @@ -786,15 +847,15 @@ impl Parser { pub fn parse_ty_bare_fn(&self) -> ty_ { /* - extern "ABI" [unsafe] fn <'lt> (S) -> T - ^~~~^ ^~~~~~~^ ^~~~^ ^~^ ^ - | | | | | - | | | | Return type - | | | Argument types - | | Lifetimes - | | - | Purity - ABI + [extern "ABI"] [unsafe] fn <'lt> (S) -> T + ^~~~^ ^~~~~~~^ ^~~~^ ^~^ ^ + | | | | | + | | | | Return type + | | | Argument types + | | Lifetimes + | | + | Purity + ABI */ @@ -828,8 +889,8 @@ impl Parser { // parse a ty_closure type pub fn parse_ty_closure(&self, - sigil: ast::Sigil, - region: Option<ast::Lifetime>) + opt_sigil: Option<ast::Sigil>, + mut region: Option<ast::Lifetime>) -> ty_ { /* @@ -852,10 +913,58 @@ impl Parser { let purity = self.parse_unsafety(); let onceness = parse_onceness(self); - self.expect_keyword(keywords::Fn); - let bounds = self.parse_optional_ty_param_bounds(); - let (decl, lifetimes) = self.parse_ty_fn_decl(); + let (sigil, decl, lifetimes, bounds) = match opt_sigil { + Some(sigil) => { + // Old-style closure syntax (`fn(A)->B`). + self.expect_keyword(keywords::Fn); + let bounds = self.parse_optional_ty_param_bounds(); + let (decl, lifetimes) = self.parse_ty_fn_decl(); + (sigil, decl, lifetimes, bounds) + } + None => { + // New-style closure syntax (`<'lt>|A|:K -> B`). + let lifetimes = if self.eat(&token::LT) { + let lifetimes = self.parse_lifetimes(); + self.expect_gt(); + + // Re-parse the region here. What a hack. + if region.is_some() { + self.span_err(*self.last_span, + "lifetime declarations must precede \ + the lifetime associated with a \ + closure"); + } + region = self.parse_opt_lifetime(); + + lifetimes + } else { + opt_vec::Empty + }; + + let inputs = if self.eat(&token::OROR) { + ~[] + } else { + self.expect_or(); + let inputs = self.parse_seq_to_before_or( + &token::COMMA, + |p| p.parse_arg_general(false)); + self.expect_or(); + inputs + }; + + let bounds = self.parse_optional_ty_param_bounds(); + + let (return_style, output) = self.parse_ret_ty(); + let decl = ast::fn_decl { + inputs: inputs, + output: output, + cf: return_style, + }; + + (BorrowedSigil, decl, lifetimes, bounds) + } + }; return ty_closure(@TyClosure { sigil: sigil, @@ -1120,13 +1229,23 @@ impl Parser { // BORROWED POINTER self.bump(); self.parse_borrowed_pointee() - } else if self.eat_keyword(keywords::Extern) { - // EXTERN FUNCTION + } else if self.is_keyword(keywords::Extern) || + self.token_is_bare_fn_keyword() { + // BARE FUNCTION self.parse_ty_bare_fn() - } else if self.token_is_closure_keyword(self.token) { + } else if self.token_is_closure_keyword() || + *self.token == token::BINOP(token::OR) || + *self.token == token::OROR || + *self.token == token::LT || + self.token_is_lifetime(self.token) { // CLOSURE - let result = self.parse_ty_closure(ast::BorrowedSigil, None); - self.obsolete(*self.last_span, ObsoleteBareFnType); + // + // XXX(pcwalton): Eventually `token::LT` will not unambiguously + // introduce a closure, once procs can have lifetime bounds. We + // will need to refactor the grammar a little bit at that point. + + let lifetime = self.parse_opt_lifetime(); + let result = self.parse_ty_closure(None, lifetime); result } else if self.eat_keyword(keywords::Typeof) { // TYPEOF @@ -1161,12 +1280,12 @@ impl Parser { match *self.token { token::LIFETIME(*) => { let lifetime = self.parse_lifetime(); - return self.parse_ty_closure(sigil, Some(lifetime)); + return self.parse_ty_closure(Some(sigil), Some(lifetime)); } token::IDENT(*) => { - if self.token_is_closure_keyword(self.token) { - return self.parse_ty_closure(sigil, None); + if self.token_is_old_style_closure_keyword() { + return self.parse_ty_closure(Some(sigil), None); } } _ => {} @@ -1187,8 +1306,8 @@ impl Parser { // look for `&'lt` or `&'foo ` and interpret `foo` as the region name: let opt_lifetime = self.parse_opt_lifetime(); - if self.token_is_closure_keyword(self.token) { - return self.parse_ty_closure(BorrowedSigil, opt_lifetime); + if self.token_is_old_style_closure_keyword() { + return self.parse_ty_closure(Some(BorrowedSigil), opt_lifetime); } let mt = self.parse_mt(); @@ -4390,8 +4509,13 @@ impl Parser { } } - // parse a string as an ABI spec on an extern type or module + // Parses a string as an ABI spec on an extern type or module. Consumes + // the `extern` keyword, if one is found. fn parse_opt_abis(&self) -> Option<AbiSet> { + if !self.eat_keyword(keywords::Extern) { + return None + } + match *self.token { token::LIT_STR(s) | token::LIT_STR_RAW(s, _) => { @@ -4467,7 +4591,7 @@ impl Parser { }); } // either a view item or an item: - if self.eat_keyword(keywords::Extern) { + if self.is_keyword(keywords::Extern) { let opt_abis = self.parse_opt_abis(); if self.eat_keyword(keywords::Fn) { |
