Remove 'proc_macro' features.

This commit is contained in:
Sergio Benitez 2019-09-21 13:36:57 -07:00
parent 7bcf82a199
commit 3f2b8f6006
25 changed files with 243 additions and 215 deletions

View File

@ -20,7 +20,7 @@ proc-macro = true
[dependencies]
quote = "1.0"
devise = { git = "https://github.com/SergioBenitez/Devise.git", rev = "e58b3ac9a" }
devise = { git = "https://github.com/SergioBenitez/Devise.git", rev = "57d6eb80" }
[build-dependencies]
yansi = "0.5"

View File

@ -1,5 +1,6 @@
use proc_macro::TokenStream;
use devise::{Spanned, Result};
use devise::{Spanned, Result, ext::SpanDiagnosticExt};
use crate::syn::{DataStruct, Fields, Data, Type, LitStr, DeriveInput, Ident, Visibility};
#[derive(Debug)]

View File

@ -1,4 +1,3 @@
#![feature(proc_macro_diagnostic)]
#![recursion_limit="256"]
#![warn(rust_2018_idioms)]
@ -42,8 +41,6 @@ use proc_macro::TokenStream;
#[cfg(feature = "database_attribute")]
#[proc_macro_attribute]
pub fn database(attr: TokenStream, input: TokenStream) -> TokenStream {
crate::database::database_attr(attr, input).unwrap_or_else(|diag| {
diag.emit();
TokenStream::new()
})
crate::database::database_attr(attr, input)
.unwrap_or_else(|diag| diag.emit_as_tokens().into())
}

View File

@ -19,7 +19,7 @@ proc-macro = true
indexmap = "1.0"
quote = "1.0"
rocket_http = { version = "0.5.0-dev", path = "../http/" }
devise = { git = "https://github.com/SergioBenitez/Devise.git", rev = "e58b3ac9a" }
devise = { git = "https://github.com/SergioBenitez/Devise.git", rev = "17f647e" }
glob = "0.3"
[build-dependencies]

View File

@ -1,15 +1,13 @@
use proc_macro::{TokenStream, Span};
use devise::{syn, Spanned, Result};
use crate::proc_macro2::TokenStream as TokenStream2;
use crate::syn_ext::syn_to_diag;
use devise::{syn, Diagnostic, Spanned, Result};
use devise::ext::SpanDiagnosticExt;
use devise::proc_macro2::{TokenStream, Span};
trait EntryAttr {
/// Whether the attribute requires the attributed function to be `async`.
const REQUIRES_ASYNC: bool;
/// Return a new or rewritten function, using block as the main execution.
fn function(f: &syn::ItemFn, body: &syn::Block) -> Result<TokenStream2>;
fn function(f: &syn::ItemFn, body: &syn::Block) -> Result<TokenStream>;
}
struct Main;
@ -17,13 +15,12 @@ struct Main;
impl EntryAttr for Main {
const REQUIRES_ASYNC: bool = true;
fn function(f: &syn::ItemFn, block: &syn::Block) -> Result<TokenStream2> {
fn function(f: &syn::ItemFn, block: &syn::Block) -> Result<TokenStream> {
let (attrs, vis, mut sig) = (&f.attrs, &f.vis, f.sig.clone());
if sig.ident != "main" {
Span::call_site()
return Err(Span::call_site()
.warning("attribute is typically applied to `main` function")
.span_note(sig.span(), "this function is not `main`")
.emit();
.span_note(sig.span(), "this function is not `main`"));
}
sig.asyncness = None;
@ -38,7 +35,7 @@ struct Test;
impl EntryAttr for Test {
const REQUIRES_ASYNC: bool = true;
fn function(f: &syn::ItemFn, block: &syn::Block) -> Result<TokenStream2> {
fn function(f: &syn::ItemFn, block: &syn::Block) -> Result<TokenStream> {
let (attrs, vis, mut sig) = (&f.attrs, &f.vis, f.sig.clone());
sig.asyncness = None;
Ok(quote_spanned!(block.span().into() => #(#attrs)* #[test] #vis #sig {
@ -52,7 +49,7 @@ struct Launch;
impl EntryAttr for Launch {
const REQUIRES_ASYNC: bool = false;
fn function(f: &syn::ItemFn, block: &syn::Block) -> Result<TokenStream2> {
fn function(f: &syn::ItemFn, block: &syn::Block) -> Result<TokenStream> {
if f.sig.ident == "main" {
return Err(Span::call_site()
.error("attribute cannot be applied to `main` function")
@ -89,9 +86,9 @@ impl EntryAttr for Launch {
}
}
fn parse_input<A: EntryAttr>(input: TokenStream) -> Result<syn::ItemFn> {
fn parse_input<A: EntryAttr>(input: proc_macro::TokenStream) -> Result<syn::ItemFn> {
let function: syn::ItemFn = syn::parse(input)
.map_err(syn_to_diag)
.map_err(Diagnostic::from)
.map_err(|d| d.help("attribute can only be applied to functions"))?;
if A::REQUIRES_ASYNC && function.sig.asyncness.is_none() {
@ -109,19 +106,26 @@ fn parse_input<A: EntryAttr>(input: TokenStream) -> Result<syn::ItemFn> {
Ok(function)
}
fn _async_entry<A: EntryAttr>(_args: TokenStream, input: TokenStream) -> Result<TokenStream> {
fn _async_entry<A: EntryAttr>(
_args: proc_macro::TokenStream,
input: proc_macro::TokenStream
) -> Result<TokenStream> {
let function = parse_input::<A>(input)?;
A::function(&function, &function.block).map(|t| t.into())
}
pub fn async_test_attribute(args: TokenStream, input: TokenStream) -> TokenStream {
_async_entry::<Test>(args, input).unwrap_or_else(|d| { d.emit(); TokenStream::new() })
macro_rules! async_entry {
($name:ident, $kind:ty, $default:expr) => (
pub fn $name(a: proc_macro::TokenStream, i: proc_macro::TokenStream) -> TokenStream {
_async_entry::<$kind>(a, i).unwrap_or_else(|d| {
let d = d.emit_as_tokens();
let default = $default;
quote!(#d #default)
})
}
)
}
pub fn main_attribute(args: TokenStream, input: TokenStream) -> TokenStream {
_async_entry::<Main>(args, input).unwrap_or_else(|d| { d.emit(); quote!(fn main() {}).into() })
}
pub fn launch_attribute(args: TokenStream, input: TokenStream) -> TokenStream {
_async_entry::<Launch>(args, input).unwrap_or_else(|d| { d.emit(); quote!(fn main() {}).into() })
}
async_entry!(async_test_attribute, Test, quote!());
async_entry!(main_attribute, Main, quote!(fn main() {}));
async_entry!(launch_attribute, Launch, quote!(fn main() {}));

View File

@ -1,9 +1,9 @@
use proc_macro::{TokenStream, Span};
use devise::{syn, Spanned, Result, FromMeta};
use crate::proc_macro2::TokenStream as TokenStream2;
use devise::{syn, Spanned, Result, FromMeta, Diagnostic};
use devise::ext::SpanDiagnosticExt;
use crate::proc_macro2::{TokenStream, Span};
use crate::http_codegen::Status;
use crate::syn_ext::{syn_to_diag, IdentExt, ReturnTypeExt, TokenStreamExt};
use crate::syn_ext::{IdentExt, ReturnTypeExt, TokenStreamExt};
use self::syn::{Attribute, parse::Parser};
use crate::{CATCH_FN_PREFIX, CATCH_STRUCT_PREFIX};
@ -22,12 +22,16 @@ struct CatchParams {
function: syn::ItemFn,
}
fn parse_params(args: TokenStream2, input: TokenStream) -> Result<CatchParams> {
let function: syn::ItemFn = syn::parse(input).map_err(syn_to_diag)
fn parse_params(
args: TokenStream,
input: proc_macro::TokenStream
) -> Result<CatchParams> {
let function: syn::ItemFn = syn::parse(input)
.map_err(Diagnostic::from)
.map_err(|diag| diag.help("`#[catch]` can only be used on functions"))?;
let full_attr = quote!(#[catch(#args)]);
let attrs = Attribute::parse_outer.parse2(full_attr).map_err(syn_to_diag)?;
let attrs = Attribute::parse_outer.parse2(full_attr)?;
let attribute = match CatchAttribute::from_attrs("catch", &attrs) {
Some(result) => result.map_err(|d| {
d.help("`#[catch]` expects a single status integer, e.g.: #[catch(404)]")
@ -38,9 +42,12 @@ fn parse_params(args: TokenStream2, input: TokenStream) -> Result<CatchParams> {
Ok(CatchParams { status: attribute.status, function })
}
pub fn _catch(args: TokenStream, input: TokenStream) -> Result<TokenStream> {
pub fn _catch(
args: proc_macro::TokenStream,
input: proc_macro::TokenStream
) -> Result<TokenStream> {
// Parse and validate all of the user's input.
let catch = parse_params(TokenStream2::from(args), input)?;
let catch = parse_params(args.into(), input)?;
// Gather everything we'll need to generate the catcher.
let user_catcher_fn = &catch.function;
@ -124,9 +131,12 @@ pub fn _catch(args: TokenStream, input: TokenStream) -> Result<TokenStream> {
code: #status_code,
handler: #generated_fn_name,
};
}.into())
})
}
pub fn catch_attribute(args: TokenStream, input: TokenStream) -> TokenStream {
_catch(args, input).unwrap_or_else(|d| { d.emit(); TokenStream::new() })
pub fn catch_attribute(
args: proc_macro::TokenStream,
input: proc_macro::TokenStream
) -> TokenStream {
_catch(args, input).unwrap_or_else(|d| d.emit_as_tokens())
}

View File

@ -2,17 +2,17 @@ use std::sync::atomic::{AtomicUsize, Ordering};
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
use proc_macro::{TokenStream, Span};
use crate::proc_macro2::TokenStream as TokenStream2;
use devise::{syn, Spanned, SpanWrapped, Result, FromMeta, ext::TypeExt};
use devise::{syn, Spanned, SpanWrapped, Result, FromMeta, Diagnostic};
use devise::ext::{SpanDiagnosticExt, TypeExt};
use indexmap::IndexSet;
use crate::proc_macro_ext::{Diagnostics, StringLit};
use crate::syn_ext::{syn_to_diag, IdentExt};
use self::syn::{Attribute, parse::Parser};
use crate::syn_ext::IdentExt;
use crate::proc_macro2::{TokenStream, Span};
use crate::http_codegen::{Method, MediaType, RoutePath, DataSegment, Optional};
use crate::attribute::segments::{Source, Kind, Segment};
use crate::syn::{Attribute, parse::Parser};
use crate::{ROUTE_FN_PREFIX, ROUTE_STRUCT_PREFIX, URI_MACRO_PREFIX, ROCKET_PARAM_PREFIX};
/// The raw, parsed `#[route]` attribute.
@ -59,9 +59,10 @@ fn parse_route(attr: RouteAttribute, function: syn::ItemFn) -> Result<Route> {
if let Some(ref data) = attr.data {
if !attr.method.0.supports_payload() {
let msg = format!("'{}' does not typically support payloads", attr.method.0);
// FIXME(diag: warning)
data.full_span.warning("`data` used with non-payload-supporting method")
.span_note(attr.method.span, msg)
.emit()
.emit_as_tokens();
}
}
@ -127,10 +128,10 @@ fn parse_route(attr: RouteAttribute, function: syn::ItemFn) -> Result<Route> {
diags.head_err_or(Route { attribute: attr, function, inputs, segments })
}
fn param_expr(seg: &Segment, ident: &syn::Ident, ty: &syn::Type) -> TokenStream2 {
fn param_expr(seg: &Segment, ident: &syn::Ident, ty: &syn::Type) -> TokenStream {
define_vars_and_mods!(req, data, error, log, request, _None, _Some, _Ok, _Err, Outcome);
let i = seg.index.expect("dynamic parameters must be indexed");
let span = ident.span().unstable().join(ty.span()).unwrap().into();
let span = ident.span().join(ty.span()).unwrap_or_else(|| ty.span());
let name = ident.to_string();
// All dynamic parameter should be found if this function is being called;
@ -175,9 +176,9 @@ fn param_expr(seg: &Segment, ident: &syn::Ident, ty: &syn::Type) -> TokenStream2
}
}
fn data_expr(ident: &syn::Ident, ty: &syn::Type) -> TokenStream2 {
fn data_expr(ident: &syn::Ident, ty: &syn::Type) -> TokenStream {
define_vars_and_mods!(req, data, FromTransformedData, Outcome, Transform);
let span = ident.span().unstable().join(ty.span()).unwrap().into();
let span = ident.span().join(ty.span()).unwrap_or_else(|| ty.span());
quote_spanned! { span =>
let __transform = <#ty as #FromTransformedData>::transform(#req, #data).await;
@ -204,7 +205,7 @@ fn data_expr(ident: &syn::Ident, ty: &syn::Type) -> TokenStream2 {
}
}
fn query_exprs(route: &Route) -> Option<TokenStream2> {
fn query_exprs(route: &Route) -> Option<TokenStream> {
define_vars_and_mods!(_None, _Some, _Ok, _Err, _Option);
define_vars_and_mods!(data, trail, log, request, req, Outcome, SmallVec, Query);
let query_segments = route.attribute.path.query.as_ref()?;
@ -217,7 +218,7 @@ fn query_exprs(route: &Route) -> Option<TokenStream2> {
.map(|(_, rocket_ident, ty)| (rocket_ident, ty))
.unwrap();
let span = ident.span().unstable().join(ty.span()).unwrap();
let span = ident.span().join(ty.span()).unwrap_or_else(|| ty.span());
(Some(ident), Some(ty), span.into())
} else {
(None, None, segment.span.into())
@ -309,9 +310,9 @@ fn query_exprs(route: &Route) -> Option<TokenStream2> {
})
}
fn request_guard_expr(ident: &syn::Ident, ty: &syn::Type) -> TokenStream2 {
fn request_guard_expr(ident: &syn::Ident, ty: &syn::Type) -> TokenStream {
define_vars_and_mods!(req, data, request, Outcome);
let span = ident.span().unstable().join(ty.span()).unwrap().into();
let span = ident.span().join(ty.span()).unwrap_or_else(|| ty.span());
quote_spanned! { span =>
#[allow(non_snake_case, unreachable_patterns, unreachable_code)]
let #ident: #ty = match <#ty as #request::FromRequest>::from_request(#req).await {
@ -322,7 +323,7 @@ fn request_guard_expr(ident: &syn::Ident, ty: &syn::Type) -> TokenStream2 {
}
}
fn generate_internal_uri_macro(route: &Route) -> TokenStream2 {
fn generate_internal_uri_macro(route: &Route) -> TokenStream {
// Keep a global counter (+ thread ID later) to generate unique ids.
static COUNTER: AtomicUsize = AtomicUsize::new(0);
@ -344,7 +345,7 @@ fn generate_internal_uri_macro(route: &Route) -> TokenStream2 {
let inner_generated_macro_name = generated_macro_name.append(&hasher.finish().to_string());
let route_uri = route.attribute.path.origin.0.to_string();
quote! {
quote_spanned! { Span::call_site() =>
#[doc(hidden)]
#[macro_export]
macro_rules! #inner_generated_macro_name {
@ -360,7 +361,7 @@ fn generate_internal_uri_macro(route: &Route) -> TokenStream2 {
}
}
fn generate_respond_expr(route: &Route) -> TokenStream2 {
fn generate_respond_expr(route: &Route) -> TokenStream {
let ret_span = match route.function.sig.output {
syn::ReturnType::Default => route.function.sig.ident.span(),
syn::ReturnType::Type(_, ref ty) => ty.span().into()
@ -460,12 +461,13 @@ fn codegen_route(route: Route) -> Result<TokenStream> {
}.into())
}
fn complete_route(args: TokenStream2, input: TokenStream) -> Result<TokenStream> {
let function: syn::ItemFn = syn::parse(input).map_err(syn_to_diag)
fn complete_route(args: TokenStream, input: TokenStream) -> Result<TokenStream> {
let function: syn::ItemFn = syn::parse2(input)
.map_err(|e| Diagnostic::from(e))
.map_err(|diag| diag.help("`#[route]` can only be used on functions"))?;
let full_attr = quote!(#[route(#args)]);
let attrs = Attribute::parse_outer.parse2(full_attr).map_err(syn_to_diag)?;
let attrs = Attribute::parse_outer.parse2(full_attr)?;
let attribute = match RouteAttribute::from_attrs("route", &attrs) {
Some(result) => result?,
None => return Err(Span::call_site().error("internal error: bad attribute"))
@ -476,7 +478,7 @@ fn complete_route(args: TokenStream2, input: TokenStream) -> Result<TokenStream>
fn incomplete_route(
method: crate::http::Method,
args: TokenStream2,
args: TokenStream,
input: TokenStream
) -> Result<TokenStream> {
let method_str = method.to_string().to_lowercase();
@ -486,11 +488,12 @@ fn incomplete_route(
let method_ident = syn::Ident::new(&method_str, method_span.into());
let function: syn::ItemFn = syn::parse(input).map_err(syn_to_diag)
let function: syn::ItemFn = syn::parse2(input)
.map_err(|e| Diagnostic::from(e))
.map_err(|d| d.help(format!("#[{}] can only be used on functions", method_str)))?;
let full_attr = quote!(#[#method_ident(#args)]);
let attrs = Attribute::parse_outer.parse2(full_attr).map_err(syn_to_diag)?;
let attrs = Attribute::parse_outer.parse2(full_attr)?;
let method_attribute = match MethodRouteAttribute::from_attrs(&method_str, &attrs) {
Some(result) => result?,
None => return Err(Span::call_site().error("internal error: bad attribute"))
@ -511,13 +514,13 @@ fn incomplete_route(
pub fn route_attribute<M: Into<Option<crate::http::Method>>>(
method: M,
args: TokenStream,
input: TokenStream
args: proc_macro::TokenStream,
input: proc_macro::TokenStream
) -> TokenStream {
let result = match method.into() {
Some(method) => incomplete_route(method, args.into(), input),
None => complete_route(args.into(), input)
Some(method) => incomplete_route(method, args.into(), input.into()),
None => complete_route(args.into(), input.into())
};
result.unwrap_or_else(|diag| { diag.emit(); TokenStream::new() })
result.unwrap_or_else(|diag| diag.emit_as_tokens())
}

View File

@ -1,7 +1,7 @@
use std::hash::{Hash, Hasher};
use devise::syn;
use proc_macro::{Span, Diagnostic};
use devise::{syn, Diagnostic, ext::SpanDiagnosticExt};
use crate::proc_macro2::Span;
use crate::http::uri::{UriPart, Path};
use crate::http::route::RouteSegment;
@ -36,7 +36,7 @@ impl From<&syn::Ident> for Segment {
Segment {
kind: Kind::Static,
source: Source::Unknown,
span: ident.span().unstable(),
span: ident.span(),
name: ident.to_string(),
index: None,
}

View File

@ -1,9 +1,9 @@
use proc_macro::TokenStream;
use crate::proc_macro2::TokenStream as TokenStream2;
use devise::Result;
use devise::{syn, Spanned, Result};
use self::syn::{Path, punctuated::Punctuated, parse::Parser, token::Comma};
use crate::syn_ext::{IdentExt, syn_to_diag};
use crate::syn_ext::IdentExt;
use crate::syn::{Path, punctuated::Punctuated, parse::Parser, Token};
use crate::syn::spanned::Spanned;
use crate::proc_macro2::TokenStream;
use crate::{ROUTE_STRUCT_PREFIX, CATCH_STRUCT_PREFIX};
mod uri;
@ -17,13 +17,11 @@ pub fn prefix_last_segment(path: &mut Path, prefix: &str) {
fn _prefixed_vec(
prefix: &str,
input: TokenStream,
ty: &TokenStream2
) -> Result<TokenStream2> {
input: proc_macro::TokenStream,
ty: &TokenStream
) -> Result<TokenStream> {
// Parse a comma-separated list of paths.
let mut paths = <Punctuated<Path, Comma>>::parse_terminated
.parse(input)
.map_err(syn_to_diag)?;
let mut paths = <Punctuated<Path, Token![,]>>::parse_terminated.parse(input)?;
// Prefix the last segment in each path with `prefix`.
paths.iter_mut().for_each(|p| prefix_last_segment(p, prefix));
@ -35,39 +33,46 @@ fn _prefixed_vec(
Ok(quote!(vec![#(#prefixed_mapped_paths),*]))
}
fn prefixed_vec(prefix: &str, input: TokenStream, ty: TokenStream2) -> TokenStream {
let vec = _prefixed_vec(prefix, input, &ty)
.map_err(|diag| diag.emit())
.unwrap_or_else(|_| quote!(vec![]));
quote!({
let __vector: Vec<#ty> = #vec;
__vector
}).into()
fn prefixed_vec(
prefix: &str,
input: proc_macro::TokenStream,
ty: TokenStream
) -> TokenStream {
define_vars_and_mods!(_Vec);
_prefixed_vec(prefix, input, &ty)
.map(|vec| quote!({
let __vector: #_Vec<#ty> = #vec;
__vector
}))
.unwrap_or_else(|diag| {
let diag_tokens = diag.emit_as_tokens();
quote!({
#diag_tokens
let __vec: #_Vec<#ty> = vec![];
__vec
})
})
}
pub fn routes_macro(input: TokenStream) -> TokenStream {
pub fn routes_macro(input: proc_macro::TokenStream) -> TokenStream {
prefixed_vec(ROUTE_STRUCT_PREFIX, input, quote!(::rocket::Route))
}
pub fn catchers_macro(input: TokenStream) -> TokenStream {
pub fn catchers_macro(input: proc_macro::TokenStream) -> TokenStream {
prefixed_vec(CATCH_STRUCT_PREFIX, input, quote!(::rocket::Catcher))
}
pub fn uri_macro(input: TokenStream) -> TokenStream {
uri::_uri_macro(input)
.map_err(|diag| diag.emit())
.unwrap_or_else(|_| quote!(()).into())
pub fn uri_macro(input: proc_macro::TokenStream) -> TokenStream {
uri::_uri_macro(input.into())
.unwrap_or_else(|diag| diag.emit_as_tokens())
}
pub fn uri_internal_macro(input: TokenStream) -> TokenStream {
uri::_uri_internal_macro(input)
.map_err(|diag| diag.emit())
.unwrap_or_else(|_| quote!(()).into())
pub fn uri_internal_macro(input: proc_macro::TokenStream) -> TokenStream {
uri::_uri_internal_macro(input.into())
.unwrap_or_else(|diag| diag.emit_as_tokens())
}
pub fn guide_tests_internal(input: TokenStream) -> TokenStream {
pub fn guide_tests_internal(input: proc_macro::TokenStream) -> TokenStream {
test_guide::_macro(input)
.map_err(|diag| diag.emit())
.unwrap_or_else(|_| quote!(()).into())
.unwrap_or_else(|diag| diag.emit_as_tokens())
}

View File

@ -1,16 +1,14 @@
use std::path::Path;
use std::error::Error;
use proc_macro::TokenStream;
use devise::{syn::{self, Ident, LitStr}, Result};
use devise::ext::SpanDiagnosticExt;
use devise::syn::{self, Ident, LitStr};
use devise::proc_macro2::TokenStream;
use crate::syn_ext::syn_to_diag;
use crate::proc_macro2::TokenStream as TokenStream2;
pub fn _macro(input: TokenStream) -> Result<TokenStream> {
let root_glob = syn::parse::<LitStr>(input.into()).map_err(syn_to_diag)?;
pub fn _macro(input: proc_macro::TokenStream) -> devise::Result<TokenStream> {
let root_glob = syn::parse::<LitStr>(input.into())?;
let modules = entry_to_modules(&root_glob)
.map_err(|e| root_glob.span().unstable().error(format!("failed to read: {}", e)))?;
.map_err(|e| root_glob.span().error(format!("failed to read: {}", e)))?;
Ok(quote_spanned!(root_glob.span() =>
#[allow(dead_code)]
@ -19,7 +17,7 @@ pub fn _macro(input: TokenStream) -> Result<TokenStream> {
).into())
}
fn entry_to_modules(root_glob: &LitStr) -> std::result::Result<Vec<TokenStream2>, Box<dyn Error>> {
fn entry_to_modules(root_glob: &LitStr) -> Result<Vec<TokenStream>, Box<dyn Error>> {
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").expect("MANIFEST_DIR");
let full_glob = Path::new(&manifest_dir).join(&root_glob.value()).display().to_string();

View File

@ -1,15 +1,15 @@
use std::fmt::Display;
use proc_macro::TokenStream;
use crate::proc_macro2::TokenStream as TokenStream2;
use devise::{syn, Result};
use devise::syn::{Expr, Ident, Type, spanned::Spanned};
use devise::{syn, Result, ext::SpanDiagnosticExt};
use crate::http::{uri::{Origin, Path, Query}, ext::IntoOwned};
use crate::http::route::{RouteSegment, Kind, Source};
use crate::syn::{Expr, Ident, Type, spanned::Spanned};
use crate::http_codegen::Optional;
use crate::syn_ext::{IdentExt, syn_to_diag};
use crate::syn_ext::IdentExt;
use crate::bang::{prefix_last_segment, uri_parsing::*};
use crate::proc_macro2::TokenStream;
use crate::URI_MACRO_PREFIX;
@ -24,12 +24,12 @@ macro_rules! p {
}
pub fn _uri_macro(input: TokenStream) -> Result<TokenStream> {
let input2: TokenStream2 = input.clone().into();
let mut params = syn::parse::<UriParams>(input).map_err(syn_to_diag)?;
let input2: TokenStream = input.clone().into();
let mut params = syn::parse2::<UriParams>(input)?;
prefix_last_segment(&mut params.route_path, URI_MACRO_PREFIX);
let path = &params.route_path;
Ok(quote!(#path!(#input2)).into())
Ok(quote!(#path!(#input2)))
}
fn extract_exprs<'a>(internal: &'a InternalUriParams) -> Result<(
@ -43,8 +43,7 @@ fn extract_exprs<'a>(internal: &'a InternalUriParams) -> Result<(
let path_param_count = internal.route_uri.path().matches('<').count();
for expr in exprs.iter().take(path_param_count) {
if !expr.as_expr().is_some() {
return Err(expr.span().unstable()
.error("path parameters cannot be ignored"));
return Err(expr.span().error("path parameters cannot be ignored"));
}
}
@ -91,13 +90,13 @@ fn extract_exprs<'a>(internal: &'a InternalUriParams) -> Result<(
if !extra.is_empty() {
let (ps, msg) = join(extra.iter());
let spans: Vec<_> = extra.iter().map(|ident| ident.span().unstable()).collect();
let spans: Vec<_> = extra.iter().map(|ident| ident.span()).collect();
diag = diag.span_help(spans, format!("unknown {}: {}", ps, msg));
}
if !dup.is_empty() {
let (ps, msg) = join(dup.iter());
let spans: Vec<_> = dup.iter().map(|ident| ident.span().unstable()).collect();
let spans: Vec<_> = dup.iter().map(|ident| ident.span()).collect();
diag = diag.span_help(spans, format!("duplicate {}: {}", ps, msg));
}
@ -106,7 +105,7 @@ fn extract_exprs<'a>(internal: &'a InternalUriParams) -> Result<(
}
}
fn add_binding(to: &mut Vec<TokenStream2>, ident: &Ident, ty: &Type, expr: &Expr, source: Source) {
fn add_binding(to: &mut Vec<TokenStream>, ident: &Ident, ty: &Type, expr: &Expr, source: Source) {
let uri_mod = quote!(rocket::http::uri);
let (span, ident_tmp) = (expr.span(), ident.prepend("__tmp_"));
let from_uri_param = if source == Source::Query {
@ -124,9 +123,9 @@ fn add_binding(to: &mut Vec<TokenStream2>, ident: &Ident, ty: &Type, expr: &Expr
fn explode_path<'a, I: Iterator<Item = (&'a Ident, &'a Type, &'a Expr)>>(
uri: &Origin<'_>,
bindings: &mut Vec<TokenStream2>,
bindings: &mut Vec<TokenStream>,
mut items: I
) -> TokenStream2 {
) -> TokenStream {
let (uri_mod, path) = (quote!(rocket::http::uri), uri.path());
if !path.contains('<') {
return quote!(#uri_mod::UriArgumentsKind::Static(#path));
@ -153,9 +152,9 @@ fn explode_path<'a, I: Iterator<Item = (&'a Ident, &'a Type, &'a Expr)>>(
fn explode_query<'a, I: Iterator<Item = (&'a Ident, &'a Type, &'a ArgExpr)>>(
uri: &Origin<'_>,
bindings: &mut Vec<TokenStream2>,
bindings: &mut Vec<TokenStream>,
mut items: I
) -> Option<TokenStream2> {
) -> Option<TokenStream> {
let (uri_mod, query) = (quote!(rocket::http::uri), uri.query()?);
if !query.contains('<') {
return Some(quote!(#uri_mod::UriArgumentsKind::Static(#query)));
@ -215,7 +214,7 @@ fn build_origin(internal: &InternalUriParams) -> Origin<'static> {
pub fn _uri_internal_macro(input: TokenStream) -> Result<TokenStream> {
// Parse the internal invocation and the user's URI param expressions.
let internal = syn::parse::<InternalUriParams>(input).map_err(syn_to_diag)?;
let internal = syn::parse2::<InternalUriParams>(input)?;
let (path_params, query_params) = extract_exprs(&internal)?;
let mut bindings = vec![];
@ -227,5 +226,5 @@ pub fn _uri_internal_macro(input: TokenStream) -> Result<TokenStream> {
Ok(quote!({
#(#bindings)*
#uri_mod::UriArguments { path: #path, query: #query, }.into_origin()
}).into())
}))
}

View File

@ -1,16 +1,15 @@
use proc_macro::Span;
use devise::{syn, Spanned};
use devise::proc_macro2::TokenStream as TokenStream2;
use devise::ext::TypeExt;
use indexmap::IndexMap;
use devise::{Spanned, ext::TypeExt};
use quote::ToTokens;
use self::syn::{Expr, Ident, LitStr, Path, Token, Type};
use self::syn::parse::{self, Parse, ParseStream};
use self::syn::punctuated::Punctuated;
use crate::syn::{self, Expr, Ident, LitStr, Path, Token, Type};
use crate::syn::parse::{self, Parse, ParseStream};
use crate::syn::punctuated::Punctuated;
use crate::http::{uri::Origin, ext::IntoOwned};
use indexmap::IndexMap;
use crate::proc_macro2::{TokenStream, Span};
// TODO(diag): Use 'Diagnostic' in place of syn::Error.
#[derive(Debug)]
pub enum ArgExpr {
@ -124,7 +123,7 @@ impl Parse for UriParams {
})?;
if !input.peek(Token![,]) && input.cursor().eof() {
return err(string.span().unstable(), "unexpected end of input: \
return err(string.span(), "unexpected end of input: \
expected ',' followed by route path");
}
@ -327,7 +326,7 @@ impl ArgExpr {
}
impl ToTokens for ArgExpr {
fn to_tokens(&self, tokens: &mut TokenStream2) {
fn to_tokens(&self, tokens: &mut TokenStream) {
match self {
ArgExpr::Expr(e) => e.to_tokens(tokens),
ArgExpr::Ignored(e) => e.to_tokens(tokens)
@ -336,7 +335,7 @@ impl ToTokens for ArgExpr {
}
impl ToTokens for Arg {
fn to_tokens(&self, tokens: &mut TokenStream2) {
fn to_tokens(&self, tokens: &mut TokenStream) {
match self {
Arg::Unnamed(e) => e.to_tokens(tokens),
Arg::Named(ident, eq, expr) => tokens.extend(quote!(#ident #eq #expr)),
@ -345,7 +344,7 @@ impl ToTokens for Arg {
}
impl ToTokens for Args {
fn to_tokens(&self, tokens: &mut TokenStream2) {
fn to_tokens(&self, tokens: &mut TokenStream) {
match self {
Args::Unnamed(e) | Args::Named(e) => e.to_tokens(tokens)
}

View File

@ -1,5 +1,6 @@
use proc_macro::{Span, TokenStream};
use devise::{*, ext::{TypeExt, Split3}};
use devise::{*, ext::{TypeExt, Split3, SpanDiagnosticExt}};
use crate::proc_macro2::{Span, TokenStream};
#[derive(FromMeta)]
pub struct Form {
@ -57,7 +58,7 @@ fn validate_struct(gen: &DeriveGenerator, data: Struct<'_>) -> Result<()> {
Ok(())
}
pub fn derive_from_form(input: TokenStream) -> TokenStream {
pub fn derive_from_form(input: proc_macro::TokenStream) -> TokenStream {
let form_error = quote!(::rocket::request::FormParseError);
DeriveGenerator::build_for(input, quote!(impl<'__f> ::rocket::request::FromForm<'__f>))
.generic_support(GenericSupport::Lifetime | GenericSupport::Type)
@ -126,5 +127,5 @@ pub fn derive_from_form(input: TokenStream) -> TokenStream {
#_Ok(Self { #(#builders)* })
})
})
.to_tokens()
.to_tokens2()
}

View File

@ -1,12 +1,13 @@
use devise::*;
use proc_macro::TokenStream;
use devise::{*, ext::SpanDiagnosticExt};
use crate::proc_macro2::TokenStream;
#[derive(FromMeta)]
struct Form {
value: String,
}
pub fn derive_from_form_value(input: TokenStream) -> TokenStream {
pub fn derive_from_form_value(input: proc_macro::TokenStream) -> TokenStream {
define_vars_and_mods!(_Ok, _Err, _Result);
DeriveGenerator::build_for(input, quote!(impl<'__v> ::rocket::request::FromFormValue<'__v>))
.generic_support(GenericSupport::None)
@ -21,7 +22,8 @@ pub fn derive_from_form_value(input: TokenStream) -> TokenStream {
// Emit a warning if the enum is empty.
if data.variants.is_empty() {
generator.input.span().warning("deriving for empty enum").emit();
return Err(generator.input.span()
.error("enum must have at least one field"));
}
Ok(())
@ -51,5 +53,5 @@ pub fn derive_from_form_value(input: TokenStream) -> TokenStream {
}
})
})
.to_tokens()
.to_tokens2()
}

View File

@ -1,8 +1,8 @@
use quote::ToTokens;
use proc_macro::TokenStream;
use devise::{*, ext::TypeExt};
use devise::proc_macro2::TokenStream as TokenStream2;
use quote::ToTokens;
use devise::{*, ext::{TypeExt, SpanDiagnosticExt}};
use crate::proc_macro2::TokenStream;
use crate::http_codegen::{ContentType, Status};
#[derive(Default, FromMeta)]
@ -16,15 +16,11 @@ struct FieldAttr {
ignore: bool,
}
pub fn derive_responder(input: TokenStream) -> TokenStream {
// NOTE: Due to a bug in devise, we can't do the more correct:
// quote!(impl<'__r, '__o: '__r> ::rocket::response::Responder<'__r, '__o>))
// replace_generic(1, 0)
// A bugfix (on devise master) fixes this so the above works. Hack.
DeriveGenerator::build_for(input, quote!(impl<'__r> ::rocket::response::Responder<'__r, '__r>))
pub fn derive_responder(input: proc_macro::TokenStream) -> TokenStream {
DeriveGenerator::build_for(input, quote!(impl<'__r, '__o: '__r> ::rocket::response::Responder<'__r, '__o>))
.generic_support(GenericSupport::Lifetime)
.data_support(DataSupport::Struct | DataSupport::Enum)
.replace_generic(0, 0)
.replace_generic(1, 0)
.validate_generics(|_, generics| match generics.lifetimes().count() > 1 {
true => Err(generics.span().error("only one lifetime is supported")),
false => Ok(())
@ -37,13 +33,13 @@ pub fn derive_responder(input: TokenStream) -> TokenStream {
fn respond_to(
self,
__req: &'__r ::rocket::request::Request
) -> ::rocket::response::Result<'__r> {
) -> ::rocket::response::Result<'__o> {
#inner
}
})
.try_map_fields(|_, fields| {
define_vars_and_mods!(_Ok);
fn set_header_tokens<T: ToTokens + Spanned>(item: T) -> TokenStream2 {
fn set_header_tokens<T: ToTokens + Spanned>(item: T) -> TokenStream {
quote_spanned!(item.span().into() => __res.set_header(#item);)
}
@ -82,5 +78,5 @@ pub fn derive_responder(input: TokenStream) -> TokenStream {
#_Ok(__res)
})
})
.to_tokens()
.to_tokens2()
}

View File

@ -1,8 +1,8 @@
use proc_macro::{Span, TokenStream};
use devise::*;
use devise::{*, ext::SpanDiagnosticExt};
use crate::derive::from_form::Form;
use crate::proc_macro2::TokenStream as TokenStream2;
use crate::proc_macro2::{TokenStream, Span};
const NO_EMPTY_FIELDS: &str = "fieldless structs or variants are not supported";
const NO_NULLARY: &str = "nullary items are not supported";
@ -39,7 +39,7 @@ fn validate_enum(gen: &DeriveGenerator, data: Enum<'_>) -> Result<()> {
}
#[allow(non_snake_case)]
pub fn derive_uri_display_query(input: TokenStream) -> TokenStream {
pub fn derive_uri_display_query(input: proc_macro::TokenStream) -> TokenStream {
let Query = quote!(::rocket::http::uri::Query);
let UriDisplay = quote!(::rocket::http::uri::UriDisplay<#Query>);
let Formatter = quote!(::rocket::http::uri::Formatter<#Query>);
@ -116,15 +116,15 @@ pub fn derive_uri_display_query(input: TokenStream) -> TokenStream {
})
.to_tokens();
let mut ts = TokenStream2::from(uri_display);
ts.extend(TokenStream2::from(from_self));
ts.extend(TokenStream2::from(from_ref));
ts.extend(TokenStream2::from(from_mut));
let mut ts = TokenStream::from(uri_display);
ts.extend(TokenStream::from(from_self));
ts.extend(TokenStream::from(from_ref));
ts.extend(TokenStream::from(from_mut));
ts.into()
}
#[allow(non_snake_case)]
pub fn derive_uri_display_path(input: TokenStream) -> TokenStream {
pub fn derive_uri_display_path(input: proc_macro::TokenStream) -> TokenStream {
let Path = quote!(::rocket::http::uri::Path);
let UriDisplay = quote!(::rocket::http::uri::UriDisplay<#Path>);
let Formatter = quote!(::rocket::http::uri::Formatter<#Path>);
@ -179,8 +179,8 @@ pub fn derive_uri_display_path(input: TokenStream) -> TokenStream {
})
.to_tokens();
let mut ts = TokenStream2::from(uri_display);
ts.extend(TokenStream2::from(from_self));
ts.extend(TokenStream2::from(from_ref));
let mut ts = TokenStream::from(uri_display);
ts.extend(TokenStream::from(from_self));
ts.extend(TokenStream::from(from_ref));
ts.into()
}

View File

@ -1,6 +1,7 @@
use quote::ToTokens;
use crate::proc_macro2::TokenStream as TokenStream2;
use devise::{FromMeta, MetaItem, Result, ext::{Split2, PathExt}};
use devise::{FromMeta, MetaItem, Result, ext::{Split2, PathExt, SpanDiagnosticExt}};
use crate::proc_macro2::TokenStream;
use crate::http::{self, ext::IntoOwned};
use crate::http::uri::{Path, Query};
use crate::attribute::segments::{parse_segments, parse_data_segment, Segment, Kind};
@ -53,7 +54,7 @@ impl FromMeta for Status {
}
impl ToTokens for Status {
fn to_tokens(&self, tokens: &mut TokenStream2) {
fn to_tokens(&self, tokens: &mut TokenStream) {
let (code, reason) = (self.0.code, self.0.reason);
tokens.extend(quote!(rocket::http::Status { code: #code, reason: #reason }));
}
@ -68,7 +69,7 @@ impl FromMeta for ContentType {
}
impl ToTokens for ContentType {
fn to_tokens(&self, tokens: &mut TokenStream2) {
fn to_tokens(&self, tokens: &mut TokenStream) {
// Yeah, yeah. (((((i))).kn0w()))
let media_type = MediaType((self.0).clone().0);
tokens.extend(quote!(::rocket::http::ContentType(#media_type)));
@ -81,9 +82,10 @@ impl FromMeta for MediaType {
.ok_or(meta.value_span().error("invalid or unknown media type"))?;
if !mt.is_known() {
// FIXME(diag: warning)
meta.value_span()
.warning(format!("'{}' is not a known media type", mt))
.emit();
.emit_as_tokens();
}
Ok(MediaType(mt))
@ -91,7 +93,7 @@ impl FromMeta for MediaType {
}
impl ToTokens for MediaType {
fn to_tokens(&self, tokens: &mut TokenStream2) {
fn to_tokens(&self, tokens: &mut TokenStream) {
use std::iter::repeat;
let (top, sub) = (self.0.top().as_str(), self.0.sub().as_str());
let (keys, values) = self.0.params().split2();
@ -150,7 +152,7 @@ impl FromMeta for Method {
}
impl ToTokens for Method {
fn to_tokens(&self, tokens: &mut TokenStream2) {
fn to_tokens(&self, tokens: &mut TokenStream) {
let method_tokens = match self.0 {
http::Method::Get => quote!(::rocket::http::Method::Get),
http::Method::Put => quote!(::rocket::http::Method::Put),
@ -234,7 +236,7 @@ impl FromMeta for RoutePath {
}
impl<T: ToTokens> ToTokens for Optional<T> {
fn to_tokens(&self, tokens: &mut TokenStream2) {
fn to_tokens(&self, tokens: &mut TokenStream) {
define_vars_and_mods!(_Some, _None);
let opt_tokens = match self.0 {
Some(ref val) => quote!(#_Some(#val)),

View File

@ -1,4 +1,3 @@
#![feature(proc_macro_diagnostic, proc_macro_span)]
#![recursion_limit="128"]
#![doc(html_root_url = "https://api.rocket.rs/v0.5")]
@ -101,6 +100,7 @@ vars_and_mods! {
_Ok => ::std::result::Result::Ok,
_Err => ::std::result::Result::Err,
_Box => ::std::boxed::Box,
_Vec => ::std::vec::Vec,
}
macro_rules! define_vars_and_mods {
@ -118,7 +118,7 @@ mod syn_ext;
use crate::http::Method;
use proc_macro::TokenStream;
use devise::proc_macro2;
use devise::{proc_macro2, syn};
static ROUTE_STRUCT_PREFIX: &str = "static_rocket_route_info_for_";
static CATCH_STRUCT_PREFIX: &str = "static_rocket_catch_info_for_";
@ -129,15 +129,19 @@ static ROCKET_PARAM_PREFIX: &str = "__rocket_param_";
macro_rules! emit {
($tokens:expr) => ({
let tokens = $tokens;
use devise::ext::SpanDiagnosticExt;
let mut tokens = $tokens;
if std::env::var_os("ROCKET_CODEGEN_DEBUG").is_some() {
proc_macro::Span::call_site()
let debug_tokens = proc_macro2::Span::call_site()
.note("emitting Rocket code generation debug output")
.note(tokens.to_string())
.emit()
.emit_as_tokens();
tokens.extend(debug_tokens);
}
tokens
tokens.into()
})
}

View File

@ -1,6 +1,8 @@
use std::ops::RangeBounds;
use proc_macro::{Span, Diagnostic, Literal};
use devise::Diagnostic;
use crate::proc_macro2::{Span, Literal};
pub type PResult<T> = std::result::Result<T, Diagnostic>;
@ -27,7 +29,8 @@ impl Diagnostics {
let mut iter = self.0.into_iter();
let mut last = iter.next().expect("Diagnostic::emit_head empty");
for diag in iter {
last.emit();
// FIXME(diag: emit, can there be errors here?)
last.emit_as_tokens();
last = diag;
}
@ -86,7 +89,8 @@ impl StringLit {
}
/// Attempt to obtain a subspan, or, failing that, produce the full span.
/// This will create suboptimal diagnostics, but better than failing to build entirely.
/// This will create suboptimal diagnostics, but better than failing to
/// build entirely.
pub fn subspan<R: RangeBounds<usize>>(&self, range: R) -> Span {
self.1.subspan(range).unwrap_or_else(|| self.span())
}

View File

@ -1,11 +1,6 @@
//! Extensions to `syn` types.
use devise::syn;
use proc_macro::Diagnostic;
pub fn syn_to_diag(error: syn::parse::Error) -> Diagnostic {
error.span().unstable().error(error.to_string())
}
pub trait IdentExt {
fn prepend(&self, string: &str) -> syn::Ident;

View File

@ -22,7 +22,7 @@ enum Foo4 {
#[derive(FromFormValue)]
enum Foo5 { }
//~^ WARNING empty enum
//~^ ERROR at least one field
#[derive(FromFormValue)]
enum Foo6<T> {

View File

@ -53,11 +53,18 @@ note: error occurred while deriving `FromFormValue`
| ^^^^^^^^^^^^^
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
warning: deriving for empty enum
error: enum must have at least one field
--> $DIR/from_form_value.rs:24:1
|
24 | enum Foo5 { }
| ^^^^^^^^^^^^^
|
note: error occurred while deriving `FromFormValue`
--> $DIR/from_form_value.rs:23:10
|
23 | #[derive(FromFormValue)]
| ^^^^^^^^^^^^^
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: type generics are not supported
--> $DIR/from_form_value.rs:28:11
@ -98,5 +105,5 @@ note: error occurred while deriving `FromFormValue`
| ^^^^^^^^^^^^^
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 7 previous errors; 1 warning emitted
error: aborting due to 8 previous errors

View File

@ -51,10 +51,10 @@ note: error occurred while deriving `UriDisplay`
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: tuple structs or variants must have exactly one field
--> $DIR/uri_display.rs:39:12
--> $DIR/uri_display.rs:39:13
|
39 | struct Foo5(String, String);
| ^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^
|
note: error occurred while deriving `UriDisplay`
--> $DIR/uri_display.rs:35:10
@ -77,10 +77,10 @@ note: error occurred while deriving `UriDisplay`
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: struct must have exactly one field
--> $DIR/uri_display.rs:55:12
--> $DIR/uri_display.rs:55:13
|
55 | struct Foo7(String, usize);
| ^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^
|
note: error occurred while deriving `UriDisplay`
--> $DIR/uri_display.rs:52:10

View File

@ -8,7 +8,6 @@ publish = false
[dependencies]
rocket = { path = "../../core/lib" }
lazy_static = "1.0"
uuid = "0.8"
[dependencies.rocket_contrib]
default-features = false

View File

@ -2,7 +2,9 @@
#[macro_use] extern crate lazy_static;
use std::collections::HashMap;
use rocket_contrib::uuid::Uuid;
use rocket_contrib::uuid::uuid_crate as uuid;
#[cfg(test)] mod tests;