about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorEric Holk <eric.holk@gmail.com>2012-07-23 18:50:53 -0700
committerEric Holk <eric.holk@gmail.com>2012-07-25 12:12:25 -0700
commit7f5f1f90a06961b769162c437681194900ef3b7e (patch)
treee8ccac02944c70bfe397bfdb8c08370f7a585013 /src/libsyntax
parentb97fe9835430553c0b566cf1f5687e6c7403821b (diff)
Compiled a bounded version of pingpong.
There are some failures in the other pipe tests, but these seem to just be a matter of generalizing the library code.

Updating pipes library so all tests pass again
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ext/pipes/ast_builder.rs73
-rw-r--r--src/libsyntax/ext/pipes/pipec.rs183
-rw-r--r--src/libsyntax/ext/pipes/proto.rs19
-rw-r--r--src/libsyntax/parse.rs12
4 files changed, 244 insertions, 43 deletions
diff --git a/src/libsyntax/ext/pipes/ast_builder.rs b/src/libsyntax/ext/pipes/ast_builder.rs
index c03b5e28adc..b70100de4c5 100644
--- a/src/libsyntax/ext/pipes/ast_builder.rs
+++ b/src/libsyntax/ext/pipes/ast_builder.rs
@@ -7,6 +7,14 @@ import ast::{ident, node_id};
 import codemap::span;
 import ext::base::mk_ctxt;
 
+// Transitional reexports so qquote can find the paths it is looking for
+mod syntax {
+    import ext;
+    export ext;
+    import parse;
+    export parse;
+}
+
 fn ident(s: ~str) -> ast::ident {
     @(copy s)
 }
@@ -93,9 +101,60 @@ trait ext_ctxt_ast_builder {
     fn ty_vars(+ty_params: ~[ast::ty_param]) -> ~[@ast::ty];
     fn ty_field_imm(name: ident, ty: @ast::ty) -> ast::ty_field;
     fn ty_rec(+~[ast::ty_field]) -> @ast::ty;
+    fn field_imm(name: ident, e: @ast::expr) -> ast::field;
+    fn rec(+~[ast::field]) -> @ast::expr;
+    fn block(+stmts: ~[@ast::stmt], e: @ast::expr) -> ast::blk;
+    fn stmt_let(ident: ident, e: @ast::expr) -> @ast::stmt;
+    fn stmt_expr(e: @ast::expr) -> @ast::stmt;
+    fn block_expr(b: ast::blk) -> @ast::expr;
 }
 
 impl ast_builder of ext_ctxt_ast_builder for ext_ctxt {
+    fn block_expr(b: ast::blk) -> @ast::expr {
+        @{id: self.next_id(),
+          callee_id: self.next_id(),
+          node: ast::expr_block(b),
+          span: empty_span()}
+    }
+
+    fn stmt_expr(e: @ast::expr) -> @ast::stmt {
+        @{node: ast::stmt_expr(e, self.next_id()),
+          span: empty_span()}
+    }
+
+    fn stmt_let(ident: ident, e: @ast::expr) -> @ast::stmt {
+        // If the quasiquoter could interpolate idents, this is all
+        // we'd need.
+        //
+        //let ext_cx = self;
+        //#ast[stmt] { let $(ident) = $(e) }
+
+        @{node: ast::stmt_decl(@{node: ast::decl_local(~[
+            @{node: {is_mutbl: false,
+                     ty: self.ty_infer(),
+                     pat: @{id: self.next_id(),
+                            node: ast::pat_ident(path(ident), none),
+                            span: empty_span()},
+                     init: some({op: ast::init_move,
+                                 expr: e}),
+                     id: self.next_id()},
+              span: empty_span()}]),
+                               span: empty_span()}, self.next_id()),
+         span: empty_span()}
+    }
+
+    fn field_imm(name: ident, e: @ast::expr) -> ast::field {
+        {node: {mutbl: ast::m_imm, ident: name, expr: e},
+         span: empty_span()}
+    }
+
+    fn rec(+fields: ~[ast::field]) -> @ast::expr {
+        @{id: self.next_id(),
+          callee_id: self.next_id(),
+          node: ast::expr_rec(fields, none),
+          span: empty_span()}
+    }
+
     fn ty_field_imm(name: ident, ty: @ast::ty) -> ast::ty_field {
         {node: {ident: name, mt: { ty: ty, mutbl: ast::m_imm } },
           span: empty_span()}
@@ -107,6 +166,12 @@ impl ast_builder of ext_ctxt_ast_builder for ext_ctxt {
           span: empty_span()}
     }
 
+    fn ty_infer() -> @ast::ty {
+        @{id: self.next_id(),
+          node: ast::ty_infer,
+          span: empty_span()}
+    }
+
     fn ty_param(id: ast::ident, +bounds: ~[ast::ty_param_bound])
         -> ast::ty_param
     {
@@ -128,9 +193,9 @@ impl ast_builder of ext_ctxt_ast_builder for ext_ctxt {
          id: self.next_id()}
     }
 
-    fn expr_block(e: @ast::expr) -> ast::blk {
+    fn block(+stmts: ~[@ast::stmt], e: @ast::expr) -> ast::blk {
         let blk = {view_items: ~[],
-                   stmts: ~[],
+                   stmts: stmts,
                    expr: some(e),
                    id: self.next_id(),
                    rules: ast::default_blk};
@@ -139,6 +204,10 @@ impl ast_builder of ext_ctxt_ast_builder for ext_ctxt {
          span: empty_span()}
     }
 
+    fn expr_block(e: @ast::expr) -> ast::blk {
+        self.block(~[], e)
+    }
+
     fn fn_decl(+inputs: ~[ast::arg],
                output: @ast::ty) -> ast::fn_decl {
         {inputs: inputs,
diff --git a/src/libsyntax/ext/pipes/pipec.rs b/src/libsyntax/ext/pipes/pipec.rs
index 849c3a39efe..7dd33e35bc8 100644
--- a/src/libsyntax/ext/pipes/pipec.rs
+++ b/src/libsyntax/ext/pipes/pipec.rs
@@ -23,6 +23,14 @@ import ast_builder::methods;
 import ast_builder::path;
 import ast_builder::path_concat;
 
+// Transitional reexports so qquote can find the paths it is looking for
+mod syntax {
+    import ext;
+    export ext;
+    import parse;
+    export parse;
+}
+
 trait gen_send {
     fn gen_send(cx: ext_ctxt) -> @ast::item;
 }
@@ -60,14 +68,34 @@ impl compile of gen_send for message {
                               ast::by_copy)],
                 args_ast);
 
-            let pat = alt (this.dir, next.dir) {
-              (send, send) { ~"(c, s)" }
-              (send, recv) { ~"(s, c)" }
-              (recv, send) { ~"(s, c)" }
-              (recv, recv) { ~"(c, s)" }
-            };
+            let mut body = ~"{\n";
+
+            if this.proto.is_bounded() {
+                let (sp, rp) = alt (this.dir, next.dir) {
+                  (send, send) { ("c", "s") }
+                  (send, recv) { ("s", "c") }
+                  (recv, send) { ("s", "c") }
+                  (recv, recv) { ("c", "s") }
+                };
 
-            let mut body = #fmt("{ let %s = pipes::entangle();\n", pat);
+                body += "let b = pipe.reuse_buffer();\n";
+                body += #fmt("let %s = pipes::send_packet_buffered(\
+                              ptr::addr_of(b.buffer.data.%s));\n",
+                             sp, *next.name);
+                body += #fmt("let %s = pipes::recv_packet_buffered(\
+                              ptr::addr_of(b.buffer.data.%s));\n",
+                             rp, *next.name);
+            }
+            else {
+                let pat = alt (this.dir, next.dir) {
+                  (send, send) { ~"(c, s)" }
+                  (send, recv) { ~"(s, c)" }
+                  (recv, send) { ~"(s, c)" }
+                  (recv, recv) { ~"(c, s)" }
+                };
+
+                body += #fmt("let %s = pipes::entangle();\n", pat);
+            }
             body += #fmt("let message = %s::%s(%s);\n",
                          *this.proto.name,
                          *self.name(),
@@ -189,42 +217,121 @@ impl compile of to_type_decls for state {
             }
         }
 
-        vec::push(items,
-                  cx.item_ty_poly(
-                      self.data_name(),
-                      cx.ty_path_ast_builder(
-                          (@~"pipes" + @(dir.to_str() + ~"_packet"))
-                          .add_ty(cx.ty_path_ast_builder(
-                              (self.proto.name + self.data_name())
-                              .add_tys(cx.ty_vars(self.ty_params))))),
-                      self.ty_params));
+        if !self.proto.is_bounded() {
+            vec::push(items,
+                      cx.item_ty_poly(
+                          self.data_name(),
+                          cx.ty_path_ast_builder(
+                              (@~"pipes" + @(dir.to_str() + ~"_packet"))
+                              .add_ty(cx.ty_path_ast_builder(
+                                  (self.proto.name + self.data_name())
+                                  .add_tys(cx.ty_vars(self.ty_params))))),
+                          self.ty_params));
+        }
+        else {
+            let ext_cx = cx;
+            vec::push(items,
+                      cx.item_ty_poly(
+                          self.data_name(),
+                          cx.ty_path_ast_builder(
+                              (@~"pipes" + @(dir.to_str()
+                                             + ~"_packet_buffered"))
+                              .add_tys(~[cx.ty_path_ast_builder(
+                                  (self.proto.name + self.data_name())
+                                  .add_tys(cx.ty_vars(self.ty_params))),
+                                         #ast[ty] { buffer }])),
+                          self.ty_params));
+        };
         items
     }
 }
 
 impl compile of gen_init for protocol {
     fn gen_init(cx: ext_ctxt) -> @ast::item {
+        let ext_cx = cx;
+
         #debug("gen_init");
         let start_state = self.states[0];
 
-        let body = alt start_state.dir {
-          send { cx.parse_expr(~"pipes::entangle()") }
-          recv {
-            cx.parse_expr(~"{ \
-                           let (s, c) = pipes::entangle(); \
-                           (c, s) \
-                           }")
-          }
+        let body = if !self.is_bounded() {
+            alt start_state.dir {
+              send { #ast { pipes::entangle() } }
+              recv {
+                #ast {{
+                    let (s, c) = pipes::entangle();
+                    (c, s)
+                }}
+              }
+            }
+        }
+        else {
+            let body = self.gen_init_bounded(ext_cx);
+            alt start_state.dir {
+              send { body }
+              recv {
+                #ast {{
+                    let (s, c) = $(body);
+                    (c, s)
+                }}
+              }
+            }
         };
 
         cx.parse_item(#fmt("fn init%s() -> (client::%s, server::%s)\
-                            { %s }",
+                            { import pipes::has_buffer; %s }",
                            start_state.ty_params.to_source(),
                            start_state.to_ty(cx).to_source(),
                            start_state.to_ty(cx).to_source(),
                            body.to_source()))
     }
 
+    fn gen_buffer_init(ext_cx: ext_ctxt) -> @ast::expr {
+        ext_cx.rec(self.states.map_to_vec(|s| {
+            let fty = ext_cx.ty_path_ast_builder(path(s.name));
+            ext_cx.field_imm(s.name, #ast { pipes::mk_packet::<$(fty)>() })
+        }))
+    }
+
+    fn gen_init_bounded(ext_cx: ext_ctxt) -> @ast::expr {
+        #debug("gen_init_bounded");
+        let buffer_fields = self.gen_buffer_init(ext_cx);
+
+        let buffer = #ast {
+            ~{header: pipes::buffer_header(),
+              data: $(buffer_fields)}
+        };
+
+        let entangle_body = ext_cx.block_expr(
+            ext_cx.block(
+                self.states.map_to_vec(
+                    |s| ext_cx.parse_stmt(
+                        #fmt("data.%s.set_buffer(buffer)", *s.name))),
+                ext_cx.parse_expr(
+                    #fmt("ptr::addr_of(data.%s)", *self.states[0].name))));
+
+        #ast {{
+            let buffer = $(buffer);
+            do pipes::entangle_buffer(buffer) |buffer, data| {
+                $(entangle_body)
+            }
+        }}
+    }
+
+    fn gen_buffer_type(cx: ext_ctxt) -> @ast::item {
+        let ext_cx = cx;
+        cx.item_ty(
+            @~"buffer",
+            cx.ty_rec(
+                (copy self.states).map_to_vec(
+                    |s| {
+                        let ty = cx.ty_path_ast_builder(path(s.name));
+                        let fty = #ast[ty] {
+                            pipes::packet<$(ty)>
+                        };
+                        cx.ty_field_imm(s.name, fty)
+                    })))
+    }
+
     fn compile(cx: ext_ctxt) -> @ast::item {
         let mut items = ~[self.gen_init(cx)];
         let mut client_states = ~[];
@@ -239,20 +346,7 @@ impl compile of gen_init for protocol {
         }
 
         if self.is_bounded() {
-            vec::push(
-                items,
-                cx.item_ty(
-                    @~"buffer",
-                    cx.ty_rec(
-                        (copy self.states).map_to_vec(
-                            |s| cx.ty_field_imm(
-                                s.name,
-                                cx.ty_path_ast_builder(
-                                    (path(@~"pipes")
-                                     + @~"packet")
-                                    .add_ty(
-                                        cx.ty_path_ast_builder(
-                                            path(s.name)))))))))
+            vec::push(items, self.gen_buffer_type(cx))
         }
 
         vec::push(items,
@@ -310,6 +404,7 @@ impl of to_source for @ast::expr {
 trait ext_ctxt_parse_utils {
     fn parse_item(s: ~str) -> @ast::item;
     fn parse_expr(s: ~str) -> @ast::expr;
+    fn parse_stmt(s: ~str) -> @ast::stmt;
 }
 
 impl parse_utils of ext_ctxt_parse_utils for ext_ctxt {
@@ -330,6 +425,15 @@ impl parse_utils of ext_ctxt_parse_utils for ext_ctxt {
         }
     }
 
+    fn parse_stmt(s: ~str) -> @ast::stmt {
+        parse::parse_stmt_from_source_str(
+            ~"***protocol expansion***",
+            @(copy s),
+            self.cfg(),
+            ~[],
+            self.parse_sess())
+    }
+
     fn parse_expr(s: ~str) -> @ast::expr {
         parse::parse_expr_from_source_str(
             ~"***protocol expansion***",
@@ -338,4 +442,3 @@ impl parse_utils of ext_ctxt_parse_utils for ext_ctxt {
             self.parse_sess())
     }
 }
-
diff --git a/src/libsyntax/ext/pipes/proto.rs b/src/libsyntax/ext/pipes/proto.rs
index 8a535e85188..a0091806b02 100644
--- a/src/libsyntax/ext/pipes/proto.rs
+++ b/src/libsyntax/ext/pipes/proto.rs
@@ -131,7 +131,24 @@ class protocol_ {
 
     fn num_states() -> uint { self.states.len() }
 
-    fn is_bounded() -> bool { self.bounded.get() }
+    fn has_ty_params() -> bool {
+        for self.states.each |s| {
+            if s.ty_params.len() > 0 {
+                ret true;
+            }
+        }
+        false
+    }
+    fn is_bounded() -> bool {
+        let bounded = self.bounded.get();
+        if bounded && self.has_ty_params() {
+            #debug("protocol %s has is bounded, but type parameters\
+                    are not yet supported.",
+                   *self.name);
+            false
+        }
+        else { bounded }
+    }
 }
 
 impl methods for protocol {
diff --git a/src/libsyntax/parse.rs b/src/libsyntax/parse.rs
index 9d56754e5d4..39f4654a138 100644
--- a/src/libsyntax/parse.rs
+++ b/src/libsyntax/parse.rs
@@ -10,6 +10,7 @@ export new_parser_from_tt;
 export parse_crate_from_file, parse_crate_from_crate_file;
 export parse_crate_from_source_str;
 export parse_expr_from_source_str, parse_item_from_source_str;
+export parse_stmt_from_source_str;
 export parse_from_source_str;
 
 import parser::parser;
@@ -129,6 +130,17 @@ fn parse_item_from_source_str(name: ~str, source: @~str, cfg: ast::crate_cfg,
     ret r;
 }
 
+fn parse_stmt_from_source_str(name: ~str, source: @~str, cfg: ast::crate_cfg,
+                              +attrs: ~[ast::attribute],
+                              sess: parse_sess) -> @ast::stmt {
+    let (p, rdr) = new_parser_etc_from_source_str(sess, cfg, name,
+                                                  codemap::fss_none, source);
+    let r = p.parse_stmt(attrs);
+    sess.chpos = rdr.chpos;
+    sess.byte_pos = sess.byte_pos + rdr.pos;
+    ret r;
+}
+
 fn parse_from_source_str<T>(f: fn (p: parser) -> T,
                             name: ~str, ss: codemap::file_substr,
                             source: @~str, cfg: ast::crate_cfg,