about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@mimiga.net>2012-11-02 13:33:51 -0700
committerPatrick Walton <pcwalton@mimiga.net>2012-11-05 13:17:02 -0800
commitbe93b29d304b310ec56630f5313ccddf3ae470ea (patch)
tree72c84b2fdbd5b82b9366162382461f0d2fa38b1f /src/libsyntax
parent9aadfc3f4b5df00a7f8e9b362385118ae1dba73e (diff)
downloadrust-be93b29d304b310ec56630f5313ccddf3ae470ea.tar.gz
rust-be93b29d304b310ec56630f5313ccddf3ae470ea.zip
rustc: Implement parsing and typechecking for "once fn"
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ast.rs21
-rw-r--r--src/libsyntax/fold.rs9
-rw-r--r--src/libsyntax/parse/parser.rs39
-rw-r--r--src/libsyntax/parse/token.rs1
-rw-r--r--src/libsyntax/print/pprust.rs36
-rw-r--r--src/libsyntax/visit.rs2
6 files changed, 88 insertions, 20 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 21b0af9420f..8667f36c749 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -1061,6 +1061,25 @@ enum region_ {
 
 #[auto_serialize]
 #[auto_deserialize]
+enum Onceness {
+    Once,
+    Many
+}
+
+impl Onceness : cmp::Eq {
+    pure fn eq(other: &Onceness) -> bool {
+        match (self, *other) {
+            (Once, Once) | (Many, Many) => true,
+            _ => false
+        }
+    }
+    pure fn ne(other: &Onceness) -> bool {
+        !self.eq(other)
+    }
+}
+
+#[auto_serialize]
+#[auto_deserialize]
 enum ty_ {
     ty_nil,
     ty_bot, /* bottom type */
@@ -1070,7 +1089,7 @@ enum ty_ {
     ty_ptr(mt),
     ty_rptr(@region, mt),
     ty_rec(~[ty_field]),
-    ty_fn(proto, purity, @~[ty_param_bound], fn_decl),
+    ty_fn(proto, purity, Onceness, @~[ty_param_bound], fn_decl),
     ty_tup(~[@Ty]),
     ty_path(@path, node_id),
     ty_fixed_length(@Ty, Option<uint>),
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index a8b0f444514..7c8909668f5 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -524,10 +524,11 @@ fn noop_fold_ty(t: ty_, fld: ast_fold) -> ty_ {
       ty_ptr(mt) => ty_ptr(fold_mt(mt, fld)),
       ty_rptr(region, mt) => ty_rptr(region, fold_mt(mt, fld)),
       ty_rec(fields) => ty_rec(vec::map(fields, |f| fold_field(*f, fld))),
-      ty_fn(proto, purity, bounds, decl) =>
-        ty_fn(proto, purity,
-              @vec::map(*bounds,
-                        |x| fold_ty_param_bound(*x, fld)),
+      ty_fn(proto, purity, onceness, bounds, decl) =>
+        ty_fn(proto,
+              purity,
+              onceness,
+              @vec::map(*bounds, |x| fold_ty_param_bound(*x, fld)),
               fold_fn_decl(decl, fld)),
       ty_tup(tys) => ty_tup(vec::map(tys, |ty| fld.fold_ty(*ty))),
       ty_path(path, id) => ty_path(fld.fold_path(path), fld.new_id(id)),
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 6615bc75169..63545a69608 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -287,7 +287,7 @@ impl Parser {
 
     pure fn id_to_str(id: ident) -> @~str { self.sess.interner.get(id) }
 
-    fn parse_ty_fn(purity: ast::purity) -> ty_ {
+    fn parse_ty_fn(purity: ast::purity, onceness: ast::Onceness) -> ty_ {
         let proto, bounds;
         if self.eat_keyword(~"extern") {
             self.expect_keyword(~"fn");
@@ -298,7 +298,17 @@ impl Parser {
             proto = self.parse_fn_ty_proto();
             bounds = self.parse_optional_ty_param_bounds();
         };
-        ty_fn(proto, purity, bounds, self.parse_ty_fn_decl())
+        ty_fn(proto, purity, onceness, bounds, self.parse_ty_fn_decl())
+    }
+
+    fn parse_ty_fn_with_onceness(purity: ast::purity) -> ty_ {
+        let onceness = self.parse_optional_onceness();
+        self.parse_ty_fn(purity, onceness)
+    }
+
+    fn parse_ty_fn_with_purity_and_onceness() -> ty_ {
+        let purity = self.parse_optional_purity();
+        self.parse_ty_fn_with_onceness(purity)
     }
 
     fn parse_ty_fn_decl() -> fn_decl {
@@ -526,15 +536,18 @@ impl Parser {
             let region = self.parse_region_with_sep();
             let mt = self.parse_mt();
             ty_rptr(region, mt)
+        } else if self.eat_keyword(~"once") {
+            self.parse_ty_fn(ast::impure_fn, ast::Once)
         } else if self.eat_keyword(~"pure") {
-            self.parse_ty_fn(ast::pure_fn)
+            self.parse_ty_fn_with_onceness(ast::pure_fn)
         } else if self.eat_keyword(~"unsafe") {
-            self.parse_ty_fn(ast::unsafe_fn)
+            self.parse_ty_fn_with_onceness(ast::unsafe_fn)
         } else if self.is_keyword(~"fn") {
-            self.parse_ty_fn(ast::impure_fn)
+            self.parse_ty_fn_with_onceness(ast::impure_fn)
         } else if self.eat_keyword(~"extern") {
             self.expect_keyword(~"fn");
-            ty_fn(proto_bare, ast::impure_fn, @~[], self.parse_ty_fn_decl())
+            ty_fn(proto_bare, ast::impure_fn, ast::Many, @~[],
+                  self.parse_ty_fn_decl())
         } else if self.token == token::MOD_SEP || is_ident(self.token) {
             let path = self.parse_path_with_tps(colons_before_params);
             ty_path(path, self.get_id())
@@ -2275,6 +2288,20 @@ impl Parser {
             self.get_id()), span: self.last_span}
     }
 
+    fn parse_optional_purity() -> ast::purity {
+        if self.eat_keyword(~"pure") {
+            ast::pure_fn
+        } else if self.eat_keyword(~"unsafe") {
+            ast::unsafe_fn
+        } else {
+            ast::impure_fn
+        }
+    }
+
+    fn parse_optional_onceness() -> ast::Onceness {
+        if self.eat_keyword(~"once") { ast::Once } else { ast::Many }
+    }
+
     fn parse_optional_ty_param_bounds() -> @~[ty_param_bound] {
         let mut bounds = ~[];
         if self.eat(token::COLON) {
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index 53c1ce1c7f5..0d139b101d8 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -427,6 +427,7 @@ fn strict_keyword_table() -> HashMap<~str, ()> {
         ~"if", ~"impl",
         ~"let", ~"log", ~"loop",
         ~"match", ~"mod", ~"move", ~"mut",
+        ~"once",
         ~"priv", ~"pub", ~"pure",
         ~"ref", ~"return",
         ~"struct",
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 3836c21ff24..e0b9958bcb7 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -394,8 +394,9 @@ fn print_type_ex(s: ps, &&ty: @ast::Ty, print_colons: bool) {
         commasep(s, inconsistent, elts, print_type);
         pclose(s);
       }
-      ast::ty_fn(proto, purity, bounds, d) => {
-        print_ty_fn(s, Some(proto), purity, bounds, d, None, None, None);
+      ast::ty_fn(proto, purity, onceness, bounds, d) => {
+        print_ty_fn(s, Some(proto), purity, onceness, bounds, d, None, None,
+                    None);
       }
       ast::ty_path(path, _) => print_path(s, path, print_colons),
       ast::ty_fixed_length(t, v) => {
@@ -804,7 +805,7 @@ fn print_ty_method(s: ps, m: ast::ty_method) {
     hardbreak_if_not_bol(s);
     maybe_print_comment(s, m.span.lo);
     print_outer_attributes(s, m.attrs);
-    print_ty_fn(s, None, m.purity,
+    print_ty_fn(s, None, m.purity, ast::Many,
                 @~[], m.decl, Some(m.ident), Some(m.tps),
                 Some(m.self_ty.node));
     word(s.s, ~";");
@@ -1273,7 +1274,7 @@ fn print_expr(s: ps, &&expr: @ast::expr) {
         cbox(s, indent_unit);
         // head-box, will be closed by print-block at start
         ibox(s, 0u);
-        word(s.s, fn_header_info_to_str(None, None, Some(proto),
+        word(s.s, fn_header_info_to_str(None, None, Some(proto), ast::Many,
                                         ast::inherited));
         print_fn_args_and_ret(s, decl, *cap_clause, None);
         space(s.s);
@@ -1606,12 +1607,15 @@ fn print_self_ty(s: ps, self_ty: ast::self_ty_) -> bool {
     return true;
 }
 
-fn print_fn(s: ps, decl: ast::fn_decl, purity: Option<ast::purity>,
+fn print_fn(s: ps,
+            decl: ast::fn_decl,
+            purity: Option<ast::purity>,
             name: ast::ident,
             typarams: ~[ast::ty_param],
             opt_self_ty: Option<ast::self_ty_>,
             vis: ast::visibility) {
-    head(s, fn_header_info_to_str(opt_self_ty, purity, None, vis));
+    head(s, fn_header_info_to_str(opt_self_ty, purity, None, ast::Many,
+                                  vis));
     print_ident(s, name);
     print_type_params(s, typarams);
     print_fn_args_and_ret(s, decl, ~[], opt_self_ty);
@@ -1831,14 +1835,17 @@ fn print_arg(s: ps, input: ast::arg) {
     end(s);
 }
 
-fn print_ty_fn(s: ps, opt_proto: Option<ast::proto>, purity: ast::purity,
+fn print_ty_fn(s: ps,
+               opt_proto: Option<ast::proto>,
+               purity: ast::purity,
+               onceness: ast::Onceness,
                bounds: @~[ast::ty_param_bound],
                decl: ast::fn_decl, id: Option<ast::ident>,
                tps: Option<~[ast::ty_param]>,
                opt_self_ty: Option<ast::self_ty_>) {
     ibox(s, indent_unit);
     word(s.s, fn_header_info_to_str(opt_self_ty, Some(purity), opt_proto,
-                                    ast::inherited));
+                                    onceness, ast::inherited));
     print_bounds(s, bounds);
     match id { Some(id) => { word(s.s, ~" "); print_ident(s, id); } _ => () }
     match tps { Some(tps) => print_type_params(s, tps), _ => () }
@@ -2062,6 +2069,7 @@ fn next_comment(s: ps) -> Option<comments::cmnt> {
 fn fn_header_info_to_str(opt_sty: Option<ast::self_ty_>,
                          opt_purity: Option<ast::purity>,
                          opt_p: Option<ast::proto>,
+                         onceness: ast::Onceness,
                          vis: ast::visibility) -> ~str {
 
     let mut s = visibility_qualified(vis, ~"");
@@ -2082,6 +2090,11 @@ fn fn_header_info_to_str(opt_sty: Option<ast::self_ty_>,
 
     str::push_str(&mut s, opt_proto_to_str(opt_p));
 
+    match onceness {
+        ast::Once => str::push_str(&mut s, ~"once "),
+        ast::Many => {}
+    }
+
     return s;
 }
 
@@ -2101,6 +2114,13 @@ pure fn purity_to_str(p: ast::purity) -> ~str {
     }
 }
 
+pure fn onceness_to_str(o: ast::Onceness) -> ~str {
+    match o {
+        ast::Once => ~"once",
+        ast::Many => ~"many"
+    }
+}
+
 fn print_purity(s: ps, p: ast::purity) {
     match p {
       ast::impure_fn => (),
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 2dbe2b16044..be6fb4cefa8 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -203,7 +203,7 @@ fn visit_ty<E>(t: @Ty, e: E, v: vt<E>) {
       ty_tup(ts) => for ts.each |tt| {
         v.visit_ty(*tt, e, v);
       },
-      ty_fn(_, _, bounds, decl) => {
+      ty_fn(_, _, _, bounds, decl) => {
         for decl.inputs.each |a| { v.visit_ty(a.ty, e, v); }
         visit_ty_param_bounds(bounds, e, v);
         v.visit_ty(decl.output, e, v);