diff options
Diffstat (limited to 'src/libsyntax/ext')
| -rw-r--r-- | src/libsyntax/ext/base.rs | 6 | ||||
| -rw-r--r-- | src/libsyntax/ext/pipes/ast_builder.rs | 63 | ||||
| -rw-r--r-- | src/libsyntax/ext/pipes/check.rs | 82 | ||||
| -rw-r--r-- | src/libsyntax/ext/pipes/liveness.rs | 106 | ||||
| -rw-r--r-- | src/libsyntax/ext/pipes/mod.rs | 84 | ||||
| -rw-r--r-- | src/libsyntax/ext/pipes/parse_proto.rs | 124 | ||||
| -rw-r--r-- | src/libsyntax/ext/pipes/pipec.rs | 467 | ||||
| -rw-r--r-- | src/libsyntax/ext/pipes/proto.rs | 227 | ||||
| -rw-r--r-- | src/libsyntax/ext/quote.rs | 2 |
9 files changed, 3 insertions, 1158 deletions
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index ea87646e60b..90e1c7db91a 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -81,8 +81,8 @@ pub enum SyntaxExtension { // An IdentTT is a macro that has an // identifier in between the name of the // macro and the argument. Currently, - // the only examples of this are - // macro_rules! and proto! + // the only examples of this is + // macro_rules! // perhaps macro_rules! will lose its odd special identifier argument, // and this can go away also @@ -197,8 +197,6 @@ pub fn syntax_expander_table() -> SyntaxEnv { syntax_expanders.insert(intern(&"module_path"), builtin_normal_tt( ext::source_util::expand_mod)); - syntax_expanders.insert(intern(&"proto"), - builtin_item_tt(ext::pipes::expand_proto)); syntax_expanders.insert(intern(&"asm"), builtin_normal_tt(ext::asm::expand_asm)); syntax_expanders.insert( diff --git a/src/libsyntax/ext/pipes/ast_builder.rs b/src/libsyntax/ext/pipes/ast_builder.rs deleted file mode 100644 index eb8b01c427d..00000000000 --- a/src/libsyntax/ext/pipes/ast_builder.rs +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2012-2013 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. - -// Functions for building ASTs, without having to fuss with spans. -// -// To start with, it will be use dummy spans, but it might someday do -// something smarter. - -use ast::ident; -use ast; -use codemap::span; - -use std::vec; - -// Transitional reexports so qquote can find the paths it is looking for -mod syntax { - pub use ext; - pub use parse; -} - -pub fn path(ids: ~[ident], span: span) -> ast::Path { - ast::Path { span: span, - global: false, - idents: ids, - rp: None, - types: ~[] } -} - -pub fn path_global(ids: ~[ident], span: span) -> ast::Path { - ast::Path { span: span, - global: true, - idents: ids, - rp: None, - types: ~[] } -} - -pub trait append_types { - fn add_ty(&self, ty: ast::Ty) -> ast::Path; - fn add_tys(&self, tys: ~[ast::Ty]) -> ast::Path; -} - -impl append_types for ast::Path { - fn add_ty(&self, ty: ast::Ty) -> ast::Path { - ast::Path { - types: vec::append_one(self.types.clone(), ty), - .. (*self).clone() - } - } - - fn add_tys(&self, tys: ~[ast::Ty]) -> ast::Path { - ast::Path { - types: vec::append(self.types.clone(), tys), - .. (*self).clone() - } - } -} diff --git a/src/libsyntax/ext/pipes/check.rs b/src/libsyntax/ext/pipes/check.rs deleted file mode 100644 index adf10215cb5..00000000000 --- a/src/libsyntax/ext/pipes/check.rs +++ /dev/null @@ -1,82 +0,0 @@ -// 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. - -/// Correctness for protocols - -/* - -This section of code makes sure the protocol is likely to generate -correct code. The correctness criteria include: - - * No protocols transition to states that don't exist. - * Messages step to states with the right number of type parameters. - -In addition, this serves as a lint pass. Lint warns for the following -things. - - * States with no messages, it's better to step to !. - -It would also be nice to warn about unreachable states, but the -visitor infrastructure for protocols doesn't currently work well for -that. - -*/ - -use ast; -use codemap::span; -use ext::base::ExtCtxt; -use ext::pipes::proto::{state, protocol, next_state}; -use ext::pipes::proto; - -impl proto::visitor<(), (), ()> for @ExtCtxt { - fn visit_proto(&self, _proto: protocol, _states: &[()]) { } - - fn visit_state(&self, state: state, _m: &[()]) { - let messages = &*state.messages; - if messages.len() == 0 { - self.span_warn( - state.span, // use a real span! - fmt!("state %s contains no messages, \ - consider stepping to a terminal state instead", - state.name)) - } - } - - fn visit_message(&self, name: @str, _span: span, _tys: &[ast::Ty], - this: state, next: Option<next_state>) { - match next { - Some(ref next_state) => { - let proto = this.proto; - if !proto.has_state(next_state.state) { - // This should be a span fatal, but then we need to - // track span information. - self.span_err( - proto.get_state(next_state.state).span, - fmt!("message %s steps to undefined state, %s", - name, next_state.state)); - } - else { - let next = proto.get_state(next_state.state); - - if next.generics.ty_params.len() != next_state.tys.len() { - self.span_err( - next.span, // use a real span - fmt!("message %s target (%s) \ - needs %u type parameters, but got %u", - name, next.name, - next.generics.ty_params.len(), - next_state.tys.len())); - } - } - } - None => () - } - } -} diff --git a/src/libsyntax/ext/pipes/liveness.rs b/src/libsyntax/ext/pipes/liveness.rs deleted file mode 100644 index b080a730f3e..00000000000 --- a/src/libsyntax/ext/pipes/liveness.rs +++ /dev/null @@ -1,106 +0,0 @@ -// 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. - -/* - -Liveness analysis for protocols. This is useful for a lot of possible -optimizations. - -This analysis computes the "co-live" relationship between -states. Co-live is defined inductively as follows. - -1. u is co-live with v if u can transition to v in one message. - -2. u is co-live with v if there exists a w such that u and w are -co-live, w and v are co-live, and u and w have the same direction. - -This relationship approximates when it is safe to store two states in -the same memory location. If there is no u such u is co-live with -itself, then the protocol is bounded. - -(These assertions could use proofs) - -In addition, this analysis does reachability, to warn when we have -useless states. - -The algorithm is a fixpoint computation. For each state, we initialize -a bitvector containing whether it is co-live with each other state. At -first we use rule (1) above to set each vector. Then we iterate -updating the states using rule (2) until there are no changes. - -*/ - -use ext::base::ExtCtxt; -use ext::pipes::proto::{protocol_}; - -use extra::bitv::Bitv; - -pub fn analyze(proto: @mut protocol_, _cx: @ExtCtxt) { - debug!("initializing colive analysis"); - let num_states = proto.num_states(); - let mut colive: ~[~Bitv] = do proto.states.iter().transform() |state| { - let mut bv = ~Bitv::new(num_states, false); - for state.reachable |s| { - bv.set(s.id, true); - } - bv - }.collect(); - - let mut i = 0; - let mut changed = true; - while changed { - changed = false; - debug!("colive iteration %?", i); - let mut new_colive = ~[]; - foreach (i, this_colive) in colive.iter().enumerate() { - let mut result = this_colive.clone(); - let this = proto.get_state_by_id(i); - for this_colive.ones |j| { - let next = proto.get_state_by_id(j); - if this.dir == next.dir { - changed = result.union(colive[j]) || changed; - } - } - new_colive.push(result) - } - colive = new_colive; - i += 1; - } - - debug!("colive analysis complete"); - - // Determine if we're bounded - let mut self_live = ~[]; - foreach (i, bv) in colive.iter().enumerate() { - if bv.get(i) { - self_live.push(proto.get_state_by_id(i)) - } - } - - if self_live.len() > 0 { - let states = self_live.map(|s| s.name).connect(" "); - - debug!("protocol %s is unbounded due to loops involving: %s", - proto.name, - states); - - // Someday this will be configurable with a warning - //cx.span_warn(empty_span(), - // fmt!("protocol %s is unbounded due to loops \ - // involving these states: %s", - // *proto.name, - // states)); - - proto.bounded = Some(false); - } else { - debug!("protocol %s is bounded. yay!", proto.name); - proto.bounded = Some(true); - } -} diff --git a/src/libsyntax/ext/pipes/mod.rs b/src/libsyntax/ext/pipes/mod.rs deleted file mode 100644 index b8a0da8fe8f..00000000000 --- a/src/libsyntax/ext/pipes/mod.rs +++ /dev/null @@ -1,84 +0,0 @@ -// 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. - -/*! Implementation of proto! extension. - -This is frequently called the pipe compiler. It handles code such as... - -~~~ -proto! pingpong ( - ping: send { - ping -> pong - } - pong: recv { - pong -> ping - } -) -~~~ - -There are several components: - - * The parser (libsyntax/ext/pipes/parse_proto.rs) - * Responsible for building an AST from a protocol specification. - - * The checker (libsyntax/ext/pipes/check.rs) - * Basic correctness checking for protocols (i.e. no undefined states, etc.) - - * The analyzer (libsyntax/ext/pipes/liveness.rs) - * Determines whether the protocol is bounded or unbounded. - - * The compiler (libsynatx/ext/pipes/pipec.rs) - * Generates a Rust AST from the protocol AST and the results of analysis. - -There is more documentation in each of the files referenced above. - -FIXME (#3072) - This is still incomplete. - -*/ - -use ast; -use codemap::span; -use ext::base; -use ext::base::ExtCtxt; -use ext::pipes::parse_proto::proto_parser; -use ext::pipes::pipec::gen_init; -use ext::pipes::proto::visit; -use parse::lexer::{new_tt_reader, reader}; -use parse::parser::Parser; - -pub mod ast_builder; -pub mod parse_proto; -pub mod pipec; -pub mod proto; -pub mod check; -pub mod liveness; - - -pub fn expand_proto(cx: @ExtCtxt, _sp: span, id: ast::ident, - tt: ~[ast::token_tree]) -> base::MacResult { - let sess = cx.parse_sess(); - let cfg = cx.cfg(); - let tt_rdr = new_tt_reader(cx.parse_sess().span_diagnostic, - None, - tt.clone()); - let rdr = tt_rdr as @reader; - let rust_parser = Parser(sess, cfg, rdr.dup()); - - let proto = rust_parser.parse_proto(cx.str_of(id)); - - // check for errors - visit(proto, cx); - - // do analysis - liveness::analyze(proto, cx); - - // compile - base::MRItem(proto.compile(cx)) -} diff --git a/src/libsyntax/ext/pipes/parse_proto.rs b/src/libsyntax/ext/pipes/parse_proto.rs deleted file mode 100644 index e5219721594..00000000000 --- a/src/libsyntax/ext/pipes/parse_proto.rs +++ /dev/null @@ -1,124 +0,0 @@ -// 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. - -// Parsing pipes protocols from token trees. - -use ast_util; -use ext::pipes::proto::*; -use parse::common::SeqSep; -use parse::parser; -use parse::token; -use parse::token::{interner_get}; - -pub trait proto_parser { - fn parse_proto(&self, id: @str) -> protocol; - fn parse_state(&self, proto: protocol); - fn parse_message(&self, state: state); -} - -impl proto_parser for parser::Parser { - fn parse_proto(&self, id: @str) -> protocol { - let proto = protocol(id, *self.span); - - self.parse_seq_to_before_end( - &token::EOF, - SeqSep { - sep: None, - trailing_sep_allowed: false, - }, - |this| this.parse_state(proto) - ); - - return proto; - } - - fn parse_state(&self, proto: protocol) { - let id = self.parse_ident(); - let name = interner_get(id.name); - - self.expect(&token::COLON); - let dir = match (*self.token).clone() { - token::IDENT(n, _) => interner_get(n.name), - _ => fail!() - }; - self.bump(); - let dir = match dir.as_slice() { - "send" => send, - "recv" => recv, - _ => fail!() - }; - - let generics = if *self.token == token::LT { - self.parse_generics() - } else { - ast_util::empty_generics() - }; - - let state = proto.add_state_poly(name, id, dir, generics); - - // parse the messages - self.parse_unspanned_seq( - &token::LBRACE, - &token::RBRACE, - SeqSep { - sep: Some(token::COMMA), - trailing_sep_allowed: true, - }, - |this| this.parse_message(state) - ); - } - - fn parse_message(&self, state: state) { - let mname = interner_get(self.parse_ident().name); - - let args = if *self.token == token::LPAREN { - self.parse_unspanned_seq( - &token::LPAREN, - &token::RPAREN, - SeqSep { - sep: Some(token::COMMA), - trailing_sep_allowed: true, - }, - |p| p.parse_ty(false) - ) - } - else { ~[] }; - - self.expect(&token::RARROW); - - let next = match *self.token { - token::IDENT(_, _) => { - let name = interner_get(self.parse_ident().name); - let ntys = if *self.token == token::LT { - self.parse_unspanned_seq( - &token::LT, - &token::GT, - SeqSep { - sep: Some(token::COMMA), - trailing_sep_allowed: true, - }, - |p| p.parse_ty(false) - ) - } - else { ~[] }; - Some(next_state {state: name, tys: ntys}) - } - token::NOT => { - // -> ! - self.bump(); - None - } - _ => self.fatal("invalid next state") - }; - - state.add_message(mname, *self.span, args, next); - - } -} diff --git a/src/libsyntax/ext/pipes/pipec.rs b/src/libsyntax/ext/pipes/pipec.rs deleted file mode 100644 index 02aef13a3a8..00000000000 --- a/src/libsyntax/ext/pipes/pipec.rs +++ /dev/null @@ -1,467 +0,0 @@ -// 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. - -// A protocol compiler for Rust. - -use ast; -use codemap::{dummy_sp, spanned}; -use ext::base::ExtCtxt; -use ext::build::AstBuilder; -use ext::pipes::ast_builder::{append_types, path}; -use ext::pipes::ast_builder::{path_global}; -use ext::pipes::proto::*; -use ext::quote::rt::*; -use opt_vec; -use opt_vec::OptVec; - -use std::vec; - -pub trait gen_send { - fn gen_send(&mut self, cx: @ExtCtxt, try: bool) -> @ast::item; - fn to_ty(&mut self, cx: @ExtCtxt) -> ast::Ty; -} - -pub trait to_type_decls { - fn to_type_decls(&self, cx: @ExtCtxt) -> ~[@ast::item]; - fn to_endpoint_decls(&self, cx: @ExtCtxt, - dir: direction) -> ~[@ast::item]; -} - -pub trait gen_init { - fn gen_init(&self, cx: @ExtCtxt) -> @ast::item; - fn compile(&self, cx: @ExtCtxt) -> @ast::item; - fn buffer_ty_path(&self, cx: @ExtCtxt) -> ast::Ty; - fn gen_buffer_type(&self, cx: @ExtCtxt) -> @ast::item; - fn gen_buffer_init(&self, ext_cx: @ExtCtxt) -> @ast::expr; - fn gen_init_bounded(&self, ext_cx: @ExtCtxt) -> @ast::expr; -} - -impl gen_send for message { - fn gen_send(&mut self, cx: @ExtCtxt, try: bool) -> @ast::item { - debug!("pipec: gen_send"); - let name = self.name(); - - match *self { - message(ref _id, span, ref tys, this, Some(ref next_state)) => { - debug!("pipec: next state exists"); - let next = this.proto.get_state(next_state.state); - assert!(next_state.tys.len() == - next.generics.ty_params.len()); - let arg_names = vec::from_fn(tys.len(), |i| cx.ident_of("x_"+i.to_str())); - let args_ast: ~[ast::arg] = arg_names.iter().zip(tys.iter()) - .transform(|(n, t)| - cx.arg(span, (*n).clone(), (*t).clone())).collect(); - - let pipe_ty = cx.ty_path( - path(~[this.data_name()], span) - .add_tys(cx.ty_vars(&this.generics.ty_params)), None); - let args_ast = vec::append( - ~[cx.arg(span, cx.ident_of("pipe"), pipe_ty)], - args_ast); - - let mut body = ~"{\n"; - body.push_str(fmt!("use super::%s;\n", name)); - body.push_str("let mut pipe = pipe;\n"); - - if this.proto.is_bounded() { - let (sp, rp) = match (this.dir, next.dir) { - (send, send) => (~"c", ~"s"), - (send, recv) => (~"s", ~"c"), - (recv, send) => (~"s", ~"c"), - (recv, recv) => (~"c", ~"s") - }; - - body.push_str("let mut b = pipe.reuse_buffer();\n"); - body.push_str(fmt!("let %s = ::std::pipes::SendPacketBuffered(\ - &mut (b.buffer.data.%s));\n", - sp, - next.name)); - body.push_str(fmt!("let %s = ::std::pipes::RecvPacketBuffered(\ - &mut (b.buffer.data.%s));\n", - rp, - next.name)); - } - else { - let pat = match (this.dir, next.dir) { - (send, send) => "(s, c)", - (send, recv) => "(c, s)", - (recv, send) => "(c, s)", - (recv, recv) => "(s, c)" - }; - - body.push_str(fmt!("let %s = ::std::pipes::entangle();\n", pat)); - } - body.push_str(fmt!("let message = %s(%s);\n", - name, - vec::append_one(arg_names.map(|x| cx.str_of(*x)), @"s") - .connect(", "))); - - if !try { - body.push_str(fmt!("::std::pipes::send(pipe, message);\n")); - // return the new channel - body.push_str("c }"); - } - else { - body.push_str(fmt!("if ::std::pipes::send(pipe, message) {\n \ - ::std::pipes::rt::make_some(c) \ - } else { ::std::pipes::rt::make_none() } }")); - } - - let body = cx.parse_expr(body.to_managed()); - - let mut rty = cx.ty_path(path(~[next.data_name()], - span) - .add_tys(next_state.tys.clone()), None); - if try { - rty = cx.ty_option(rty); - } - - let name = if try {cx.ident_of(~"try_" + name)} else {cx.ident_of(name)}; - - cx.item_fn_poly(dummy_sp(), - name, - args_ast, - rty, - self.get_generics(), - cx.blk_expr(body)) - } - - message(ref _id, span, ref tys, this, None) => { - debug!("pipec: no next state"); - let arg_names = vec::from_fn(tys.len(), |i| "x_" + i.to_str()); - - let args_ast: ~[ast::arg] = arg_names.iter().zip(tys.iter()) - .transform(|(n, t)| - cx.arg(span, cx.ident_of(*n), (*t).clone())).collect(); - - let args_ast = vec::append( - ~[cx.arg(span, - cx.ident_of("pipe"), - cx.ty_path( - path(~[this.data_name()], span) - .add_tys(cx.ty_vars( - &this.generics.ty_params)), None))], - args_ast); - - let message_args = if arg_names.len() == 0 { - ~"" - } - else { - ~"(" + arg_names.map(|x| (*x).clone()).connect(", ") + ")" - }; - - let mut body = ~"{ "; - body.push_str(fmt!("use super::%s;\n", name)); - body.push_str(fmt!("let message = %s%s;\n", name, message_args)); - - if !try { - body.push_str(fmt!("::std::pipes::send(pipe, message);\n")); - body.push_str(" }"); - } else { - body.push_str(fmt!("if ::std::pipes::send(pipe, message) \ - { \ - ::std::pipes::rt::make_some(()) \ - } else { \ - ::std::pipes::rt::make_none() \ - } }")); - } - - let body = cx.parse_expr(body.to_managed()); - - let name = if try {cx.ident_of(~"try_" + name)} else {cx.ident_of(name)}; - - cx.item_fn_poly(dummy_sp(), - name, - args_ast, - if try { - cx.ty_option(cx.ty_nil()) - } else { - cx.ty_nil() - }, - self.get_generics(), - cx.blk_expr(body)) - } - } - } - - fn to_ty(&mut self, cx: @ExtCtxt) -> ast::Ty { - cx.ty_path(path(~[cx.ident_of(self.name())], self.span()) - .add_tys(cx.ty_vars(&self.get_generics().ty_params)), None) - } -} - -impl to_type_decls for state { - fn to_type_decls(&self, cx: @ExtCtxt) -> ~[@ast::item] { - debug!("pipec: to_type_decls"); - // This compiles into two different type declarations. Say the - // state is called ping. This will generate both `ping` and - // `ping_message`. The first contains data that the user cares - // about. The second is the same thing, but extended with a - // next packet pointer, which is used under the covers. - - let name = self.data_name(); - - let mut items_msg = ~[]; - - foreach m in self.messages.iter() { - let message(name, span, tys, this, next) = (*m).clone(); - - let tys = match next { - Some(ref next_state) => { - let next = this.proto.get_state((next_state.state)); - let next_name = cx.str_of(next.data_name()); - - let dir = match this.dir { - send => "server", - recv => "client" - }; - - vec::append_one(tys, - cx.ty_path( - path(~[cx.ident_of(dir), - cx.ident_of(next_name)], span) - .add_tys(next_state.tys.clone()), None)) - } - None => tys - }; - - let v = cx.variant(span, cx.ident_of(name), tys); - - items_msg.push(v); - } - - ~[ - cx.item_enum_poly( - self.span, - name, - ast::enum_def { variants: items_msg }, - cx.strip_bounds(&self.generics) - ) - ] - } - - fn to_endpoint_decls(&self, cx: @ExtCtxt, - dir: direction) -> ~[@ast::item] { - debug!("pipec: to_endpoint_decls"); - let dir = match dir { - send => (*self).dir, - recv => (*self).dir.reverse() - }; - let mut items = ~[]; - - { - foreach m in self.messages.mut_iter() { - if dir == send { - items.push(m.gen_send(cx, true)); - items.push(m.gen_send(cx, false)); - } - } - } - - if !self.proto.is_bounded() { - items.push( - cx.item_ty_poly( - self.span, - self.data_name(), - cx.ty_path( - path_global(~[cx.ident_of("std"), - cx.ident_of("pipes"), - cx.ident_of(dir.to_str() + "Packet")], - dummy_sp()) - .add_ty(cx.ty_path( - path(~[cx.ident_of("super"), - self.data_name()], - dummy_sp()) - .add_tys(cx.ty_vars( - &self.generics.ty_params)), None)), None), - cx.strip_bounds(&self.generics))); - } - else { - items.push( - cx.item_ty_poly( - self.span, - self.data_name(), - cx.ty_path( - path_global(~[cx.ident_of("std"), - cx.ident_of("pipes"), - cx.ident_of(dir.to_str() - + "PacketBuffered")], - dummy_sp()) - .add_tys(~[cx.ty_path( - path(~[cx.ident_of("super"), - self.data_name()], - dummy_sp()) - .add_tys(cx.ty_vars_global( - &self.generics.ty_params)), None), - self.proto.buffer_ty_path(cx)]), None), - cx.strip_bounds(&self.generics))); - }; - items - } -} - -impl gen_init for protocol { - fn gen_init(&self, cx: @ExtCtxt) -> @ast::item { - let ext_cx = cx; - - debug!("gen_init"); - let start_state = self.states[0]; - - let body = if !self.is_bounded() { - quote_expr!( ::std::pipes::entangle() ) - } - else { - self.gen_init_bounded(ext_cx) - }; - - cx.parse_item(fmt!("pub fn init%s() -> (server::%s, client::%s)\ - { pub use std::pipes::HasBuffer; %s }", - start_state.generics.to_source(), - start_state.to_ty(cx).to_source(), - start_state.to_ty(cx).to_source(), - body.to_source()).to_managed()) - } - - fn gen_buffer_init(&self, ext_cx: @ExtCtxt) -> @ast::expr { - ext_cx.expr_struct( - dummy_sp(), - path(~[ext_cx.ident_of("__Buffer")], - dummy_sp()), - self.states.iter().transform(|s| { - let fty = s.to_ty(ext_cx); - ext_cx.field_imm(dummy_sp(), - ext_cx.ident_of(s.name), - quote_expr!( - ::std::pipes::mk_packet::<$fty>() - )) - }).collect()) - } - - fn gen_init_bounded(&self, ext_cx: @ExtCtxt) -> @ast::expr { - debug!("gen_init_bounded"); - let buffer_fields = self.gen_buffer_init(ext_cx); - let buffer = quote_expr!(~::std::pipes::Buffer { - header: ::std::pipes::BufferHeader(), - data: $buffer_fields, - }); - - let entangle_body = ext_cx.expr_blk( - ext_cx.blk( - dummy_sp(), - self.states.iter().transform( - |s| ext_cx.parse_stmt( - fmt!("data.%s.set_buffer(buffer)", - s.name).to_managed())).collect(), - Some(ext_cx.parse_expr(fmt!( - "::std::ptr::to_mut_unsafe_ptr(&mut (data.%s))", - self.states[0].name).to_managed())))); - - quote_expr!({ - let buffer = $buffer; - do ::std::pipes::entangle_buffer(buffer) |buffer, data| { - $entangle_body - } - }) - } - - fn buffer_ty_path(&self, cx: @ExtCtxt) -> ast::Ty { - let mut params: OptVec<ast::TyParam> = opt_vec::Empty; - foreach s in self.states.iter() { - foreach tp in s.generics.ty_params.iter() { - match params.iter().find_(|tpp| tp.ident == tpp.ident) { - None => params.push((*tp).clone()), - _ => () - } - } - } - - cx.ty_path(path(~[cx.ident_of("super"), - cx.ident_of("__Buffer")], - self.span) - .add_tys(cx.ty_vars_global(¶ms)), None) - } - - fn gen_buffer_type(&self, cx: @ExtCtxt) -> @ast::item { - let ext_cx = cx; - let mut params: OptVec<ast::TyParam> = opt_vec::Empty; - let fields = do self.states.iter().transform |s| { - foreach tp in s.generics.ty_params.iter() { - match params.iter().find_(|tpp| tp.ident == tpp.ident) { - None => params.push((*tp).clone()), - _ => () - } - } - - let ty = s.to_ty(cx); - let fty = quote_ty!( ::std::pipes::Packet<$ty> ); - - @spanned { - node: ast::struct_field_ { - kind: ast::named_field(cx.ident_of(s.name), - ast::inherited), - id: cx.next_id(), - ty: fty, - attrs: ~[], - }, - span: dummy_sp() - } - }.collect(); - - let generics = Generics { - lifetimes: opt_vec::Empty, - ty_params: params - }; - - cx.item_struct_poly( - dummy_sp(), - cx.ident_of("__Buffer"), - ast::struct_def { - fields: fields, - ctor_id: None - }, - cx.strip_bounds(&generics)) - } - - fn compile(&self, cx: @ExtCtxt) -> @ast::item { - let mut items = ~[self.gen_init(cx)]; - let mut client_states = ~[]; - let mut server_states = ~[]; - - foreach s in self.states.iter() { - items.push_all_move(s.to_type_decls(cx)); - - client_states.push_all_move(s.to_endpoint_decls(cx, send)); - server_states.push_all_move(s.to_endpoint_decls(cx, recv)); - } - - if self.is_bounded() { - items.push(self.gen_buffer_type(cx)) - } - - items.push(cx.item_mod(self.span, - cx.ident_of("client"), - ~[], ~[], - client_states)); - items.push(cx.item_mod(self.span, - cx.ident_of("server"), - ~[], ~[], - server_states)); - - // XXX: Would be nice if our generated code didn't violate - // Rust coding conventions - let allows = cx.attribute( - self.span, - cx.meta_list(self.span, - @"allow", - ~[cx.meta_word(self.span, @"non_camel_case_types"), - cx.meta_word(self.span, @"unused_mut")])); - cx.item_mod(self.span, cx.ident_of(self.name), ~[allows], ~[], items) - } -} diff --git a/src/libsyntax/ext/pipes/proto.rs b/src/libsyntax/ext/pipes/proto.rs deleted file mode 100644 index 5d2ebb68b8a..00000000000 --- a/src/libsyntax/ext/pipes/proto.rs +++ /dev/null @@ -1,227 +0,0 @@ -// 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. - -use ast; -use codemap::span; -use ext::base::ExtCtxt; -use ext::build::AstBuilder; -use ext::pipes::ast_builder::{append_types, path}; - -#[deriving(Eq)] -pub enum direction { send, recv } - -impl ToStr for direction { - fn to_str(&self) -> ~str { - match *self { - send => ~"Send", - recv => ~"Recv" - } - } -} - -impl direction { - pub fn reverse(&self) -> direction { - match *self { - send => recv, - recv => send - } - } -} - -#[deriving(Clone)] -pub struct next_state { - state: @str, - tys: ~[ast::Ty], -} - -// name, span, data, current state, next state -#[deriving(Clone)] -pub struct message(@str, span, ~[ast::Ty], state, Option<next_state>); - -impl message { - pub fn name(&mut self) -> @str { - match *self { - message(id, _, _, _, _) => id - } - } - - pub fn span(&mut self) -> span { - match *self { - message(_, span, _, _, _) => span - } - } - - /// Return the type parameters actually used by this message - pub fn get_generics(&self) -> ast::Generics { - match *self { - message(_, _, _, this, _) => this.generics.clone() - } - } -} - -pub type state = @state_; - -pub struct state_ { - id: uint, - name: @str, - ident: ast::ident, - span: span, - dir: direction, - generics: ast::Generics, - messages: @mut ~[message], - proto: protocol -} - -impl state_ { - pub fn add_message(@self, - name: @str, - span: span, - data: ~[ast::Ty], - next: Option<next_state>) { - self.messages.push(message(name, span, data, self, - next)); - } - - pub fn filename(&self) -> ~str { - self.proto.filename() - } - - pub fn data_name(&self) -> ast::ident { - self.ident - } - - /// Returns the type that is used for the messages. - pub fn to_ty(&self, cx: @ExtCtxt) -> ast::Ty { - cx.ty_path - (path(~[cx.ident_of(self.name)],self.span).add_tys( - cx.ty_vars(&self.generics.ty_params)), None) - } - - /// Iterate over the states that can be reached in one message - /// from this state. - pub fn reachable(&self, f: &fn(state) -> bool) -> bool { - foreach m in self.messages.iter() { - match *m { - message(_, _, _, _, Some(next_state { state: ref id, _ })) => { - let state = self.proto.get_state((*id)); - if !f(state) { return false; } - } - _ => () - } - } - return true; - } -} - -pub type protocol = @mut protocol_; - -pub fn protocol(name: @str, span: span) -> protocol { - @mut protocol_(name, span) -} - -pub fn protocol_(name: @str, span: span) -> protocol_ { - protocol_ { - name: name, - span: span, - states: @mut ~[], - bounded: None - } -} - -pub struct protocol_ { - name: @str, - span: span, - states: @mut ~[state], - - bounded: Option<bool>, -} - -impl protocol_ { - /// Get a state. - pub fn get_state(&self, name: &str) -> state { - let mut i = self.states.iter(); - *i.find_(|i| name == i.name).get() - } - - pub fn get_state_by_id(&self, id: uint) -> state { self.states[id] } - - pub fn has_state(&self, name: &str) -> bool { - self.states.iter().find_(|i| name == i.name).is_some() - } - - pub fn filename(&self) -> ~str { - ~"proto://" + self.name - } - - pub fn num_states(&self) -> uint { - let states = &mut *self.states; - states.len() - } - - pub fn has_ty_params(&self) -> bool { - foreach s in self.states.iter() { - if s.generics.ty_params.len() > 0 { - return true; - } - } - false - } - - pub fn is_bounded(&self) -> bool { - let bounded = self.bounded.get(); - bounded - } -} - -impl protocol_ { - pub fn add_state_poly(@mut self, - name: @str, - ident: ast::ident, - dir: direction, - generics: ast::Generics) - -> state { - let messages = @mut ~[]; - let states = &mut *self.states; - - let state = @state_ { - id: states.len(), - name: name, - ident: ident, - span: self.span, - dir: dir, - generics: generics, - messages: messages, - proto: self - }; - - states.push(state); - state - } -} - -pub trait visitor<Tproto, Tstate, Tmessage> { - fn visit_proto(&self, proto: protocol, st: &[Tstate]) -> Tproto; - fn visit_state(&self, state: state, m: &[Tmessage]) -> Tstate; - fn visit_message(&self, name: @str, spane: span, tys: &[ast::Ty], - this: state, next: Option<next_state>) -> Tmessage; -} - -pub fn visit<Tproto, Tstate, Tmessage, V: visitor<Tproto, Tstate, Tmessage>>( - proto: protocol, visitor: V) -> Tproto { - - let states: ~[Tstate] = do proto.states.iter().transform |&s| { - let messages: ~[Tmessage] = do s.messages.iter().transform |m| { - let message(name, span, tys, this, next) = (*m).clone(); - visitor.visit_message(name, span, tys, this, next) - }.collect(); - visitor.visit_state(s, messages) - }.collect(); - visitor.visit_proto(proto, states) -} diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index bcfd898dc6f..4e7b0612e64 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -683,7 +683,7 @@ fn expand_tts(cx: @ExtCtxt, // the site the string literal occurred, which was in a source file // _other_ than the one the user has control over. For example, an // error in a quote from the protocol compiler, invoked in user code - // using proto! for example, will be attributed to the pipec.rs file in + // using macro_rules! for example, will be attributed to the macro_rules.rs file in // libsyntax, which the user might not even have source to (unless they // happen to have a compiler on hand). Over all, the phase distinction // just makes quotes "hard to attribute". Possibly this could be fixed |
