2012-12-03 16:48:01 -08:00
|
|
|
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2012-12-23 17:41:37 -05:00
|
|
|
use ast;
|
2012-12-13 13:05:22 -08:00
|
|
|
use ext::pipes::ast_builder::{path, append_types};
|
2012-07-16 17:27:04 -07:00
|
|
|
|
2012-12-23 17:41:37 -05:00
|
|
|
use core::cmp;
|
|
|
|
use core::dvec::DVec;
|
|
|
|
use core::to_str::ToStr;
|
|
|
|
|
2012-08-27 16:26:35 -07:00
|
|
|
enum direction { send, recv }
|
|
|
|
|
2012-09-19 18:00:26 -07:00
|
|
|
impl direction : cmp::Eq {
|
2012-11-14 18:59:30 -08:00
|
|
|
pure fn eq(&self, other: &direction) -> bool {
|
|
|
|
match ((*self), (*other)) {
|
|
|
|
(send, send) => true,
|
|
|
|
(recv, recv) => true,
|
|
|
|
(send, _) => false,
|
|
|
|
(recv, _) => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pure fn ne(&self, other: &direction) -> bool { !(*self).eq(other) }
|
2012-09-19 18:00:26 -07:00
|
|
|
}
|
2012-07-16 17:27:04 -07:00
|
|
|
|
2012-08-13 16:20:27 -07:00
|
|
|
impl direction: ToStr {
|
2012-10-11 14:12:50 -07:00
|
|
|
pure fn to_str() -> ~str {
|
2012-08-06 12:34:08 -07:00
|
|
|
match self {
|
2012-08-28 11:11:15 -07:00
|
|
|
send => ~"Send",
|
|
|
|
recv => ~"Recv"
|
2012-07-16 17:27:04 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-07 18:10:06 -07:00
|
|
|
impl direction {
|
2012-07-16 17:27:04 -07:00
|
|
|
fn reverse() -> direction {
|
2012-08-06 12:34:08 -07:00
|
|
|
match self {
|
2012-08-03 19:59:04 -07:00
|
|
|
send => recv,
|
|
|
|
recv => send
|
2012-07-16 17:27:04 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-15 14:56:42 -07:00
|
|
|
type next_state = Option<{state: ~str, tys: ~[@ast::Ty]}>;
|
2012-07-16 17:27:04 -07:00
|
|
|
|
|
|
|
enum message {
|
2012-07-24 16:58:48 -07:00
|
|
|
// name, span, data, current state, next state
|
2012-10-15 14:56:42 -07:00
|
|
|
message(~str, span, ~[@ast::Ty], state, next_state)
|
2012-07-16 17:27:04 -07:00
|
|
|
}
|
|
|
|
|
2012-08-07 18:10:06 -07:00
|
|
|
impl message {
|
2012-07-18 16:18:02 -07:00
|
|
|
fn name() -> ~str {
|
2012-08-06 12:34:08 -07:00
|
|
|
match self {
|
2012-12-04 10:50:00 -08:00
|
|
|
message(ref id, _, _, _, _) => (*id)
|
2012-07-16 17:27:04 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-24 16:58:48 -07:00
|
|
|
fn span() -> span {
|
2012-08-06 12:34:08 -07:00
|
|
|
match self {
|
2012-08-03 19:59:04 -07:00
|
|
|
message(_, span, _, _, _) => span
|
2012-07-24 16:58:48 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-16 17:27:04 -07:00
|
|
|
/// Return the type parameters actually used by this message
|
|
|
|
fn get_params() -> ~[ast::ty_param] {
|
2012-08-06 12:34:08 -07:00
|
|
|
match self {
|
2012-08-03 19:59:04 -07:00
|
|
|
message(_, _, _, this, _) => this.ty_params
|
2012-07-16 17:27:04 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
enum state {
|
|
|
|
state_(@{
|
2012-07-17 17:03:27 -07:00
|
|
|
id: uint,
|
2012-07-18 16:18:02 -07:00
|
|
|
name: ~str,
|
|
|
|
ident: ast::ident,
|
2012-07-24 16:58:48 -07:00
|
|
|
span: span,
|
2012-07-16 17:27:04 -07:00
|
|
|
dir: direction,
|
|
|
|
ty_params: ~[ast::ty_param],
|
2012-08-14 16:54:13 -07:00
|
|
|
messages: DVec<message>,
|
2012-07-16 17:27:04 -07:00
|
|
|
proto: protocol,
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
|
2012-08-07 18:10:06 -07:00
|
|
|
impl state {
|
2012-07-18 16:18:02 -07:00
|
|
|
fn add_message(name: ~str, span: span,
|
2012-10-15 14:56:42 -07:00
|
|
|
+data: ~[@ast::Ty], next: next_state) {
|
2012-07-24 16:58:48 -07:00
|
|
|
self.messages.push(message(name, span, data, self,
|
2012-07-16 17:27:04 -07:00
|
|
|
next));
|
|
|
|
}
|
|
|
|
|
|
|
|
fn filename() -> ~str {
|
|
|
|
(*self).proto.filename()
|
|
|
|
}
|
|
|
|
|
2012-07-18 16:18:02 -07:00
|
|
|
fn data_name() -> ast::ident {
|
|
|
|
self.ident
|
2012-07-16 17:27:04 -07:00
|
|
|
}
|
|
|
|
|
2012-07-24 18:00:08 -07:00
|
|
|
/// Returns the type that is used for the messages.
|
2012-10-15 14:56:42 -07:00
|
|
|
fn to_ty(cx: ext_ctxt) -> @ast::Ty {
|
2012-07-17 16:49:54 -07:00
|
|
|
cx.ty_path_ast_builder
|
2012-07-18 16:18:02 -07:00
|
|
|
(path(~[cx.ident_of(self.name)],self.span).add_tys(
|
|
|
|
cx.ty_vars(self.ty_params)))
|
2012-07-16 17:27:04 -07:00
|
|
|
}
|
2012-07-17 17:03:27 -07:00
|
|
|
|
|
|
|
/// Iterate over the states that can be reached in one message
|
|
|
|
/// from this state.
|
|
|
|
fn reachable(f: fn(state) -> bool) {
|
|
|
|
for self.messages.each |m| {
|
2012-09-19 16:55:01 -07:00
|
|
|
match *m {
|
2012-12-04 10:50:00 -08:00
|
|
|
message(_, _, _, _, Some({state: ref id, _})) => {
|
|
|
|
let state = self.proto.get_state((*id));
|
2012-07-17 17:03:27 -07:00
|
|
|
if !f(state) { break }
|
|
|
|
}
|
2012-08-03 19:59:04 -07:00
|
|
|
_ => ()
|
2012-07-17 17:03:27 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-07-16 17:27:04 -07:00
|
|
|
}
|
|
|
|
|
2012-07-23 13:50:12 -07:00
|
|
|
type protocol = @protocol_;
|
2012-07-16 17:27:04 -07:00
|
|
|
|
2012-07-18 16:18:02 -07:00
|
|
|
fn protocol(name: ~str, +span: span) -> protocol {
|
2012-07-24 16:58:48 -07:00
|
|
|
@protocol_(name, span)
|
|
|
|
}
|
2012-07-16 17:27:04 -07:00
|
|
|
|
2012-09-05 15:58:43 -07:00
|
|
|
fn protocol_(name: ~str, span: span) -> protocol_ {
|
|
|
|
protocol_ {
|
|
|
|
name: name,
|
|
|
|
span: span,
|
|
|
|
states: DVec(),
|
|
|
|
bounded: None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-15 18:46:55 -07:00
|
|
|
struct protocol_ {
|
2012-09-06 19:40:15 -07:00
|
|
|
name: ~str,
|
|
|
|
span: span,
|
|
|
|
states: DVec<state>,
|
2012-07-23 13:50:12 -07:00
|
|
|
|
2012-09-06 19:40:15 -07:00
|
|
|
mut bounded: Option<bool>,
|
2012-09-07 19:04:40 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
impl protocol_ {
|
2012-07-23 13:50:12 -07:00
|
|
|
|
|
|
|
/// Get a state.
|
2012-07-18 16:18:02 -07:00
|
|
|
fn get_state(name: ~str) -> state {
|
2012-07-16 17:27:04 -07:00
|
|
|
self.states.find(|i| i.name == name).get()
|
|
|
|
}
|
|
|
|
|
2012-07-17 17:03:27 -07:00
|
|
|
fn get_state_by_id(id: uint) -> state { self.states[id] }
|
|
|
|
|
2012-07-18 16:18:02 -07:00
|
|
|
fn has_state(name: ~str) -> bool {
|
2012-09-07 18:53:14 -07:00
|
|
|
self.states.find(|i| i.name == name).is_some()
|
2012-07-16 17:27:04 -07:00
|
|
|
}
|
|
|
|
|
2012-07-23 13:50:12 -07:00
|
|
|
fn filename() -> ~str {
|
2012-07-18 16:18:02 -07:00
|
|
|
~"proto://" + self.name
|
2012-07-23 13:50:12 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
fn num_states() -> uint { self.states.len() }
|
|
|
|
|
2012-07-23 18:50:53 -07:00
|
|
|
fn has_ty_params() -> bool {
|
|
|
|
for self.states.each |s| {
|
|
|
|
if s.ty_params.len() > 0 {
|
2012-08-01 17:30:05 -07:00
|
|
|
return true;
|
2012-07-23 18:50:53 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
false
|
|
|
|
}
|
|
|
|
fn is_bounded() -> bool {
|
|
|
|
let bounded = self.bounded.get();
|
2012-07-24 16:58:48 -07:00
|
|
|
bounded
|
|
|
|
//if bounded && self.has_ty_params() {
|
2012-08-22 17:24:52 -07:00
|
|
|
// debug!("protocol %s has is bounded, but type parameters\
|
2012-07-24 16:58:48 -07:00
|
|
|
// are not yet supported.",
|
2012-08-22 17:24:52 -07:00
|
|
|
// *self.name);
|
2012-07-24 16:58:48 -07:00
|
|
|
// false
|
|
|
|
//}
|
|
|
|
//else { bounded }
|
2012-07-23 18:50:53 -07:00
|
|
|
}
|
2012-07-23 13:50:12 -07:00
|
|
|
}
|
|
|
|
|
2012-08-07 18:10:06 -07:00
|
|
|
impl protocol {
|
2012-07-18 16:18:02 -07:00
|
|
|
fn add_state_poly(name: ~str, ident: ast::ident, dir: direction,
|
2012-07-16 17:27:04 -07:00
|
|
|
+ty_params: ~[ast::ty_param]) -> state {
|
2012-08-27 14:22:25 -07:00
|
|
|
let messages = DVec();
|
2012-07-16 17:27:04 -07:00
|
|
|
|
|
|
|
let state = state_(@{
|
2012-07-17 17:03:27 -07:00
|
|
|
id: self.states.len(),
|
2012-07-16 17:27:04 -07:00
|
|
|
name: name,
|
2012-07-18 16:18:02 -07:00
|
|
|
ident: ident,
|
2012-07-24 16:58:48 -07:00
|
|
|
span: self.span,
|
2012-07-16 17:27:04 -07:00
|
|
|
dir: dir,
|
|
|
|
ty_params: ty_params,
|
2012-09-10 18:28:00 -07:00
|
|
|
messages: move messages,
|
2012-07-16 17:27:04 -07:00
|
|
|
proto: self
|
|
|
|
});
|
|
|
|
|
|
|
|
self.states.push(state);
|
|
|
|
state
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
trait visitor<Tproto, Tstate, Tmessage> {
|
|
|
|
fn visit_proto(proto: protocol, st: &[Tstate]) -> Tproto;
|
|
|
|
fn visit_state(state: state, m: &[Tmessage]) -> Tstate;
|
2012-10-15 14:56:42 -07:00
|
|
|
fn visit_message(name: ~str, spane: span, tys: &[@ast::Ty],
|
2012-07-16 17:27:04 -07:00
|
|
|
this: state, next: next_state) -> Tmessage;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn visit<Tproto, Tstate, Tmessage, V: visitor<Tproto, Tstate, Tmessage>>(
|
|
|
|
proto: protocol, visitor: V) -> Tproto {
|
|
|
|
|
|
|
|
// the copy keywords prevent recursive use of dvec
|
2012-12-17 20:36:12 -08:00
|
|
|
let states = do (copy proto.states).map_to_vec |&s| {
|
|
|
|
let messages = do (copy s.messages).map_to_vec |&m| {
|
2012-09-28 17:04:39 -07:00
|
|
|
let message(name, span, tys, this, next) = m;
|
2012-07-24 16:58:48 -07:00
|
|
|
visitor.visit_message(name, span, tys, this, next)
|
2012-07-16 17:27:04 -07:00
|
|
|
};
|
2012-09-28 17:04:39 -07:00
|
|
|
visitor.visit_state(s, messages)
|
2012-07-16 17:27:04 -07:00
|
|
|
};
|
|
|
|
visitor.visit_proto(proto, states)
|
|
|
|
}
|