]> git.lizzy.rs Git - rust.git/commitdiff
Add support for terminal states (issue #2862)
authorEric Holk <eric.holk@gmail.com>
Mon, 16 Jul 2012 21:44:27 +0000 (14:44 -0700)
committerEric Holk <eric.holk@gmail.com>
Mon, 16 Jul 2012 21:50:47 +0000 (14:50 -0700)
src/libsyntax/ext/pipes/ast_builder.rs
src/libsyntax/ext/pipes/parse_proto.rs
src/libsyntax/ext/pipes/pipec.rs
src/test/run-pass/pipe-select.rs

index 2a2fbe2628a88ea3d82b0cf38a0723f40d061a1f..3ea088b50e2dfb6019f192afea658822695af003 100644 (file)
@@ -160,6 +160,12 @@ fn ty_path(path: @ast::path) -> @ast::ty {
           span: empty_span()}
     }
 
+    fn ty_nil() -> @ast::ty {
+        @{id: self.next_id(),
+          node: ast::ty_nil,
+          span: empty_span()}
+    }
+
     fn item_ty_poly(name: ident,
                     ty: @ast::ty,
                     +params: ~[ast::ty_param]) -> @ast::item {
index cf29c409e6ba9d8addb037d0da24bc22b4db812f..39084def7e4b9a965fe59fe49ce753a53e1dae5f 100644 (file)
@@ -44,33 +44,45 @@ fn parse_state(proto: protocol) {
         self.parse_unspanned_seq(
             token::LBRACE, token::RBRACE,
             {sep: some(token::COMMA), trailing_sep_allowed: true},
-            |self| {
-                let mname = self.parse_ident();
+            |self| self.parse_message(state));
+    }
 
-                let args = if self.token == token::LPAREN {
-                    self.parse_unspanned_seq(token::LPAREN,
-                                             token::RPAREN,
-                                             {sep: some(token::COMMA),
-                                              trailing_sep_allowed: true},
-                                             |p| p.parse_ty(false))
-                }
-                else { ~[] };
+    fn parse_message(state: state) {
+        let mname = self.parse_ident();
 
-                self.expect(token::RARROW);
+        let args = if self.token == token::LPAREN {
+            self.parse_unspanned_seq(token::LPAREN,
+                                     token::RPAREN,
+                                     {sep: some(token::COMMA),
+                                      trailing_sep_allowed: true},
+                                     |p| p.parse_ty(false))
+        }
+        else { ~[] };
 
-                let next = self.parse_ident();
+        self.expect(token::RARROW);
 
-                let ntys = if self.token == token::LT {
-                    self.parse_unspanned_seq(token::LT,
-                                             token::GT,
-                                             {sep: some(token::COMMA),
-                                              trailing_sep_allowed: true},
-                                             |p| p.parse_ty(false))
-                }
-                else { ~[] };
+        let next = alt copy self.token {
+          token::IDENT(_, _) {
+            let name = self.parse_ident();
+            let ntys = if self.token == token::LT {
+                self.parse_unspanned_seq(token::LT,
+                                         token::GT,
+                                         {sep: some(token::COMMA),
+                                          trailing_sep_allowed: true},
+                                         |p| p.parse_ty(false))
+            }
+            else { ~[] };
+            some({state: name, tys: ntys})
+          }
+          token::NOT {
+            // -> !
+            self.bump();
+            none
+          }
+          _ { self.fatal(~"invalid next state") }
+        };
 
-                state.add_message(mname, args, next, ntys);
+        state.add_message(mname, args, next);
 
-            });
     }
 }
index 9406458d1acdc8317b84bb33213829268200dd60..fa8fd67f0315651df9083bb880dfc7725a687924 100644 (file)
@@ -40,15 +40,17 @@ fn reverse() -> direction {
     }
 }
 
+type next_state = option<{state: ident, tys: ~[@ast::ty]}>;
+
 enum message {
-    // name, data, current state, next state, next tys
-    message(ident, ~[@ast::ty], state, ident, ~[@ast::ty])
+    // name, data, current state, next state
+    message(ident, ~[@ast::ty], state, next_state)
 }
 
 impl methods for message {
     fn name() -> ident {
         alt self {
-          message(id, _, _, _, _) {
+          message(id, _, _, _) {
             id
           }
         }
@@ -57,15 +59,17 @@ fn name() -> ident {
     // Return the type parameters actually used by this message
     fn get_params() -> ~[ast::ty_param] {
         alt self {
-          message(_, _, this, _, _) {
+          message(_, _, this, _) {
             this.ty_params
           }
         }
     }
 
     fn gen_send(cx: ext_ctxt) -> @ast::item {
+        #debug("pipec: gen_send");
         alt self {
-          message(id, tys, this, next, next_tys) {
+          message(id, tys, this, some({state: next, tys: next_tys})) {
+            #debug("pipec: next state exists");
             let next = this.proto.get_state(next);
             assert next_tys.len() == next.ty_params.len();
             let arg_names = tys.mapi(|i, _ty| @(~"x_" + i.to_str()));
@@ -107,6 +111,45 @@ fn gen_send(cx: ext_ctxt) -> @ast::item {
                             self.get_params(),
                             cx.expr_block(body))
           }
+
+          message(id, tys, this, none) {
+            #debug("pipec: no next state");
+            let arg_names = tys.mapi(|i, _ty| @(~"x_" + i.to_str()));
+
+            let args_ast = (arg_names, tys).map(
+                |n, t| cx.arg_mode(n, t, ast::by_copy)
+            );
+
+            let args_ast = vec::append(
+                ~[cx.arg_mode(@~"pipe",
+                              cx.ty_path(path(this.data_name())
+                                        .add_tys(cx.ty_vars(this.ty_params))),
+                              ast::by_copy)],
+                args_ast);
+
+            let message_args = if arg_names.len() == 0 {
+                ~""
+            }
+            else {
+                ~"(" + str::connect(arg_names.map(|x| *x), ~", ") + ~")"
+            };
+
+            let mut body = ~"{ ";
+            body += #fmt("let message = %s::%s%s;\n",
+                         *this.proto.name,
+                         *self.name(),
+                         message_args);
+            body += #fmt("pipes::send(pipe, message);\n");
+            body += ~" }";
+
+            let body = cx.parse_expr(body);
+
+            cx.item_fn_poly(self.name(),
+                            args_ast,
+                            cx.ty_nil(),
+                            self.get_params(),
+                            cx.expr_block(body))
+          }
         }
     }
 }
@@ -122,9 +165,9 @@ enum state {
 }
 
 impl methods for state {
-    fn add_message(name: ident, +data: ~[@ast::ty], next: ident,
-                   +next_tys: ~[@ast::ty]) {
-        self.messages.push(message(name, data, self, next, next_tys));
+    fn add_message(name: ident, +data: ~[@ast::ty], next: next_state) {
+        self.messages.push(message(name, data, self,
+                                   next));
     }
 
     fn filename() -> ~str {
@@ -140,6 +183,7 @@ fn to_ty(cx: ext_ctxt) -> @ast::ty {
     }
 
     fn to_type_decls(cx: ext_ctxt) -> ~[@ast::item] {
+        #debug("pipec: to_type_decls");
         // This compiles into two different type declarations. Say the
         // state is called ping. This will generate both `ping` and
         // `ping_message`. The first contains data that the user cares
@@ -151,22 +195,26 @@ fn to_type_decls(cx: ext_ctxt) -> ~[@ast::item] {
         let mut items_msg = ~[];
 
         for self.messages.each |m| {
-            let message(_, tys, this, next, next_tys) = m;
-
-            let name = m.name();
-            let next = this.proto.get_state(next);
-            let next_name = next.data_name();
-
-            let dir = alt this.dir {
-              send { @~"server" }
-              recv { @~"client" }
+            let message(name, tys, this, next) = m;
+
+            let tys = alt next {
+              some({state: next, tys: next_tys}) {
+                let next = this.proto.get_state(next);
+                let next_name = next.data_name();
+
+                let dir = alt this.dir {
+                  send { @~"server" }
+                  recv { @~"client" }
+                };
+
+                vec::append_one(tys,
+                                cx.ty_path((dir + next_name)
+                                           .add_tys(next_tys)))
+              }
+              none { tys }
             };
 
-            let v = cx.variant(name,
-                               vec::append_one(
-                                   tys,
-                                   cx.ty_path((dir + next_name)
-                                              .add_tys(next_tys))));
+            let v = cx.variant(name, tys);
 
             vec::push(items_msg, v);
         }
@@ -175,6 +223,7 @@ fn to_type_decls(cx: ext_ctxt) -> ~[@ast::item] {
     }
 
     fn to_endpoint_decls(cx: ext_ctxt, dir: direction) -> ~[@ast::item] {
+        #debug("pipec: to_endpoint_decls");
         let dir = alt dir {
           send { (*self).dir }
           recv { (*self).dir.reverse() }
index 05fe8f5ad05d5fa66d84e98e55c141048c002a30..5aab6b634b8107408885d802a3f3fb691f21a975 100644 (file)
@@ -1,4 +1,3 @@
-// xfail-test
 // xfail-pretty
 // xfail-win32
 
@@ -10,7 +9,7 @@
 
 proto! oneshot {
     waiting:send {
-        signal -> signaled
+        signal -> !
     }
 
     signaled:send { }
@@ -86,14 +85,14 @@ fn test_select2() {
       either::right(*) { fail }
     }
 
-    stream::client::send(bc, "abc");
+    stream::client::send(bc, ~"abc");
 
     #error("done with first select2");
 
     let (ac, ap) = stream::init();
     let (bc, bp) = stream::init();
 
-    stream::client::send(bc, "abc");
+    stream::client::send(bc, ~"abc");
 
     alt pipes::select2(ap, bp) {
       either::left(*) { fail }