Skip to content

Commit d39f6fc

Browse files
committed
Add support for terminal states (issue #2862)
1 parent c46bf6e commit d39f6fc

File tree

4 files changed

+114
-48
lines changed

4 files changed

+114
-48
lines changed

src/libsyntax/ext/pipes/ast_builder.rs

+6
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,12 @@ impl ast_builder for ext_ctxt {
160160
span: empty_span()}
161161
}
162162

163+
fn ty_nil() -> @ast::ty {
164+
@{id: self.next_id(),
165+
node: ast::ty_nil,
166+
span: empty_span()}
167+
}
168+
163169
fn item_ty_poly(name: ident,
164170
ty: @ast::ty,
165171
+params: ~[ast::ty_param]) -> @ast::item {

src/libsyntax/ext/pipes/parse_proto.rs

+34-22
Original file line numberDiff line numberDiff line change
@@ -44,33 +44,45 @@ impl proto_parser for parser {
4444
self.parse_unspanned_seq(
4545
token::LBRACE, token::RBRACE,
4646
{sep: some(token::COMMA), trailing_sep_allowed: true},
47-
|self| {
48-
let mname = self.parse_ident();
47+
|self| self.parse_message(state));
48+
}
4949

50-
let args = if self.token == token::LPAREN {
51-
self.parse_unspanned_seq(token::LPAREN,
52-
token::RPAREN,
53-
{sep: some(token::COMMA),
54-
trailing_sep_allowed: true},
55-
|p| p.parse_ty(false))
56-
}
57-
else { ~[] };
50+
fn parse_message(state: state) {
51+
let mname = self.parse_ident();
5852

59-
self.expect(token::RARROW);
53+
let args = if self.token == token::LPAREN {
54+
self.parse_unspanned_seq(token::LPAREN,
55+
token::RPAREN,
56+
{sep: some(token::COMMA),
57+
trailing_sep_allowed: true},
58+
|p| p.parse_ty(false))
59+
}
60+
else { ~[] };
6061

61-
let next = self.parse_ident();
62+
self.expect(token::RARROW);
6263

63-
let ntys = if self.token == token::LT {
64-
self.parse_unspanned_seq(token::LT,
65-
token::GT,
66-
{sep: some(token::COMMA),
67-
trailing_sep_allowed: true},
68-
|p| p.parse_ty(false))
69-
}
70-
else { ~[] };
64+
let next = alt copy self.token {
65+
token::IDENT(_, _) {
66+
let name = self.parse_ident();
67+
let ntys = if self.token == token::LT {
68+
self.parse_unspanned_seq(token::LT,
69+
token::GT,
70+
{sep: some(token::COMMA),
71+
trailing_sep_allowed: true},
72+
|p| p.parse_ty(false))
73+
}
74+
else { ~[] };
75+
some({state: name, tys: ntys})
76+
}
77+
token::NOT {
78+
// -> !
79+
self.bump();
80+
none
81+
}
82+
_ { self.fatal(~"invalid next state") }
83+
};
7184

72-
state.add_message(mname, args, next, ntys);
85+
state.add_message(mname, args, next);
7386

74-
});
7587
}
7688
}

src/libsyntax/ext/pipes/pipec.rs

+71-22
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,17 @@ impl methods for direction {
4040
}
4141
}
4242

43+
type next_state = option<{state: ident, tys: ~[@ast::ty]}>;
44+
4345
enum message {
44-
// name, data, current state, next state, next tys
45-
message(ident, ~[@ast::ty], state, ident, ~[@ast::ty])
46+
// name, data, current state, next state
47+
message(ident, ~[@ast::ty], state, next_state)
4648
}
4749

4850
impl methods for message {
4951
fn name() -> ident {
5052
alt self {
51-
message(id, _, _, _, _) {
53+
message(id, _, _, _) {
5254
id
5355
}
5456
}
@@ -57,15 +59,17 @@ impl methods for message {
5759
// Return the type parameters actually used by this message
5860
fn get_params() -> ~[ast::ty_param] {
5961
alt self {
60-
message(_, _, this, _, _) {
62+
message(_, _, this, _) {
6163
this.ty_params
6264
}
6365
}
6466
}
6567

6668
fn gen_send(cx: ext_ctxt) -> @ast::item {
69+
#debug("pipec: gen_send");
6770
alt self {
68-
message(id, tys, this, next, next_tys) {
71+
message(id, tys, this, some({state: next, tys: next_tys})) {
72+
#debug("pipec: next state exists");
6973
let next = this.proto.get_state(next);
7074
assert next_tys.len() == next.ty_params.len();
7175
let arg_names = tys.mapi(|i, _ty| @(~"x_" + i.to_str()));
@@ -107,6 +111,45 @@ impl methods for message {
107111
self.get_params(),
108112
cx.expr_block(body))
109113
}
114+
115+
message(id, tys, this, none) {
116+
#debug("pipec: no next state");
117+
let arg_names = tys.mapi(|i, _ty| @(~"x_" + i.to_str()));
118+
119+
let args_ast = (arg_names, tys).map(
120+
|n, t| cx.arg_mode(n, t, ast::by_copy)
121+
);
122+
123+
let args_ast = vec::append(
124+
~[cx.arg_mode(@~"pipe",
125+
cx.ty_path(path(this.data_name())
126+
.add_tys(cx.ty_vars(this.ty_params))),
127+
ast::by_copy)],
128+
args_ast);
129+
130+
let message_args = if arg_names.len() == 0 {
131+
~""
132+
}
133+
else {
134+
~"(" + str::connect(arg_names.map(|x| *x), ~", ") + ~")"
135+
};
136+
137+
let mut body = ~"{ ";
138+
body += #fmt("let message = %s::%s%s;\n",
139+
*this.proto.name,
140+
*self.name(),
141+
message_args);
142+
body += #fmt("pipes::send(pipe, message);\n");
143+
body += ~" }";
144+
145+
let body = cx.parse_expr(body);
146+
147+
cx.item_fn_poly(self.name(),
148+
args_ast,
149+
cx.ty_nil(),
150+
self.get_params(),
151+
cx.expr_block(body))
152+
}
110153
}
111154
}
112155
}
@@ -122,9 +165,9 @@ enum state {
122165
}
123166

124167
impl methods for state {
125-
fn add_message(name: ident, +data: ~[@ast::ty], next: ident,
126-
+next_tys: ~[@ast::ty]) {
127-
self.messages.push(message(name, data, self, next, next_tys));
168+
fn add_message(name: ident, +data: ~[@ast::ty], next: next_state) {
169+
self.messages.push(message(name, data, self,
170+
next));
128171
}
129172

130173
fn filename() -> ~str {
@@ -140,6 +183,7 @@ impl methods for state {
140183
}
141184

142185
fn to_type_decls(cx: ext_ctxt) -> ~[@ast::item] {
186+
#debug("pipec: to_type_decls");
143187
// This compiles into two different type declarations. Say the
144188
// state is called ping. This will generate both `ping` and
145189
// `ping_message`. The first contains data that the user cares
@@ -151,22 +195,26 @@ impl methods for state {
151195
let mut items_msg = ~[];
152196

153197
for self.messages.each |m| {
154-
let message(_, tys, this, next, next_tys) = m;
155-
156-
let name = m.name();
157-
let next = this.proto.get_state(next);
158-
let next_name = next.data_name();
159-
160-
let dir = alt this.dir {
161-
send { @~"server" }
162-
recv { @~"client" }
198+
let message(name, tys, this, next) = m;
199+
200+
let tys = alt next {
201+
some({state: next, tys: next_tys}) {
202+
let next = this.proto.get_state(next);
203+
let next_name = next.data_name();
204+
205+
let dir = alt this.dir {
206+
send { @~"server" }
207+
recv { @~"client" }
208+
};
209+
210+
vec::append_one(tys,
211+
cx.ty_path((dir + next_name)
212+
.add_tys(next_tys)))
213+
}
214+
none { tys }
163215
};
164216

165-
let v = cx.variant(name,
166-
vec::append_one(
167-
tys,
168-
cx.ty_path((dir + next_name)
169-
.add_tys(next_tys))));
217+
let v = cx.variant(name, tys);
170218

171219
vec::push(items_msg, v);
172220
}
@@ -175,6 +223,7 @@ impl methods for state {
175223
}
176224

177225
fn to_endpoint_decls(cx: ext_ctxt, dir: direction) -> ~[@ast::item] {
226+
#debug("pipec: to_endpoint_decls");
178227
let dir = alt dir {
179228
send { (*self).dir }
180229
recv { (*self).dir.reverse() }

src/test/run-pass/pipe-select.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// xfail-test
21
// xfail-pretty
32
// xfail-win32
43

@@ -10,7 +9,7 @@ import pipes::{recv, select};
109

1110
proto! oneshot {
1211
waiting:send {
13-
signal -> signaled
12+
signal -> !
1413
}
1514

1615
signaled:send { }
@@ -86,14 +85,14 @@ fn test_select2() {
8685
either::right(*) { fail }
8786
}
8887

89-
stream::client::send(bc, "abc");
88+
stream::client::send(bc, ~"abc");
9089

9190
#error("done with first select2");
9291

9392
let (ac, ap) = stream::init();
9493
let (bc, bp) = stream::init();
9594

96-
stream::client::send(bc, "abc");
95+
stream::client::send(bc, ~"abc");
9796

9897
alt pipes::select2(ap, bp) {
9998
either::left(*) { fail }

0 commit comments

Comments
 (0)