From 8733649dffc9dfc786f7f24b672b9d493c46735e Mon Sep 17 00:00:00 2001 From: LouisTakePILLz Date: Thu, 2 Apr 2015 09:06:45 -0400 Subject: [PATCH] Fix trailing value handling Allow for tag couples to hold values for trailing value parsing Simplify negative value detection --- ArgumentParser/Parser.cs | 118 ++++++++++++------ .../Patterns/POSIXParameterPattern.cs | 25 ++-- ArgumentParser/RawParameter.cs | 13 +- ArgumentParserTest/ContextTestUnit.cs | 2 +- 4 files changed, 106 insertions(+), 52 deletions(-) diff --git a/ArgumentParser/Parser.cs b/ArgumentParser/Parser.cs index 2faffa9..ab3263a 100644 --- a/ArgumentParser/Parser.cs +++ b/ArgumentParser/Parser.cs @@ -19,6 +19,7 @@ using System; using System.Collections.Generic; using System.ComponentModel; +using System.Diagnostics; using System.Globalization; using System.Linq; using System.Reflection; @@ -364,18 +365,22 @@ public static IEnumerable GetParameters(String input, ParserOptions o RegexOptions.Singleline); var matchElements = - matches.OfType().SelectMany(x => x.Groups["tag"].Captures - .OfType() - .GroupBy(c => c.Value, (c, e) => new RawParameter( - prefix: x.Groups["prefix"].Value, - tag: c, - value: x.Groups["value"].Success - ? (options.Detokenize - ? DetokenizeValue(options, x.Groups["value"].Value) - : x.Groups["value"].Value) - : null, - count: e.Count()))) - .ToArray(); + matches.OfType().SelectMany(x => + { + var captures = x.Groups["tag"].Captures.OfType().ToArray(); + + return captures + .GroupBy(c => c.Value, (c, e) => new RawParameter( + prefix: x.Groups["prefix"].Value, + tag: c, + value: x.Groups["value"].Success + ? (options.Detokenize + ? DetokenizeValue(options, x.Groups["value"].Value) + : x.Groups["value"].Value) + : null, + count: e.Count(), + totalCount: captures.Length)); + }).ToArray(); List unboundValues = new List(); @@ -388,23 +393,14 @@ public static IEnumerable GetParameters(String input, ParserOptions o { var parameters = p.ToArray(); var flag = a as IFlag; + String[][] trailingValues; - if (flag != null) - return GetFlagPair(options, flag, parameters); - - if (a.AllowCompositeValues) - return new ParameterPair(a, parameters.Select(x => x.Value == null ? null : ParseValue(options, a, x.Value))); - - var values = parameters - .Select(x => x.Value == null - ? null - : x.Value.Split(new[] { '\x20' }, StringSplitOptions.RemoveEmptyEntries)) - .ToArray(); - - var pair = new ParameterPair(a, values.Select(x => ParseValue(options, a, x.First()))); + var pair = flag != null + ? GetFlagPair(options, flag, parameters, out trailingValues) + : GetParameterPair(options, a, parameters, out trailingValues); - unboundValues.AddRange(values - .Where(x => x.Any()) + unboundValues.AddRange(trailingValues + .Where(x => x != null && x.Any()) .SelectMany(x => x.Skip(1)) .Select(x => new UnboundValue(pair, x))); @@ -462,24 +458,59 @@ private static String GetParameterPattern(ParameterTokenStyle tokenStyle) } } - private static FlagPair GetFlagPair(ParserOptions options, IFlag flag, RawParameter[] parameters) + private static ParameterPair GetParameterPair(ParserOptions options, IArgument argument, RawParameter[] parameters, out String[][] trailingValues) + { + if (argument.AllowCompositeValues) + { + trailingValues = new String[0][]; + return new ParameterPair( + argument: argument, + values: parameters + .Where(x => x != null) + .Select(x => x.Value == null || x.TotalCount > 1 + ? null + : ParseValue(options, argument, x.Value))); + } + + trailingValues = GetCompositeValueParts(parameters); + + return new ParameterPair( + argument: argument, + values: trailingValues.Select(x => x == null ? null : ParseValue(options, argument, x.First()))); + } + + private static FlagPair GetFlagPair(ParserOptions options, IFlag flag, RawParameter[] parameters, out String[][] trailingValues) { if (!parameters.Any()) + { + trailingValues = new String[0][]; return new FlagPair(flag, new Object[0], 0); + } bool isBoolean = flag.Type == typeof (Boolean); - var values = parameters.Select(x => new - { - Parameter = x, - Value = x.Value == null ? 1 : ValueConverter.GetFlagValue(options.Culture, isBoolean, x.Value) - }).ToArray(); + var values = parameters.Where(x => x != null).Select(x => new + { + Parameter = x, + Value = x.Value == null || x.TotalCount > 1 + ? 1 + : ValueConverter.GetFlagValue(options.Culture, isBoolean, x.Value) + }).ToArray(); + // Skip special flag logic for booleans, as such operations can not be done on single bits. if (isBoolean) { bool? defaultValue = flag.DefaultValue as Boolean?; bool invertDefault = defaultValue.HasValue && defaultValue.Value; - return new FlagPair(flag, values.Select(x => (Object) x.Value), values.Last().Value == 0 ^ invertDefault ? 1 : 0); + + var flagPair = new FlagPair( + argument: flag, + values: values.Select(x => (Object) x.Value), + count: values.Last().Value == 0 ^ invertDefault ? 1 : 0); + + trailingValues = flag.AllowCompositeValues ? new String[0][] : GetCompositeValueParts(parameters); + + return flagPair; } bool aggregateImplicit = (flag.Options & FlagOptions.AggregateImplicit) != 0, @@ -526,7 +557,13 @@ private static FlagPair GetFlagPair(ParserOptions options, IFlag flag, RawParame explicitCount = bitFieldExplicit ? GetFlagValue(explicitParameter.Parameter.Count) : explicitParameter.Parameter.Count; } - return new FlagPair(flag, values.Select(x => (Object) x.Value), implicitCount + explicitCount); + { + var flagPair = new FlagPair(flag, values.Select(x => (Object) x.Value), implicitCount + explicitCount); + + trailingValues = flag.AllowCompositeValues ? new String[0][] : GetCompositeValueParts(parameters); + + return flagPair; + } } private static Int32 GetFlagValue(Int32 value) @@ -537,6 +574,17 @@ private static Int32 GetFlagValue(Int32 value) return 1 << (value - 1); } + private static String[][] GetCompositeValueParts(RawParameter[] parameters) + { + var values = parameters + .Where(x => x != null) + .Select(x => x.Value == null || x.TotalCount > 1 + ? null + : x.Value.Split(new[] { '\x20' }, StringSplitOptions.RemoveEmptyEntries)) + .ToArray(); + return values; + } + private static String DetokenizeValue(ParserOptions options, String value) { try diff --git a/ArgumentParser/Patterns/POSIXParameterPattern.cs b/ArgumentParser/Patterns/POSIXParameterPattern.cs index 8d25768..1b063f6 100644 --- a/ArgumentParser/Patterns/POSIXParameterPattern.cs +++ b/ArgumentParser/Patterns/POSIXParameterPattern.cs @@ -28,29 +28,28 @@ public static partial class Parser ( (?--) ( - (?(?!-)[\-\w-[\d]]+)\s+ - (? - ( + (?(?!-)\w+) + ( + \s+ + (? ("" (?> \\. | [^""])* "")| (' (?> \\. | [^'])* ')| (?> \\. | [^\-""'] | (? \-\d [\,\.\d]* ) + (?> \-\d [\,\.\w]* ) ) - )| - (?(?!-)[\w\-]+) + )? )| (?-) - (?\w)\s+ - (? - ( + (?\w)+ + ( + \s+ + (? ("" (?> \\. | [^""])* "")| (' (?> \\. | [^'])* ')| (?> \\. | [^\-""'] | (? \-\d[\,\.\d]* ) + (?> \-\d [\,\.\w]* ) ) - )| - (?-) - (?\w)+ + )? )(?=\s|$)"; #else private const String UNIX_PARAMETERS_PATTERN = @"(?<=^|\s)((?--)((?(?!-)[\-\w-[\d]]+)\s+(?((""(?>\\.|[^""])*"")|('(?>\\.|[^'])*')|(?>\\.|[^\-""']|(?\-\d[\,\.\d]*)))|(?(?!-)[\w\-]+))|(?-)(?\w)\s+(?((""(?>\\.|[^""])*"")|('(?>\\.|[^'])*')|(?>\\.|[^\-""']|(?\-\d[\,\.\d]*)))|(?-)(?\w)+)(?=\s|$)"; diff --git a/ArgumentParser/RawParameter.cs b/ArgumentParser/RawParameter.cs index c78e4fc..a713f8f 100644 --- a/ArgumentParser/RawParameter.cs +++ b/ArgumentParser/RawParameter.cs @@ -43,10 +43,12 @@ public RawParameter(String prefix, String tag, String value) /// The prefix of the parameter. /// The tag that defines the parameter. /// The value of the parameter. - /// The tag couple count. - public RawParameter(String prefix, String tag, String value, Int32 count) + /// The total tag couple count. + /// The count of identical tags. + public RawParameter(String prefix, String tag, String value, Int32 totalCount, Int32 count) : this(prefix, tag, value) { + this.TotalCount = totalCount; this.Count = count; } @@ -56,10 +58,15 @@ public RawParameter(String prefix, String tag, String value, Int32 count) public Key Key { get; private set; } /// - /// Gets the tag couple count. + /// Gets the count of identical tags within the same couple. /// public Int32 Count { get; private set; } + /// + /// Gets the total tag couple count. + /// + public Int32 TotalCount { get; private set; } + /// /// Gets the value of the parameter. /// diff --git a/ArgumentParserTest/ContextTestUnit.cs b/ArgumentParserTest/ContextTestUnit.cs index d51c2cc..d5dc805 100644 --- a/ArgumentParserTest/ContextTestUnit.cs +++ b/ArgumentParserTest/ContextTestUnit.cs @@ -116,7 +116,7 @@ public void Init(String[] verbs) public void HandleParameter(RawParameter parameter) { - Debug.WriteLine("{0} #{1}: \"{2}\"", parameter.Key, parameter.Count, parameter.Value); + Debug.WriteLine("{0} #{1}: \"{2}\" (Compound: {3})", parameter.Key, parameter.Count, parameter.Value, parameter.TotalCount > 1); } public void HandleValue(UnboundValue value)