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