mirror of https://github.com/rwf2/Rocket.git
Refactored parsing code into its own module.
This commit is contained in:
parent
3a89cb8e2b
commit
c7b1eebd20
|
@ -1,8 +1,7 @@
|
||||||
use utils::*;
|
use utils::*;
|
||||||
|
use meta_item_parser::MetaItemParser;
|
||||||
use super::{CATCH_STRUCT_PREFIX, CATCH_FN_PREFIX};
|
use super::{CATCH_STRUCT_PREFIX, CATCH_FN_PREFIX};
|
||||||
|
|
||||||
use route_decorator::get_fn_decl;
|
|
||||||
|
|
||||||
use syntax::codemap::{Span};
|
use syntax::codemap::{Span};
|
||||||
use syntax::ast::{MetaItem};
|
use syntax::ast::{MetaItem};
|
||||||
use syntax::ext::base::{Annotatable, ExtCtxt};
|
use syntax::ext::base::{Annotatable, ExtCtxt};
|
||||||
|
@ -16,7 +15,7 @@ struct Params {
|
||||||
code: KVSpanned<u16>,
|
code: KVSpanned<u16>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_error_params(ecx: &mut ExtCtxt, meta_item: &MetaItem) -> Params {
|
fn get_error_params(ecx: &ExtCtxt, meta_item: &MetaItem) -> Params {
|
||||||
// Ensure we've been supplied with a k = v meta item. Error out if not.
|
// Ensure we've been supplied with a k = v meta item. Error out if not.
|
||||||
let params = meta_item.expect_list(ecx, "Bad use. Expected: #[error(...)]");
|
let params = meta_item.expect_list(ecx, "Bad use. Expected: #[error(...)]");
|
||||||
|
|
||||||
|
@ -49,7 +48,9 @@ fn get_error_params(ecx: &mut ExtCtxt, meta_item: &MetaItem) -> Params {
|
||||||
|
|
||||||
pub fn error_decorator(ecx: &mut ExtCtxt, sp: Span, meta_item: &MetaItem,
|
pub fn error_decorator(ecx: &mut ExtCtxt, sp: Span, meta_item: &MetaItem,
|
||||||
annotated: &Annotatable, push: &mut FnMut(Annotatable)) {
|
annotated: &Annotatable, push: &mut FnMut(Annotatable)) {
|
||||||
let (item, _fn_decl) = get_fn_decl(ecx, sp, annotated);
|
let parser = MetaItemParser::new(ecx, meta_item, annotated, &sp);
|
||||||
|
let item = parser.expect_item();
|
||||||
|
|
||||||
let error_params = get_error_params(ecx, meta_item);
|
let error_params = get_error_params(ecx, meta_item);
|
||||||
debug!("Error parameters are: {:?}", error_params);
|
debug!("Error parameters are: {:?}", error_params);
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ mod errors_macro;
|
||||||
mod route_decorator;
|
mod route_decorator;
|
||||||
mod error_decorator;
|
mod error_decorator;
|
||||||
mod derive_form;
|
mod derive_form;
|
||||||
|
mod meta_item_parser;
|
||||||
|
|
||||||
use rustc_plugin::Registry;
|
use rustc_plugin::Registry;
|
||||||
use syntax::ext::base::SyntaxExtension;
|
use syntax::ext::base::SyntaxExtension;
|
||||||
|
@ -39,4 +40,6 @@ pub fn plugin_registrar(reg: &mut Registry) {
|
||||||
SyntaxExtension::MultiDecorator(Box::new(from_form_derive)));
|
SyntaxExtension::MultiDecorator(Box::new(from_form_derive)));
|
||||||
reg.register_macro("routes", routes_macro);
|
reg.register_macro("routes", routes_macro);
|
||||||
reg.register_macro("errors", errors_macro);
|
reg.register_macro("errors", errors_macro);
|
||||||
|
|
||||||
|
// reg.register_macro("GET", get_macro);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,211 @@
|
||||||
|
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;
|
||||||
|
|
||||||
|
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.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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<Item> {
|
||||||
|
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<FnDecl> = match item.node {
|
||||||
|
ItemKind::Fn(ref decl, _, _, _, _, _) => decl,
|
||||||
|
_ => bad_item("other")
|
||||||
|
};
|
||||||
|
|
||||||
|
span(fn_decl, item.span)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expect_list(&self) -> &'a Vec<P<MetaItem>> {
|
||||||
|
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<Spanned<&'s str>> {
|
||||||
|
// 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.len() == 0 {
|
||||||
|
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<Method>,
|
||||||
|
pub path: KVSpanned<String>,
|
||||||
|
pub form: Option<KVSpanned<String>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait RouteDecoratorExt {
|
||||||
|
fn bad_method(&self, sp: Span, message: &str);
|
||||||
|
fn parse_method(&self, default: Method) -> Spanned<Method>;
|
||||||
|
fn parse_route(&self, known_method: Option<Spanned<Method>>) -> RouteParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'c> RouteDecoratorExt for MetaItemParser<'a, 'c> {
|
||||||
|
fn bad_method(&self, sp: Span, message: &str) {
|
||||||
|
let message = format!("{} Valid methods are: [GET, PUT, POST, DELETE, \
|
||||||
|
OPTIONS, HEAD, TRACE, CONNECT, PATCH]", message);
|
||||||
|
self.ctxt.span_err(sp, message.as_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_method(&self, default: Method) -> Spanned<Method> {
|
||||||
|
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<Spanned<Method>>) -> 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; 1] = ["form"];
|
||||||
|
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").map_or(None, |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: \"<param>\"")
|
||||||
|
.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))
|
||||||
|
});
|
||||||
|
|
||||||
|
RouteParams {
|
||||||
|
method: method,
|
||||||
|
path: path,
|
||||||
|
form: form
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,11 +1,11 @@
|
||||||
use super::{ROUTE_STRUCT_PREFIX, ROUTE_FN_PREFIX};
|
use super::{ROUTE_STRUCT_PREFIX, ROUTE_FN_PREFIX};
|
||||||
use utils::*;
|
use utils::*;
|
||||||
|
use meta_item_parser::{MetaItemParser, RouteDecoratorExt};
|
||||||
|
|
||||||
use std::str::FromStr;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use syntax::codemap::{Span, BytePos, /* DUMMY_SP, */ Spanned};
|
use syntax::codemap::{Span, BytePos, /* DUMMY_SP, */ Spanned};
|
||||||
use syntax::ast::{Stmt, Item, Expr, ItemKind, MetaItem, MetaItemKind, FnDecl};
|
use syntax::ast::{Stmt, Expr, MetaItem, FnDecl};
|
||||||
use syntax::ext::base::{Annotatable, ExtCtxt};
|
use syntax::ext::base::{Annotatable, ExtCtxt};
|
||||||
use syntax::ptr::P;
|
use syntax::ptr::P;
|
||||||
use syntax::print::pprust::{item_to_string, stmt_to_string};
|
use syntax::print::pprust::{item_to_string, stmt_to_string};
|
||||||
|
@ -16,156 +16,16 @@ use rocket::Method;
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
const DEBUG: bool = true;
|
const DEBUG: bool = true;
|
||||||
|
|
||||||
struct Params {
|
pub fn extract_params_from_kv<'a>(parser: &MetaItemParser,
|
||||||
method: Spanned<Method>,
|
params: &'a KVSpanned<String>) -> Vec<Spanned<&'a str>> {
|
||||||
path: KVSpanned<String>,
|
|
||||||
form: Option<KVSpanned<String>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bad_item_fatal(ecx: &mut ExtCtxt, dec_sp: Span, i_sp: Span) -> ! {
|
|
||||||
ecx.span_err(dec_sp, "This decorator cannot be used on non-functions...");
|
|
||||||
ecx.span_fatal(i_sp, "...but it was used on the item below.")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bad_method_err(ecx: &mut ExtCtxt, dec_sp: Span, message: &str) -> Method {
|
|
||||||
let message = format!("{} Valid methods are: [GET, PUT, POST, DELETE, \
|
|
||||||
OPTIONS, HEAD, TRACE, CONNECT, PATCH]", message);
|
|
||||||
ecx.span_err(dec_sp, message.as_str());
|
|
||||||
Method::Get
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_fn_decl<'a>(ecx: &mut ExtCtxt, sp: Span, annotated: &'a Annotatable)
|
|
||||||
-> (&'a P<Item>, Spanned<&'a FnDecl>) {
|
|
||||||
// `annotated` is the AST object for the annotated item.
|
|
||||||
let item: &P<Item> = match *annotated {
|
|
||||||
Annotatable::Item(ref item) => item,
|
|
||||||
Annotatable::TraitItem(ref item) => bad_item_fatal(ecx, sp, item.span),
|
|
||||||
Annotatable::ImplItem(ref item) => bad_item_fatal(ecx, sp, item.span)
|
|
||||||
};
|
|
||||||
|
|
||||||
let fn_decl: &P<FnDecl> = match item.node {
|
|
||||||
ItemKind::Fn(ref decl, _, _, _, _, _) => decl,
|
|
||||||
_ => bad_item_fatal(ecx, sp, item.span)
|
|
||||||
};
|
|
||||||
|
|
||||||
(item, wrap_span(&*fn_decl, item.span))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parses the MetaItem derived from the route(...) macro.
|
|
||||||
fn parse_route(ecx: &mut ExtCtxt, meta_item: &MetaItem) -> Params {
|
|
||||||
// Ensure we've been supplied with a k = v meta item. Error out if not.
|
|
||||||
let params = meta_item.expect_list(ecx, "Bad use. Expected: #[route(...)]");
|
|
||||||
if params.len() < 1 {
|
|
||||||
bad_method_err(ecx, meta_item.span, "HTTP method parameter is missing.");
|
|
||||||
ecx.span_fatal(meta_item.span, "At least 2 arguments are required.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the method and the rest of the k = v params.
|
|
||||||
let (method_param, kv_params) = params.split_first().unwrap();
|
|
||||||
|
|
||||||
// Ensure method parameter is valid. If it's not, issue an error but use
|
|
||||||
// "GET" to continue parsing. method :: Spanned<Method>.
|
|
||||||
let method = if let MetaItemKind::Word(ref word) = method_param.node {
|
|
||||||
let method = Method::from_str(word).unwrap_or_else(|_| {
|
|
||||||
let message = format!("{} is not a valid method.", word);
|
|
||||||
bad_method_err(ecx, method_param.span, message.as_str())
|
|
||||||
});
|
|
||||||
|
|
||||||
Spanned { span: method_param.span, node: method }
|
|
||||||
} else {
|
|
||||||
let method = bad_method_err(ecx, method_param.span, "Invalid parameter. \
|
|
||||||
Expected a valid HTTP method at this position.");
|
|
||||||
dummy_span(method)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Now grab all of the required and optional parameters.
|
|
||||||
let req: [&'static str; 1] = ["path"];
|
|
||||||
let opt: [&'static str; 1] = ["form"];
|
|
||||||
let kv_pairs = get_key_values(ecx, 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").map_or(None, |f| {
|
|
||||||
if method.node != Method::Post {
|
|
||||||
ecx.span_err(f.p_span, "Use of `form` requires a POST method...");
|
|
||||||
let message = format!("...but {} was found instead.", method.node);
|
|
||||||
ecx.span_err(method_param.span, message.as_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
if !(f.node.starts_with('<') && f.node.ends_with('>')) {
|
|
||||||
ecx.struct_span_err(f.p_span, "`form` cannot contain arbitrary text")
|
|
||||||
.help("`form` must be exactly one parameter: \"<param>\"")
|
|
||||||
.emit();
|
|
||||||
}
|
|
||||||
|
|
||||||
if f.node.chars().filter(|c| *c == '<' || *c == '>').count() != 2 {
|
|
||||||
ecx.span_err(f.p_span, "`form` must contain exactly one parameter");
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(f.clone().map(String::from))
|
|
||||||
});
|
|
||||||
|
|
||||||
Params {
|
|
||||||
method: method,
|
|
||||||
path: path,
|
|
||||||
form: form
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Put something like this in the library. Maybe as an iterator?
|
|
||||||
pub fn extract_params<'a>(ecx: &ExtCtxt, params: &Spanned<&'a str>)
|
|
||||||
-> Vec<Spanned<&'a str>> {
|
|
||||||
let mut output_params = vec![];
|
|
||||||
let bad_match_err = "Parameter string is malformed.";
|
|
||||||
|
|
||||||
let mut start = 0;
|
|
||||||
let mut matching = false;
|
|
||||||
for (i, c) in params.node.char_indices() {
|
|
||||||
match c {
|
|
||||||
'<' if !matching => {
|
|
||||||
matching = true;
|
|
||||||
start = i;
|
|
||||||
},
|
|
||||||
'>' if matching => {
|
|
||||||
matching = false;
|
|
||||||
|
|
||||||
let mut param_span = params.span;
|
|
||||||
param_span.lo = params.span.lo + BytePos(start as u32);
|
|
||||||
param_span.hi = params.span.lo + BytePos((i + 1) as u32);
|
|
||||||
|
|
||||||
if i > start + 1 {
|
|
||||||
let param_name = ¶ms.node[(start + 1)..i];
|
|
||||||
output_params.push(wrap_span(param_name, param_span))
|
|
||||||
} else {
|
|
||||||
ecx.span_err(param_span, "Parameter names cannot be empty.");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'<' if matching => ecx.span_err(params.span, bad_match_err),
|
|
||||||
'>' if !matching => ecx.span_err(params.span, bad_match_err),
|
|
||||||
_ => { /* ... */ }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
output_params
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn extract_params_from_kv<'a>(ecx: &ExtCtxt, params: &'a KVSpanned<String>)
|
|
||||||
-> Vec<Spanned<&'a str>> {
|
|
||||||
let mut param_span = params.v_span;
|
let mut param_span = params.v_span;
|
||||||
param_span.lo = params.v_span.lo + BytePos(1);
|
param_span.lo = params.v_span.lo + BytePos(1);
|
||||||
extract_params(ecx, &Spanned {
|
let spanned = span(&*params.node, param_span);
|
||||||
span: param_span,
|
parser.iter_params(&spanned).collect()
|
||||||
node: &*params.node
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Analyzes the declared parameters against the function declaration. Returns
|
// Analyzes the declared parameters against the function declaration. Returns
|
||||||
// two vectors. The first is the set of parameters declared by the user, and
|
// a vector of all of the parameters in the order the user wants them.
|
||||||
// the second is the set of parameters not declared by the user.
|
|
||||||
fn get_fn_params<'a, T: Iterator<Item=&'a Spanned<&'a str>>>(ecx: &ExtCtxt,
|
fn get_fn_params<'a, T: Iterator<Item=&'a Spanned<&'a str>>>(ecx: &ExtCtxt,
|
||||||
declared_params: T, fn_decl: &Spanned<&FnDecl>)
|
declared_params: T, fn_decl: &Spanned<&FnDecl>)
|
||||||
-> Vec<UserParam> {
|
-> Vec<UserParam> {
|
||||||
|
@ -273,15 +133,16 @@ fn method_variant_to_expr(ecx: &ExtCtxt, method: Method) -> P<Expr> {
|
||||||
pub fn route_decorator(ecx: &mut ExtCtxt, sp: Span, meta_item: &MetaItem,
|
pub fn route_decorator(ecx: &mut ExtCtxt, sp: Span, meta_item: &MetaItem,
|
||||||
annotated: &Annotatable, push: &mut FnMut(Annotatable)) {
|
annotated: &Annotatable, push: &mut FnMut(Annotatable)) {
|
||||||
// Get the encompassing item and function declaration for the annotated func.
|
// Get the encompassing item and function declaration for the annotated func.
|
||||||
let (item, fn_decl) = get_fn_decl(ecx, sp, annotated);
|
let parser = MetaItemParser::new(ecx, meta_item, annotated, &sp);
|
||||||
|
let (item, fn_decl) = (parser.expect_item(), parser.expect_fn_decl());
|
||||||
|
|
||||||
// Parse and retrieve all of the parameters of the route.
|
// Parse and retrieve all of the parameters of the route.
|
||||||
let route = parse_route(ecx, meta_item);
|
let route = parser.parse_route(None);
|
||||||
|
|
||||||
// Get a list of the user declared parameters in `path` and `form`.
|
// Get a list of the user declared parameters in `path` and `form`.
|
||||||
let path_params = extract_params_from_kv(ecx, &route.path);
|
let path_params = extract_params_from_kv(&parser, &route.path);
|
||||||
let form_thing = route.form.unwrap_or_default(); // Default is empty string.
|
let form_thing = route.form.unwrap_or_default(); // Default is empty string.
|
||||||
let form_params = extract_params_from_kv(ecx, &form_thing);
|
let form_params = extract_params_from_kv(&parser, &form_thing);
|
||||||
|
|
||||||
// Ensure the params match the function declaration and return the params.
|
// Ensure the params match the function declaration and return the params.
|
||||||
let all_params = path_params.iter().chain(form_params.iter());
|
let all_params = path_params.iter().chain(form_params.iter());
|
||||||
|
|
|
@ -23,7 +23,7 @@ pub fn routes_macro(ecx: &mut ExtCtxt, _sp: Span, args: &[TokenTree])
|
||||||
|
|
||||||
// Build up the P<Expr> for each path.
|
// Build up the P<Expr> for each path.
|
||||||
let path_exprs: Vec<P<Expr>> = paths.iter().map(|p| {
|
let path_exprs: Vec<P<Expr>> = paths.iter().map(|p| {
|
||||||
quote_expr!(ecx, rocket::Route::from(&$p))
|
quote_expr!(ecx, ::rocket::Route::from(&$p))
|
||||||
}).collect();
|
}).collect();
|
||||||
|
|
||||||
// Now put them all in one vector and return the thing.
|
// Now put them all in one vector and return the thing.
|
||||||
|
|
|
@ -37,7 +37,7 @@ pub fn append_ident<T: ToString>(ident: &Ident, other: T) -> Ident {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn wrap_span<T>(t: T, span: Span) -> Spanned<T> {
|
pub fn span<T>(t: T, span: Span) -> Spanned<T> {
|
||||||
Spanned {
|
Spanned {
|
||||||
span: span,
|
span: span,
|
||||||
node: t,
|
node: t,
|
||||||
|
@ -95,7 +95,7 @@ impl<T> KVSpanned<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_key_values<'b>(ecx: &mut ExtCtxt, sp: Span, required: &[&str],
|
pub fn get_key_values<'b>(ecx: &ExtCtxt, sp: Span, required: &[&str],
|
||||||
optional: &[&str], kv_params: &'b [P<MetaItem>])
|
optional: &[&str], kv_params: &'b [P<MetaItem>])
|
||||||
-> HashMap<&'b str, KVSpanned<&'b str>> {
|
-> HashMap<&'b str, KVSpanned<&'b str>> {
|
||||||
let mut seen = HashSet::new();
|
let mut seen = HashSet::new();
|
||||||
|
@ -160,9 +160,21 @@ pub fn token_separate<T: ToTokens>(ecx: &ExtCtxt, things: &[T],
|
||||||
pub trait MetaItemExt {
|
pub trait MetaItemExt {
|
||||||
fn expect_list<'a>(&'a self, ecx: &ExtCtxt, msg: &str) -> &'a Vec<P<MetaItem>>;
|
fn expect_list<'a>(&'a self, ecx: &ExtCtxt, msg: &str) -> &'a Vec<P<MetaItem>>;
|
||||||
fn expect_word<'a>(&'a self, ecx: &ExtCtxt, msg: &str) -> &'a str;
|
fn expect_word<'a>(&'a self, ecx: &ExtCtxt, msg: &str) -> &'a str;
|
||||||
|
fn is_word(&self) -> bool;
|
||||||
|
fn name<'a>(&'a self) -> &'a str;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MetaItemExt for MetaItem {
|
impl MetaItemExt for MetaItem {
|
||||||
|
fn name<'a>(&'a self) -> &'a str {
|
||||||
|
let interned_name = match self.node {
|
||||||
|
MetaItemKind::Word(ref s) => s,
|
||||||
|
MetaItemKind::List(ref s, _) => s,
|
||||||
|
MetaItemKind::NameValue(ref s, _) => s
|
||||||
|
};
|
||||||
|
|
||||||
|
&*interned_name
|
||||||
|
}
|
||||||
|
|
||||||
fn expect_list<'a>(&'a self, ecx: &ExtCtxt, msg: &str) -> &'a Vec<P<MetaItem>> {
|
fn expect_list<'a>(&'a self, ecx: &ExtCtxt, msg: &str) -> &'a Vec<P<MetaItem>> {
|
||||||
match self.node {
|
match self.node {
|
||||||
MetaItemKind::List(_, ref params) => params,
|
MetaItemKind::List(_, ref params) => params,
|
||||||
|
@ -176,6 +188,13 @@ impl MetaItemExt for MetaItem {
|
||||||
_ => ecx.span_fatal(self.span, msg)
|
_ => ecx.span_fatal(self.span, msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_word(&self) -> bool {
|
||||||
|
match self.node {
|
||||||
|
MetaItemKind::Word(_) => true,
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait PatExt {
|
pub trait PatExt {
|
||||||
|
|
Loading…
Reference in New Issue