aboutsummaryrefslogtreecommitdiff
path: root/structopt/structopt-derive/src/parse.rs
diff options
context:
space:
mode:
Diffstat (limited to 'structopt/structopt-derive/src/parse.rs')
-rw-r--r--structopt/structopt-derive/src/parse.rs304
1 files changed, 0 insertions, 304 deletions
diff --git a/structopt/structopt-derive/src/parse.rs b/structopt/structopt-derive/src/parse.rs
deleted file mode 100644
index a704742..0000000
--- a/structopt/structopt-derive/src/parse.rs
+++ /dev/null
@@ -1,304 +0,0 @@
-use std::iter::FromIterator;
-
-use proc_macro_error::{abort, ResultExt};
-use quote::ToTokens;
-use syn::{
- self, parenthesized,
- parse::{Parse, ParseBuffer, ParseStream},
- parse2,
- punctuated::Punctuated,
- spanned::Spanned,
- Attribute, Expr, ExprLit, Ident, Lit, LitBool, LitStr, Token,
-};
-
-pub struct StructOptAttributes {
- pub paren_token: syn::token::Paren,
- pub attrs: Punctuated<StructOptAttr, Token![,]>,
-}
-
-impl Parse for StructOptAttributes {
- fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
- let content;
- let paren_token = parenthesized!(content in input);
- let attrs = content.parse_terminated(StructOptAttr::parse)?;
-
- Ok(StructOptAttributes { paren_token, attrs })
- }
-}
-
-pub enum StructOptAttr {
- // single-identifier attributes
- Short(Ident),
- Long(Ident),
- Env(Ident),
- Flatten(Ident),
- Subcommand(Ident),
- NoVersion(Ident),
- VerbatimDocComment(Ident),
-
- // ident [= "string literal"]
- About(Ident, Option<LitStr>),
- Author(Ident, Option<LitStr>),
-
- // ident = "string literal"
- Version(Ident, LitStr),
- RenameAllEnv(Ident, LitStr),
- RenameAll(Ident, LitStr),
- NameLitStr(Ident, LitStr),
-
- // parse(parser_kind [= parser_func])
- Parse(Ident, ParserSpec),
-
- // ident [= arbitrary_expr]
- Skip(Ident, Option<Expr>),
-
- // ident = arbitrary_expr
- NameExpr(Ident, Expr),
-
- // ident(arbitrary_expr,*)
- MethodCall(Ident, Vec<Expr>),
-}
-
-impl Parse for StructOptAttr {
- fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
- use self::StructOptAttr::*;
-
- let name: Ident = input.parse()?;
- let name_str = name.to_string();
-
- if input.peek(Token![=]) {
- // `name = value` attributes.
- let assign_token = input.parse::<Token![=]>()?; // skip '='
-
- if input.peek(LitStr) {
- let lit: LitStr = input.parse()?;
- let lit_str = lit.value();
-
- let check_empty_lit = |s| {
- if lit_str.is_empty() {
- abort!(
- lit.span(),
- "`#[structopt({} = \"\")]` is deprecated in structopt 0.3, \
- now it's default behavior",
- s
- );
- }
- };
-
- match &*name_str.to_string() {
- "rename_all" => Ok(RenameAll(name, lit)),
- "rename_all_env" => Ok(RenameAllEnv(name, lit)),
-
- "version" => {
- check_empty_lit("version");
- Ok(Version(name, lit))
- }
-
- "author" => {
- check_empty_lit("author");
- Ok(Author(name, Some(lit)))
- }
-
- "about" => {
- check_empty_lit("about");
- Ok(About(name, Some(lit)))
- }
-
- "skip" => {
- let expr = ExprLit {
- attrs: vec![],
- lit: Lit::Str(lit),
- };
- let expr = Expr::Lit(expr);
- Ok(Skip(name, Some(expr)))
- }
-
- _ => Ok(NameLitStr(name, lit)),
- }
- } else {
- match input.parse::<Expr>() {
- Ok(expr) => {
- if name_str == "skip" {
- Ok(Skip(name, Some(expr)))
- } else {
- Ok(NameExpr(name, expr))
- }
- }
-
- Err(_) => abort! {
- assign_token.span(),
- "expected `string literal` or `expression` after `=`"
- },
- }
- }
- } else if input.peek(syn::token::Paren) {
- // `name(...)` attributes.
- let nested;
- parenthesized!(nested in input);
-
- match name_str.as_ref() {
- "parse" => {
- let parser_specs: Punctuated<ParserSpec, Token![,]> =
- nested.parse_terminated(ParserSpec::parse)?;
-
- if parser_specs.len() == 1 {
- Ok(Parse(name, parser_specs[0].clone()))
- } else {
- abort!(name.span(), "parse must have exactly one argument")
- }
- }
-
- "raw" => match nested.parse::<LitBool>() {
- Ok(bool_token) => {
- let expr = ExprLit {
- attrs: vec![],
- lit: Lit::Bool(bool_token),
- };
- let expr = Expr::Lit(expr);
- Ok(MethodCall(name, vec![expr]))
- }
-
- Err(_) => {
- abort!(name.span(),
- "`#[structopt(raw(...))` attributes are removed in structopt 0.3, \
- they are replaced with raw methods";
- help = "if you meant to call `clap::Arg::raw()` method \
- you should use bool literal, like `raw(true)` or `raw(false)`";
- note = raw_method_suggestion(nested);
- );
- }
- },
-
- _ => {
- let method_args: Punctuated<_, Token![,]> =
- nested.parse_terminated(Expr::parse)?;
- Ok(MethodCall(name, Vec::from_iter(method_args)))
- }
- }
- } else {
- // Attributes represented with a sole identifier.
- match name_str.as_ref() {
- "long" => Ok(Long(name)),
- "short" => Ok(Short(name)),
- "env" => Ok(Env(name)),
- "flatten" => Ok(Flatten(name)),
- "subcommand" => Ok(Subcommand(name)),
- "no_version" => Ok(NoVersion(name)),
- "verbatim_doc_comment" => Ok(VerbatimDocComment(name)),
-
- "about" => (Ok(About(name, None))),
- "author" => (Ok(Author(name, None))),
-
- "skip" => Ok(Skip(name, None)),
-
- "version" => abort!(
- name.span(),
- "#[structopt(version)] is invalid attribute, \
- structopt 0.3 inherits version from Cargo.toml by default, \
- no attribute needed"
- ),
-
- _ => abort!(name.span(), "unexpected attribute: {}", name_str),
- }
- }
- }
-}
-
-#[derive(Clone)]
-pub struct ParserSpec {
- pub kind: Ident,
- pub eq_token: Option<Token![=]>,
- pub parse_func: Option<Expr>,
-}
-
-impl Parse for ParserSpec {
- fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
- let kind = input
- .parse()
- .map_err(|_| input.error("parser specification must start with identifier"))?;
- let eq_token = input.parse()?;
- let parse_func = match eq_token {
- None => None,
- Some(_) => Some(input.parse()?),
- };
- Ok(ParserSpec {
- kind,
- eq_token,
- parse_func,
- })
- }
-}
-
-struct CommaSeparated<T>(Punctuated<T, Token![,]>);
-
-impl<T: Parse> Parse for CommaSeparated<T> {
- fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
- let res = Punctuated::parse_separated_nonempty(input)?;
- Ok(CommaSeparated(res))
- }
-}
-
-fn raw_method_suggestion(ts: ParseBuffer) -> String {
- let do_parse = move || -> Result<(Ident, CommaSeparated<Expr>), syn::Error> {
- let name = ts.parse()?;
- let _eq: Token![=] = ts.parse()?;
- let val: LitStr = ts.parse()?;
- Ok((name, syn::parse_str(&val.value())?))
- };
-
- fn to_string<T: ToTokens>(val: &T) -> String {
- val.to_token_stream()
- .to_string()
- .replace(" ", "")
- .replace(",", ", ")
- }
-
- if let Ok((name, val)) = do_parse() {
- let exprs = val.0;
- let suggestion = if exprs.len() == 1 {
- let val = to_string(&exprs[0]);
- format!(" = {}", val)
- } else {
- let val = exprs
- .into_iter()
- .map(|expr| to_string(&expr))
- .collect::<Vec<_>>()
- .join(", ");
-
- format!("({})", val)
- };
-
- format!(
- "if you need to call `clap::Arg/App::{}` method you \
- can do it like this: #[structopt({}{})]",
- name, name, suggestion
- )
- } else {
- "if you need to call some method from `clap::Arg/App` \
- you should use raw method, see \
- https://docs.rs/structopt/0.3/structopt/#raw-methods"
- .into()
- }
-}
-
-pub fn parse_structopt_attributes(all_attrs: &[Attribute]) -> Vec<StructOptAttr> {
- all_attrs
- .iter()
- .filter(|attr| attr.path.is_ident("structopt"))
- .flat_map(|attr| {
- let attrs: StructOptAttributes = parse2(attr.tokens.clone())
- .map_err(|e| match &*e.to_string() {
- // this error message is misleading and points to Span::call_site()
- // so we patch it with something meaningful
- "unexpected end of input, expected parentheses" => {
- let span = attr.path.span();
- let patch_msg = "expected parentheses after `structopt`";
- syn::Error::new(span, patch_msg)
- }
- _ => e,
- })
- .unwrap_or_abort();
- attrs.attrs
- })
- .collect()
-}