about summary refs log tree commit diff
path: root/src/libsyntax/parse/parser.rs
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@mimiga.net>2013-10-29 15:06:13 -0700
committerPatrick Walton <pcwalton@mimiga.net>2013-10-31 10:30:32 -0700
commitf27272d60f193c6d27cc283f48c5be0e41562814 (patch)
tree6647a01e6d2a80a05213cedf75b651d7accc9828 /src/libsyntax/parse/parser.rs
parente976de32dc590f759e6c0c72d286844ca373e775 (diff)
downloadrust-f27272d60f193c6d27cc283f48c5be0e41562814.tar.gz
rust-f27272d60f193c6d27cc283f48c5be0e41562814.zip
librustc: Implement `|A| -> B` syntax for closures and make bare `fn`
work
Diffstat (limited to 'src/libsyntax/parse/parser.rs')
-rw-r--r--src/libsyntax/parse/parser.rs186
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) {