1 /++
2 $(H2 The extenstion module for Cmdline)
3 
4 This module give a new programming way to build the command line prgram.
5 And it is publicly imported into main modlue `cmdline`.
6 
7 Using the following mixin-macro which are used for being embedded in a struct whose name
8 is end with `Result` and fields must be among `ArgVal`, `OptVal` and the pointer to other
9 structs that are satisfied with and the two function `coustruct` and `parse`, you can 
10 build and parse the command line argument and option parameters. And Also, We can get the
11 parsed value from command line more easily.
12 
13 Authors: 笑愚(xiaoyu)
14 +/
15 module cmdline.ext;
16 
17 import std.traits;
18 import std.meta;
19 import std.range : ElementType;
20 
21 import cmdline.option;
22 import cmdline.argument;
23 import cmdline.command;
24 
25 public:
26 
27 enum __CMDLINE_EXT_isInnerArgValField__(T) = hasMember!(T, "ARGVAL_FLAG_");
28 enum __CMDLINE_EXT_isInnerOptValField__(T) = hasMember!(T, "OPTVAL_FLAG_");
29 enum __CMDLINE_EXT_isInnerValField__(T) = __CMDLINE_EXT_isInnerArgValField__!T
30     || __CMDLINE_EXT_isInnerOptValField__!T;
31 enum __CMDLINE_EXT_isInnerSubField__(T) = isPointer!T && isOutputResult!(PointerTarget!T);
32 enum __CMDLINE_EXT_isInnerValFieldOrResult__(T) = __CMDLINE_EXT_isInnerValField__!T
33     || __CMDLINE_EXT_isInnerSubField__!T;
34 
35 /// check whether a type is the struct that can be the  
36 /// container to store the parsed value from command line. 
37 enum isOutputResult(T) = is(T == struct)
38     && T.stringof.length > 6 && (T.stringof)[$ - 6 .. $] == "Result"
39     && FieldTypeTuple!T.length > 0
40     && anySatisfy!(__CMDLINE_EXT_isInnerValFieldOrResult__, FieldTypeTuple!T);
41 
42 /// Add description to a registered argument.
43 /// Params:
44 ///   field = the argument in the type of `ArgVal`
45 ///   desc = the description
46 mixin template DESC_ARG(alias field, string desc) {
47     static assert(__CMDLINE_EXT_isInnerArgValField__!(typeof(field)));
48     debug pragma(msg, "enum DESC_ARG_" ~ field.stringof ~ "_ = \"" ~ desc ~ "\";");
49     mixin("enum DESC_ARG_" ~ field.stringof ~ "_ = \"" ~ desc ~ "\";");
50 }
51 
52 /// Add description to a registered option.
53 /// Params:
54 ///   field = the option in the type of `OptVal`
55 ///   desc = the description
56 mixin template DESC_OPT(alias field, string desc) {
57     static assert(__CMDLINE_EXT_isInnerOptValField__!(typeof(field)));
58     debug pragma(msg, "enum DESC_OPT_" ~ field.stringof ~ "_ = \"" ~ desc ~ "\";");
59     mixin("enum DESC_OPT_" ~ field.stringof ~ "_ = \"" ~ desc ~ "\";");
60 }
61 
62 /// Add description to a registered option or argument.
63 /// Params:
64 ///   field = the option or argument in the type of `OptVal` or `ArgVal`
65 ///   desc = the description
66 mixin template DESC(alias field, string desc) {
67     static if (__CMDLINE_EXT_isInnerArgValField__!(typeof(field))) {
68         mixin DESC_ARG!(field, desc);
69     }
70     else static if (__CMDLINE_EXT_isInnerOptValField__!(typeof(field))) {
71         mixin DESC_OPT!(field, desc);
72     }
73     else {
74         static assert(0);
75     }
76 }
77 
78 /// set the default value to a registered option or argument
79 /// Params:
80 ///   field = the option or argument in the type of `OptVal` or `ArgVal`
81 ///   val = the default value
82 mixin template DEFAULT(alias field, alias val) {
83     alias ___FType___CMDLINE = typeof(field);
84     static assert(!is(___FType___CMDLINE.InnerType == bool));
85     static if (__CMDLINE_EXT_isInnerOptValField__!___FType___CMDLINE
86         && ___FType___CMDLINE.VARIADIC
87         && is(ElementType!(___FType___CMDLINE.InnerType) == void)) {
88         static assert(is(typeof(val) == ___FType___CMDLINE.InnerType[]));
89     }
90     else {
91         static assert(is(typeof(val) : ___FType___CMDLINE.InnerType));
92     }
93     debug pragma(msg, "static " ~ typeof(val)
94             .stringof ~ " DEFAULT_" ~ field.stringof ~ "_ = " ~ val.stringof ~ ";");
95     mixin("static " ~ typeof(val).stringof ~ " DEFAULT_" ~ field.stringof ~ "_ = " ~ val.stringof ~ ";");
96 }
97 
98 /// set the preset value to a registered option
99 /// Params:
100 ///   field = the option in the type of `OptVal`
101 ///   val = the preset value
102 mixin template PRESET(alias field, alias val) {
103     alias ___FType___CMDLINE = typeof(field);
104     static assert(__CMDLINE_EXT_isInnerOptValField__!___FType___CMDLINE && !is(
105             ___FType___CMDLINE.InnerType == bool) && ___FType___CMDLINE
106             .OPTIONAL);
107     static if (___FType___CMDLINE.VARIADIC && is(ElementType!(___FType___CMDLINE.InnerType) == void)) {
108         static assert(is(typeof(val) == ___FType___CMDLINE.InnerType[]));
109     }
110     else {
111         static assert(is(typeof(val) : ___FType___CMDLINE.InnerType));
112     }
113     debug pragma(msg, "static " ~ typeof(val)
114             .stringof ~ " PRESET_" ~ field.stringof ~ "_ = " ~ val.stringof ~ ";");
115     mixin("static " ~ typeof(val).stringof ~ " PRESET_" ~ field.stringof ~ "_ = " ~ val.stringof ~ ";");
116 }
117 
118 /// set the env key from which get the values to a registered option
119 /// Params:
120 ///   field = the option in the type of `OptVal`
121 ///   envKey = the env key
122 mixin template ENV(alias field, string envKey) {
123     alias ___FType___CMDLINE = typeof(field);
124     static assert(__CMDLINE_EXT_isInnerOptValField__!___FType___CMDLINE && !is(
125             ___FType___CMDLINE.InnerType == bool));
126     debug pragma(msg, "enum ENV_" ~ field.stringof ~ "_ = \"" ~ envKey ~ "\";");
127     mixin("enum ENV_" ~ field.stringof ~ "_ = \"" ~ envKey ~ "\";");
128 }
129 
130 /// set the choices list to a registered option or argument
131 /// Params:
132 ///   field = the option or argument in the type of `OptVal` or `ArgVal`
133 ///   Args = the choices list items
134 mixin template CHOICES(alias field, Args...) {
135     static assert(Args.length);
136     alias ___FType___CMDLINE = typeof(field);
137     static assert(!is(___FType___CMDLINE.InnerType == bool));
138     enum isRegularType(alias val) = is(typeof(val) : ___FType___CMDLINE.InnerType)
139         || is(ElementType!(___FType___CMDLINE.InnerType) == typeof(val));
140     import std.meta;
141 
142     static assert(allSatisfy!(isRegularType, Args));
143     debug pragma(msg, "static " ~ typeof(
144             Args[0])[].stringof ~
145             " CHOICES_" ~ field.stringof ~
146             "_ = " ~ [Args].stringof ~ ";");
147     mixin("static " ~ typeof(
148             Args[0])[].stringof ~
149             " CHOICES_" ~ field.stringof ~
150             "_ = " ~ [Args].stringof ~ ";");
151 }
152 
153 /// set the range of a registered option or argument which inner
154 /// type is numeric type
155 /// Params:
156 ///   field = the option or argument in the type of `OptVal` or `ArgVal`
157 ///   Args = the minimum and the maximum in numeric type
158 mixin template RANGE(alias field, Args...) {
159     static assert(Args.length > 1);
160     alias ___FType___CMDLINE = typeof(field);
161     static assert(is(___FType___CMDLINE.InnerType == int) || is(
162             ___FType___CMDLINE.InnerType == double));
163     static assert(is(typeof(Args[0]) == typeof(Args[1])) && is(typeof(Args[0])));
164     static assert(is(typeof(Args[0]) : ___FType___CMDLINE.InnerType) && Args[0] < Args[1]);
165     debug pragma(msg, "enum RANGE_" ~ field.stringof ~ "_MIN_ = " ~ Args[0].stringof ~ ";");
166     debug pragma(msg, "enum RANGE_" ~ field.stringof ~ "_MAX_ = " ~ Args[1].stringof ~ ";");
167     mixin("enum RANGE_" ~ field.stringof ~ "_MIN_ = " ~ Args[0].stringof ~ ";");
168     mixin("enum RANGE_" ~ field.stringof ~ "_MAX_ = " ~ Args[1].stringof ~ ";");
169 }
170 
171 /// disable the merge feature of a registered variadic option
172 /// Params:
173 ///   field = the registered variadic option in the type of `OptVal`
174 mixin template DISABLE_MERGE(alias field) {
175     alias ___FType___CMDLINE = typeof(field);
176     static assert(___FType___CMDLINE.VARIADIC);
177     debug pragma(msg, "enum DISABLE_MERGE_" ~ field.stringof ~ "_ = " ~ "true;");
178     mixin("enum DISABLE_MERGE_" ~ field.stringof ~ "_ = " ~ "true;");
179 }
180 
181 /// hide a registered option from `help` sub-command and action-option
182 /// Params:
183 ///   field = the registered option in the type of `OptVal`
184 mixin template HIDE(alias field) {
185     static assert(__CMDLINE_EXT_isInnerOptValField__!(typeof(field)));
186     debug pragma(msg, "enum HIDE_" ~ field.stringof ~ "_ = " ~ "true;");
187     mixin("enum HIDE_" ~ field.stringof ~ "_ = " ~ "true;");
188 }
189 
190 /// set a negate option for a registered option, and its long flag is
191 /// `--no-NAME_OF_OPTION`
192 /// Params:
193 ///   field = the registered option in the type of `OptVal`
194 ///   shortFlag = the short flag of the negate option
195 ///   desc = the description of the negate option
196 mixin template NEGATE(alias field, string shortFlag, string desc = "") {
197     static assert(__CMDLINE_EXT_isInnerOptValField__!(typeof(field)));
198     debug pragma(msg, "enum NEGATE_" ~ field.stringof ~ "_ = \"" ~ shortFlag ~ "\";");
199     mixin("enum NEGATE_" ~ field.stringof ~ "_ = \"" ~ shortFlag ~ "\";");
200     static if (desc.length) {
201         mixin("enum NEGATE_" ~ field.stringof ~ "_DESC_ =\"" ~ desc ~ "\";");
202     }
203 }
204 
205 /// set the version string and enable the `version` sub-command and action-option
206 /// Params:
207 ///   ver = the version string
208 ///   flags = the flag of the version action-option which name would be the name of
209 ///     the relevant sub-command. if not defied then the flag would be `--version -V`
210 mixin template VERSION(string ver, string flags = "") {
211     debug pragma(msg, "enum VERSION_ = \"" ~ ver ~ "\";");
212     mixin("enum VERSION_ = \"" ~ ver ~ "\";");
213     debug pragma(msg, "enum VERSION_FLAGS_ = \"" ~ flags ~ "\";");
214     mixin("enum VERSION_FLAGS_ = \"" ~ flags ~ "\";");
215 }
216 
217 /// set an alias
218 /// Params:
219 ///   name = the alias
220 mixin template ALIAS(string name) {
221     debug pragma(msg, "enum ALIAS_ = \"" ~ name ~ "\";");
222     mixin("enum ALIAS_ = \"" ~ name ~ "\";");
223 }
224 
225 /// set description
226 /// Params:
227 ///   desc = the description
228 mixin template DESC(string desc) {
229     enum DESC_ = desc;
230 }
231 
232 /// <br><br>
233 /// hide the command from `help` sub-command and action-option, usually used on sub-command
234 mixin template HIDE() {
235     enum HIDE_ = true;
236 }
237 
238 /// disallow the excess arguments
239 mixin template DISALLOW_EXCESS_ARGS() {
240     enum DISALLOW_EXCESS_ARGS_ = true;
241 }
242 
243 /// show help after parsing error
244 mixin template SHOW_HELP_AFTER_ERR() {
245     enum SHOW_HELP_AFTER_ERR_ = true;
246 }
247 
248 /// don't show suggestions after parsing error
249 mixin template NO_SUGGESTION() {
250     enum NO_SUGGESTION_ = true;
251 }
252 
253 /// disallow the feature that can combine flags
254 mixin template DISALLOW_COMBINE() {
255     enum DONT_COMBINE_ = true;
256 }
257 
258 /// <br><br>
259 /// disable the feature that variadic options under the command can merge value
260 /// from various source
261 mixin template DISABLE_MERGE() {
262     enum DISABLE_MERGE_ = true;
263 }
264 
265 /// disable the `help` sub-command and action-option
266 mixin template DISABLE_HELP() {
267     enum DISABLE_HELP_ = true;
268 }
269 
270 /// allow the command to pass through its option flag behind sub command
271 mixin template PASS_THROUGH() {
272     enum bool PASS_THROUGH_ = true;
273 }
274 
275 /// add custom help text before command help text
276 mixin template HELP_TEXT_BEFORE(string text) {
277     enum HELP_TEXT_BEFORE_ = text;
278 }
279 
280 /// add custom help text after command help text
281 mixin template HELP_TEXT_AFTER(string text) {
282     enum HELP_TEXT_AFTER_ = text;
283 }
284 
285 /// apply `Command.exportAs` to the command line container
286 ///Params: 
287 ///     field = the field with the type of `OptVal`
288 ///     Flags = the new flags
289 mixin template EXPORT(alias field, Flags...) {
290     import std.meta;
291     import std.traits;
292 
293     static assert(__CMDLINE_EXT_isInnerOptValField__!(typeof(field)));
294     enum bool ___is_str___CMDLINE__(alias arg) = isSomeString!(typeof(arg));
295     static assert(allSatisfy!(___is_str___CMDLINE__, Flags));
296     mixin("static string[] EXPORT_" ~ field.stringof ~ "_ = " ~ [Flags].stringof ~ ";");
297 }
298 
299 /// apply `Command.exportNAs` to the command line container
300 /// Params:
301 ///     field = the field with the type of `OptVal`, the field must be set with negate option
302 ///     Flags = the new flags
303 mixin template EXPORT_N(alias field, Flags...) {
304     import std.meta;
305     import std.traits;
306 
307     static assert(__CMDLINE_EXT_isInnerOptValField__!(typeof(field)));
308     enum bool ___is_str___CMDLINE__(alias arg) = isSomeString!(typeof(arg));
309     static assert(allSatisfy!(___is_str___CMDLINE__, Flags));
310     // static assert(hasMember!(__SELF__, "NEGATE_" ~ field.stringof ~ "_"));
311     mixin("static string[] EXPORT_N_" ~ field.stringof ~ "_ = " ~ [Flags].stringof ~ ";");
312 }
313 
314 /// enable gaining value from config file in json and set an option that specifies
315 /// the directories where the config file should be
316 /// Params:
317 ///   flags = the flag of the config option which is used for specifying the directories
318 ///     where the config file should be. if not defied then the flag would be
319 ///     `-C, --config <config-dirs...>`
320 mixin template CONFIG(string flags = "") {
321     debug pragma(msg, "enum CONFIG_FLAGS_ = \"" ~ flags ~ "\";");
322     mixin("enum CONFIG_FLAGS_ = \"" ~ flags ~ "\";");
323 }
324 
325 /// set the options acting as arguments on command line
326 /// Params:
327 ///   Args = the options in the type of `OptVal`
328 mixin template OPT_TO_ARG(Args...) {
329     static assert(Args.length);
330     enum ___to_string___CMDLINE(alias var) = var.stringof;
331     import std.meta;
332 
333     debug pragma(msg, "static " ~ string[Args.length].stringof ~
334             " OPT_TO_ARG_ = " ~ [staticMap!(___to_string___CMDLINE, Args)].stringof ~ ";");
335     mixin("static " ~ string[Args.length].stringof ~
336             " OPT_TO_ARG_ = " ~ [staticMap!(___to_string___CMDLINE, Args)].stringof ~ ";");
337 }
338 
339 /// set the default sub-command which would act like the main-command except
340 /// `help`, `version` and `config` options and sub-command if exists.
341 /// Params:
342 ///   sub = the sub command of the command
343 mixin template DEFAULT(alias sub) {
344     alias ___SubType___CMDLINE = typeof(sub);
345     import std.traits;
346 
347     static assert(isPointer!___SubType___CMDLINE && isOutputResult!(
348             PointerTarget!___SubType___CMDLINE));
349     enum DEFAULT_ = sub.stringof;
350 }
351 
352 /// set sub commands
353 /// Params:
354 ///   SubCmds = the sub command containers that satisfies with `isOutputResult`
355 mixin template SUB_CMD(SubCmds...) {
356     import std.meta;
357 
358     static assert(SubCmds.length && allSatisfy!(isOutputResult, SubCmds));
359     static foreach (sub; SubCmds) {
360         debug pragma(msg, sub.stringof ~ "* " ~ (sub.stringof)[0 .. $ - 6] ~ "Sub;");
361         mixin(sub.stringof ~ "* " ~ (sub.stringof)[0 .. $ - 6] ~ "Sub;");
362     }
363 }
364 
365 /// prepare for the future use of function `ready` and `getParent`, which must be embedded at the top
366 /// of struct domain with `END` mixin-marco at the end of this struct domain.
367 mixin template BEGIN() {
368     enum bool __SPE_BEGIN_SEPCIAL__ = true;
369     alias __SELF__ = __traits(parent, __SPE_BEGIN_SEPCIAL__);
370     static void* __PARENT__;
371     static string __PARENT_STRING_OF__;
372 }
373 
374 /// prepare for the future use of function `ready` and `getParent`, which must be embedded at the end
375 /// of struct domain with `BEGIN` mixin-marco at the begin of this struct domain.
376 mixin template END() {
377     import std.traits;
378     import std.meta;
379 
380     enum bool __SPE_END_SEPCIAL__ = true;
381     static foreach (index, Type; Filter!(__CMDLINE_EXT_isInnerSubField__, FieldTypeTuple!__SELF__)) {
382         mixin("static bool IF_" ~ PointerTarget!Type.stringof ~ "_ = false;");
383     }
384 
385     static T* __GET_PARENT__(T)() {
386         if (this.__PARENT__ is null)
387             return null;
388         if (this.__PARENT_STRING_OF__ != T.stringof)
389             return null;
390         return cast(T*) this.__PARENT__;
391     }
392 
393     // init opt_to_arg, export, export_n from mxin DEF
394     enum __IS_FIELD_A_NAME__(string name) = name.length > 18
395         && name[0 .. 18] == "__CMDLINE_FIELD_A_";
396     enum __IS_FIELD_E_NAME__(string name) = name.length > 18
397         && name[0 .. 18] == "__CMDLINE_FIELD_E_";
398     enum __IS_FIELD_N_NAME__(string name) = name.length > 18
399         && name[0 .. 18] == "__CMDLINE_FIELD_N_";
400 
401     enum __GET_FIELD_NAME__(string name) = name[18 .. $];
402     alias __GET_FIELD_FLAGS__(string name) = __traits(getMember, __SELF__, name);
403 
404     alias __OPT_A_NAMES__ = staticMap!(__GET_FIELD_NAME__, Filter!(__IS_FIELD_A_NAME__, __traits(allMembers, __SELF__)));
405     alias __OPT_E_NAMES__ = staticMap!(__GET_FIELD_NAME__, Filter!(__IS_FIELD_E_NAME__, __traits(allMembers, __SELF__)));
406     alias __OPT_N_NAMES__ = staticMap!(__GET_FIELD_NAME__, Filter!(__IS_FIELD_N_NAME__, __traits(allMembers, __SELF__)));
407 
408     static if (__OPT_A_NAMES__.length) {
409         mixin("static " ~ string[__OPT_A_NAMES__.length].stringof ~
410                 " OPT_TO_ARG_ = " ~ [__OPT_A_NAMES__].stringof ~ ";");
411     }
412 
413     static if (__OPT_E_NAMES__.length) {
414         alias __OPT_E_FLAGS__ = staticMap!(__GET_FIELD_FLAGS__, Filter!(__IS_FIELD_E_NAME__, __traits(allMembers, __SELF__)));
415         debug pragma(msg, __OPT_E_FLAGS__);
416         static foreach (idx, nm; __OPT_E_NAMES__) {
417             mixin("static string[] EXPORT_" ~ nm ~ "_ = " ~ [__OPT_E_FLAGS__].stringof ~ ";");
418         }
419     }
420 
421     static if (__OPT_N_NAMES__.length) {
422         alias __OPT_N_FLAGS__ = staticMap!(__GET_FIELD_FLAGS__, Filter!(__IS_FIELD_N_NAME__, __traits(allMembers, __SELF__)));
423         debug pragma(msg, __OPT_N_FLAGS__);
424         static foreach (idx, nm; __OPT_N_NAMES__) {
425             mixin("static string[] EXPORT_N_" ~ nm ~ "_ = " ~ [__OPT_N_FLAGS__].stringof ~ ";");
426         }
427     }
428 }
429 
430 /// get the pointer to result container of parent.
431 /// Params:
432 ///   subOutput = the sub result container
433 /// Returns: `null` if type of `subOutput` not embeds `BEGIN` and `END` or `T` is not correct
434 T* getParent(T, U)(in U subOutput) if (isOutputResult!U && isOutputResult!T) {
435     static if (hasMember!(U, "__SPE_BEGIN_SEPCIAL__") && hasMember!(U, "__SPE_END_SEPCIAL__")) {
436         return subOutput.__GET_PARENT__!T;
437     }
438     else {
439         return null;
440     }
441 }
442 
443 /// get the pointer to result container of parent.
444 /// Params:
445 ///   subOutput = the pointer to the sub result container
446 /// Returns: `null` if type of `subOutput` not embeds `BEGIN` and `END` or `T` is not correct
447 T* getParent(T, U)(const(U)* subOutput) if (isOutputResult!U && isOutputResult!T) {
448     static if (hasMember!(U, "__SPE_BEGIN_SEPCIAL__") && hasMember!(U, "__SPE_END_SEPCIAL__")) {
449         return subOutput.__GET_PARENT__!T;
450     }
451     else {
452         return null;
453     }
454 }
455 
456 /// detect whether a sub command's container of a main command is ready for use.
457 /// for using this function, the `BEGIN` and `END` mixin-macro must be embeed in
458 /// main command container.
459 /// `T` is the type in sub-command container, `U` is the type in main-command container
460 /// Params:
461 ///   output = the main-command container
462 /// Returns: `true` if the sub-command is ready, otherwise is not ready.
463 bool ready(T, U)(const U* output)
464         if (isOutputResult!T && isOutputResult!U && hasMember!(U, "__SPE_END_SEPCIAL__")) {
465     return mixin(output.stringof ~ '.' ~ "IF_" ~ T.stringof ~ '_');
466 }
467 
468 /// get a pointer to sub-command container.
469 /// `T` is the type in sub-command container, `U` is the type in main-command container
470 /// Params:
471 ///   output = the main-command container
472 /// Returns: a pointer to sub-command container if the sub-command is ready,
473 ///     otherwise `null` 
474 inout(T)* subResult(T, U)(inout(U)* output)
475         if (isOutputResult!T && isOutputResult!U) {
476     alias ftypes = FieldTypeTuple!U;
477     alias fnames = FieldNameTuple!U;
478     static foreach (index, Type; ftypes) {
479         {
480             static if (__CMDLINE_EXT_isInnerSubField__!Type && is(PointerTarget!Type == T)) {
481                 return mixin(output.stringof ~ '.' ~ fnames[index]);
482             }
483         }
484     }
485     return null;
486 }
487 
488 /// the field of command container which is used to register a argument on the command.
489 /// the name of it is the name of this argument.
490 /// can implicitly convert to bool value same as the result of `ArgVal.isValid`.
491 /// `T` is the innerType of the argument,
492 /// `isOptional` `true` to set it optional, default is `false`.
493 struct ArgVal(T, bool isOptional = false) {
494     static assert(isArgValueType!T);
495     Argument _inner;
496 
497     enum ARGVAL_FLAG_ = true;
498     enum OPTIONAL = isOptional;
499 
500     /// the inner type of the argument
501     alias InnerType = T;
502 
503     /// test whether the inner value is ready.
504     /// Returns: `true` if ready, otherwise not ready.
505     bool isValid() const {
506         return _inner.settled;
507     }
508 
509     // make `ArgVal` enable to implicitly convert to bool value
510     // same as the result of `isValid`
511     alias isValid this;
512 
513     /// get the inner value
514     auto get() const {
515         return _inner.get!T;
516     }
517 
518     /// assign the inner value through passing into `Argument` variable
519     auto opAssign(Argument value) {
520         this._inner = value;
521         return this;
522     }
523 }
524 
525 /// the field of command container which is used to register a option on the command.
526 /// the name of it is the name of this option.
527 /// can implicitly convert to bool value same as the result of `ArgVal.isValid`.
528 /// `T` is the innerType of the option or the elemental type of innerType
529 /// `isMandatory` `true` to set it mandatory, default is `false`,
530 /// `shortAndVal` the short flag and value flag(if needed) seperated by space, comma and `|`
531 struct OptVal(T, string shortAndVal, bool isMandatory = false) {
532     static assert(isOptionValueType!T);
533     Option _inner;
534 
535     /// the inner type of the option
536     alias InnerType = T;
537 
538     enum OPTVAL_FLAG_ = true;
539     enum SHORT_FLAG_AND_VAL_STR = shortAndVal;
540     enum MANDATORY = isMandatory;
541 
542     static if (!is(T == bool)) {
543         static if (shortAndVal[$ - 1] == ']') {
544             enum OPTIONAL = true;
545         }
546         else static if (shortAndVal[$ - 1] == '>') {
547             enum OPTIONAL = false;
548         }
549         else {
550             static assert(0);
551         }
552         static if (shortAndVal.length > 5 && shortAndVal[$ - 4 .. $ - 1] == "...") {
553             enum VARIADIC = true;
554         }
555         else {
556             enum VARIADIC = false;
557         }
558     }
559 
560     /// test whether the inner value is ready.
561     /// Returns: `true` if ready, otherwise not ready.
562     bool isValid() const {
563         return _inner !is null && _inner.settled;
564     }
565 
566     // make `OptVal` enable to implicitly convert to bool value
567     // same as the result of `isValid`
568     alias isValid this;
569 
570     /// get the value in type of `T`
571     auto get() const {
572         assert(isValid);
573         return _inner.get!T;
574     }
575 
576     /// assign the inner value through passing into `Option` variable
577     auto opAssign(Option value) {
578         this._inner = value;
579         return this;
580     }
581 }
582 
583 /// use for defining a command line argument
584 /// Params:
585 ///   name = the argument's name
586 ///   T = the type of argument
587 ///   Args = the configs
588 mixin template DEF_ARG(string name, T, Args...) {
589     mixin DEF!(name, T, Args);
590 }
591 
592 /// use for defining a command line option
593 /// Params:
594 ///   name = the name of option
595 ///   T = the type of option
596 ///   flag = the flag of option wihout long-flag
597 ///   Args = the configs
598 mixin template DEF_OPT(string name, T, string flag, Args...) {
599     mixin DEF!(name, T, Flag_d!flag, Args);
600 }
601 
602 /// the basic version of both `DEF_ARG` and `DEF_OPT`
603 /// Params:
604 ///   name = the name of argument or option
605 ///   T = the type of argument or option
606 ///   Args = the configs
607 mixin template DEF(string name, T, Args...) {
608     import std.meta;
609 
610     static assert(allSatisfy!(__CMDLINE_isFieldDef__, Args));
611 
612     static if (!is(__CMDLINE_getFiledById__!(-2, Args) == void)) {
613         mixin("enum " ~ "__CMDLINE_FIELD_isOptional_" ~ name ~ " = " ~ true.stringof ~ ";");
614     }
615     else {
616         mixin("enum " ~ "__CMDLINE_FIELD_isOptional_" ~ name ~ " = " ~ false.stringof ~ ";");
617     }
618 
619     static if (!is(__CMDLINE_getFiledById__!(-1, Args) == void)) {
620         mixin("OptVal!(" ~ T.stringof ~ ", \"" ~ Args[0].args ~ "\", "
621                 ~ "__CMDLINE_FIELD_isOptional_" ~ name ~ ")" ~ name ~ ";");
622         debug pragma(msg, "OptVal!(" ~ T.stringof ~ ", \"" ~ Args[0].args ~ "\", "
623                 ~ "__CMDLINE_FIELD_isOptional_" ~ name ~ ")" ~ name ~ ";");
624     }
625     else {
626         mixin("ArgVal!(" ~ T.stringof ~ ", " ~ "__CMDLINE_FIELD_isOptional_" ~ name ~ ")" ~ name ~ ";");
627         debug pragma(msg, "ArgVal!(" ~ T.stringof ~ ", " ~ "__CMDLINE_FIELD_isOptional_" ~ name ~ ")" ~ name ~ ";");
628     }
629 
630     mixin("alias " ~ "__CMDLINE_FIELD_F_" ~ name ~ "= " ~ name ~ ";");
631 
632     static foreach (decl; Args) {
633         static if (decl.__CMDLINE_FIELD_DEF__ == 0) {
634             mixin DESC!(
635                 mixin("__CMDLINE_FIELD_F_" ~ name),
636                 decl.args
637             );
638         }
639         else static if (decl.__CMDLINE_FIELD_DEF__ == 1) {
640             mixin RANGE!(
641                 mixin("__CMDLINE_FIELD_F_" ~ name),
642                 decl.args
643             );
644         }
645         else static if (decl.__CMDLINE_FIELD_DEF__ == 2) {
646             mixin CHOICES!(
647                 mixin("__CMDLINE_FIELD_F_" ~ name),
648                 decl.args
649             );
650         }
651         else static if (decl.__CMDLINE_FIELD_DEF__ == 3) {
652             mixin DEFAULT!(
653                 mixin("__CMDLINE_FIELD_F_" ~ name),
654                 decl.args
655             );
656         }
657         else static if (decl.__CMDLINE_FIELD_DEF__ == 4) {
658             mixin PRESET!(
659                 mixin("__CMDLINE_FIELD_F_" ~ name),
660                 decl.args
661             );
662         }
663         else static if (decl.__CMDLINE_FIELD_DEF__ == 5) {
664             mixin ENV!(
665                 mixin("__CMDLINE_FIELD_F_" ~ name),
666                 decl.args
667             );
668         }
669         else static if (decl.__CMDLINE_FIELD_DEF__ == 6) {
670             mixin NEGATE!(
671                 mixin("__CMDLINE_FIELD_F_" ~ name),
672                 decl.args
673             );
674         }
675         else static if (decl.__CMDLINE_FIELD_DEF__ == 7) {
676             mixin HIDE!(mixin("__CMDLINE_FIELD_F_" ~ name));
677         }
678         else static if (decl.__CMDLINE_FIELD_DEF__ == 8) {
679             mixin DISABLE_MERGE!(mixin("__CMDLINE_FIELD_F_" ~ name));
680         }
681         else static if (decl.__CMDLINE_FIELD_DEF__ == 9) {
682             mixin("enum " ~ "__CMDLINE_FIELD_A_" ~ name ~ " = 1;");
683         }
684         else static if (decl.__CMDLINE_FIELD_DEF__ == 10) {
685             mixin("alias " ~ "__CMDLINE_FIELD_E_" ~ name ~ " = decl.args;");
686         }
687         else static if (decl.__CMDLINE_FIELD_DEF__ == 11) {
688             mixin("alias " ~ "__CMDLINE_FIELD_N_" ~ name ~ " = decl.args;");
689         }
690     }
691 }
692 
693 /// used inside the bracket of `DEF` to set the option mandatory or set the argument optional
694 struct Optional_d {
695     enum __CMDLINE_FIELD_DEF__ = -2;
696 }
697 
698 /// used inside the bracket of `DEF` to set the flag of an option
699 struct Flag_d(alias flag) {
700     enum __CMDLINE_FIELD_DEF__ = -1;
701     alias args = flag;
702 }
703 
704 /// used inside the bracket of `DEF`, `DEF_ARG` and `DEF_OPT` to set the desc of an option or an argument
705 struct Desc_d(alias desc) {
706     enum __CMDLINE_FIELD_DEF__ = 0;
707     alias args = desc;
708 }
709 
710 /// used inside the bracket of `DEF`, `DEF_ARG` and `DEF_OPT` to set the range of an option or an argument
711 struct Range_d(Args...) {
712     enum __CMDLINE_FIELD_DEF__ = 1;
713     alias args = Args;
714 }
715 
716 /// used inside the bracket of `DEF`, `DEF_ARG` and `DEF_OPT` to set the choices of an option or an argument
717 struct Choices_d(Args...) {
718     enum __CMDLINE_FIELD_DEF__ = 2;
719     alias args = Args;
720 }
721 
722 /// used inside the bracket of `DEF`, `DEF_ARG` and `DEF_OPT` to set the default value of an option or an argument
723 struct Default_d(alias val) {
724     enum __CMDLINE_FIELD_DEF__ = 3;
725     alias args = val;
726 }
727 
728 /// used inside the bracket of `DEF`, `DEF_OPT` to set the preset value of an option
729 struct Preset_d(alias val) {
730     enum __CMDLINE_FIELD_DEF__ = 4;
731     alias args = val;
732 }
733 
734 /// used inside the bracket of `DEF`, `DEF_OPT` to set the value from environment of an option
735 struct Env_d(alias envKey) {
736     enum __CMDLINE_FIELD_DEF__ = 5;
737     alias args = envKey;
738 }
739 
740 /// used inside the bracket of `DEF`, `DEF_OPT` to set the negate option of an option
741 struct Negate_d(alias shortFlag, alias desc = "") {
742     enum __CMDLINE_FIELD_DEF__ = 6;
743     alias args = AliasSeq!(shortFlag, desc);
744 }
745 
746 /// used inside the bracket of `DEF`, `DEF_OPT` to hide an option from help info
747 struct Hide_d {
748     enum __CMDLINE_FIELD_DEF__ = 7;
749 }
750 
751 /// used inside the bracket of `DEF`, `DEF_OPT` to disable the merge feature of variadic option
752 struct DisableMerge_d {
753     enum __CMDLINE_FIELD_DEF__ = 8;
754 }
755 
756 /// used inside the bracket of `DEF`, `DEF_OPT` to make an option act like an argument
757 struct ToArg_d {
758     enum __CMDLINE_FIELD_DEF__ = 9;
759 }
760 
761 /// used inside the bracket of `DEF`, `DEF_OPT`, see `EXPORT`
762 struct Export_d(Args...) {
763     enum __CMDLINE_FIELD_DEF__ = 10;
764     alias args = Args;
765 }
766 
767 /// used inside the bracket of `DEF`, `DEF_OPT`, see `EXPORT_N`
768 struct N_Export_d(Args...) {
769     enum __CMDLINE_FIELD_DEF__ = 11;
770     alias args = Args;
771 }
772 
773 enum __CMDLINE_isFieldDef__(T) = hasMember!(T, "__CMDLINE_FIELD_DEF__");
774 template __CMDLINE_getFiledById__(int id, Types...) {
775     enum __XX(T) = T.__CMDLINE_FIELD_DEF__ == id;
776     alias tmp = Filter!(__XX, Types);
777     static if (tmp.length)
778         alias __CMDLINE_getFiledById__ = tmp[0];
779     else
780         alias __CMDLINE_getFiledById__ = void;
781 }
782 
783 private alias getMember(alias T, string flag) = __traits(getMember, T, flag);
784 
785 /// construct the command line program without action callback
786 /// Returns: the root command in `Command` that is confiured according to the given command conatiner type.
787 Command construct(T)() if (isOutputResult!T) {
788     alias fnames = FieldNameTuple!T;
789     alias ftypes = FieldTypeTuple!T;
790     Command cmd = createCommand(T.stringof[0 .. $ - 6]._tokeytab);
791     static if (hasMember!(T, "DESC_")) {
792         cmd.description(T.DESC_);
793     }
794     static if (hasMember!(T, "HIDE_")) {
795         cmd._hidden = true;
796     }
797     static if (hasMember!(T, "DISALLOW_EXCESS_ARGS_")) {
798         cmd.allowExcessArguments(false);
799     }
800     static if (hasMember!(T, "VERSION_")) {
801         cmd.setVersion(T.VERSION_, T.VERSION_FLAGS_);
802     }
803     static if (hasMember!(T, "SHOW_HELP_AFTER_ERR_")) {
804         cmd.showHelpAfterError(true);
805     }
806     static if (hasMember!(T, "NO_SUGGESTION_")) {
807         cmd.showSuggestionAfterError(false);
808     }
809     static if (hasMember!(T, "DONT_COMBINE_")) {
810         cmd.comineFlagAndOptionValue(false);
811     }
812     static if (hasMember!(T, "DISABLE_MERGE_")) {
813         cmd.allowVariadicMerge(false);
814     }
815     static if (hasMember!(T, "DISABLE_HELP_")) {
816         cmd.disableHelp();
817     }
818     static if (hasMember!(T, "CONFIG_FLAGS_")) {
819         cmd.setConfigOption(T.CONFIG_FLAGS_);
820     }
821     static if (hasMember!(T, "DEFAULT_")) {
822         cmd._defaultCommandName = T.DEFAULT_;
823     }
824     static if (hasMember!(T, "PASS_THROUGH_")) {
825         cmd._passThroughOptionValue = true;
826     }
827     static if (hasMember!(T, "ALIAS_")) {
828         cmd.aliasName(T.ALIAS_);
829     }
830     static if (hasMember!(T, "HELP_TEXT_BEFORE_")) {
831         cmd.addHelpText(AddHelpPos.Before, T.HELP_TEXT_BEFORE_);
832     }
833     static if (hasMember!(T, "HELP_TEXT_AFTER_")) {
834         cmd.addHelpText(AddHelpPos.After, T.HELP_TEXT_AFTER_);
835     }
836     static foreach (index, Type; ftypes) {
837         static if (__CMDLINE_EXT_isInnerArgValField__!Type) {
838             {
839                 mixin SetArgValField!(cmd, Type, T, index, fnames);
840             }
841         }
842         else static if (__CMDLINE_EXT_isInnerOptValField__!Type) {
843             {
844                 mixin SetOptValField!(cmd, Type, T, index, fnames);
845             }
846         }
847         else static if (__CMDLINE_EXT_isInnerSubField__!Type) {
848             {
849                 mixin SetSubCommand!(cmd, Type);
850             }
851         }
852     }
853     static if (hasStaticMember!(T, "OPT_TO_ARG_")) {
854         auto arr = getMember!(T, "OPT_TO_ARG_");
855         import std.algorithm;
856         import std.array;
857 
858         auto tmp = arr[].map!(str => _tokeytab(str)).array;
859         cmd.argToOpt(tmp[0], tmp[1 .. $]);
860     }
861     return cmd;
862 }
863 
864 /// parse the command line option and argument parameters according to the given command conatiner type.
865 /// T = the command conatiner type
866 /// Params:
867 ///   argv = the command line arguments in string
868 /// Returns: an initialized instance of the command conatiner type
869 T* parse(T)(in string[] argv) if (isOutputResult!T) {
870     alias fnames = FieldNameTuple!T;
871     alias ftypes = FieldTypeTuple!T;
872     assert(argv.length);
873     auto cmd = construct!T;
874     cmd.parse(argv);
875     T* output = new T;
876     static foreach (index, name; fnames) {
877         {
878             mixin InitOutputResultField!(cmd, output, index, name, ftypes);
879         }
880     }
881     return output;
882 }
883 
884 /// parse the command line option and argument parameters  according to the given command conatiner type.
885 /// And invoke the `action` member function and return if exists, otherwise invoke member container's `action`
886 /// member function recursely.
887 /// T = the root command container type
888 /// Params:
889 ///   argv = the arguments list in string
890 void run(T)(in string[] argv) if (isOutputResult!T) {
891     T* output = parse!T(argv);
892     runImpl(output);
893 }
894 
895 private:
896 
897 void runImpl(T)(T* output) if (isOutputResult!T) {
898     static if (hasMember!(T, "action")) {
899         output.action();
900     }
901     else {
902         alias fnames = FieldNameTuple!T;
903         static foreach (index, Type; Filter!(__CMDLINE_EXT_isInnerSubField__, FieldTypeTuple!T)) {
904             if (auto sub_output = output.subResult!(PointerTarget!Type)) {
905                 runImpl(sub_output);
906             }
907         }
908     }
909 }
910 
911 mixin template InitOutputResultField(alias cmd, alias output, alias index, alias name, ftypes...) {
912     alias Type = ftypes[index];
913     static if (__CMDLINE_EXT_isInnerArgValField__!Type) {
914         auto x = mixin(output.stringof ~ '.' ~ name) = cmd.findArgument(name._tokeytab);
915     }
916     else static if (__CMDLINE_EXT_isInnerOptValField__!Type) {
917         auto x = mixin(output.stringof ~ '.' ~ name) = cmd.findOption(name._tokeytab);
918     }
919     else static if (__CMDLINE_EXT_isInnerSubField__!Type) {
920         alias T = PointerTarget!Type;
921         alias sfnames = FieldNameTuple!T;
922         alias sftypes = FieldTypeTuple!T;
923         debug pragma(msg, T.stringof, " ", typeof(output).stringof);
924         Command sub = cmd.findCommand(T.stringof[0 .. $ - 6]._tokeytab);
925         auto xfn = () {
926             if (cmd._called_sub == sub._name) {
927                 static if (hasMember!(typeof(output), "__SPE_END_SEPCIAL__")) {
928                     mixin(output.stringof ~ '.' ~ "IF_" ~ T.stringof ~ '_') = true;
929                 }
930                 auto sub_output = mixin(output.stringof ~ '.' ~ name) = new T;
931                 static if (hasMember!(T, "__SPE_BEGIN_SEPCIAL__") && hasMember!(T, "__SPE_END_SEPCIAL__")) {
932                     auto x = T.__PARENT__ = output;
933                     auto xx = T.__PARENT_STRING_OF__ = PointerTarget!(typeof(output)).stringof;
934                 }
935                 static foreach (index, name; sfnames) {
936                     {
937                         mixin InitOutputResultField!(sub, sub_output, index, name, sftypes);
938                     }
939                 }
940             }
941             return 1;
942         };
943         auto _x_ = xfn();
944     }
945 }
946 
947 mixin template SetArgValField(alias cmd, Type, T, alias index, fnames...) {
948     alias IType = Type.InnerType;
949     enum string arg_name = fnames[index];
950     enum bool optional = Type.OPTIONAL;
951     enum bool variadic = !isSomeString!IType && !is(ElementType!IType == void);
952     string nameOutput = _tokeytab(arg_name) ~ (variadic ? "..." : "");
953     Argument arg = createArgument!(IType)(
954         optional ? "[" ~ nameOutput ~ "]" : "<" ~ nameOutput ~ ">"
955     );
956     enum string fdesc = "DESC_ARG_" ~ arg_name ~ '_';
957     enum string fdef = "DEFAULT_" ~ arg_name ~ '_';
958     enum string fchoices = "CHOICES_" ~ arg_name ~ "_";
959     enum string frange_min = "RANGE_" ~ arg_name ~ "_MIN_";
960     enum string frange_max = "RANGE_" ~ arg_name ~ "_MAX_";
961     static if (hasMember!(T, fdesc)) {
962         auto x = arg.description(getMember!(T, fdesc));
963     }
964     static if (hasStaticMember!(T, fdef)) {
965         auto xx = arg.defaultVal(getMember!(T, fdef));
966     }
967     static if (hasStaticMember!(T, fchoices)) {
968         auto xxx = arg.choices(getMember!(T, fchoices));
969     }
970     static if (hasMember!(T, frange_min) && hasMember!(T, frange_max)) {
971         auto xxxxx = arg.rangeOf(
972             getMember!(T, frange_min),
973             getMember!(T, frange_max)
974         );
975     }
976     auto xxxxxx = cmd.addArgument(arg);
977 }
978 
979 mixin template SetOptValField(alias cmd, Type, T, alias idnex, fnames...) {
980     alias IType = Type.InnerType;
981     enum string opt_name = fnames[idnex];
982     enum bool mandatory = Type.MANDATORY;
983     string kname = _tokeytab(opt_name);
984     Option opt = createOption!IType("--" ~ kname ~ ' '
985             ~ Type.SHORT_FLAG_AND_VAL_STR);
986     enum string fdesc = "DESC_OPT_" ~ opt_name ~ '_';
987     enum string fdef = "DEFAULT_" ~ opt_name ~ '_';
988     enum string fpreset = "PRESET_" ~ opt_name ~ '_';
989     enum string fenv = "ENV_" ~ opt_name ~ '_';
990     enum string fchoices = "CHOICES_" ~ opt_name ~ "_";
991     enum string frange_min = "RANGE_" ~ opt_name ~ "_MIN_";
992     enum string frange_max = "RANGE_" ~ opt_name ~ "_MAX_";
993     enum string fnegate_sh = "NEGATE_" ~ opt_name ~ '_';
994     enum string fnegate_desc = "NEGATE_" ~ opt_name ~ "_DESC_";
995     enum string fexport = "EXPORT_" ~ opt_name ~ "_";
996     enum string fexport_n = "EXPORT_N_" ~ opt_name ~ "_";
997     auto x = opt.makeMandatory(mandatory);
998     static if (hasMember!(T, "DISABLE_MERGE_" ~ opt_name ~ '_')) {
999         auto xx = opt.merge(false);
1000     }
1001     static if (hasMember!(T, "HIDE_" ~ opt_name ~ '_')) {
1002         auto xxx = opt.hidden = true;
1003     }
1004     NegateOption nopt = null;
1005     static if (hasMember!(T, fnegate_sh)) {
1006         string short_flag = getMember!(T, fnegate_sh);
1007         static if (hasMember!(T, fnegate_desc)) {
1008             auto _x_ = getMember!(T, fnegate_desc);
1009         }
1010         else {
1011             auto _x_ = "";
1012         }
1013         auto xxxx = nopt = createNegateOption("--no-" ~ kname ~ ' ' ~ short_flag, _x_);
1014     }
1015     static if (hasMember!(T, fdesc)) {
1016         auto xxxxx = opt.description(getMember!(T, fdesc));
1017     }
1018     static if (hasStaticMember!(T, fdef)) {
1019         auto xxxxxx = opt.defaultVal(getMember!(T, fdef));
1020     }
1021     static if (hasStaticMember!(T, fchoices)) {
1022         auto xxxxxxx = opt.choices(getMember!(T, fchoices));
1023     }
1024     static if (hasMember!(T, frange_min) && hasMember!(T, frange_max)) {
1025         auto xxxxxxxx = opt.rangeOf(
1026             getMember!(T, frange_min),
1027             getMember!(T, frange_max)
1028         );
1029     }
1030     static if (hasStaticMember!(T, fpreset)) {
1031         auto xxxxxxxxx = opt.preset(getMember!(T, fpreset));
1032     }
1033     static if (hasMember!(T, fenv)) {
1034         auto xxxxxxxxxx = opt.env(getMember!(T, fenv));
1035     }
1036     auto xxxxxxxxxxx = cmd.addOption(opt);
1037     auto xxxxxxxxxxxx = nopt ? cmd.addOption(nopt) : cmd;
1038     static if (hasStaticMember!(T, fexport)) {
1039         auto xxxxxxxxxxxxx = cmd.exportAs(opt_name, getMember!(T, fexport));
1040     }
1041     static if (hasStaticMember!(T, fexport_n)) {
1042         auto xxxxxxxxxxxxxx = cmd.exportNAs(opt_name, getMember!(T, fexport_n));
1043     }
1044     // 14 x
1045 }
1046 
1047 mixin template SetSubCommand(alias cmd, Type) {
1048     alias SubT = PointerTarget!Type;
1049     Command sub = construct!SubT;
1050     auto x = cmd.addCommand(sub);
1051 }
1052 
1053 string _tokeytab(string from) {
1054     import std.regex;
1055     import std.string : toLower;
1056 
1057     auto trans = (Captures!(string) m) { return '-' ~ toLower(m.hit); };
1058     return cast(char) toLower(from[0]) ~ replaceAll!(trans)(from[1 .. $], regex(`[A-Z]`));
1059 }
1060 
1061 // mixin template IMPLIES(alias field, string key, alias val) {
1062 //     alias ___FType___CMDLINE = typeof(field);
1063 //     static assert(__CMDLINE_EXT_isInnerOptValField__!___FType___CMDLINE && !is(___FType___CMDLINE.InnerType == bool));
1064 //     static assert(isOptionValueType!(typeof(val)));
1065 //     debug pragma(msg, "static " ~ typeof(val)
1066 //             .stringof ~
1067 //             " IMPLIES_" ~ field.stringof ~ "_" ~ key ~
1068 //             "_ = " ~ val.stringof ~ ";");
1069 //     mixin("static " ~ typeof(val)
1070 //             .stringof ~
1071 //             " IMPLIES_" ~ field.stringof ~ "_" ~ key ~
1072 //             "_ = " ~ val.stringof ~ ";");
1073 // }
1074 
1075 // mixin template IMPLIES_BOOL(alias field, Args...) {
1076 //     static assert(Args.length);
1077 //     alias ___FType___CMDLINE = typeof(field);
1078 //     static assert(allSatisfy!(isSomeString, Args));
1079 //     debug pragma(msg, "static " ~ typeof(
1080 //             Args[0])[].stringof ~
1081 //             " IMPLIES_" ~ field.stringof ~
1082 //             "_ = " ~ [Args].stringof ~ ";");
1083 //     mixin("static " ~ typeof(
1084 //             Args[0])[].stringof ~
1085 //             " IMPLIES_" ~ field.stringof ~
1086 //             "_ = " ~ [Args].stringof ~ ";");
1087 // }