]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/ext/pipes/proto.rs
libsyntax: Explicit-self-ify pipes compiler.
[rust.git] / src / libsyntax / ext / pipes / proto.rs
1 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use core::prelude::*;
12
13 use ast;
14 use codemap::span;
15 use ext::base::ext_ctxt;
16 use ext::pipes::ast_builder::{append_types, ext_ctxt_ast_builder, path};
17
18 use core::cmp;
19 use core::dvec::DVec;
20 use core::to_str::ToStr;
21
22 #[deriving_eq]
23 pub enum direction { send, recv }
24
25 pub impl ToStr for direction {
26     pure fn to_str(&self) -> ~str {
27         match *self {
28           send => ~"Send",
29           recv => ~"Recv"
30         }
31     }
32 }
33
34 pub impl direction {
35     fn reverse(&self) -> direction {
36         match *self {
37           send => recv,
38           recv => send
39         }
40     }
41 }
42
43 pub struct next_state {
44     state: ~str,
45     tys: ~[@ast::Ty],
46 }
47
48 pub enum message {
49     // name, span, data, current state, next state
50     message(~str, span, ~[@ast::Ty], state, Option<next_state>)
51 }
52
53 pub impl message {
54     fn name(&self) -> ~str {
55         match *self {
56           message(ref id, _, _, _, _) => (*id)
57         }
58     }
59
60     fn span(&self) -> span {
61         match *self {
62           message(_, span, _, _, _) => span
63         }
64     }
65
66     /// Return the type parameters actually used by this message
67     fn get_params(&self) -> ~[ast::ty_param] {
68         match *self {
69           message(_, _, _, this, _) => this.ty_params
70         }
71     }
72 }
73
74 pub type state = @state_;
75
76 pub struct state_ {
77     id: uint,
78     name: ~str,
79     ident: ast::ident,
80     span: span,
81     dir: direction,
82     ty_params: ~[ast::ty_param],
83     messages: DVec<message>,
84     proto: protocol
85 }
86
87 pub impl state_ {
88     fn add_message(@self, name: ~str, span: span,
89                    +data: ~[@ast::Ty], next: Option<next_state>) {
90         self.messages.push(message(name, span, data, self,
91                                    next));
92     }
93
94     fn filename(&self) -> ~str {
95         self.proto.filename()
96     }
97
98     fn data_name(&self) -> ast::ident {
99         self.ident
100     }
101
102     /// Returns the type that is used for the messages.
103     fn to_ty(&self, cx: ext_ctxt) -> @ast::Ty {
104         cx.ty_path_ast_builder
105             (path(~[cx.ident_of(self.name)],self.span).add_tys(
106                 cx.ty_vars(self.ty_params)))
107     }
108
109     /// Iterate over the states that can be reached in one message
110     /// from this state.
111     fn reachable(&self, f: fn(state) -> bool) {
112         for self.messages.each |m| {
113             match *m {
114               message(_, _, _, _, Some(next_state { state: ref id, _ })) => {
115                 let state = self.proto.get_state((*id));
116                 if !f(state) { break }
117               }
118               _ => ()
119             }
120         }
121     }
122 }
123
124 pub type protocol = @protocol_;
125
126 pub fn protocol(name: ~str, +span: span) -> protocol {
127     @protocol_(name, span)
128 }
129
130 pub fn protocol_(name: ~str, span: span) -> protocol_ {
131     protocol_ {
132         name: name,
133         span: span,
134         states: DVec(),
135         bounded: None
136     }
137 }
138
139 pub struct protocol_ {
140     name: ~str,
141     span: span,
142     states: DVec<state>,
143
144     mut bounded: Option<bool>,
145 }
146
147 pub impl protocol_ {
148     /// Get a state.
149     fn get_state(&self, name: ~str) -> state {
150         self.states.find(|i| i.name == name).get()
151     }
152
153     fn get_state_by_id(&self, id: uint) -> state { self.states[id] }
154
155     fn has_state(&self, name: ~str) -> bool {
156         self.states.find(|i| i.name == name).is_some()
157     }
158
159     fn filename(&self) -> ~str {
160         ~"proto://" + self.name
161     }
162
163     fn num_states(&self) -> uint { self.states.len() }
164
165     fn has_ty_params(&self) -> bool {
166         for self.states.each |s| {
167             if s.ty_params.len() > 0 {
168                 return true;
169             }
170         }
171         false
172     }
173     fn is_bounded(&self) -> bool {
174         let bounded = self.bounded.get();
175         bounded
176     }
177 }
178
179 pub impl protocol {
180     fn add_state_poly(&self, name: ~str, ident: ast::ident, dir: direction,
181                       +ty_params: ~[ast::ty_param]) -> state {
182         let messages = DVec();
183
184         let state = @state_ {
185             id: self.states.len(),
186             name: name,
187             ident: ident,
188             span: self.span,
189             dir: dir,
190             ty_params: ty_params,
191             messages: messages,
192             proto: *self
193         };
194
195         self.states.push(state);
196         state
197     }
198 }
199
200 pub trait visitor<Tproto, Tstate, Tmessage> {
201     fn visit_proto(&self, proto: protocol, st: &[Tstate]) -> Tproto;
202     fn visit_state(&self, state: state, m: &[Tmessage]) -> Tstate;
203     fn visit_message(&self, name: ~str, spane: span, tys: &[@ast::Ty],
204                      this: state, next: Option<next_state>) -> Tmessage;
205 }
206
207 pub fn visit<Tproto, Tstate, Tmessage, V: visitor<Tproto, Tstate, Tmessage>>(
208     proto: protocol, visitor: V) -> Tproto {
209
210     // the copy keywords prevent recursive use of dvec
211     let states = do (copy proto.states).map_to_vec |&s| {
212         let messages = do (copy s.messages).map_to_vec |&m| {
213             let message(name, span, tys, this, next) = m;
214             visitor.visit_message(name, span, tys, this, next)
215         };
216         visitor.visit_state(s, messages)
217     };
218     visitor.visit_proto(proto, states)
219 }
220