about summary refs log tree commit diff
path: root/src/librustsyntax
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2012-05-04 12:33:04 -0700
committerNiko Matsakis <niko@alum.mit.edu>2012-05-04 12:33:08 -0700
commit50ec6bd2c3c472ea140ed60de38dd50c672fc80a (patch)
treedd040e82e0eba8038dd06424091b6fc575f720aa /src/librustsyntax
parent8affc78e8a0e420e1755a34fc7f5e4021c512e9d (diff)
downloadrust-50ec6bd2c3c472ea140ed60de38dd50c672fc80a.tar.gz
rust-50ec6bd2c3c472ea140ed60de38dd50c672fc80a.zip
new cap clause syntax
Diffstat (limited to 'src/librustsyntax')
-rw-r--r--src/librustsyntax/ast.rs10
-rw-r--r--src/librustsyntax/fold.rs5
-rw-r--r--src/librustsyntax/parse/parser.rs238
-rw-r--r--src/librustsyntax/print/pprust.rs95
-rw-r--r--src/librustsyntax/visit.rs2
5 files changed, 185 insertions, 165 deletions
diff --git a/src/librustsyntax/ast.rs b/src/librustsyntax/ast.rs
index 4a4b5ea4d38..12e29bcc3ec 100644
--- a/src/librustsyntax/ast.rs
+++ b/src/librustsyntax/ast.rs
@@ -311,8 +311,8 @@ enum expr_ {
        (implicit) condition is always true. */
     expr_loop(blk),
     expr_alt(@expr, [arm], alt_mode),
-    expr_fn(proto, fn_decl, blk, @capture_clause),
-    expr_fn_block(fn_decl, blk),
+    expr_fn(proto, fn_decl, blk, capture_clause),
+    expr_fn_block(fn_decl, blk, capture_clause),
     // Inner expr is always an expr_fn_block. We need the wrapping node to
     // sanely type this (a function returning nil on the inside but bool on
     // the outside).
@@ -356,15 +356,13 @@ enum expr_ {
 #[auto_serialize]
 type capture_item = {
     id: int,
+    is_move: bool,
     name: ident, // Currently, can only capture a local var.
     span: span
 };
 
 #[auto_serialize]
-type capture_clause = {
-    copies: [@capture_item],
-    moves: [@capture_item]
-};
+type capture_clause = [capture_item];
 
 /*
 // Says whether this is a block the user marked as
diff --git a/src/librustsyntax/fold.rs b/src/librustsyntax/fold.rs
index 30e8c5173b2..5ebaee71339 100644
--- a/src/librustsyntax/fold.rs
+++ b/src/librustsyntax/fold.rs
@@ -456,8 +456,9 @@ fn noop_fold_expr(e: expr_, fld: ast_fold) -> expr_ {
               expr_fn(proto, fold_fn_decl(decl, fld),
                       fld.fold_block(body), captures)
           }
-          expr_fn_block(decl, body) {
-            expr_fn_block(fold_fn_decl(decl, fld), fld.fold_block(body))
+          expr_fn_block(decl, body, captures) {
+            expr_fn_block(fold_fn_decl(decl, fld), fld.fold_block(body),
+                          captures)
           }
           expr_block(blk) { expr_block(fld.fold_block(blk)) }
           expr_move(el, er) {
diff --git a/src/librustsyntax/parse/parser.rs b/src/librustsyntax/parse/parser.rs
index 0c681900dd5..0432faecba0 100644
--- a/src/librustsyntax/parse/parser.rs
+++ b/src/librustsyntax/parse/parser.rs
@@ -398,25 +398,51 @@ fn parse_arg_mode(p: parser) -> ast::mode {
     } else { ast::infer(p.get_id()) }
 }
 
-fn parse_arg(p: parser) -> ast::arg {
+fn parse_capture_item_or(
+    p: parser,
+    parse_arg_fn: fn() -> arg_or_capture_item) -> arg_or_capture_item {
+
+    fn parse_capture_item(p: parser, is_move: bool) -> ast::capture_item {
+        let id = p.get_id();
+        let sp = mk_sp(p.span.lo, p.span.hi);
+        let ident = parse_ident(p);
+        {id: id, is_move: is_move, name: ident, span: sp}
+    }
+
+    if eat_keyword(p, "move") {
+        either::right(parse_capture_item(p, true))
+    } else if eat_keyword(p, "copy") {
+        either::right(parse_capture_item(p, false))
+    } else {
+        parse_arg_fn()
+    }
+}
+
+fn parse_arg(p: parser) -> arg_or_capture_item {
     let m = parse_arg_mode(p);
     let i = parse_value_ident(p);
     expect(p, token::COLON);
     let t = parse_ty(p, false);
-    ret {mode: m, ty: t, ident: i, id: p.get_id()};
+    either::left({mode: m, ty: t, ident: i, id: p.get_id()})
 }
 
-fn parse_fn_block_arg(p: parser) -> ast::arg {
-    let m = parse_arg_mode(p);
-    let i = parse_value_ident(p);
-    let t = if eat(p, token::COLON) {
-                parse_ty(p, false)
-            } else {
-                @{id: p.get_id(),
-                  node: ast::ty_infer,
-                  span: mk_sp(p.span.lo, p.span.hi)}
-            };
-    ret {mode: m, ty: t, ident: i, id: p.get_id()};
+fn parse_arg_or_capture_item(p: parser) -> arg_or_capture_item {
+    parse_capture_item_or(p) {|| parse_arg(p) }
+}
+
+fn parse_fn_block_arg(p: parser) -> arg_or_capture_item {
+    parse_capture_item_or(p) {||
+        let m = parse_arg_mode(p);
+        let i = parse_value_ident(p);
+        let t = if eat(p, token::COLON) {
+                    parse_ty(p, false)
+                } else {
+                    @{id: p.get_id(),
+                      node: ast::ty_infer,
+                      span: mk_sp(p.span.lo, p.span.hi)}
+                };
+        either::left({mode: m, ty: t, ident: i, id: p.get_id()})
+    }
 }
 
 fn maybe_parse_dollar_mac(p: parser) -> option<ast::mac_> {
@@ -1149,74 +1175,27 @@ fn parse_if_expr(p: parser) -> @ast::expr {
     }
 }
 
-// Parses:
-//
-//   CC := [copy ID*; move ID*]
-//
-// where any part is optional and trailing ; is permitted.
-fn parse_capture_clause(p: parser) -> @ast::capture_clause {
-    fn expect_opt_trailing_semi(p: parser) {
-        if !eat(p, token::SEMI) {
-            if p.token != token::RBRACKET {
-                p.fatal("expecting ; or ]");
-            }
-        }
-    }
-
-    fn eat_ident_list(p: parser) -> [@ast::capture_item] {
-        let mut res = [];
-        loop {
-            alt p.token {
-              token::IDENT(_, _) {
-                let id = p.get_id();
-                let sp = mk_sp(p.span.lo, p.span.hi);
-                let ident = parse_ident(p);
-                res += [@{id:id, name:ident, span:sp}];
-                if !eat(p, token::COMMA) {
-                    ret res;
-                }
-              }
-
-              _ { ret res; }
-            }
-        };
-    }
-
-    let mut copies = [];
-    let mut moves = [];
+fn parse_fn_expr(p: parser, proto: ast::proto) -> @ast::expr {
+    let lo = p.last_span.lo;
 
-    if eat(p, token::LBRACKET) {
-        while !eat(p, token::RBRACKET) {
-            if eat_keyword(p, "copy") {
-                copies += eat_ident_list(p);
-                expect_opt_trailing_semi(p);
-            } else if eat_keyword(p, "move") {
-                moves += eat_ident_list(p);
-                expect_opt_trailing_semi(p);
-            } else {
-                let s: str = "expecting send, copy, or move clause";
-                p.fatal(s);
-            }
-        }
-    }
+    let cc_old = parse_old_skool_capture_clause(p);
 
-    ret @{copies: copies, moves: moves};
-}
+    // if we want to allow fn expression argument types to be inferred in the
+    // future, just have to change parse_arg to parse_fn_block_arg.
+    let (decl, capture_clause) =
+        parse_fn_decl(p, ast::impure_fn, parse_arg_or_capture_item);
 
-fn parse_fn_expr(p: parser, proto: ast::proto) -> @ast::expr {
-    let lo = p.last_span.lo;
-    let capture_clause = parse_capture_clause(p);
-    let decl = parse_fn_decl(p, ast::impure_fn);
     let body = parse_block(p);
     ret mk_expr(p, lo, body.span.hi,
-                ast::expr_fn(proto, decl, body, capture_clause));
+                ast::expr_fn(proto, decl, body, capture_clause + cc_old));
 }
 
 fn parse_fn_block_expr(p: parser) -> @ast::expr {
     let lo = p.last_span.lo;
-    let decl = parse_fn_block_decl(p);
+    let (decl, captures) = parse_fn_block_decl(p);
     let body = parse_block_tail(p, lo, ast::default_blk);
-    ret mk_expr(p, lo, body.span.hi, ast::expr_fn_block(decl, body));
+    ret mk_expr(p, lo, body.span.hi,
+                ast::expr_fn_block(decl, body, captures));
 }
 
 fn parse_else_expr(p: parser) -> @ast::expr {
@@ -1699,46 +1678,107 @@ fn parse_ty_params(p: parser) -> [ast::ty_param] {
     } else { [] }
 }
 
-fn parse_fn_decl(p: parser, purity: ast::purity)
-    -> ast::fn_decl {
-    let inputs: ast::spanned<[ast::arg]> =
+// FIXME Remove after snapshot
+fn parse_old_skool_capture_clause(p: parser) -> ast::capture_clause {
+    fn expect_opt_trailing_semi(p: parser) {
+        if !eat(p, token::SEMI) {
+            if p.token != token::RBRACKET {
+                p.fatal("expecting ; or ]");
+            }
+        }
+    }
+
+    fn eat_ident_list(p: parser, is_move: bool) -> [ast::capture_item] {
+        let mut res = [];
+        loop {
+            alt p.token {
+              token::IDENT(_, _) {
+                let id = p.get_id();
+                let sp = mk_sp(p.span.lo, p.span.hi);
+                let ident = parse_ident(p);
+                res += [{id:id, is_move: is_move, name:ident, span:sp}];
+                if !eat(p, token::COMMA) {
+                    ret res;
+                }
+              }
+
+              _ { ret res; }
+            }
+        };
+    }
+
+    let mut cap_items = [];
+
+    if eat(p, token::LBRACKET) {
+        while !eat(p, token::RBRACKET) {
+            if eat_keyword(p, "copy") {
+                cap_items += eat_ident_list(p, false);
+                expect_opt_trailing_semi(p);
+            } else if eat_keyword(p, "move") {
+                cap_items += eat_ident_list(p, true);
+                expect_opt_trailing_semi(p);
+            } else {
+                let s: str = "expecting send, copy, or move clause";
+                p.fatal(s);
+            }
+        }
+    }
+
+    ret cap_items;
+}
+
+type arg_or_capture_item = either<ast::arg, ast::capture_item>;
+
+
+fn parse_fn_decl(p: parser, purity: ast::purity,
+                 parse_arg_fn: fn(parser) -> arg_or_capture_item)
+    -> (ast::fn_decl, ast::capture_clause) {
+
+    let args_or_capture_items: [arg_or_capture_item] =
         parse_seq(token::LPAREN, token::RPAREN, seq_sep(token::COMMA),
-                  parse_arg, p);
+                  parse_arg_fn, p).node;
+
+    let inputs = either::lefts(args_or_capture_items);
+    let capture_clause = either::rights(args_or_capture_items);
+
     // Use the args list to translate each bound variable
     // mentioned in a constraint to an arg index.
     // Seems weird to do this in the parser, but I'm not sure how else to.
     let mut constrs = [];
     if p.token == token::COLON {
         p.bump();
-        constrs = parse_constrs({|x| parse_ty_constr(inputs.node, x) }, p);
+        constrs = parse_constrs({|x| parse_ty_constr(inputs, x) }, p);
     }
     let (ret_style, ret_ty) = parse_ret_ty(p);
-    ret {inputs: inputs.node,
-         output: ret_ty,
-         purity: purity,
-         cf: ret_style,
-         constraints: constrs};
+    ret ({inputs: inputs,
+          output: ret_ty,
+          purity: purity,
+          cf: ret_style,
+          constraints: constrs}, capture_clause);
 }
 
-fn parse_fn_block_decl(p: parser) -> ast::fn_decl {
-    let inputs = if eat(p, token::OROR) {
-                     []
-                 } else {
-                     parse_seq(token::BINOP(token::OR),
-                               token::BINOP(token::OR),
-                               seq_sep(token::COMMA),
-                               parse_fn_block_arg, p).node
-                 };
+fn parse_fn_block_decl(p: parser) -> (ast::fn_decl, ast::capture_clause) {
+    let inputs_captures = {
+        if eat(p, token::OROR) {
+            []
+        } else {
+            parse_seq(token::BINOP(token::OR),
+                      token::BINOP(token::OR),
+                      seq_sep(token::COMMA),
+                      parse_fn_block_arg, p).node
+        }
+    };
     let output = if eat(p, token::RARROW) {
                      parse_ty(p, false)
                  } else {
                      @{id: p.get_id(), node: ast::ty_infer, span: p.span}
                  };
-    ret {inputs: inputs,
-         output: output,
-         purity: ast::impure_fn,
-         cf: ast::return_val,
-         constraints: []};
+    ret ({inputs: either::lefts(inputs_captures),
+          output: output,
+          purity: ast::impure_fn,
+          cf: ast::return_val,
+          constraints: []},
+         either::rights(inputs_captures));
 }
 
 fn parse_fn_header(p: parser) -> {ident: ast::ident, tps: [ast::ty_param]} {
@@ -1760,7 +1800,7 @@ fn parse_item_fn(p: parser, purity: ast::purity,
                  attrs: [ast::attribute]) -> @ast::item {
     let lo = p.last_span.lo;
     let t = parse_fn_header(p);
-    let decl = parse_fn_decl(p, purity);
+    let (decl, _) = parse_fn_decl(p, purity, parse_arg);
     let (inner_attrs, body) = parse_inner_attrs_and_block(p, true);
     let attrs = attrs + inner_attrs;
     ret mk_item(p, lo, body.span.hi, t.ident,
@@ -1785,7 +1825,7 @@ fn parse_method(p: parser, pr: ast::privacy) -> @ast::method {
     let lo = p.span.lo, pur = parse_fn_purity(p);
     let ident = parse_method_name(p);
     let tps = parse_ty_params(p);
-    let decl = parse_fn_decl(p, pur);
+    let (decl, _) = parse_fn_decl(p, pur, parse_arg);
     let (inner_attrs, body) = parse_inner_attrs_and_block(p, true);
     let attrs = attrs + inner_attrs;
     @{ident: ident, attrs: attrs, tps: tps, decl: decl, body: body,
@@ -1969,7 +2009,7 @@ fn parse_class_item(p:parser, class_name_with_tps: @ast::path)
         let lo = p.last_span.lo;
         // Can ctors have attrs?
             // result type is always the type of the class
-        let decl_ = parse_fn_decl(p, ast::impure_fn);
+        let (decl_, _) = parse_fn_decl(p, ast::impure_fn, parse_arg);
         let decl = {output: @{id: p.get_id(),
                       node: ast::ty_path(class_name_with_tps, p.get_id()),
                       span: decl_.output.span}
@@ -2048,7 +2088,7 @@ fn parse_item_native_fn(p: parser, attrs: [ast::attribute],
                         purity: ast::purity) -> @ast::native_item {
     let lo = p.last_span.lo;
     let t = parse_fn_header(p);
-    let decl = parse_fn_decl(p, purity);
+    let (decl, _) = parse_fn_decl(p, purity, parse_arg);
     let mut hi = p.span.hi;
     expect(p, token::SEMI);
     ret @{ident: t.ident,
diff --git a/src/librustsyntax/print/pprust.rs b/src/librustsyntax/print/pprust.rs
index b50f4f341a7..6e573041265 100644
--- a/src/librustsyntax/print/pprust.rs
+++ b/src/librustsyntax/print/pprust.rs
@@ -519,7 +519,7 @@ fn print_item(s: ps, &&item: @ast::item) {
           hardbreak_if_not_bol(s);
           maybe_print_comment(s, ctor.span.lo);
           head(s, "new");
-          print_fn_args_and_ret(s, ctor.node.dec);
+          print_fn_args_and_ret(s, ctor.node.dec, []);
           space(s.s);
           print_block(s, ctor.node.body);
           for items.each {|ci|
@@ -1018,18 +1018,17 @@ fn print_expr(s: ps, &&expr: @ast::expr) {
         // head-box, will be closed by print-block at start
         ibox(s, 0u);
         word(s.s, proto_to_str(proto));
-        print_cap_clause(s, *cap_clause);
-        print_fn_args_and_ret(s, decl);
+        print_fn_args_and_ret(s, decl, cap_clause);
         space(s.s);
         print_block(s, body);
       }
-      ast::expr_fn_block(decl, body) {
+      ast::expr_fn_block(decl, body, cap_clause) {
         // containing cbox, will be closed by print-block at }
         cbox(s, indent_unit);
         // head-box, will be closed by print-block at start
         ibox(s, 0u);
         word(s.s, "{");
-        print_fn_block_args(s, decl);
+        print_fn_block_args(s, decl, cap_clause);
         print_possibly_embedded_block(s, body, block_block_fn, indent_unit);
       }
       ast::expr_loop_body(body) {
@@ -1319,46 +1318,27 @@ fn print_fn(s: ps, decl: ast::fn_decl, name: ast::ident,
     }
     word(s.s, name);
     print_type_params(s, typarams);
-    print_fn_args_and_ret(s, decl);
+    print_fn_args_and_ret(s, decl, []);
 }
 
-fn print_cap_clause(s: ps, cap_clause: ast::capture_clause) {
-    fn print_cap_item(s: ps, &&cap_item: @ast::capture_item) {
-        word(s.s, cap_item.name);
-    }
-
-    let has_copies = vec::is_not_empty(cap_clause.copies);
-    let has_moves = vec::is_not_empty(cap_clause.moves);
-    if !has_copies && !has_moves { ret; }
-
-    word(s.s, "[");
-
-    if has_copies {
-        word_nbsp(s, "copy");
-        commasep(s, inconsistent, cap_clause.copies, print_cap_item);
-        if has_moves {
-            word_space(s, ";");
+fn print_fn_args(s: ps, decl: ast::fn_decl,
+                 cap_items: [ast::capture_item]) {
+    commasep(s, inconsistent, decl.inputs, print_arg);
+    if cap_items.is_not_empty() {
+        let mut first = decl.inputs.is_empty();
+        for cap_items.each { |cap_item|
+            if first { first = false; } else { word_space(s, ","); }
+            if cap_item.is_move { word_nbsp(s, "move") }
+            else { word_nbsp(s, "copy") }
+            word(s.s, cap_item.name);
         }
     }
-
-    if has_moves {
-        word_nbsp(s, "move");
-        commasep(s, inconsistent, cap_clause.moves, print_cap_item);
-    }
-
-    word(s.s, "]");
 }
 
-fn print_fn_args_and_ret(s: ps, decl: ast::fn_decl) {
+fn print_fn_args_and_ret(s: ps, decl: ast::fn_decl,
+                         cap_items: [ast::capture_item]) {
     popen(s);
-    fn print_arg(s: ps, x: ast::arg) {
-        ibox(s, indent_unit);
-        print_arg_mode(s, x.mode);
-        word_space(s, x.ident + ":");
-        print_type(s, x.ty);
-        end(s);
-    }
-    commasep(s, inconsistent, decl.inputs, print_arg);
+    print_fn_args(s, decl, cap_items);
     pclose(s);
     word(s.s, constrs_str(decl.constraints, {|c|
         ast_fn_constr_to_str(decl, c)
@@ -1372,19 +1352,10 @@ fn print_fn_args_and_ret(s: ps, decl: ast::fn_decl) {
     }
 }
 
-fn print_fn_block_args(s: ps, decl: ast::fn_decl) {
+fn print_fn_block_args(s: ps, decl: ast::fn_decl,
+                       cap_items: [ast::capture_item]) {
     word(s.s, "|");
-    fn print_arg(s: ps, x: ast::arg) {
-        ibox(s, indent_unit);
-        print_arg_mode(s, x.mode);
-        word(s.s, x.ident);
-        if x.ty.node != ast::ty_infer {
-            word_space(s, ":");
-            print_type(s, x.ty);
-        }
-        end(s);
-    }
-    commasep(s, inconsistent, decl.inputs, print_arg);
+    print_fn_args(s, decl, cap_items);
     word(s.s, "|");
     if decl.output.node != ast::ty_infer {
         space_if_not_bol(s);
@@ -1541,6 +1512,23 @@ fn print_mt(s: ps, mt: ast::mt) {
     print_type(s, mt.ty);
 }
 
+fn print_arg(s: ps, input: ast::arg) {
+    ibox(s, indent_unit);
+    print_arg_mode(s, input.mode);
+    alt input.ty.node {
+      ast::ty_infer {
+        word(s.s, input.ident);
+      }
+      _ {
+        if str::len(input.ident) > 0u {
+            word_space(s, input.ident + ":");
+        }
+        print_type(s, input.ty);
+      }
+    }
+    end(s);
+}
+
 fn print_ty_fn(s: ps, opt_proto: option<ast::proto>,
                decl: ast::fn_decl, id: option<ast::ident>,
                tps: option<[ast::ty_param]>) {
@@ -1550,13 +1538,6 @@ fn print_ty_fn(s: ps, opt_proto: option<ast::proto>,
     alt tps { some(tps) { print_type_params(s, tps); } _ { } }
     zerobreak(s.s);
     popen(s);
-    fn print_arg(s: ps, input: ast::arg) {
-        print_arg_mode(s, input.mode);
-        if str::len(input.ident) > 0u {
-            word_space(s, input.ident + ":");
-        }
-        print_type(s, input.ty);
-    }
     commasep(s, inconsistent, decl.inputs, print_arg);
     pclose(s);
     maybe_print_comment(s, decl.output.span.lo);
diff --git a/src/librustsyntax/visit.rs b/src/librustsyntax/visit.rs
index d2188977af0..2cac7f53e83 100644
--- a/src/librustsyntax/visit.rs
+++ b/src/librustsyntax/visit.rs
@@ -384,7 +384,7 @@ fn visit_expr<E>(ex: @expr, e: E, v: vt<E>) {
       expr_fn(proto, decl, body, _) {
         v.visit_fn(fk_anon(proto), decl, body, ex.span, ex.id, e, v);
       }
-      expr_fn_block(decl, body) {
+      expr_fn_block(decl, body, _) {
         v.visit_fn(fk_fn_block, decl, body, ex.span, ex.id, e, v);
       }
       expr_block(b) { v.visit_block(b, e, v); }