Skip to content

Commit

Permalink
Migrate from syn 1.x to syn 2.x
Browse files Browse the repository at this point in the history
  • Loading branch information
jirutka committed Aug 26, 2023
1 parent 3908455 commit 48fb402
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 101 deletions.
2 changes: 1 addition & 1 deletion argp_derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ proc-macro = true
proc-macro2 = "1.0"
pulldown-cmark = "0.9"
quote = "1.0"
syn = "1.0"
syn = "2.0"

[dev-dependencies]
indoc = "2"
Expand Down
34 changes: 14 additions & 20 deletions argp_derive/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ pub struct Errors {
errors: RefCell<Vec<syn::Error>>,
}

/// Produce functions to expect particular variants of `syn::Lit`
/// Produce functions to expect particular literals in `syn::Expr`
macro_rules! expect_lit_fn {
($(($fn_name:ident, $syn_type:ident, $variant:ident, $lit_name:literal),)*) => {
$(
pub fn $fn_name<'a>(&self, lit: &'a syn::Lit) -> Option<&'a syn::$syn_type> {
if let syn::Lit::$variant(inner) = lit {
pub fn $fn_name<'a>(&self, expr: &'a syn::Expr) -> Option<&'a syn::$syn_type> {
if let syn::Expr::Lit(syn::ExprLit { lit: syn::Lit::$variant(inner), .. }) = expr {
Some(inner)
} else {
self.unexpected_lit($lit_name, lit);
self.unexpected_lit($lit_name, expr);
None
}
}
Expand Down Expand Up @@ -64,17 +64,6 @@ impl Errors {
self.err_span(first, &format!("First {} attribute here", attr_kind));
}

/// Error on literals, expecting attribute syntax.
pub fn expect_nested_meta<'a>(&self, nm: &'a syn::NestedMeta) -> Option<&'a syn::Meta> {
match nm {
syn::NestedMeta::Lit(l) => {
self.err(l, "Unexpected literal");
None
}
syn::NestedMeta::Meta(m) => Some(m),
}
}

expect_lit_fn![
(expect_lit_str, LitStr, Str, "string"),
(expect_lit_char, LitChar, Char, "character"),
Expand All @@ -86,7 +75,7 @@ impl Errors {
(expect_meta_name_value, MetaNameValue, NameValue, "name-value pair"),
];

fn unexpected_lit(&self, expected: &str, found: &syn::Lit) {
fn unexpected_lit(&self, expected: &str, found: &syn::Expr) {
fn lit_kind(lit: &syn::Lit) -> &'static str {
use syn::Lit::{Bool, Byte, ByteStr, Char, Float, Int, Str, Verbatim};
match lit {
Expand All @@ -98,13 +87,18 @@ impl Errors {
Float(_) => "float",
Bool(_) => "boolean",
Verbatim(_) => "unknown (possibly extra-large integer)",
_ => "unknown literal kind",
}
}

self.err(
found,
&format!("Expected {} literal, found {} literal", expected, lit_kind(found)),
)
if let syn::Expr::Lit(syn::ExprLit { lit, .. }) = found {
self.err(
found,
&format!("Expected {} literal, found {} literal", expected, lit_kind(lit)),
)
} else {
self.err(found, &format!("Expected {} literal, found non-literal expression", expected))
}
}

fn unexpected_meta(&self, expected: &str, found: &syn::Meta) {
Expand Down
119 changes: 39 additions & 80 deletions argp_derive/src/parse_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,57 +78,51 @@ impl FieldAttrs {
continue;
};

for meta in &ml.nested {
let meta = if let Some(m) = errors.expect_nested_meta(meta) {
m
} else {
continue;
};

for meta in ml {
let name = meta.path();
if name.is_ident("arg_name") {
if let Some(m) = errors.expect_meta_name_value(meta) {
if let Some(m) = errors.expect_meta_name_value(&meta) {
parse_attr_single_string(errors, m, "arg_name", &mut this.arg_name);
}
} else if name.is_ident("default") {
if let Some(m) = errors.expect_meta_name_value(meta) {
if let Some(m) = errors.expect_meta_name_value(&meta) {
parse_attr_single_string(errors, m, "default", &mut this.default);
}
} else if name.is_ident("description") {
if let Some(m) = errors.expect_meta_name_value(meta) {
if let Some(m) = errors.expect_meta_name_value(&meta) {
parse_attr_description(errors, m, &mut this.description);
}
} else if name.is_ident("from_str_fn") {
if let Some(m) = errors.expect_meta_list(meta) {
if let Some(m) = errors.expect_meta_list(&meta) {
parse_attr_fn_path(errors, m, "from_str_fn", &mut this.from_str_fn);
}
} else if name.is_ident("from_os_str_fn") {
if let Some(m) = errors.expect_meta_list(meta) {
if let Some(m) = errors.expect_meta_list(&meta) {
parse_attr_fn_path(errors, m, "from_os_str_fn", &mut this.from_os_str_fn);
}
} else if name.is_ident("long") {
if let Some(m) = errors.expect_meta_name_value(meta) {
if let Some(m) = errors.expect_meta_name_value(&meta) {
this.parse_attr_long(errors, m);
}
} else if name.is_ident("option") {
parse_attr_field_type(errors, meta, FieldKind::Option, &mut this.field_type);
parse_attr_field_type(errors, &meta, FieldKind::Option, &mut this.field_type);
} else if name.is_ident("short") {
if let Some(m) = errors.expect_meta_name_value(meta) {
if let Some(m) = errors.expect_meta_name_value(&meta) {
this.parse_attr_short(errors, m);
}
} else if name.is_ident("subcommand") {
parse_attr_field_type(
errors,
meta,
&meta,
FieldKind::SubCommand,
&mut this.field_type,
);
} else if name.is_ident("switch") {
parse_attr_field_type(errors, meta, FieldKind::Switch, &mut this.field_type);
parse_attr_field_type(errors, &meta, FieldKind::Switch, &mut this.field_type);
} else if name.is_ident("positional") {
parse_attr_field_type(
errors,
meta,
&meta,
FieldKind::Positional,
&mut this.field_type,
);
Expand Down Expand Up @@ -201,7 +195,7 @@ impl FieldAttrs {
fn parse_attr_short(&mut self, errors: &Errors, m: &syn::MetaNameValue) {
if let Some(first) = &self.short {
errors.duplicate_attrs("short", first, m);
} else if let Some(lit_char) = errors.expect_lit_char(&m.lit) {
} else if let Some(lit_char) = errors.expect_lit_char(&m.value) {
self.short = Some(lit_char.clone());
if !lit_char.value().is_ascii() {
errors.err(lit_char, "Short names must be ASCII");
Expand Down Expand Up @@ -246,18 +240,7 @@ fn parse_attr_fn_path(
if let Some(first) = slot {
errors.duplicate_attrs(attr_name, first, m);
}

if m.nested.len() != 1 {
errors.err(&m.nested, "Expected a single argument containing the function name");
return;
}

// `unwrap` will not fail because of the call above
let nested = m.nested.first().unwrap();
*slot = errors
.expect_nested_meta(nested)
.and_then(|m| errors.expect_meta_word(m))
.cloned();
*slot = m.parse_args().map_err(|e| errors.push(e)).ok();
}

fn parse_attr_field_type(
Expand All @@ -280,7 +263,7 @@ fn parse_attr_field_type(

// Whether the attribute is one like `#[<name> ...]`
fn is_matching_attr(name: &str, attr: &syn::Attribute) -> bool {
attr.path.segments.len() == 1 && attr.path.segments[0].ident == name
attr.path().segments.len() == 1 && attr.path().segments[0].ident == name
}

/// Checks for `#[doc ...]`, which is generated by doc comments.
Expand All @@ -293,34 +276,21 @@ fn is_argp_attr(attr: &syn::Attribute) -> bool {
is_matching_attr("argp", attr)
}

fn attr_to_meta_subtype<R: Clone>(
/// Filters out non-`#[argp(...)]` attributes and converts to a sequence of
/// `syn::Meta`.
fn argp_attr_to_meta_list(
errors: &Errors,
attr: &syn::Attribute,
f: impl FnOnce(&syn::Meta) -> Option<&R>,
) -> Option<R> {
match attr.parse_meta() {
Ok(meta) => f(&meta).cloned(),
Err(e) => {
errors.push(e);
None
}
}
}

fn attr_to_meta_list(errors: &Errors, attr: &syn::Attribute) -> Option<syn::MetaList> {
attr_to_meta_subtype(errors, attr, |m| errors.expect_meta_list(m))
}

fn attr_to_meta_name_value(errors: &Errors, attr: &syn::Attribute) -> Option<syn::MetaNameValue> {
attr_to_meta_subtype(errors, attr, |m| errors.expect_meta_name_value(m))
}

/// Filters out non-`#[argp(...)]` attributes and converts to `syn::MetaList`.
fn argp_attr_to_meta_list(errors: &Errors, attr: &syn::Attribute) -> Option<syn::MetaList> {
) -> Option<impl IntoIterator<Item = syn::Meta>> {
if !is_argp_attr(attr) {
return None;
}
attr_to_meta_list(errors, attr)
let meta_list = errors.expect_meta_list(&attr.meta)?;

meta_list
.parse_args_with(syn::punctuated::Punctuated::<syn::Meta, syn::Token![,]>::parse_terminated)
.map_err(|e| errors.push(e))
.ok()
}

/// Represents a `#[derive(FromArgs)]` type's top-level attributes.
Expand Down Expand Up @@ -349,28 +319,23 @@ impl TypeAttrs {
continue;
};

for meta in &ml.nested {
let meta = if let Some(m) = errors.expect_nested_meta(meta) {
m
} else {
continue;
};

for meta in ml {
let name = meta.path();
if name.is_ident("description") {
if let Some(m) = errors.expect_meta_name_value(meta) {
if let Some(m) = errors.expect_meta_name_value(&meta) {
parse_attr_description(errors, m, &mut this.description);
}
} else if name.is_ident("footer") {
if let Some(m) = errors.expect_meta_name_value(meta) {
if let Some(m) = errors.expect_meta_name_value(&meta) {
parse_attr_multi_string(errors, m, &mut this.footer)
}
} else if name.is_ident("name") {
if let Some(m) = errors.expect_meta_name_value(meta) {
if let Some(m) = errors.expect_meta_name_value(&meta) {
this.parse_attr_name(errors, m);
}
} else if name.is_ident("subcommand") {
if let Some(ident) = errors.expect_meta_word(meta).and_then(|p| p.get_ident()) {
if let Some(ident) = errors.expect_meta_word(&meta).and_then(|p| p.get_ident())
{
this.parse_attr_subcommand(errors, ident);
}
} else {
Expand Down Expand Up @@ -438,19 +403,13 @@ impl VariantAttrs {
continue;
};

for meta in &ml.nested {
let meta = if let Some(m) = errors.expect_nested_meta(meta) {
m
} else {
continue;
};

for meta in ml {
let name = meta.path();
if name.is_ident("dynamic") {
if let Some(prev) = this.is_dynamic.as_ref() {
errors.duplicate_attrs("dynamic", prev, meta);
errors.duplicate_attrs("dynamic", prev, &meta);
} else {
this.is_dynamic = errors.expect_meta_word(meta).cloned();
this.is_dynamic = errors.expect_meta_word(&meta).cloned();
}
} else {
errors.err(
Expand All @@ -474,19 +433,19 @@ fn parse_attr_single_string(
) {
if let Some(first) = slot {
errors.duplicate_attrs(name, first, m);
} else if let Some(lit_str) = errors.expect_lit_str(&m.lit) {
} else if let Some(lit_str) = errors.expect_lit_str(&m.value) {
*slot = Some(lit_str.clone());
}
}

fn parse_attr_multi_string(errors: &Errors, m: &syn::MetaNameValue, list: &mut Vec<syn::LitStr>) {
if let Some(lit_str) = errors.expect_lit_str(&m.lit) {
if let Some(lit_str) = errors.expect_lit_str(&m.value) {
list.push(lit_str.clone());
}
}

fn parse_attr_doc(errors: &Errors, attr: &syn::Attribute, slot: &mut Option<Description>) {
let nv = if let Some(nv) = attr_to_meta_name_value(errors, attr) {
let nv = if let Some(nv) = errors.expect_meta_name_value(&attr.meta) {
nv
} else {
return;
Expand All @@ -497,7 +456,7 @@ fn parse_attr_doc(errors: &Errors, attr: &syn::Attribute, slot: &mut Option<Desc
return;
}

if let Some(lit_str) = errors.expect_lit_str(&nv.lit) {
if let Some(lit_str) = errors.expect_lit_str(&nv.value) {
if let Some(slot) = slot {
slot.lines.push(lit_str.value());
} else {
Expand All @@ -511,7 +470,7 @@ fn parse_attr_doc(errors: &Errors, attr: &syn::Attribute, slot: &mut Option<Desc
}

fn parse_attr_description(errors: &Errors, m: &syn::MetaNameValue, slot: &mut Option<Description>) {
let lit_str = if let Some(lit_str) = errors.expect_lit_str(&m.lit) {
let lit_str = if let Some(lit_str) = errors.expect_lit_str(&m.value) {
lit_str
} else {
return;
Expand Down

0 comments on commit 48fb402

Please sign in to comment.