diff --git a/macros/src/parser/meta_item_parser.rs b/macros/src/parser/meta_item_parser.rs deleted file mode 100644 index 5a08fe04..00000000 --- a/macros/src/parser/meta_item_parser.rs +++ /dev/null @@ -1,246 +0,0 @@ -use std::str::FromStr; - -use syntax::ext::base::{Annotatable, ExtCtxt}; -use syntax::ast::{Item, ItemKind, MetaItem, FnDecl}; -use syntax::codemap::{Span, Spanned, BytePos}; -use syntax::ptr::P; - -use utils::*; -use rocket::{Method, ContentType}; - -pub struct MetaItemParser<'a, 'c: 'a> { - attr_name: &'a str, - ctxt: &'a ExtCtxt<'c>, - meta_item: &'a MetaItem, - annotated: &'a Annotatable, - span: Span -} - -pub struct ParamIter<'s, 'a, 'c: 'a> { - ctxt: &'a ExtCtxt<'c>, - span: Span, - string: &'s str -} - -impl<'a, 'c> MetaItemParser<'a, 'c> { - pub fn new(ctxt: &'a ExtCtxt<'c>, meta_item: &'a MetaItem, - annotated: &'a Annotatable, span: &'a Span) -> MetaItemParser<'a, 'c> { - MetaItemParser { - attr_name: meta_item.name(), - ctxt: ctxt, - meta_item: meta_item, - annotated: annotated, - span: *span, - } - } - - fn bad_item(&self, expected: &str, got: &str, sp: Span) -> ! { - let msg_a = format!("Expected a {} item...", expected); - let msg_b = format!("...but found a {} item instead.", got); - self.ctxt.span_err(self.span, msg_a.as_str()); - self.ctxt.span_fatal(sp, msg_b.as_str()) - } - - - pub fn expect_item(&self) -> &'a P { - let bad_item = |name: &str, sp: Span| self.bad_item("regular", name, sp); - - match *self.annotated { - Annotatable::Item(ref item) => item, - Annotatable::TraitItem(ref item) => bad_item("trait", item.span), - Annotatable::ImplItem(ref item) => bad_item("impl", item.span) - } - } - - pub fn expect_fn_decl(&self) -> Spanned<&'a FnDecl> { - let item = self.expect_item(); - let bad_item = |name: &str| self.bad_item("fn_decl", name, item.span); - - let fn_decl: &P = match item.node { - ItemKind::Fn(ref decl, _, _, _, _, _) => decl, - _ => bad_item("other") - }; - - span(fn_decl, item.span) - } - - fn expect_list(&self) -> &'a Vec> { - let msg = format!("Bad use. Expected: #[{}(...)]", self.attr_name); - self.meta_item.expect_list(self.ctxt, msg.as_str()) - } - - pub fn iter_params<'s>(&self, from: &Spanned<&'s str>) -> ParamIter<'s, 'a, 'c> { - ParamIter { - ctxt: self.ctxt, - span: from.span, - string: from.node - } - } -} - -impl<'s, 'a, 'c> Iterator for ParamIter<'s, 'a, 'c> { - type Item = Spanned<&'s str>; - - fn next(&mut self) -> Option> { - // Find the start and end indexes for the next parameter, if any. - let (start, end) = match (self.string.find('<'), self.string.find('>')) { - (Some(i), Some(j)) => (i, j), - _ => return None - }; - - // Ensure we found a valid parameter. - if end <= start { - self.ctxt.span_err(self.span, "Parameter list is malformed."); - return None; - } - - // Calculate the parameter and the span for the parameter. - let param = &self.string[(start + 1)..end]; - let mut param_span = self.span; - param_span.lo = self.span.lo + BytePos(start as u32); - param_span.hi = self.span.lo + BytePos((end + 1) as u32); - - // Check for nonemptiness and that the characters are correct. - if param.is_empty() { - self.ctxt.span_err(param_span, "Parameter names cannot be empty."); - None - } else if param.contains(|c: char| !c.is_alphanumeric()) { - self.ctxt.span_err(param_span, "Parameters must be alphanumeric."); - None - } else { - self.string = &self.string[(end + 1)..]; - self.span.lo = self.span.lo + BytePos((end + 1) as u32); - Some(span(param, param_span)) - } - } -} - -pub struct RouteParams { - pub method: Spanned, - pub path: KVSpanned, - pub form: Option>, - pub content_type: KVSpanned, - pub rank: Option>, -} - -pub trait RouteDecoratorExt { - fn bad_method(&self, sp: Span, message: &str); - fn parse_method(&self, default: Method) -> Spanned; - fn parse_route(&self, known_method: Option>) -> RouteParams; -} - -impl<'a, 'c> RouteDecoratorExt for MetaItemParser<'a, 'c> { - fn bad_method(&self, sp: Span, message: &str) { - let message = format!("{} {}", message, - "Valid methods are: [GET, PUT, POST, DELETE, PATCH]"); - self.ctxt.span_err(sp, message.as_str()); - } - - fn parse_method(&self, default: Method) -> Spanned { - let params = self.expect_list(); - if params.len() < 1 { - self.bad_method(self.span, "HTTP method parameter is missing."); - self.ctxt.span_fatal(self.span, "At least 2 arguments are required."); - } - - // Get the method and the rest of the k = v params. - let method_param = params.first().unwrap(); - - // Check that the method parameter is a word (i.e, not a list, k/v pair). - if !method_param.is_word() { - self.bad_method(method_param.span, - "Expected a valid HTTP method at this position."); - return dummy_span(default); - } - - // Parse the method from the string. If bad, error and return default. - Method::from_str(method_param.name()).ok().map_or_else(|| { - let message = format!("{} is not a valid method.", method_param.name()); - self.bad_method(method_param.span, message.as_str()); - dummy_span(default) - }, |method| span(method, method_param.span)) - } - - // Parses the MetaItem derived from the route(...) macro. - fn parse_route(&self, known_method: Option>) -> RouteParams { - let list = self.expect_list(); - let (method, kv_params) = match known_method { - Some(method) => (method, &list[..]), - None => (self.parse_method(Method::Get), list.split_first().unwrap().1) - }; - - // Now grab all of the required and optional parameters. - let req: [&'static str; 1] = ["path"]; - let opt: [&'static str; 3] = ["form", "content", "rank"]; - let kv_pairs = get_key_values(self.ctxt, self.meta_item.span, - &req, &opt, kv_params); - - // Ensure we have a path, just to keep parsing and generating errors. - let path = kv_pairs.get("path").map_or(KVSpanned::dummy("/".to_string()), |s| { - s.clone().map(String::from) - }); - - // If there's a form parameter, ensure method is POST. - let form = kv_pairs.get("form").and_then(|f| { - if method.node != Method::Post { - self.ctxt.span_err(f.p_span, "Use of `form` requires POST method..."); - let message = format!("...but {} was found instead.", method.node); - self.ctxt.span_err(method.span, message.as_str()); - } - - if !(f.node.starts_with('<') && f.node.ends_with('>')) { - self.ctxt.struct_span_err(f.p_span, - "`form` cannot contain arbitrary text") - .help("`form` must be exactly one parameter: \"\"") - .emit(); - } - - if f.node.chars().filter(|c| *c == '<' || *c == '>').count() != 2 { - self.ctxt.span_err(f.p_span, - "`form` must contain exactly one parameter"); - } - - Some(f.clone().map(String::from)) - }); - - let content_type = kv_pairs.get("content").and_then(|data| { - debug!("Found data: {:?}", data); - if let Ok(ct) = ContentType::from_str(data.node) { - if ct.is_ext() { - let msg = format!("'{}' is not a known content-type", data.node); - self.ctxt.span_warn(data.v_span, &msg); - } - - Some(data.clone().map(|_| ct)) - } else { - let msg = format!("'{}' is not a valid content-type", data.node); - self.ctxt.span_err(data.v_span, &msg); - None - } - }).unwrap_or_else(|| KVSpanned::dummy(ContentType::any())); - - let rank = kv_pairs.get("rank").and_then(|data| { - debug!("Found data: {:?}", data); - if let Ok(rank) = isize::from_str(data.node) { - if rank < 0 { - self.ctxt.span_err(data.v_span, "rank must be nonnegative"); - None - } else { - Some(data.clone().map(|_| rank)) - } - } else { - self.ctxt.span_err(data.v_span, "rank value must be an integer"); - None - } - }); - - RouteParams { - method: method, - path: path, - form: form, - content_type: content_type, - rank: rank - } - } - -} diff --git a/macros/src/utils/pat_ext.rs b/macros/src/utils/pat_ext.rs deleted file mode 100644 index beb7f5d8..00000000 --- a/macros/src/utils/pat_ext.rs +++ /dev/null @@ -1,28 +0,0 @@ -use syntax::ast::{Pat, PatKind, Ident}; -use syntax::parse::token; -use syntax::codemap::DUMMY_SP; -use syntax::tokenstream::TokenTree; -use syntax::ext::quote::rt::ToTokens; -use syntax::ext::base::ExtCtxt; -use syntax::ptr::P; - -pub trait PatExt { - fn named(&self, name: &str) -> bool; - fn ident(&self) -> Option<&Ident>; -} - -impl PatExt for Pat { - fn named(&self, name: &str) -> bool { - match self.node { - PatKind::Ident(_, ref ident, _) => ident.node.name.as_str() == name, - _ => false, - } - } - - fn ident(&self) -> Option<&Ident> { - match self.node { - PatKind::Ident(_, ref ident, _) => Some(&ident.node), - _ => None, - } - } -}