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.
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.
15 use ext::base::ext_ctxt;
16 use ext::pipes::ast_builder::{append_types, ext_ctxt_ast_builder, path};
20 use core::to_str::ToStr;
23 pub enum direction { send, recv }
25 pub impl ToStr for direction {
26 pure fn to_str(&self) -> ~str {
35 fn reverse(&self) -> direction {
43 pub struct next_state {
49 // name, span, data, current state, next state
50 message(~str, span, ~[@ast::Ty], state, Option<next_state>)
54 fn name(&self) -> ~str {
56 message(ref id, _, _, _, _) => (*id)
60 fn span(&self) -> span {
62 message(_, span, _, _, _) => span
66 /// Return the type parameters actually used by this message
67 fn get_params(&self) -> ~[ast::ty_param] {
69 message(_, _, _, this, _) => this.ty_params
74 pub type state = @state_;
82 ty_params: ~[ast::ty_param],
83 messages: DVec<message>,
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,
94 fn filename(&self) -> ~str {
98 fn data_name(&self) -> ast::ident {
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)))
109 /// Iterate over the states that can be reached in one message
111 fn reachable(&self, f: fn(state) -> bool) {
112 for self.messages.each |m| {
114 message(_, _, _, _, Some(next_state { state: ref id, _ })) => {
115 let state = self.proto.get_state((*id));
116 if !f(state) { break }
124 pub type protocol = @protocol_;
126 pub fn protocol(name: ~str, +span: span) -> protocol {
127 @protocol_(name, span)
130 pub fn protocol_(name: ~str, span: span) -> protocol_ {
139 pub struct protocol_ {
144 mut bounded: Option<bool>,
149 fn get_state(&self, name: ~str) -> state {
150 self.states.find(|i| i.name == name).get()
153 fn get_state_by_id(&self, id: uint) -> state { self.states[id] }
155 fn has_state(&self, name: ~str) -> bool {
156 self.states.find(|i| i.name == name).is_some()
159 fn filename(&self) -> ~str {
160 ~"proto://" + self.name
163 fn num_states(&self) -> uint { self.states.len() }
165 fn has_ty_params(&self) -> bool {
166 for self.states.each |s| {
167 if s.ty_params.len() > 0 {
173 fn is_bounded(&self) -> bool {
174 let bounded = self.bounded.get();
180 fn add_state_poly(&self, name: ~str, ident: ast::ident, dir: direction,
181 +ty_params: ~[ast::ty_param]) -> state {
182 let messages = DVec();
184 let state = @state_ {
185 id: self.states.len(),
190 ty_params: ty_params,
195 self.states.push(state);
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;
207 pub fn visit<Tproto, Tstate, Tmessage, V: visitor<Tproto, Tstate, Tmessage>>(
208 proto: protocol, visitor: V) -> Tproto {
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)
216 visitor.visit_state(s, messages)
218 visitor.visit_proto(proto, states)