Use three block form for the macro, fix some bugs, construct metadata tokens.

This commit is contained in:
Jimmy Cuadra 2017-05-13 01:16:44 -07:00
parent bf7189048a
commit d0a35341a2
3 changed files with 101 additions and 27 deletions

View File

@ -8,7 +8,7 @@ extern crate syn;
use proc_macro::TokenStream;
use quote::Tokens;
use quote::{ToTokens, Tokens};
use syn::{Expr, Field, Ident, Item};
use parse::{Entry, parse_entries};
@ -38,17 +38,26 @@ impl Api {
impl From<Vec<Entry>> for Api {
fn from(entries: Vec<Entry>) -> Api {
if entries.len() != 3 {
panic!("ruma_api! expects 3 blocks: metadata, request, and response");
}
let mut metadata = None;
let mut request = None;
let mut response = None;
for entry in entries {
match entry {
Entry::Metadata(fields) => metadata = Some(Metadata::from(fields)),
Entry::Request(fields) => request = Some(Request::from(fields)),
Entry::Response(fields) => response = Some(Response::from(fields)),
}
}
Api {
metadata: Metadata {
description: Tokens::new(),
method: Tokens::new(),
name: Tokens::new(),
path: Tokens::new(),
rate_limited: Tokens::new(),
requires_authentication: Tokens::new(),
},
request: Request,
response: Response,
metadata: metadata.expect("ruma_api! is missing metadata"),
request: request.expect("ruma_api! is missing request"),
response: response.expect("ruma_api! is missing response"),
}
}
}
@ -62,20 +71,68 @@ struct Metadata {
requires_authentication: Tokens,
}
impl From<Vec<(Ident, Expr)>> for Metadata {
fn from(fields: Vec<(Ident, Expr)>) -> Self {
let mut description = None;
let mut method = None;
let mut name = None;
let mut path = None;
let mut rate_limited = None;
let mut requires_authentication = None;
for field in fields {
let (identifier, expression) = field;
if identifier == Ident::new("description") {
description = Some(tokens_for(expression));
} else if identifier == Ident::new("method") {
method = Some(tokens_for(expression));
} else if identifier == Ident::new("name") {
name = Some(tokens_for(expression));
} else if identifier == Ident::new("path") {
path = Some(tokens_for(expression));
} else if identifier == Ident::new("rate_limited") {
rate_limited = Some(tokens_for(expression));
} else if identifier == Ident::new("requires_authentication") {
requires_authentication = Some(tokens_for(expression));
} else {
panic!("ruma_api! metadata included unexpected field: {}", identifier);
}
}
Metadata {
description: description.expect("ruma_api! metadata is missing description"),
method: method.expect("ruma_api! metadata is missing method"),
name: name.expect("ruma_api! metadata is missing name"),
path: path.expect("ruma_api! metadata is missing path"),
rate_limited: rate_limited.expect("ruma_api! metadata is missing rate_limited"),
requires_authentication: requires_authentication
.expect("ruma_api! metadata is missing requires_authentication"),
}
}
}
struct Request;
impl From<Item> for Request {
fn from(item: Item) -> Self {
impl From<Vec<Field>> for Request {
fn from(fields: Vec<Field>) -> Self {
Request
// panic!("ruma_api! could not parse Request");
}
}
struct Response;
impl From<Item> for Response {
fn from(item: Item) -> Self {
impl From<Vec<Field>> for Response {
fn from(fields: Vec<Field>) -> Self {
Response
// panic!("ruma_api! could not parse Response");
}
}
/// Helper method for turning a value into tokens.
fn tokens_for<T>(value: T) -> Tokens where T: ToTokens {
let mut tokens = Tokens::new();
value.to_tokens(&mut tokens);
tokens
}

View File

@ -16,6 +16,7 @@ use syn::{
use syn::parse::{expr, ident, lit, ty};
use synom::space::{block_comment, whitespace};
#[derive(Debug)]
pub enum Entry {
Metadata(Vec<(Ident, Expr)>),
Request(Vec<Field>),
@ -30,25 +31,25 @@ named!(pub parse_entries -> Vec<Entry>, do_parse!(
named!(entry -> Entry, alt!(
do_parse!(
keyword!("metadata") >>
punct!(":") >>
punct!("{") >>
fields: many0!(struct_init_field) >>
punct!("}") >>
(Entry::Metadata(fields))
)
|
do_parse!(
keyword!("request") >>
punct!(":") >>
punct!("{") >>
fields: many0!(struct_field) >>
fields: terminated_list!(punct!(","), struct_field) >>
punct!("}") >>
(Entry::Request(fields))
)
|
do_parse!(
keyword!("response") >>
punct!(":") >>
punct!("{") >>
fields: many0!(struct_field) >>
fields: terminated_list!(punct!(","), struct_field) >>
punct!("}") >>
(Entry::Response(fields))
)
));
@ -63,14 +64,22 @@ named!(struct_init_field -> (Ident, Expr), do_parse!(
(ident, expr)
));
named!(pub struct_like_body -> Vec<Field>, do_parse!(
punct!("{") >>
fields: terminated_list!(punct!(","), struct_field) >>
punct!("}") >>
(fields)
));
named!(struct_field -> Field, do_parse!(
attrs: many0!(outer_attr) >>
vis: visibility >>
id: ident >>
punct!(":") >>
ty: ty >>
(Field {
ident: Some(id),
vis: Visibility::Public,
vis: Visibility::Public, // Ignore declared visibility, always make fields public
attrs: attrs,
ty: ty,
})
@ -142,3 +151,9 @@ named!(nested_meta_item -> NestedMetaItem, alt!(
|
lit => { NestedMetaItem::Literal }
));
named!(visibility -> Visibility, alt!(
keyword!("pub") => { |_| Visibility::Public }
|
epsilon!() => { |_| Visibility::Inherited }
));

View File

@ -8,16 +8,18 @@ pub mod get_supported_versions {
use ruma_api_macros::ruma_api;
ruma_api! {
metadata: {
metadata {
description: "Get the versions of the client-server API supported by this homeserver.",
method: Method::Get,
name: "api_versions",
path: "/_matrix/client/versions",
rate_limited: false,
requires_authentication: true,
},
request: {},
response: {
}
request {}
response {
/// A list of Matrix client API protocol versions supported by the homeserver.
pub versions: Vec<String>,
}