1#![allow(clippy::style)]
4
5extern crate proc_macro;
6
7mod utils;
8use utils::*;
9
10use proc_macro::TokenStream;
11use quote::quote;
12
13use core::fmt::Write;
14
15struct Argument {
16 field_name: String,
17 name: String,
18 desc: String,
19 required: bool,
20 is_optional: bool,
21 default: Option<String>,
22}
23
24#[derive(PartialEq, Eq, Debug)]
25enum OptValueType {
26 Help,
27 Bool,
28 Value,
29 MultiValue,
30}
31
32struct Opt {
33 arg: Argument,
34 long: String,
35 short: Option<String>,
36 typ: OptValueType,
37}
38
39struct Command {
40 variant_name: String,
41 command_name: String,
42 desc: String,
43}
44
45const CONCAT_DEFAULT_PROG_NAME_ARGS: &str = "env!(\"CARGO_PKG_NAME\"), \" \", env!(\"CARGO_PKG_VERSION\")";
46const FROM_FN: &str = "core::str::FromStr::from_str";
47const TAB: &str = " ";
48const PARSER_TRAIT: &str = "arg::Args";
49const DEFAULT_INIT: &str = "Default::default()";
50const INVALID_ARG_TYPE_STRING: &str = "Attribute accepts only str";
51const INVALID_REQUIRED_BOOL: &str = "Attribute required cannot be applied to bool switch";
52const UNKNOWN_ARG_ATTR: &str = "Unknown attribute is used";
53const ARG_INVALID_CHARS: &[char] = &[' ', '\t'];
54const ARG_NAME_SPACE_ERROR: &str = "Name contains space character";
55
56fn parse_segment(segment: &syn::PathSegment) -> OptValueType {
57 if segment.ident == "bool" {
58 OptValueType::Bool
59 } else if segment.ident == "Vec" {
60 OptValueType::MultiValue
61 } else {
62 OptValueType::Value
63 }
64}
65
66fn from_enum(ast: &syn::DeriveInput, payload: &syn::DataEnum) -> TokenStream {
67 let mut about_prog = String::new();
68 for attr in ast.attrs.iter() {
69 match &attr.meta {
70 syn::Meta::NameValue(value) => if value.path.is_ident("doc") {
71 let literal = match &value.value {
72 syn::Expr::Lit(literal) => &literal.lit,
73 _ => return syn::Error::new_spanned(value.clone(), "Attribute should be liberal").to_compile_error().into()
74 };
75 if let syn::Lit::Str(ref text) = literal {
76 about_prog.push_str(&text.value());
77 about_prog.push_str("\n");
78 }
79 },
80 _ => (),
81 }
82 }
83 about_prog.pop();
84
85 let mut commands = Vec::new();
86 for variant in payload.variants.iter() {
87 let mut desc = String::new();
88 let variant_name = variant.ident.to_string();
89 if variant_name.is_empty() {
90 return syn::Error::new_spanned(&variant.ident, "Oi, mate, You cannot have enum variant without name").to_compile_error().into()
91 }
92 let command_name = to_hyphenated_lower_case(&variant_name);
93 if command_name.eq_ignore_ascii_case("help") {
94 return syn::Error::new_spanned(&variant.ident, "Oi, mate, You cannot use variant 'Help'").to_compile_error().into()
95 }
96
97 for attr in variant.attrs.iter() {
98 match &attr.meta {
99 syn::Meta::NameValue(value) => if value.path.is_ident("doc") {
100 let literal = match &value.value {
101 syn::Expr::Lit(literal) => &literal.lit,
102 _ => return syn::Error::new_spanned(value.clone(), "Attribute should be liberal").to_compile_error().into()
103 };
104
105 if let syn::Lit::Str(ref text) = literal {
106 desc.push_str(&text.value());
107 desc.push_str(" ");
108 }
109 },
110 _ => continue
111 }
112 }
113
114 let field = match &variant.fields {
115 syn::Fields::Unit => return syn::Error::new_spanned(&variant.fields, "Unit variant cannot be used").to_compile_error().into(),
116 syn::Fields::Named(_) => return syn::Error::new_spanned(&variant.fields, "I'm too lazy to support named variant").to_compile_error().into(),
117 syn::Fields::Unnamed(fields) => {
118 if fields.unnamed.empty_or_trailing() {
119 return syn::Error::new_spanned(&fields, "MUST specify single field").to_compile_error().into();
120 } else if fields.unnamed.len() > 1 {
121 return syn::Error::new_spanned(fields, "MUST not specify more than 1 field").to_compile_error().into();
122 } else {
123 fields.unnamed.first().unwrap()
124 }
125 },
126 };
127
128 match &field.ty {
129 syn::Type::Path(ref ty) => {
130 let ty = ty.path.segments.last().expect("To have at least one segment");
131 if ty.ident == "Option" {
132 return syn::Error::new_spanned(ty, "Command cannot be optional").to_compile_error().into()
133 } else {
134 match parse_segment(ty) {
135 OptValueType::Bool => return syn::Error::new_spanned(ty, "Command value cannot be boolean").to_compile_error().into(),
136 OptValueType::MultiValue => return syn::Error::new_spanned(ty, "Command value Vec<_>").to_compile_error().into(),
137 _ => (),
138 }
139 }
140 },
141 ty => {
142 return syn::Error::new_spanned(ty, "Expected simple ident or path").to_compile_error().into()
143 }
144 }
145
146 commands.push(Command {
147 command_name,
148 variant_name,
149 desc
150 })
151 }
152
153 if commands.is_empty() {
154 return syn::Error::new_spanned(ast, "Enum must have at least one variant").to_compile_error().into()
155 }
156
157 let (impl_gen, type_gen, where_clause) = ast.generics.split_for_impl();
158
159 let help_msg = {
160 use std::io::Write;
161 use tabwriter::TabWriter;
162
163 let mut tw = TabWriter::new(vec![]);
164
165 let _ = writeln!(tw, "COMMANDS:");
166 for command in commands.iter() {
167 let _ = writeln!(tw, "\t{}\t{}", command.command_name, command.desc);
168 }
169
170 let _ = tw.flush();
171
172 String::from_utf8(tw.into_inner().unwrap()).unwrap()
173 };
174
175 let mut result = String::new();
176 let _ = writeln!(result, "{} {} for {}{} {{", quote!(impl#impl_gen), PARSER_TRAIT, ast.ident, quote!(#type_gen #where_clause));
177
178 let _ = writeln!(result, "{}const HELP: &'static str = \"{}\";", TAB, help_msg);
179
180 let _ = writeln!(result, "{}fn from_args<'a, T: IntoIterator<Item = &'a str>>(_args_: T) -> Result<Self, arg::ParseKind<'a>> {{", TAB);
182
183 let _ = writeln!(result, "{0}{0}let mut _args_ = _args_.into_iter();\n", TAB);
184
185 let _ = writeln!(result, "{0}{0}while let Some(_arg_) = _args_.next() {{", TAB);
187
188 let _ = writeln!(result, "{0}{0}{0}if _arg_.eq_ignore_ascii_case(\"help\") {{", TAB);
190 let _ = writeln!(result, "{0}{0}{0}{0}return Err(arg::ParseKind::Top(arg::ParseError::HelpRequested(Self::HELP)));", TAB);
191 let _ = write!(result, "{0}{0}{0}}}", TAB);
192
193 let mut allowed_commands = String::new();
194 for command in commands.iter() {
195 allowed_commands.push_str(command.command_name.as_str());
196 allowed_commands.push(',');
197 allowed_commands.push(' ');
198
199 let _ = writeln!(result, " else if _arg_.eq_ignore_ascii_case(\"{}\") {{", command.command_name);
201
202 let _ = writeln!(result, "{0}{0}{0}{0}match {1}::from_args(_args_) {{", TAB, PARSER_TRAIT);
203 let _ = writeln!(result, "{0}{0}{0}{0}{0}Ok(res) => return Ok(Self::{1}(res)),", TAB, command.variant_name);
204 let _ = writeln!(result, "{0}{0}{0}{0}{0}Err(arg::ParseKind::Top(error)) => return Err(arg::ParseKind::Sub(\"{1}\", error)),", TAB, command.command_name);
205 let _ = writeln!(result, "{0}{0}{0}{0}{0}Err(arg::ParseKind::Sub(name, error)) => return Err(arg::ParseKind::Sub(name, error)),", TAB);
206 let _ = writeln!(result, "{0}{0}{0}{0}}}", TAB);
207
208 let _ = write!(result, "{0}{0}{0}}}", TAB);
210 }
211
212 let _ = writeln!(result, " else {{");
214 let _ = writeln!(result, "{0}{0}{0}{0}return Err(arg::ParseKind::Top(arg::ParseError::InvalidArgValue(\"command\", _arg_)))", TAB);
215 let _ = write!(result, "{0}{0}{0}}}", TAB);
216
217 let _ = writeln!(result, "\n{0}{0}}}", TAB);
219
220 allowed_commands.pop();
221 allowed_commands.pop();
222 let _ = writeln!(result, "{0}{0}Err(arg::ParseKind::Top(arg::ParseError::HelpRequested(\"Missing command, possible values: [{1}]\nSee 'help' for details\")))", TAB, allowed_commands);
224
225 let _ = writeln!(result, "{}}}", TAB);
227
228 let _ = writeln!(result, "}}");
229
230 if let Ok(val) = std::env::var("ARG_RS_PRINT_PARSER") {
231 match val.trim() {
232 "0" | "false" => (),
233 _ => println!("{result}"),
234 }
235 }
236 result.parse().expect("To parse generated code")
237}
238
239fn from_struct(ast: &syn::DeriveInput, payload: &syn::DataStruct) -> TokenStream {
240 let mut infer_prog_name = false;
241 let mut about_prog = String::new();
242 for attr in ast.attrs.iter() {
243 match &attr.meta {
244 syn::Meta::NameValue(value) => if value.path.is_ident("doc") {
245 let literal = match &value.value {
246 syn::Expr::Lit(literal) => &literal.lit,
247 _ => return syn::Error::new_spanned(attr, "Attribute should be liberal").to_compile_error().into()
248 };
249 if let syn::Lit::Str(ref text) = literal {
250 about_prog.push_str(&text.value());
251 about_prog.push('\n');
252 }
253 },
254 syn::Meta::List(list) => if list.path.is_ident("arg") {
255 let nested = match attr.parse_args_with(syn::punctuated::Punctuated::<syn::Meta, syn::Token![,]>::parse_terminated) {
256 Ok(nested) => nested,
257 Err(error) => {
258 let error = format!("arg attribute should be list of attributes: {error}");
259 return syn::Error::new_spanned(list, error).to_compile_error().into();
260 }
261 };
262 for value_attr in nested {
263 match value_attr {
264 syn::Meta::Path(value_attr) => if value_attr.is_ident("infer_name") {
265 infer_prog_name = true;
266 } else {
267 let ident = utils::FormatOptionalIdent(value_attr.get_ident());
268 return syn::Error::new_spanned(&value_attr, format!("Unknown attribute: '{ident}'. Expected: infer_name")).to_compile_error().into();
269 },
270 unexpected => return syn::Error::new_spanned(&unexpected, "Unexpected attribute").to_compile_error().into(),
271 }
272 }
273 },
274 _ => (),
275 }
276 }
277
278 about_prog.pop();
279
280 let mut options = Vec::new();
281 let mut arguments = Vec::new();
282
283 options.push(Opt {
284 arg: Argument {
285 field_name: "_".to_owned(),
286 name: "help".to_owned(),
287 desc: "Prints this help information".to_owned(),
288 required: false,
289 is_optional: false,
290 default: None,
291 },
292 short: Some("h".to_owned()),
293 long: "help".to_owned(),
294 typ: OptValueType::Help,
295 });
296
297 let mut sub_command = None;
298 let mut multi_argument = None;
299
300 for field in payload.fields.iter() {
301 let field_name = field.ident.as_ref().unwrap().to_string();
302 let name = field.ident.as_ref().unwrap().to_string().trim_matches(|ch| !char::is_alphanumeric(ch)).to_owned();
303 let mut desc = String::new();
304 let mut short = None;
305 let mut long = None;
306 let mut required = false;
307 let mut is_sub = false;
308
309 let (is_optional, typ) = match field.ty {
310 syn::Type::Path(ref ty) => {
311 let ty = ty.path.segments.last().expect("To have at least one segment");
312
313 if ty.ident == "Option" {
314 let ty = match &ty.arguments {
315 syn::PathArguments::AngleBracketed(ref args) => match args.args.len() {
316 0 => return syn::Error::new_spanned(&ty.ident, "Oi, mate, Option is without type arguments. Fix it").to_compile_error().into(),
317 1 => match args.args.first().unwrap() {
318 syn::GenericArgument::Type(syn::Type::Path(ty)) => parse_segment(ty.path.segments.last().expect("To have at least one segment")),
319 _ => return syn::Error::new_spanned(&ty.ident, "Oi, mate, Option should have type argument, but got some other shite. Fix it").to_compile_error().into(),
320 },
321 _ => return syn::Error::new_spanned(&ty.ident, "Oi, mate, Option has too many type arguments. Fix it").to_compile_error().into()
322 },
323 syn::PathArguments::None => return syn::Error::new_spanned(&ty.ident, "Oi, mate, Option is without type arguments. Fix it").to_compile_error().into(),
324 syn::PathArguments::Parenthesized(_) => return syn::Error::new_spanned(&ty.ident, "Oi, mate, you got wrong brackets for your Option . Fix it").to_compile_error().into(),
325 };
326
327 (true, ty)
328 } else {
329 (false, parse_segment(ty))
330 }
331 },
332 _ => (false, OptValueType::Value),
333 };
334
335 if is_optional && typ == OptValueType::MultiValue {
336 return syn::Error::new_spanned(field, "Option<Vec<_>> makes no sense. Just use plain Vec<_>").to_compile_error().into();
337 }
338
339 let mut default = None;
340
341 for attr in field.attrs.iter() {
342 match &attr.meta {
343 syn::Meta::NameValue(value) => if value.path.is_ident("doc") {
344 let literal = match &value.value {
345 syn::Expr::Lit(literal) => &literal.lit,
346 _ => return syn::Error::new_spanned(attr, "Attribute should be liberal").to_compile_error().into()
347 };
348 if let syn::Lit::Str(ref text) = literal {
349 desc.push_str(&text.value());
350 desc.push(' ');
351 }
352 },
353 syn::Meta::List(value) => if value.path.is_ident("arg") {
354 let nested = match attr.parse_args_with(syn::punctuated::Punctuated::<syn::Meta, syn::Token![,]>::parse_terminated) {
355 Ok(nested) => nested,
356 Err(error) => {
357 let error = format!("arg attribute should be list of attributes: {error}");
358 return syn::Error::new_spanned(value, error).to_compile_error().into();
359 }
360 };
361
362 for value_attr in nested {
363 match value_attr {
364 syn::Meta::Path(value_attr) => if value_attr.is_ident("short") {
365 short = Some(format!("{}", name.chars().next().unwrap()).to_lowercase());
366 } else if value_attr.is_ident("long") {
367 long = Some(name.to_lowercase());
368 } else if value_attr.is_ident("default_value") {
369 default = Some(DEFAULT_INIT.to_owned());
370 } else if value_attr.is_ident("required") {
371 required = true;
372 } else if value_attr.is_ident("sub") {
373 if typ == OptValueType::Value {
374 is_sub = true;
375 } else {
376 return syn::Error::new_spanned(value_attr, "Sub-command must be simple value").to_compile_error().into();
377 }
378 }
379 syn::Meta::NameValue(value_attr) => if value_attr.path.is_ident("short") {
380 let literal = match &value_attr.value {
381 syn::Expr::Lit(literal) => &literal.lit,
382 _ => return syn::Error::new_spanned(attr, "Attribute should be liberal").to_compile_error().into()
383 };
384
385 if let syn::Lit::Str(ref text) = literal {
386 let value_attr_text = text.value();
387
388 if value_attr_text.contains(ARG_INVALID_CHARS) {
389 return syn::Error::new_spanned(literal.clone(), ARG_NAME_SPACE_ERROR).to_compile_error().into();
390 }
391
392 short = Some(value_attr_text);
393 } else {
394 return syn::Error::new_spanned(value_attr.path.clone(), INVALID_ARG_TYPE_STRING).to_compile_error().into();
395 }
396 } else if value_attr.path.is_ident("long") {
397 let literal = match &value_attr.value {
398 syn::Expr::Lit(literal) => &literal.lit,
399 _ => return syn::Error::new_spanned(attr, "Attribute should be liberal").to_compile_error().into()
400 };
401
402 if let syn::Lit::Str(ref text) = literal {
403 let value_attr_text = text.value();
404
405 if value_attr_text.contains(ARG_INVALID_CHARS) {
406 return syn::Error::new_spanned(literal.clone(), ARG_NAME_SPACE_ERROR).to_compile_error().into();
407 }
408
409 long = Some(value_attr_text)
410 } else {
411 return syn::Error::new_spanned(value_attr.path.clone(), INVALID_ARG_TYPE_STRING).to_compile_error().into();
412 }
413 } else if value_attr.path.is_ident("default_value") {
414 let literal = match &value_attr.value {
415 syn::Expr::Lit(literal) => &literal.lit,
416 _ => return syn::Error::new_spanned(attr, "Attribute should be liberal").to_compile_error().into()
417 };
418
419 if let syn::Lit::Str(ref text) = literal {
420 default = Some(text.value());
421 } else {
422 return syn::Error::new_spanned(value_attr.path.clone(), INVALID_ARG_TYPE_STRING).to_compile_error().into();
423 }
424 } else {
425 return syn::Error::new_spanned(value_attr.path.clone(), UNKNOWN_ARG_ATTR).to_compile_error().into();
426 }
427 _ => {
428 },
429 }
430 } },
432 _ => (),
433 }
434 }
435
436 desc.pop();
437
438 if required && default.is_some() {
439 return syn::Error::new_spanned(field.ident.clone(), "Marked as required, but default value is provided?").to_compile_error().into();
440 } else if is_optional && default.is_some() {
441 return syn::Error::new_spanned(field.ident.clone(), "Optional, but default value is provided?").to_compile_error().into();
442 } else if is_sub && is_optional {
443 return syn::Error::new_spanned(field.ident.clone(), "Sub-command cannot be optional").to_compile_error().into();
444 } else if is_sub && default.is_some() {
445 return syn::Error::new_spanned(field.ident.clone(), "Sub-command cannot have default value").to_compile_error().into();
446 } else if !required && !is_optional && default.is_none() {
447 default = Some(DEFAULT_INIT.to_owned());
448 }
449
450 if short.is_none() && long.is_none() {
451 if typ == OptValueType::MultiValue {
452 if multi_argument.is_some() {
453 return syn::Error::new_spanned(field.ident.clone(), "Second argument collection. There can be only one").to_compile_error().into();
454 } else if sub_command.is_some() {
455 return syn::Error::new_spanned(field.ident.clone(), "Multi-argument collection and sub-command are mutually exclusive").to_compile_error().into();
456 }
457
458 multi_argument = Some(Argument {
459 field_name,
460 name,
461 desc,
462 required,
463 is_optional,
464 default,
465 });
466
467 } else if is_sub {
468 if sub_command.is_some() {
469 return syn::Error::new_spanned(field.ident.clone(), "Second sub-command. There can be only one").to_compile_error().into();
470 } else if multi_argument.is_some() {
471 return syn::Error::new_spanned(field.ident.clone(), "Sub-command and multi-argument collection are mutually exclusive").to_compile_error().into();
472 }
473
474 sub_command = Some(Argument {
475 field_name,
476 name,
477 desc,
478 required: true,
479 is_optional: false,
480 default: None,
481 });
482 } else {
483 arguments.push(Argument {
484 field_name,
485 name,
486 desc,
487 required,
488 is_optional,
489 default,
490 })
491 }
492 } else {
493 if OptValueType::Bool == typ && required {
495 return syn::Error::new_spanned(field.ident.clone(), INVALID_REQUIRED_BOOL).to_compile_error().into();
497 }
498
499 let long = match long {
500 Some(long) => long,
501 None => name.clone()
502 };
503
504 options.push(Opt {
505 arg: Argument {
506 field_name,
507 name,
508 desc,
509 required,
510 is_optional,
511 default,
512 },
513 short,
514 long,
515 typ
516 })
517 }
518 }
519
520 let (impl_gen, type_gen, where_clause) = ast.generics.split_for_impl();
521
522 let help_msg = {
523 use std::io::Write;
524 use tabwriter::TabWriter;
525
526 let mut tw = TabWriter::new(vec![]);
527
528 let _ = write!(tw, "{}
529
530USAGE:", about_prog);
531
532 if !options.is_empty() {
533 let _ = write!(tw, " [OPTIONS]");
534 }
535
536 for argument in arguments.iter() {
537 let _ = if argument.required {
538 write!(tw, " <{}>", argument.name)
539 } else {
540 write!(tw, " [{}]", argument.name)
541 };
542 }
543
544 if let Some(argument) = multi_argument.as_ref() {
545 let _ = if argument.required {
546 write!(tw, " <{}>...", argument.name)
547 } else {
548 write!(tw, " [{}]...", argument.name)
549 };
550 } else if let Some(argument) = sub_command.as_ref() {
551 let _ = write!(tw, " <{}>", argument.name);
552 }
553
554 if !options.is_empty() {
555 let _ = write!(tw, "\n\nOPTIONS:\n");
556 }
557
558 for option in options.iter() {
559 let _ = write!(tw, "\t");
560 if let Some(short) = option.short.as_ref() {
561 let _ = write!(tw, "-{},", short);
562 }
563 let _ = write!(tw, "\t");
564
565 let _ = write!(tw, "--{}", option.long);
566
567 let _ = match option.typ {
568 OptValueType::MultiValue => write!(tw, " <{}>...", option.arg.name),
569 OptValueType::Value => write!(tw, " <{}>", option.arg.name),
570 _ => Ok(()),
571 };
572
573 let _ = writeln!(tw, "\t{}", option.arg.desc);
574 }
575
576 if !arguments.is_empty() || multi_argument.is_some() || sub_command.is_some() {
577 let _ = write!(tw, "\nARGS:\n");
578 }
579
580 for argument in arguments.iter() {
581 let _ = if argument.required {
582 writeln!(tw, "\t<{}>\t{}", argument.name, argument.desc)
583 } else {
584 writeln!(tw, "\t[{}]\t{}", argument.name, argument.desc)
585 };
586 }
587
588 if let Some(argument) = multi_argument.as_ref() {
589 let _ = writeln!(tw, "\t<{}>...\t{}", argument.name, argument.desc);
590 } else if let Some(command) = sub_command.as_ref() {
591 let _ = writeln!(tw, "\t<{}>\t{}", command.name, command.desc);
592 }
593
594 let _ = tw.flush();
595
596 String::from_utf8(tw.into_inner().unwrap()).unwrap()
597 };
598
599 let mut result = String::new();
600 let _ = writeln!(result, "{} {} for {}{} {{", quote!(impl#impl_gen), PARSER_TRAIT, ast.ident, quote!(#type_gen #where_clause));
601 if infer_prog_name {
602 let _ = writeln!(result, "{}const HELP: &'static str = core::concat!({CONCAT_DEFAULT_PROG_NAME_ARGS}, \"\n\", \"{}\");", TAB, help_msg);
603 } else {
604 let _ = writeln!(result, "{}const HELP: &'static str = \"{}\";", TAB, help_msg);
605 }
606
607 let _ = writeln!(result, "{}fn from_args<'a, T: IntoIterator<Item = &'a str>>(_args_: T) -> Result<Self, arg::ParseKind<'a>> {{", TAB);
608
609 for option in options.iter() {
610 if option.arg.field_name == "_" {
611 continue;
612 }
613
614 let _ = match option.typ {
615 OptValueType::MultiValue => writeln!(result, "{0}{0}let mut {1} = Vec::new();", TAB, option.arg.field_name),
616 OptValueType::Bool => writeln!(result, "{0}{0}let mut {1} = false;", TAB, option.arg.field_name),
617 _ => writeln!(result, "{0}{0}let mut {1} = None;", TAB, option.arg.field_name),
618 };
619 }
620
621 for argument in arguments.iter() {
622 let _ = writeln!(result, "{0}{0}let mut {1} = None;", TAB, argument.field_name);
623 }
624
625 if let Some(argument) = multi_argument.as_ref() {
626 let _ = writeln!(result, "{0}{0}let mut {1} = Vec::new();", TAB, argument.field_name);
627 } else if let Some(command) = sub_command.as_ref() {
628 let _ = writeln!(result, "{0}{0}let mut {1} = None;", TAB, command.field_name);
629 }
630
631 let _ = writeln!(result, "{0}{0}let mut _args_ = _args_.into_iter();\n", TAB);
632 let _ = writeln!(result, "{0}{0}while let Some(_arg_) = _args_.next() {{", TAB);
633
634 let _ = writeln!(result, "{0}{0}{0}if let Some(_arg_) = _arg_.strip_prefix('-') {{", TAB);
636 let _ = writeln!(result, "{0}{0}{0}{0}match _arg_ {{", TAB);
637 let _ = writeln!(result, "{0}{0}{0}{0}{0}\"h\" | \"-help\" => return Err(arg::ParseKind::Top(arg::ParseError::HelpRequested(Self::HELP))),", TAB);
638 let _ = writeln!(result, "{0}{0}{0}{0}{0}\"\" => (),", TAB);
639
640 for option in options.iter() {
641 if option.arg.field_name == "_" {
642 continue;
643 }
644
645 let _ = write!(result, "{0}{0}{0}{0}{0}", TAB);
646
647 if let Some(short) = option.short.as_ref() {
648 let _ = write!(result, "\"{}\" | ", short);
649 }
650
651 let _ = write!(result, "\"-{}\" => ", option.long);
652
653 let _ = match option.typ {
654 OptValueType::Help => panic!("Option Help is invalid here. Bug report it"),
655 OptValueType::Bool => write!(result, "{{ {0} = !{0}; continue }},", option.arg.field_name),
656 OptValueType::Value => write!(result, "match _args_.next() {{
657{0}{0}{0}{0}{0}{0}Some(_next_arg_) => match {1}(_next_arg_) {{
658{0}{0}{0}{0}{0}{0}{0}Ok(value) => {{ {2} = Some(value); continue }},
659{0}{0}{0}{0}{0}{0}{0}Err(_) => return Err(arg::ParseKind::Top(arg::ParseError::InvalidFlagValue(\"{3}\", _next_arg_))),
660{0}{0}{0}{0}{0}{0}}},
661{0}{0}{0}{0}{0}{0}None => return Err(arg::ParseKind::Top(arg::ParseError::MissingValue(\"{3}\"))),
662{0}{0}{0}{0}{0}}}", TAB, FROM_FN, option.arg.field_name, option.arg.name),
663 OptValueType::MultiValue => write!(result, "match _args_.next() {{
664{0}{0}{0}{0}{0}{0}Some(_next_arg_) => match {1}(_next_arg_) {{
665{0}{0}{0}{0}{0}{0}{0}Ok(value) => {{ {2}.push(value); continue }},
666{0}{0}{0}{0}{0}{0}{0}Err(_) => return Err(arg::ParseKind::Top(arg::ParseError::InvalidFlagValue(\"{3}\", _next_arg_))),
667{0}{0}{0}{0}{0}{0}}},
668{0}{0}{0}{0}{0}{0}None => return Err(arg::ParseKind::Top(arg::ParseError::MissingValue(\"{3}\"))),
669{0}{0}{0}{0}{0}}}", TAB, FROM_FN, option.arg.field_name, option.arg.name),
670 };
671 result.push('\n');
672 }
673 let _ = writeln!(result, "{0}{0}{0}{0}{0}_ => return Err(arg::ParseKind::Top(arg::ParseError::UnknownFlag(_arg_))),", TAB);
674
675 let _ = writeln!(result, "{0}{0}{0}{0}}}", TAB);
676 let _ = writeln!(result, "{0}{0}{0}}}", TAB);
677 for (idx, arg) in arguments.iter().enumerate() {
679 if idx == 0 {
680 let _ = writeln!(result, "{0}{0}{0}if {1}.is_none() {{", TAB, arg.field_name);
681 } else {
682 let _ = writeln!(result, "{0}{0}{0}}} else if {1}.is_none() {{", TAB, arg.field_name);
683 }
684 let _ = writeln!(result, "{0}{0}{0}{0}match {1}(_arg_) {{", TAB, FROM_FN);
685 let _ = writeln!(result, "{0}{0}{0}{0}{0}Ok(_res_) => {1} = Some(_res_),", TAB, arg.field_name);
686 let _ = writeln!(result, "{0}{0}{0}{0}{0}Err(_) => return Err(arg::ParseKind::Top(arg::ParseError::InvalidArgValue(\"{1}\", _arg_))),", TAB, arg.field_name);
687 let _ = writeln!(result, "{0}{0}{0}{0}}}", TAB);
688 }
689 if !arguments.is_empty() {
691 let _ = writeln!(result, "{0}{0}{0}}} else {{", TAB);
692 }
693
694 if let Some(arg) = multi_argument.as_ref() {
695 let _ = writeln!(result, "{0}{0}{0}{0}match {1}(_arg_) {{", TAB, FROM_FN);
696 let _ = writeln!(result, "{0}{0}{0}{0}{0}Ok(_res_) => {1}.push(_res_),", TAB, arg.field_name);
697 let _ = writeln!(result, "{0}{0}{0}{0}{0}Err(_) => return Err(arg::ParseKind::Top(arg::ParseError::InvalidArgValue(\"{1}\", _arg_))),", TAB, arg.field_name);
698 let _ = writeln!(result, "{0}{0}{0}{0}}}", TAB);
699 } else if let Some(command) = sub_command.as_ref() {
700 let _ = writeln!(result, "{0}{0}{0}{0}match {1}::from_args(core::iter::once(_arg_).chain(_args_)) {{", TAB, PARSER_TRAIT);
701 let _ = writeln!(result, "{0}{0}{0}{0}{0}Ok(_res_) => {{ {1} = Some(_res_); break; }},", TAB, command.field_name);
702 let _ = writeln!(result, "{0}{0}{0}{0}{0}Err(arg::ParseKind::Top(arg::ParseError::InvalidArgValue(_, invalid_value))) => return Err(arg::ParseKind::Top(arg::ParseError::InvalidArgValue(\"{1}\", invalid_value))),", TAB, command.field_name);
703 let _ = writeln!(result, "{0}{0}{0}{0}{0}Err(arg::ParseKind::Top(_)) => return Err(arg::ParseKind::Top(arg::ParseError::RequiredArgMissing(\"{1}\"))),", TAB, command.field_name);
704 let _ = writeln!(result, "{0}{0}{0}{0}{0}Err(arg::ParseKind::Sub(name, error)) => return Err(arg::ParseKind::Sub(name, error)),", TAB);
705 let _ = writeln!(result, "{0}{0}{0}{0}}}", TAB);
706 } else {
707 let _ = writeln!(result, "{0}{0}{0}{0} return Err(arg::ParseKind::Top(arg::ParseError::TooManyArgs));", TAB);
708 }
709 if !arguments.is_empty() {
711 let _ = writeln!(result, "{0}{0}{0}}}", TAB);
712 let _ = writeln!(result, "{0}{0}}}", TAB);
713 } else {
714 let _ = writeln!(result, "{0}{0}}}", TAB);
715 }
716
717 for option in options.iter() {
719 if option.arg.field_name == "_" {
720 continue;
721 }
722
723 let _ = match option.typ {
724 OptValueType::MultiValue => Ok(()),
725 OptValueType::Bool => Ok(()),
726 _ => match option.arg.default {
727 Some(ref default) => writeln!(result, "{0}{0}let {1} = if let Some(value) = {1} {{ value }} else {{ {2} }};", TAB, option.arg.field_name, default),
728 None => match option.arg.is_optional {
729 true => Ok(()),
730 false => writeln!(result, "{0}{0}let {1} = if let Some(value) = {1} {{ value }} else {{ return Err(arg::ParseKind::Top(arg::ParseError::RequiredArgMissing(\"{2}\"))) }};", TAB, option.arg.field_name, option.arg.name),
731 },
732 },
733 };
734 }
735
736 for arg in arguments.iter() {
737 let _ = match arg.default {
738 Some(ref default) => writeln!(result, "{0}{0}let {1} = if let Some(value) = {1} {{ value }} else {{ {2} }};", TAB, arg.field_name, default),
739 None => match arg.is_optional {
740 true => Ok(()),
741 false => writeln!(result, "{0}{0}let {1} = if let Some(value) = {1} {{ value }} else {{ return Err(arg::ParseKind::Top(arg::ParseError::RequiredArgMissing(\"{2}\"))) }};", TAB, arg.field_name, arg.name),
742 }
743 };
744 }
745
746 if let Some(command) = sub_command.as_ref() {
747 let _ = writeln!(result, "{0}{0}let {1} = match {1} {{", TAB, command.field_name);
748 let _ = writeln!(result, "{0}{0}{0}Some({1}) => {1},", TAB, command.field_name);
749 let _ = writeln!(result, "{0}{0}{0}None => match {1}::from_args([]) {{", TAB, PARSER_TRAIT);
751 let _ = writeln!(result, "{0}{0}{0}{0}Ok({1}) => {1},", TAB, command.field_name);
752 let _ = writeln!(result, "{0}{0}{0}{0}Err(error) => return Err(error),", TAB);
753 let _ = writeln!(result, "{0}{0}{0}}}", TAB);
754 let _ = writeln!(result, "{0}{0}}};", TAB);
756 }
757
758 let _ = writeln!(result, "{0}{0}Ok(Self {{", TAB);
760
761 for option in options.iter() {
762 if option.arg.field_name == "_" {
763 continue;
764 }
765
766 let _ = if option.arg.is_optional && option.typ == OptValueType::Bool {
767 writeln!(result, "{0}{0}{0}{1}: Some({1}),", TAB, option.arg.field_name)
768 } else {
769 writeln!(result, "{0}{0}{0}{1},", TAB, option.arg.field_name)
770 };
771 }
772
773 for arg in arguments.iter() {
774 let _ = writeln!(result, "{0}{0}{0}{1},", TAB, arg.field_name);
775 }
776
777 if let Some(arg) = multi_argument.as_ref() {
778 let _ = writeln!(result, "{0}{0}{0}{1},", TAB, arg.field_name);
779 } else if let Some(arg) = sub_command.as_ref() {
780 let _ = writeln!(result, "{0}{0}{0}{1},", TAB, arg.field_name);
781 }
782
783 let _ = writeln!(result, "{0}{0}}})", TAB);
784
785 let _ = writeln!(result, "{}}}", TAB);
787
788 let _ = writeln!(result, "}}");
789
790 if let Ok(val) = std::env::var("ARG_RS_PRINT_PARSER") {
791 match val.trim() {
792 "0" | "false" => (),
793 _ => println!("{result}"),
794 }
795 }
796 result.parse().expect("To parse generated code")
797}
798
799#[proc_macro_derive(Args, attributes(parser, arg))]
800pub fn parser_derive(input: TokenStream) -> TokenStream {
801 const INVALID_INPUT_TYPE: &str = "Unsupported parser input type. Expect: struct";
802 let ast: syn::DeriveInput = syn::parse(input).unwrap();
803
804 match ast.data {
805 syn::Data::Struct(ref data) => from_struct(&ast, data),
806 syn::Data::Enum(ref data) => from_enum(&ast, data),
807 _ => syn::Error::new_spanned(ast.ident, INVALID_INPUT_TYPE).to_compile_error().into(),
808 }
809}