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 meta_item_parser::MetaItemParser;
|
||||
use super::{CATCH_STRUCT_PREFIX, CATCH_FN_PREFIX};
|
||||
|
||||
use route_decorator::get_fn_decl;
|
||||
|
||||
use syntax::codemap::{Span};
|
||||
use syntax::ast::{MetaItem};
|
||||
use syntax::ext::base::{Annotatable, ExtCtxt};
|
||||
|
@ -16,7 +15,7 @@ struct Params {
|
|||
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.
|
||||
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,
|
||||
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);
|
||||
debug!("Error parameters are: {:?}", error_params);
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ mod errors_macro;
|
|||
mod route_decorator;
|
||||
mod error_decorator;
|
||||
mod derive_form;
|
||||
mod meta_item_parser;
|
||||
|
||||
use rustc_plugin::Registry;
|
||||
use syntax::ext::base::SyntaxExtension;
|
||||
|
@ -39,4 +40,6 @@ pub fn plugin_registrar(reg: &mut Registry) {
|
|||
SyntaxExtension::MultiDecorator(Box::new(from_form_derive)));
|
||||
reg.register_macro("routes", routes_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 utils::*;
|
||||
use meta_item_parser::{MetaItemParser, RouteDecoratorExt};
|
||||
|
||||
use std::str::FromStr;
|
||||
use std::collections::HashMap;
|
||||
|
||||
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::ptr::P;
|
||||
use syntax::print::pprust::{item_to_string, stmt_to_string};
|
||||
|
@ -16,156 +16,16 @@ use rocket::Method;
|
|||
#[allow(dead_code)]
|
||||
const DEBUG: bool = true;
|
||||
|
||||
struct Params {
|
||||
method: Spanned<Method>,
|
||||
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>> {
|
||||
pub fn extract_params_from_kv<'a>(parser: &MetaItemParser,
|
||||
params: &'a KVSpanned<String>) -> Vec<Spanned<&'a str>> {
|
||||
let mut param_span = params.v_span;
|
||||
param_span.lo = params.v_span.lo + BytePos(1);
|
||||
extract_params(ecx, &Spanned {
|
||||
span: param_span,
|
||||
node: &*params.node
|
||||
})
|
||||
let spanned = span(&*params.node, param_span);
|
||||
parser.iter_params(&spanned).collect()
|
||||
}
|
||||
|
||||
// Analyzes the declared parameters against the function declaration. Returns
|
||||
// two vectors. The first is the set of parameters declared by the user, and
|
||||
// the second is the set of parameters not declared by the user.
|
||||
// a vector of all of the parameters in the order the user wants them.
|
||||
fn get_fn_params<'a, T: Iterator<Item=&'a Spanned<&'a str>>>(ecx: &ExtCtxt,
|
||||
declared_params: T, fn_decl: &Spanned<&FnDecl>)
|
||||
-> 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,
|
||||
annotated: &Annotatable, push: &mut FnMut(Annotatable)) {
|
||||
// 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.
|
||||
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`.
|
||||
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_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.
|
||||
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.
|
||||
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();
|
||||
|
||||
// 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]
|
||||
pub fn wrap_span<T>(t: T, span: Span) -> Spanned<T> {
|
||||
pub fn span<T>(t: T, span: Span) -> Spanned<T> {
|
||||
Spanned {
|
||||
span: span,
|
||||
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>])
|
||||
-> HashMap<&'b str, KVSpanned<&'b str>> {
|
||||
let mut seen = HashSet::new();
|
||||
|
@ -160,9 +160,21 @@ pub fn token_separate<T: ToTokens>(ecx: &ExtCtxt, things: &[T],
|
|||
pub trait MetaItemExt {
|
||||
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 is_word(&self) -> bool;
|
||||
fn name<'a>(&'a self) -> &'a str;
|
||||
}
|
||||
|
||||
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>> {
|
||||
match self.node {
|
||||
MetaItemKind::List(_, ref params) => params,
|
||||
|
@ -176,6 +188,13 @@ impl MetaItemExt for MetaItem {
|
|||
_ => ecx.span_fatal(self.span, msg)
|
||||
}
|
||||
}
|
||||
|
||||
fn is_word(&self) -> bool {
|
||||
match self.node {
|
||||
MetaItemKind::Word(_) => true,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PatExt {
|
||||
|
|
Loading…
Reference in New Issue