205 lines
4.8 KiB
Rust
Raw Normal View History

import to_str::ToStr;
2012-08-27 14:22:25 -07:00
import dvec::DVec;
2012-08-07 18:10:06 -07:00
import ast_builder::{path, append_types};
enum direction {
send, recv
}
impl direction: ToStr {
fn to_str() -> ~str {
2012-08-06 12:34:08 -07:00
match self {
2012-08-03 19:59:04 -07:00
send => ~"send",
recv => ~"recv"
}
}
}
2012-08-07 18:10:06 -07:00
impl direction {
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-08-20 12:23:37 -07:00
type next_state = Option<{state: ~str, tys: ~[@ast::ty]}>;
enum message {
// name, span, data, current state, next state
2012-07-18 16:18:02 -07:00
message(~str, span, ~[@ast::ty], state, next_state)
}
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-08-03 19:59:04 -07:00
message(id, _, _, _, _) => id
}
}
fn span() -> span {
2012-08-06 12:34:08 -07:00
match self {
2012-08-03 19:59:04 -07:00
message(_, span, _, _, _) => span
}
}
/// 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
}
}
}
enum state {
state_(@{
id: uint,
2012-07-18 16:18:02 -07:00
name: ~str,
ident: ast::ident,
span: span,
dir: direction,
ty_params: ~[ast::ty_param],
2012-08-14 16:54:13 -07:00
messages: DVec<message>,
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,
+data: ~[@ast::ty], next: next_state) {
self.messages.push(message(name, span, data, self,
next));
}
fn filename() -> ~str {
(*self).proto.filename()
}
2012-07-18 16:18:02 -07:00
fn data_name() -> ast::ident {
self.ident
}
/// Returns the type that is used for the messages.
fn to_ty(cx: ext_ctxt) -> @ast::ty {
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)))
}
/// 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-08-06 12:34:08 -07:00
match m {
2012-08-20 12:23:37 -07:00
message(_, _, _, _, Some({state: id, _})) => {
let state = self.proto.get_state(id);
if !f(state) { break }
}
2012-08-03 19:59:04 -07:00
_ => ()
}
}
}
}
type protocol = @protocol_;
2012-07-18 16:18:02 -07:00
fn protocol(name: ~str, +span: span) -> protocol {
@protocol_(name, span)
}
2012-08-15 18:46:55 -07:00
struct protocol_ {
2012-07-18 16:18:02 -07:00
let name: ~str;
let span: span;
2012-08-14 16:54:13 -07:00
let states: DVec<state>;
2012-08-20 12:23:37 -07:00
let mut bounded: Option<bool>;
2012-07-18 16:18:02 -07:00
new(name: ~str, span: span) {
self.name = name;
self.span = span;
2012-08-27 14:22:25 -07:00
self.states = DVec();
2012-08-20 12:23:37 -07:00
self.bounded = None;
}
/// Get a state.
2012-07-18 16:18:02 -07:00
fn get_state(name: ~str) -> state {
self.states.find(|i| i.name == name).get()
}
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-08-20 12:23:37 -07:00
self.states.find(|i| i.name == name) != None
}
fn filename() -> ~str {
2012-07-18 16:18:02 -07:00
~"proto://" + self.name
}
fn num_states() -> uint { self.states.len() }
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;
}
}
false
}
fn is_bounded() -> bool {
let bounded = self.bounded.get();
bounded
//if bounded && self.has_ty_params() {
2012-08-22 17:24:52 -07:00
// debug!("protocol %s has is bounded, but type parameters\
// are not yet supported.",
2012-08-22 17:24:52 -07:00
// *self.name);
// false
//}
//else { bounded }
}
}
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,
+ty_params: ~[ast::ty_param]) -> state {
2012-08-27 14:22:25 -07:00
let messages = DVec();
let state = state_(@{
id: self.states.len(),
name: name,
2012-07-18 16:18:02 -07:00
ident: ident,
span: self.span,
dir: dir,
ty_params: ty_params,
messages: messages,
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-07-18 16:18:02 -07:00
fn visit_message(name: ~str, spane: span, tys: &[@ast::ty],
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
let states = do (copy proto.states).map_to_vec |s| {
let messages = do (copy s.messages).map_to_vec |m| {
let message(name, span, tys, this, next) = m;
visitor.visit_message(name, span, tys, this, next)
};
visitor.visit_state(s, messages)
};
visitor.visit_proto(proto, states)
}