Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ extra-traits = []
proc-macro = ["proc-macro2/proc-macro", "quote/proc-macro"]

[dependencies]
proc-macro2 = { version = "0.3", default-features = false }
proc-macro2 = { version = "0.4.1", default-features = false }
quote = { version = "0.5", optional = true, default-features = false }
unicode-xid = "0.1"

Expand All @@ -42,3 +42,6 @@ all-features = true

[package.metadata.playground]
all-features = true

[patch.crates-io]
quote = { git = 'https://github.com/dtolnay/quote' }
5 changes: 4 additions & 1 deletion codegen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,7 @@ syn = { path = "..", features = ["full", "extra-traits"] }
quote = "0.5"
failure = "0.1"
inflections = "1.1"
proc-macro2 = "0.3"
proc-macro2 = "0.4"

[patch.crates-io]
quote = { git = 'https://github.com/dtolnay/quote' }
105 changes: 53 additions & 52 deletions codegen/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ extern crate quote;
#[macro_use]
extern crate syn;

use quote::{ToTokens, Tokens};
use quote::ToTokens;
use syn::{Attribute, Data, DataStruct, DeriveInput, Ident, Item};
use failure::{err_msg, Error};
use proc_macro2::{Span, TokenStream};

use std::io::{Read, Write};
use std::fmt::{self, Debug};
Expand All @@ -39,23 +40,23 @@ const VISIT_MUT_SRC: &str = "../src/gen/visit_mut.rs";

const IGNORED_MODS: &[&str] = &["fold", "visit", "visit_mut"];

const EXTRA_TYPES: &[&str] = &["Ident", "Lifetime"];
const EXTRA_TYPES: &[&str] = &["Lifetime"];

const TERMINAL_TYPES: &[&str] = &["Span"];
const TERMINAL_TYPES: &[&str] = &["Span", "Ident"];

fn path_eq(a: &syn::Path, b: &syn::Path) -> bool {
if a.global() != b.global() || a.segments.len() != b.segments.len() {
return false;
fn path_eq(a: &syn::Path, b: &str) -> bool {
if a.global() {
return false
}
a.segments
.iter()
.zip(b.segments.iter())
.all(|(a, b)| a.ident == b.ident)
if a.segments.len() != 1 {
return false
}
a.segments[0].ident == b
}

fn get_features(attrs: &[Attribute], mut features: Tokens) -> Tokens {
fn get_features(attrs: &[Attribute], mut features: TokenStream) -> TokenStream {
for attr in attrs {
if path_eq(&attr.path, &"cfg".into()) {
if path_eq(&attr.path, "cfg") {
attr.to_tokens(&mut features);
}
}
Expand All @@ -65,7 +66,7 @@ fn get_features(attrs: &[Attribute], mut features: Tokens) -> Tokens {
#[derive(Clone)]
pub struct AstItem {
ast: DeriveInput,
features: Tokens,
features: TokenStream,
// True if this is an ast_enum_of_structs! item with a #full annotation.
eos_full: bool,
}
Expand All @@ -82,7 +83,7 @@ impl Debug for AstItem {
// NOTE: BTreeMap is used here instead of HashMap to have deterministic output.
type Lookup = BTreeMap<Ident, AstItem>;

fn load_file<P: AsRef<Path>>(name: P, features: &Tokens, lookup: &mut Lookup) -> Result<(), Error> {
fn load_file<P: AsRef<Path>>(name: P, features: &TokenStream, lookup: &mut Lookup) -> Result<(), Error> {
let name = name.as_ref();
let parent = name.parent().ok_or_else(|| err_msg("no parent path"))?;

Expand Down Expand Up @@ -124,7 +125,7 @@ fn load_file<P: AsRef<Path>>(name: P, features: &Tokens, lookup: &mut Lookup) ->

// Look up the submodule file, and recursively parse it.
// XXX: Only handles same-directory .rs file submodules.
let path = parent.join(&format!("{}.rs", item.ident.as_ref()));
let path = parent.join(&format!("{}.rs", item.ident));
load_file(path, &features, lookup)?;
}
Item::Macro(item) => {
Expand All @@ -134,15 +135,15 @@ fn load_file<P: AsRef<Path>>(name: P, features: &Tokens, lookup: &mut Lookup) ->

// Try to parse the AstItem declaration out of the item.
let tts = &item.mac.tts;
let found = if path_eq(&item.mac.path, &"ast_struct".into()) {
let found = if path_eq(&item.mac.path, "ast_struct") {
syn::parse_str::<parsing::AstStruct>(&quote!(#tts).to_string())
.map_err(|_| err_msg("failed to parse ast_struct"))?
.0
} else if path_eq(&item.mac.path, &"ast_enum".into()) {
} else if path_eq(&item.mac.path, "ast_enum") {
syn::parse_str::<parsing::AstEnum>(&quote!(#tts).to_string())
.map_err(|_| err_msg("failed to parse ast_enum"))?
.0
} else if path_eq(&item.mac.path, &"ast_enum_of_structs".into()) {
} else if path_eq(&item.mac.path, "ast_enum_of_structs") {
syn::parse_str::<parsing::AstEnumOfStructs>(&quote!(#tts).to_string())
.map_err(|_| err_msg("failed to parse ast_enum_of_structs"))?
.0
Expand All @@ -153,13 +154,13 @@ fn load_file<P: AsRef<Path>>(name: P, features: &Tokens, lookup: &mut Lookup) ->
// Record our features on the parsed AstItems.
for mut item in found {
features.to_tokens(&mut item.features);
lookup.insert(item.ast.ident, item);
lookup.insert(item.ast.ident.clone(), item);
}
}
Item::Struct(item) => {
let ident = item.ident;
if EXTRA_TYPES.contains(&ident.as_ref()) {
lookup.insert(ident, AstItem {
if EXTRA_TYPES.contains(&&ident.to_string()[..]) {
lookup.insert(ident.clone(), AstItem {
ast: DeriveInput {
ident: ident,
vis: item.vis,
Expand Down Expand Up @@ -188,12 +189,11 @@ mod parsing {
use syn;
use syn::synom::*;
use syn::*;
use quote::Tokens;
use proc_macro2::TokenStream;

// Parses #full - returns #[cfg(feature = "full")] if it is present, and
// nothing otherwise.
named!(full -> (Tokens, bool), map!(option!(do_parse!(
named!(full -> (TokenStream, bool), map!(option!(do_parse!(
punct!(#) >>
id: syn!(Ident) >>
cond_reduce!(id == "full") >>
Expand Down Expand Up @@ -280,7 +280,7 @@ mod parsing {
keyword!(pub) >>
variant: syn!(Ident) >>
member: option!(map!(parens!(alt!(
call!(ast_struct_inner) => { |x: AstItem| (Path::from(x.ast.ident), Some(x)) }
call!(ast_struct_inner) => { |x: AstItem| (Path::from(x.ast.ident.clone()), Some(x)) }
|
syn!(Path) => { |x| (x, None) }
)), |x| x.1)) >>
Expand All @@ -307,7 +307,7 @@ mod parsing {
// tokens to strings to re-parse them.
let enum_item = {
let variants = variants.1.iter().map(|v| {
let name = v.name;
let name = v.name.clone();
match v.member {
Some(ref member) => quote!(#name(#member)),
None => quote!(#name),
Expand All @@ -333,8 +333,9 @@ mod codegen {
use super::{AstItem, Lookup};
use syn::*;
use syn::punctuated::Punctuated;
use quote::{ToTokens, Tokens};
use quote::ToTokens;
use std::fmt::{self, Display};
use proc_macro2::{Span, TokenStream};

#[derive(Default)]
pub struct State {
Expand All @@ -348,7 +349,7 @@ mod codegen {

fn under_name(name: Ident) -> Ident {
use inflections::Inflect;
name.as_ref().to_snake_case().into()
Ident::new(&name.to_string().to_snake_case(), Span::call_site())
}

enum RelevantType<'a> {
Expand All @@ -358,21 +359,21 @@ mod codegen {
Option(&'a Type),
Tuple(&'a Punctuated<Type, Token![,]>),
Simple(&'a AstItem),
Token(Tokens),
Token(TokenStream),
Pass,
}

fn classify<'a>(ty: &'a Type, lookup: &'a Lookup) -> RelevantType<'a> {
match *ty {
Type::Path(TypePath { qself: None, ref path }) => {
let last = path.segments.last().unwrap().into_value();
match last.ident.as_ref() {
match &last.ident.to_string()[..] {
"Box" => RelevantType::Box(first_arg(&last.arguments)),
"Vec" => RelevantType::Vec(first_arg(&last.arguments)),
"Punctuated" => RelevantType::Punctuated(first_arg(&last.arguments)),
"Option" => RelevantType::Option(first_arg(&last.arguments)),
"Brace" | "Bracket" | "Paren" | "Group" => {
RelevantType::Token(last.ident.into_tokens())
RelevantType::Token(last.ident.clone().into_token_stream())
}
_ => {
if let Some(item) = lookup.get(&last.ident) {
Expand All @@ -387,7 +388,7 @@ mod codegen {
RelevantType::Tuple(elems)
}
Type::Macro(TypeMacro { ref mac }) if mac.path.segments.last().unwrap().into_value().ident == "Token" => {
RelevantType::Token(mac.into_tokens())
RelevantType::Token(mac.into_token_stream())
}
_ => RelevantType::Pass,
}
Expand All @@ -401,35 +402,35 @@ mod codegen {
}

enum Operand {
Borrowed(Tokens),
Owned(Tokens),
Borrowed(TokenStream),
Owned(TokenStream),
}

use self::Operand::*;
use self::Kind::*;

impl Operand {
fn tokens(&self) -> &Tokens {
fn tokens(&self) -> &TokenStream {
match *self {
Borrowed(ref n) | Owned(ref n) => n,
}
}

fn ref_tokens(&self) -> Tokens {
fn ref_tokens(&self) -> TokenStream {
match *self {
Borrowed(ref n) => n.clone(),
Owned(ref n) => quote!(&#n),
}
}

fn ref_mut_tokens(&self) -> Tokens {
fn ref_mut_tokens(&self) -> TokenStream {
match *self {
Borrowed(ref n) => n.clone(),
Owned(ref n) => quote!(&mut #n),
}
}

fn owned_tokens(&self) -> Tokens {
fn owned_tokens(&self) -> TokenStream {
match *self {
Borrowed(ref n) => quote!(*#n),
Owned(ref n) => n.clone(),
Expand Down Expand Up @@ -467,17 +468,17 @@ mod codegen {
match kind {
Visit => format!(
"_visitor.visit_{under_name}({name})",
under_name = under_name(item.ast.ident),
under_name = under_name(item.ast.ident.clone()),
name = name.ref_tokens(),
),
VisitMut => format!(
"_visitor.visit_{under_name}_mut({name})",
under_name = under_name(item.ast.ident),
under_name = under_name(item.ast.ident.clone()),
name = name.ref_mut_tokens(),
),
Fold => format!(
"_visitor.fold_{under_name}({name})",
under_name = under_name(item.ast.ident),
under_name = under_name(item.ast.ident.clone()),
name = name.owned_tokens(),
),
}
Expand Down Expand Up @@ -635,7 +636,7 @@ mod codegen {
}
}

fn token_visit(ty: Tokens, kind: Kind, name: &Operand) -> String {
fn token_visit(ty: TokenStream, kind: Kind, name: &Operand) -> String {
match kind {
Fold => format!(
"{ty}(tokens_helper(_visitor, &({name}).0))",
Expand Down Expand Up @@ -695,7 +696,7 @@ mod codegen {
}

pub fn generate(state: &mut State, lookup: &Lookup, s: &AstItem) {
let under_name = under_name(s.ast.ident);
let under_name = under_name(s.ast.ident.clone());

state.visit_trait.push_str(&format!(
"{features}\n\
Expand Down Expand Up @@ -758,7 +759,7 @@ mod codegen {
state.visit_mut_impl.push_str(" match *_i {\n");
state.fold_impl.push_str(" match _i {\n");
for variant in &e.variants {
let fields: Vec<(&Field, Tokens)> = match variant.fields {
let fields: Vec<(&Field, TokenStream)> = match variant.fields {
Fields::Named(..) => panic!("Doesn't support enum struct variants"),
Fields::Unnamed(ref fields) => {
let binding = format!(" {}::{}(", s.ast.ident, variant.ident);
Expand All @@ -783,7 +784,7 @@ mod codegen {
state.fold_impl.push_str(", ");

let mut tokens = quote!();
Ident::from(name).to_tokens(&mut tokens);
Ident::new(&name, Span::call_site()).to_tokens(&mut tokens);

(el, tokens)
})
Expand Down Expand Up @@ -864,15 +865,15 @@ mod codegen {
state.fold_impl.push_str(" }\n");
}
Data::Struct(ref v) => {
let fields: Vec<(&Field, Tokens)> = match v.fields {
let fields: Vec<(&Field, TokenStream)> = match v.fields {
Fields::Named(ref fields) => {
state
.fold_impl
.push_str(&format!(" {} {{\n", s.ast.ident));
fields.named
.iter()
.map(|el| {
let id = el.ident;
let id = el.ident.clone();
(el, quote!(_i.#id))
})
.collect()
Expand Down Expand Up @@ -962,10 +963,10 @@ fn main() {
for &tt in TERMINAL_TYPES {
use syn::*;
lookup.insert(
Ident::from(tt),
Ident::new(&tt, Span::call_site()),
AstItem {
ast: DeriveInput {
ident: Ident::from(tt),
ident: Ident::new(tt, Span::call_site()),
vis: Visibility::Public(VisPublic {
pub_token: Default::default(),
}),
Expand All @@ -977,7 +978,7 @@ fn main() {
semi_token: None,
}),
},
features: Default::default(),
features: TokenStream::empty(),
eos_full: false,
},
);
Expand Down Expand Up @@ -1012,6 +1013,7 @@ macro_rules! full {
#![allow(unreachable_code)]
#![cfg_attr(feature = \"cargo-clippy\", allow(needless_pass_by_value))]

#[cfg(any(feature = \"full\", feature = \"derive\"))]
use *;
#[cfg(any(feature = \"full\", feature = \"derive\"))]
use token::{{Brace, Bracket, Paren, Group}};
Expand Down Expand Up @@ -1042,9 +1044,6 @@ macro_rules! fold_span_only {{
}}
}}

fold_span_only!(fold_ident: Ident);
#[cfg(any(feature = \"full\", feature = \"derive\"))]
fold_span_only!(fold_lifetime: Lifetime);
#[cfg(any(feature = \"full\", feature = \"derive\"))]
fold_span_only!(fold_lit_byte: LitByte);
#[cfg(any(feature = \"full\", feature = \"derive\"))]
Expand Down Expand Up @@ -1075,6 +1074,7 @@ fold_span_only!(fold_lit_str: LitStr);

#![cfg_attr(feature = \"cargo-clippy\", allow(match_same_arms))]

#[cfg(any(feature = \"full\", feature = \"derive\"))]
use *;
#[cfg(any(feature = \"full\", feature = \"derive\"))]
use punctuated::Punctuated;
Expand Down Expand Up @@ -1112,6 +1112,7 @@ pub trait Visit<'ast> {{

#![cfg_attr(feature = \"cargo-clippy\", allow(match_same_arms))]

#[cfg(any(feature = \"full\", feature = \"derive\"))]
use *;
#[cfg(any(feature = \"full\", feature = \"derive\"))]
use punctuated::Punctuated;
Expand Down
Loading