]> git.lizzy.rs Git - rust.git/commitdiff
define ty and update parser for sendable lambdas
authorNiko Matsakis <niko@alum.mit.edu>
Thu, 8 Dec 2011 19:47:01 +0000 (11:47 -0800)
committerNiko Matsakis <niko@alum.mit.edu>
Wed, 14 Dec 2011 22:32:17 +0000 (14:32 -0800)
src/comp/middle/ty.rs
src/comp/syntax/ast.rs
src/comp/syntax/parse/parser.rs

index bb6deac5a02b3d2597b2036dae35f6f742fc52df..d369e818d479f714f0d9bf5df898a04438fc7192 100644 (file)
@@ -980,6 +980,7 @@ fn type_kind(cx: ctxt, ty: t) -> ast::kind {
         alt proto {
           ast::proto_block. { ast::kind_noncopyable }
           ast::proto_shared(_) { ast::kind_copyable }
+          ast::proto_send. { ast::kind_sendable }
           ast::proto_bare. { ast::kind_sendable }
         }
       }
index a20d1ae5c6f5449128025c2f53b85eeacdf30405..d9d5260416e825d8080ffd96ca45dce10ac2b2e6 100644 (file)
 
 tag proto {
     proto_bare;
+    proto_send;
     proto_shared(proto_sugar);
     proto_block;
 }
     expr_for(@local, @expr, blk);
     expr_do_while(blk, @expr);
     expr_alt(@expr, [arm]);
-    expr_fn(_fn);
+    expr_fn(_fn, @capture);
     expr_block(blk);
 
     /*
     expr_mac(mac);
 }
 
+// At the moment, one can only capture local variables.
+type capture_ = {
+    is_send: bool,
+    copies: [ident],
+    moves: [ident]
+};
+
+type capture = spanned<capture_>;
+
 /*
 // Says whether this is a block the user marked as
 // "unchecked"
index 7ff08181e1a516cfc6c217b6c51d604153722ec9..e927ffbbeffad2b6f2e87d11d6da9a33c1c011f9 100644 (file)
 
 tag file_type { CRATE_FILE; SOURCE_FILE; }
 
+tag fn_kw {
+    fn_kw_fn;
+    fn_kw_lambda;
+    fn_kw_block;
+};
+
 type parse_sess = @{cm: codemap::codemap, mutable next_id: node_id};
 
 fn next_node_id(sess: parse_sess) -> node_id {
@@ -536,7 +542,14 @@ fn parse_ty(p: parser, colons_before_params: bool) -> @ast::ty {
     } else if eat_word(p, "block") {
         t = parse_ty_fn(ast::proto_block, p);
     } else if eat_word(p, "lambda") {
-        t = parse_ty_fn(ast::proto_shared(ast::sugar_sexy), p);
+        if p.peek() == token::LBRACE { // lambda[send](...)
+            expect(p, token::LBRACE);
+            expect_word(p, "send");
+            expect(p, token::RBRACE);
+            t = parse_ty_fn(ast::proto_send, p);
+        } else { // lambda(...)
+            t = parse_ty_fn(ast::proto_shared(ast::sugar_sexy), p);
+        }
     } else if eat_word(p, "obj") {
         t = parse_ty_obj(p);
     } else if p.peek() == token::MOD_SEP || is_ident(p.peek()) {
@@ -831,11 +844,11 @@ fn parse_bottom_expr(p: parser) -> @ast::expr {
         */
     } else if eat_word(p, "fn") {
         let proto = parse_fn_anon_proto(p);
-        ret parse_fn_expr(p, proto);
+        ret parse_fn_expr(p, fn_kw_fn);
     } else if eat_word(p, "block") {
-        ret parse_fn_expr(p, ast::proto_block);
+        ret parse_fn_expr(p, fn_kw_block);
     } else if eat_word(p, "lambda") {
-        ret parse_fn_expr(p, ast::proto_shared(ast::sugar_sexy));
+        ret parse_fn_expr(p, fn_kw_lambda);
     } else if eat_word(p, "unchecked") {
         ret parse_block_expr(p, lo, ast::unchecked_blk);
     } else if eat_word(p, "unsafe") {
@@ -1274,12 +1287,78 @@ fn parse_if_expr(p: parser) -> @ast::expr {
     }
 }
 
-fn parse_fn_expr(p: parser, proto: ast::proto) -> @ast::expr {
+// Parses:
+//
+//   CC := [send; copy ID*; move ID*]
+//
+// where any part is optional and trailing ; is permitted.
+fn parse_capture_clause(p: parser) -> (bool, @ast::capture) {
+    fn expect_opt_trailing_semi(p: parser) {
+        if !eat(p, token::SEMI) {
+            if p.peek() != token::RBRACE {
+                p.fatal("expecting ; or ]");
+            }
+        }
+    }
+
+    fn eat_ident_list(p: parser) -> [ast::ident] {
+        let res = [];
+        while true {
+            alt p.peek() {
+              token::IDENT(_, _) {
+                res += parse_ident(p);
+                if !eat(p, token::COMMA) {
+                    ret res;
+                }
+              }
+
+              _ { ret res; }
+            }
+        }
+    }
+
+    let is_send = false;
+    let copies = [];
+    let moves = [];
+
+    if p.peek() != token::LBRACE {
+        ret (is_send, captures);
+    }
+
+    expect(p, token::LBRACE);
+    while p.peek() != token::RBRACE {
+        if eat_word(p, "send") {
+            is_send = true;
+            expect_opt_trailing_semi(p);
+        } else if eat_word(p, "copy") {
+            copies += eat_ident_list();
+            expect_opt_trailing_semi(p);
+        } else if eat_word(p, "move") {
+            moves += eat_ident_list();
+            expect_opt_trailing_semi(p);
+        } else {
+            let s: str = "expecting send, copy, or move clause";
+            p.fatal(s);
+        }
+    }
+
+    ret @{is_send: is_send, copies: copies, moves: moves};
+}
+
+fn parse_fn_expr(p: parser, kw: fn_kw) -> @ast::expr {
     let lo = p.get_last_lo_pos();
+    let cap = parse_capture_clause(p);
     let decl = parse_fn_decl(p, ast::impure_fn, ast::il_normal);
     let body = parse_block(p);
+    let proto = alt (kw, cap.is_send) {
+      (fn_kw_fn., true) { ast::proto_bare }
+      (fn_kw_lambda., true) { ast::proto_send }
+      (fn_kw_lambda., false) { ast::proto_shared(ast::sugar_sexy) }
+      (fn_kw_block., false) { ast::proto_block }
+      (_, true) { p.fatal("only lambda can be declared sendable"); }
+    }
     let _fn = {decl: decl, proto: proto, body: body};
-    ret mk_expr(p, lo, body.span.hi, ast::expr_fn(_fn));
+    ret mk_expr(p, lo, body.span.hi, ast::expr_fn(_fn, cap));
 }
 
 fn parse_fn_block_expr(p: parser) -> @ast::expr {