about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-10-29 10:52:25 -0700
committerbors <bors@rust-lang.org>2013-10-29 10:52:25 -0700
commitfed48cc861fd858762c1e9b498675bfa4dee2d38 (patch)
tree01c61601be0db74a12ff9504f6eace70add85385 /src/libsyntax
parent52f42f16387d0142944f376ea31c554c9caa2189 (diff)
parent7e77bf17694e31c741fe3a31c7eca5437d9cb6d5 (diff)
downloadrust-fed48cc861fd858762c1e9b498675bfa4dee2d38.tar.gz
rust-fed48cc861fd858762c1e9b498675bfa4dee2d38.zip
auto merge of #10132 : pcwalton/rust/proc, r=pcwalton
the feature gate for `once fn` if used with the `~` sigil.

r? @brson
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ast.rs1
-rw-r--r--src/libsyntax/fold.rs3
-rw-r--r--src/libsyntax/parse/parser.rs57
-rw-r--r--src/libsyntax/parse/token.rs41
-rw-r--r--src/libsyntax/print/pprust.rs61
-rw-r--r--src/libsyntax/visit.rs8
6 files changed, 145 insertions, 26 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 3467e1aaadc..cf72455a83a 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -537,6 +537,7 @@ pub enum Expr_ {
     ExprLoop(Block, Option<Ident>),
     ExprMatch(@Expr, ~[Arm]),
     ExprFnBlock(fn_decl, Block),
+    ExprProc(fn_decl, Block),
     ExprDoBody(@Expr),
     ExprBlock(Block),
 
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index fddf674a846..d579e7dd2c7 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -786,6 +786,9 @@ pub fn noop_fold_expr<T:ast_fold>(e: @ast::Expr, folder: &T) -> @ast::Expr {
                 folder.fold_block(body)
             )
         }
+        ExprProc(ref decl, ref body) => {
+            ExprProc(fold_fn_decl(decl, folder), folder.fold_block(body))
+        }
         ExprBlock(ref blk) => ExprBlock(folder.fold_block(blk)),
         ExprAssign(el, er) => {
             ExprAssign(folder.fold_expr(el), folder.fold_expr(er))
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 8b399266676..716fb5040f6 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -27,7 +27,7 @@ use ast::{ExprAssign, ExprAssignOp, ExprBinary, ExprBlock};
 use ast::{ExprBreak, ExprCall, ExprCast, ExprDoBody};
 use ast::{ExprField, ExprFnBlock, ExprIf, ExprIndex};
 use ast::{ExprLit, ExprLogLevel, ExprLoop, ExprMac};
-use ast::{ExprMethodCall, ExprParen, ExprPath, ExprRepeat};
+use ast::{ExprMethodCall, ExprParen, ExprPath, ExprProc, ExprRepeat};
 use ast::{ExprRet, ExprSelf, ExprStruct, ExprTup, ExprUnary};
 use ast::{ExprVec, ExprVstore, ExprVstoreMutBox};
 use ast::{ExprVstoreSlice, ExprVstoreBox};
@@ -814,6 +814,21 @@ impl Parser {
         });
     }
 
+    // Parses a procedure type (`proc`). The initial `proc` keyword must
+    // already have been parsed.
+    pub fn parse_proc_type(&self) -> ty_ {
+        let (decl, lifetimes) = self.parse_ty_fn_decl();
+        ty_closure(@TyClosure {
+            sigil: OwnedSigil,
+            region: None,
+            purity: impure_fn,
+            onceness: Once,
+            bounds: None,
+            decl: decl,
+            lifetimes: lifetimes,
+        })
+    }
+
     // parse a ty_closure type
     pub fn parse_ty_closure(&self,
                             sigil: ast::Sigil,
@@ -1123,6 +1138,8 @@ impl Parser {
             let e = self.parse_expr();
             self.expect(&token::RPAREN);
             ty_typeof(e)
+        } else if self.eat_keyword(keywords::Proc) {
+            self.parse_proc_type()
         } else if *self.token == token::MOD_SEP
             || is_ident_or_path(self.token) {
             // NAMED TYPE
@@ -1672,6 +1689,19 @@ impl Parser {
                                  ExprBlock(blk));
         } else if token::is_bar(&*self.token) {
             return self.parse_lambda_expr();
+        } else if self.eat_keyword(keywords::Proc) {
+            let decl = self.parse_proc_decl();
+            let body = self.parse_expr();
+            let fakeblock = ast::Block {
+                view_items: ~[],
+                stmts: ~[],
+                expr: Some(body),
+                id: ast::DUMMY_NODE_ID,
+                rules: DefaultBlock,
+                span: body.span,
+            };
+
+            return self.mk_expr(lo, body.span.hi, ExprProc(decl, fakeblock));
         } else if self.eat_keyword(keywords::Self) {
             ex = ExprSelf;
             hi = self.span.hi;
@@ -3616,6 +3646,31 @@ impl Parser {
         }
     }
 
+    // Parses the `(arg, arg) -> return_type` header on a procedure.
+    fn parse_proc_decl(&self) -> fn_decl {
+        let inputs =
+            self.parse_unspanned_seq(&token::LPAREN,
+                                     &token::RPAREN,
+                                     seq_sep_trailing_allowed(token::COMMA),
+                                     |p| p.parse_fn_block_arg());
+
+        let output = if self.eat(&token::RARROW) {
+            self.parse_ty(false)
+        } else {
+            Ty {
+                id: ast::DUMMY_NODE_ID,
+                node: ty_infer,
+                span: *self.span,
+            }
+        };
+
+        ast::fn_decl {
+            inputs: inputs,
+            output: output,
+            cf: return_val,
+        }
+    }
+
     // parse the name and optional generic types of a function header.
     fn parse_fn_header(&self) -> (Ident, ast::Generics) {
         let id = self.parse_ident();
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index 27747d94b66..3d8fa1b6728 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -486,14 +486,15 @@ fn mk_fresh_ident_interner() -> @ident_interner {
         "while",              // 62
         "in",                 // 63
         "continue",           // 64
-
-        "be",                 // 65
-        "pure",               // 66
-        "yield",              // 67
-        "typeof",             // 68
-        "alignof",            // 69
-        "offsetof",           // 70
-        "sizeof",             // 71
+        "proc",               // 65
+
+        "be",                 // 66
+        "pure",               // 67
+        "yield",              // 68
+        "typeof",             // 69
+        "alignof",            // 70
+        "offsetof",           // 71
+        "sizeof",             // 72
     ];
 
     @interner::StrInterner::prefill(init_vec)
@@ -502,9 +503,9 @@ fn mk_fresh_ident_interner() -> @ident_interner {
 static SELF_KEYWORD_NAME: uint = 8;
 static STATIC_KEYWORD_NAME: uint = 27;
 static STRICT_KEYWORD_START: uint = 32;
-static STRICT_KEYWORD_FINAL: uint = 64;
-static RESERVED_KEYWORD_START: uint = 65;
-static RESERVED_KEYWORD_FINAL: uint = 71;
+static STRICT_KEYWORD_FINAL: uint = 65;
+static RESERVED_KEYWORD_START: uint = 66;
+static RESERVED_KEYWORD_FINAL: uint = 72;
 
 // if an interner exists in TLS, return it. Otherwise, prepare a
 // fresh one.
@@ -645,6 +646,7 @@ pub mod keywords {
         Use,
         While,
         Continue,
+        Proc,
 
         // Reserved keywords
         Alignof,
@@ -694,14 +696,15 @@ pub mod keywords {
                 Use => Ident { name: 61, ctxt: 0 },
                 While => Ident { name: 62, ctxt: 0 },
                 Continue => Ident { name: 64, ctxt: 0 },
-
-                Alignof => Ident { name: 69, ctxt: 0 },
-                Be => Ident { name: 65, ctxt: 0 },
-                Offsetof => Ident { name: 70, ctxt: 0 },
-                Pure => Ident { name: 66, ctxt: 0 },
-                Sizeof => Ident { name: 71, ctxt: 0 },
-                Typeof => Ident { name: 68, ctxt: 0 },
-                Yield => Ident { name: 67, ctxt: 0 },
+                Proc => Ident { name: 65, ctxt: 0 },
+
+                Alignof => Ident { name: 70, ctxt: 0 },
+                Be => Ident { name: 66, ctxt: 0 },
+                Offsetof => Ident { name: 71, ctxt: 0 },
+                Pure => Ident { name: 67, ctxt: 0 },
+                Sizeof => Ident { name: 72, ctxt: 0 },
+                Typeof => Ident { name: 69, ctxt: 0 },
+                Yield => Ident { name: 68, ctxt: 0 },
             }
         }
     }
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index f3090c7dd16..33bdcdd1b03 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -1350,6 +1350,33 @@ pub fn print_expr(s: @ps, expr: &ast::Expr) {
         // empty box to satisfy the close.
         ibox(s, 0);
       }
+      ast::ExprProc(ref decl, ref body) => {
+        // in do/for blocks we don't want to show an empty
+        // argument list, but at this point we don't know which
+        // we are inside.
+        //
+        // if !decl.inputs.is_empty() {
+        print_proc_args(s, decl);
+        space(s.s);
+        // }
+        assert!(body.stmts.is_empty());
+        assert!(body.expr.is_some());
+        // we extract the block, so as not to create another set of boxes
+        match body.expr.unwrap().node {
+            ast::ExprBlock(ref blk) => {
+                print_block_unclosed(s, blk);
+            }
+            _ => {
+                // this is a bare expression
+                print_expr(s, body.expr.unwrap());
+                end(s); // need to close a box
+            }
+        }
+        // a box will be closed by print_expr, but we didn't want an overall
+        // wrapper so we closed the corresponding opening. so create an
+        // empty box to satisfy the close.
+        ibox(s, 0);
+      }
       ast::ExprDoBody(body) => {
         print_expr(s, body);
       }
@@ -1777,6 +1804,24 @@ pub fn print_fn_block_args(s: @ps, decl: &ast::fn_decl) {
     maybe_print_comment(s, decl.output.span.lo);
 }
 
+pub fn print_proc_args(s: @ps, decl: &ast::fn_decl) {
+    word(s.s, "proc");
+    word(s.s, "(");
+    print_fn_args(s, decl, None);
+    word(s.s, ")");
+
+    match decl.output.node {
+        ast::ty_infer => {}
+        _ => {
+            space_if_not_bol(s);
+            word_space(s, "->");
+            print_type(s, &decl.output);
+        }
+    }
+
+    maybe_print_comment(s, decl.output.span.lo);
+}
+
 pub fn print_bounds(s: @ps, bounds: &OptVec<ast::TyParamBound>,
                     print_colon_anyway: bool) {
     if !bounds.is_empty() {
@@ -1968,12 +2013,16 @@ pub fn print_ty_fn(s: @ps,
 
     // Duplicates the logic in `print_fn_header_info()`.  This is because that
     // function prints the sigil in the wrong place.  That should be fixed.
-    print_extern_opt_abis(s, opt_abis);
-    print_opt_sigil(s, opt_sigil);
-    print_opt_lifetime(s, opt_region);
-    print_purity(s, purity);
-    print_onceness(s, onceness);
-    word(s.s, "fn");
+    if opt_sigil == Some(ast::OwnedSigil) && onceness == ast::Once {
+        word(s.s, "proc");
+    } else {
+        print_extern_opt_abis(s, opt_abis);
+        print_opt_sigil(s, opt_sigil);
+        print_opt_lifetime(s, opt_region);
+        print_purity(s, purity);
+        print_onceness(s, onceness);
+        word(s.s, "fn");
+    }
     match id { Some(id) => { word(s.s, " "); print_ident(s, id); } _ => () }
     do opt_bounds.as_ref().map |bounds| { print_bounds(s, bounds, true); };
     match generics { Some(g) => print_generics(s, g), _ => () }
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index e879d67fbf2..09ee87d1701 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -560,6 +560,14 @@ pub fn walk_expr<E:Clone, V:Visitor<E>>(visitor: &mut V, expression: @Expr, env:
                              expression.id,
                              env.clone())
         }
+        ExprProc(ref function_declaration, ref body) => {
+            visitor.visit_fn(&fk_fn_block,
+                             function_declaration,
+                             body,
+                             expression.span,
+                             expression.id,
+                             env.clone())
+        }
         ExprBlock(ref block) => visitor.visit_block(block, env.clone()),
         ExprAssign(left_hand_expression, right_hand_expression) => {
             visitor.visit_expr(right_hand_expression, env.clone());