public static ParserResult <T> Build <T>( Func <T> factory, Func <IEnumerable <string>, IEnumerable <OptionSpecification>, StatePair <IEnumerable <Token> > > tokenizer, IEnumerable <string> arguments, StringComparer nameComparer, CultureInfo parsingCulture) { var instance = factory(); if (arguments.Any() && nameComparer.Equals("--help", arguments.First())) { return(ParserResult.Create( ParserResultType.Options, instance, new[] { new HelpRequestedError() })); } var specProps = instance.GetType().GetSpecifications(pi => SpecificationProperty.Create( Specification.FromProperty(pi), pi, Maybe.Nothing <object>())); var optionSpecs = (from pt in specProps select pt.Specification) .ThrowingValidate(SpecificationGuards.Lookup) .OfType <OptionSpecification>(); var tokenizerResult = tokenizer(arguments, optionSpecs); var tokens = tokenizerResult.Value; var partitions = TokenPartitioner.Partition( tokens, name => TypeLookup.GetDescriptorInfo(name, optionSpecs, nameComparer)); var optionSpecProps = OptionMapper.MapValues( (from pt in specProps where pt.Specification.IsOption() select pt), partitions.Item1, (vals, type, isScalar) => TypeConverter.ChangeType(vals, type, isScalar, parsingCulture), nameComparer); var valueSpecProps = ValueMapper.MapValues( (from pt in specProps where pt.Specification.IsValue() select pt), partitions.Item2, (vals, type, isScalar) => TypeConverter.ChangeType(vals, type, isScalar, parsingCulture)); var missingValueErrors = from token in partitions.Item3 select new MissingValueOptionError( NameInfo.FromOptionSpecification(optionSpecs.Single(o => token.Text.MatchName(o.ShortName, o.LongName, nameComparer)))); var specPropsWithValue = optionSpecProps.Value.Concat(valueSpecProps.Value); instance = instance .SetProperties(specPropsWithValue, sp => sp.Value.IsJust(), sp => sp.Value.FromJust()) .SetProperties(specPropsWithValue, sp => sp.Value.IsNothing() && sp.Specification.DefaultValue.IsJust(), sp => sp.Specification.DefaultValue.FromJust()) .SetProperties(specPropsWithValue, sp => sp.Value.IsNothing() && sp.Specification.ConversionType.ToDescriptor() == DescriptorType.Sequence && sp.Specification.DefaultValue.MatchNothing(), sp => sp.Property.PropertyType.GetGenericArguments().Single().CreateEmptyArray()); var validationErrors = specPropsWithValue.Validate(SpecificationPropertyRules.Lookup) .OfType <Just <Error> >().Select(e => e.Value); return(ParserResult.Create( ParserResultType.Options, instance, tokenizerResult.Errors .Concat(missingValueErrors) .Concat(optionSpecProps.Errors) .Concat(valueSpecProps.Errors) .Concat(validationErrors))); }
public static ParserResult <T> Build <T>( Type typeInfo, Maybe <Func <T> > factory, Func <IEnumerable <string>, IEnumerable <OptionSpecification>, Result <IEnumerable <Token>, Error> > tokenizer, IEnumerable <string> arguments, StringComparer nameComparer, bool ignoreValueCase, CultureInfo parsingCulture, IEnumerable <ErrorType> nonFatalErrors) { var isMutable = typeInfo.IsMutable(); if (!isMutable && factory.IsJust()) { throw new ArgumentException("Cannot use factor for immutable types.", "factory"); } var specProps = typeInfo.GetSpecifications(pi => SpecificationProperty.Create( Specification.FromProperty(pi), pi, Maybe.Nothing <object>())).Memorize(); var specs = from pt in specProps select pt.Specification; var optionSpecs = specs .ThrowingValidate(SpecificationGuards.Lookup) .OfType <OptionSpecification>(); Func <IEnumerable <Error>, ParserResult <T> > notParsed = errs => new NotParsed <T>(typeInfo.ToTypeInfo(), errs); Func <ParserResult <T> > buildUp = () => { var tokenizerResult = tokenizer(arguments, optionSpecs); var tokens = tokenizerResult.SucceededWith(); var partitions = TokenPartitioner.Partition( tokens, name => TypeLookup.FindTypeDescriptorAndSibling(name, optionSpecs, nameComparer)); var optionsPartition = partitions.Item1; var valuesPartition = partitions.Item2; var errorsPartition = partitions.Item3; var optionSpecPropsResult = OptionMapper.MapValues( (from pt in specProps where pt.Specification.IsOption() select pt), optionsPartition, (vals, type, isScalar) => TypeConverter.ChangeType(vals, type, isScalar, parsingCulture, ignoreValueCase), nameComparer); var valueSpecPropsResult = ValueMapper.MapValues( (from pt in specProps where pt.Specification.IsValue() orderby((ValueSpecification)pt.Specification).Index select pt), valuesPartition, (vals, type, isScalar) => TypeConverter.ChangeType(vals, type, isScalar, parsingCulture, ignoreValueCase)); var missingValueErrors = from token in errorsPartition select new MissingValueOptionError( optionSpecs.Single(o => token.Text.MatchName(o.ShortName, o.LongName, nameComparer)) .FromOptionSpecification()); var specPropsWithValue = optionSpecPropsResult.SucceededWith().Concat(valueSpecPropsResult.SucceededWith()).Memorize(); Func <T> buildMutable = () => { var mutable = factory.MapValueOrDefault(f => f(), (T)Activator.CreateInstance(typeInfo)); mutable = mutable.SetProperties(specPropsWithValue, sp => sp.Value.IsJust(), sp => sp.Value.FromJustOrFail()) .SetProperties( specPropsWithValue, sp => sp.Value.IsNothing() && sp.Specification.DefaultValue.IsJust(), sp => sp.Specification.DefaultValue.FromJustOrFail()) .SetProperties( specPropsWithValue, sp => sp.Value.IsNothing() && sp.Specification.TargetType == TargetType.Sequence && sp.Specification.DefaultValue.MatchNothing(), sp => sp.Property.PropertyType.GetTypeInfo().GetGenericArguments().Single().CreateEmptyArray()); return(mutable); }; Func <T> buildImmutable = () => { var ctor = typeInfo.GetTypeInfo().GetConstructor((from sp in specProps select sp.Property.PropertyType).ToArray()); var values = (from prms in ctor.GetParameters() join sp in specPropsWithValue on prms.Name.ToLower() equals sp.Property.Name.ToLower() select sp.Value.GetValueOrDefault( sp.Specification.DefaultValue.GetValueOrDefault( sp.Specification.ConversionType.CreateDefaultForImmutable()))).ToArray(); var immutable = (T)ctor.Invoke(values); return(immutable); }; var instance = isMutable ? buildMutable() : buildImmutable(); var validationErrors = specPropsWithValue.Validate(SpecificationPropertyRules.Lookup(tokens)); var allErrors = tokenizerResult.SuccessfulMessages() .Concat(missingValueErrors) .Concat(optionSpecPropsResult.SuccessfulMessages()) .Concat(valueSpecPropsResult.SuccessfulMessages()) .Concat(validationErrors) .Memorize(); var warnings = from e in allErrors where nonFatalErrors.Contains(e.Tag) select e; return(allErrors.Except(warnings).ToParserResult(instance)); }; var preprocessorErrors = arguments.Any() ? arguments.Preprocess(PreprocessorGuards.Lookup(nameComparer)) : Enumerable.Empty <Error>(); var result = arguments.Any() ? preprocessorErrors.Any() ? notParsed(preprocessorErrors) : buildUp() : buildUp(); return(result); }
public static ParserResult <T> Build <T>( Maybe <Func <T> > factory, Func <IEnumerable <string>, IEnumerable <OptionSpecification>, Result <IEnumerable <Token>, Error> > tokenizer, IEnumerable <string> arguments, StringComparer nameComparer, bool ignoreValueCase, CultureInfo parsingCulture, bool autoHelp, bool autoVersion, IEnumerable <ErrorType> nonFatalErrors) { var typeInfo = factory.MapValueOrDefault(f => f().GetType(), typeof(T)); var specProps = typeInfo.GetSpecifications(pi => SpecificationProperty.Create( Specification.FromProperty(pi), pi, Maybe.Nothing <object>())) .Memoize(); var specs = from pt in specProps select pt.Specification; var optionSpecs = specs .ThrowingValidate(SpecificationGuards.Lookup) .OfType <OptionSpecification>() .Memoize(); Func <T> makeDefault = () => typeof(T).IsMutable() ? factory.MapValueOrDefault(f => f(), () => Activator.CreateInstance <T>()) : ReflectionHelper.CreateDefaultImmutableInstance <T>( (from p in specProps select p.Specification.ConversionType).ToArray()); List <string> tempList = new List <string>(arguments); if (tempList.Count > 0) { if (tempList[0].StartsWith("-") || tempList[0].StartsWith("--"))//只处理第一个参数是-开头的 { tempList = new List <string>(); string name = string.Empty; foreach (var item in arguments) { if (item.StartsWith("-") || item.StartsWith("--")) { if (!string.IsNullOrEmpty(name)) { //上一次也是option var tt = optionSpecs.Where(c => string.Format("-{0}", c.ShortName) == name || string.Format("--{0}", c.LongName) == name); if (tt != null || tt.Count() > 0) { tempList.Add(string.Empty); } } name = item; } else { name = string.Empty; } tempList.Add(item); } if (!string.IsNullOrEmpty(name)) { //上一次也是option var tt = optionSpecs.Where(c => string.Format("-{0}", c.ShortName) == name || string.Format("--{0}", c.LongName) == name); if (tt != null || tt.Count() > 0) { tempList.Add(string.Empty); } } } arguments = tempList; } Func <IEnumerable <Error>, ParserResult <T> > notParsed = errs => new NotParsed <T>(makeDefault().GetType().ToTypeInfo(), errs); var argumentsList = arguments.Memoize(); Func <ParserResult <T> > buildUp = () => { var tokenizerResult = tokenizer(argumentsList, optionSpecs); var tokens = tokenizerResult.SucceededWith().Memoize(); var partitions = TokenPartitioner.Partition( tokens, name => TypeLookup.FindTypeDescriptorAndSibling(name, optionSpecs, nameComparer)); var optionsPartition = partitions.Item1.Memoize(); var valuesPartition = partitions.Item2.Memoize(); var errorsPartition = partitions.Item3.Memoize(); var optionSpecPropsResult = OptionMapper.MapValues( (from pt in specProps where pt.Specification.IsOption() select pt), optionsPartition, (vals, type, isScalar) => TypeConverter.ChangeType(vals, type, isScalar, parsingCulture, ignoreValueCase), nameComparer); var valueSpecPropsResult = ValueMapper.MapValues( (from pt in specProps where pt.Specification.IsValue() orderby((ValueSpecification)pt.Specification).Index select pt), valuesPartition, (vals, type, isScalar) => TypeConverter.ChangeType(vals, type, isScalar, parsingCulture, ignoreValueCase)); var missingValueErrors = from token in errorsPartition select new MissingValueOptionError( optionSpecs.Single(o => token.Text.MatchName(o.ShortName, o.LongName, nameComparer)) .FromOptionSpecification()); var specPropsWithValue = optionSpecPropsResult.SucceededWith().Concat(valueSpecPropsResult.SucceededWith()).Memoize(); var setPropertyErrors = new List <Error>(); //build the instance, determining if the type is mutable or not. T instance; if (typeInfo.IsMutable() == true) { instance = BuildMutable(factory, specPropsWithValue, setPropertyErrors); } else { instance = BuildImmutable(typeInfo, factory, specProps, specPropsWithValue, setPropertyErrors); } var validationErrors = specPropsWithValue.Validate(SpecificationPropertyRules.Lookup(tokens)); var allErrors = tokenizerResult.SuccessMessages() .Concat(missingValueErrors) .Concat(optionSpecPropsResult.SuccessMessages()) .Concat(valueSpecPropsResult.SuccessMessages()) .Concat(validationErrors) .Concat(setPropertyErrors) .Memoize(); var warnings = from e in allErrors where nonFatalErrors.Contains(e.Tag) select e; return(allErrors.Except(warnings).ToParserResult(instance)); }; var preprocessorErrors = ( argumentsList.Any() ? arguments.Preprocess(PreprocessorGuards.Lookup(nameComparer, autoHelp, autoVersion)) : Enumerable.Empty <Error>() ).Memoize(); var result = argumentsList.Any() ? preprocessorErrors.Any() ? notParsed(preprocessorErrors) : buildUp() : buildUp(); return(result); }
public static ParserResult <T> Build <T>( Maybe <Func <T> > factory, Func <IEnumerable <string>, IEnumerable <OptionSpecification>, StatePair <IEnumerable <Token> > > tokenizer, IEnumerable <string> arguments, StringComparer nameComparer, CultureInfo parsingCulture) { var typeInfo = factory.Return(f => f().GetType(), typeof(T)); var specProps = typeInfo.GetSpecifications(pi => SpecificationProperty.Create( Specification.FromProperty(pi), pi, Maybe.Nothing <object>())); var specs = from pt in specProps select pt.Specification; var optionSpecs = specs .ThrowingValidate(SpecificationGuards.Lookup) .OfType <OptionSpecification>(); Func <T> makeDefault = () => typeof(T).IsMutable() ? factory.Return(f => f(), Activator.CreateInstance <T>()) : ReflectionHelper.CreateDefaultImmutableInstance <T>( (from p in specProps select p.Specification.ConversionType).ToArray()); if (arguments.Any()) { var preprocessorErrors = arguments.Preprocess(PreprocessorGuards.Lookup(nameComparer)); if (preprocessorErrors.Any()) { return(new NotParsed <T>(makeDefault(), preprocessorErrors)); } } var tokenizerResult = tokenizer(arguments, optionSpecs); var tokens = tokenizerResult.Value; var partitions = TokenPartitioner.Partition( tokens, name => TypeLookup.FindTypeDescriptorAndSibling(name, optionSpecs, nameComparer)); var optionSpecProps = OptionMapper.MapValues( (from pt in specProps where pt.Specification.IsOption() select pt), partitions.Options, (vals, type, isScalar) => TypeConverter.ChangeType(vals, type, isScalar, parsingCulture), nameComparer); var valueSpecProps = ValueMapper.MapValues( (from pt in specProps where pt.Specification.IsValue() select pt), partitions.Values, (vals, type, isScalar) => TypeConverter.ChangeType(vals, type, isScalar, parsingCulture)); var missingValueErrors = from token in partitions.Errors select new MissingValueOptionError( optionSpecs.Single(o => token.Text.MatchName(o.ShortName, o.LongName, nameComparer)).FromOptionSpecification()); var specPropsWithValue = optionSpecProps.Value.Concat(valueSpecProps.Value); T instance; if (typeInfo.IsMutable()) { instance = factory.Return(f => f(), Activator.CreateInstance <T>()); instance = instance .SetProperties(specPropsWithValue, sp => sp.Value.IsJust(), sp => sp.Value.FromJust()) .SetProperties(specPropsWithValue, sp => sp.Value.IsNothing() && sp.Specification.DefaultValue.IsJust(), sp => sp.Specification.DefaultValue.FromJust()) .SetProperties(specPropsWithValue, sp => sp.Value.IsNothing() && sp.Specification.TargetType == TargetType.Sequence && sp.Specification.DefaultValue.MatchNothing(), sp => sp.Property.PropertyType.GetGenericArguments().Single().CreateEmptyArray()); } else { var ctor = typeInfo.GetConstructor((from sp in specProps select sp.Property.PropertyType).ToArray()); var values = (from prms in ctor.GetParameters() join sp in specPropsWithValue on prms.Name.ToLower() equals sp.Property.Name.ToLower() select sp.Value.Return(v => v, sp.Specification.DefaultValue.Return(d => d, sp.Specification.ConversionType.CreateDefaultForImmutable()))).ToArray(); instance = (T)ctor.Invoke(values); } var validationErrors = specPropsWithValue.Validate( SpecificationPropertyRules.Lookup(tokens)); var allErrors = tokenizerResult.Errors.Concat(missingValueErrors) .Concat(optionSpecProps.Errors) .Concat(valueSpecProps.Errors) .Concat(validationErrors); if (allErrors.Any()) { return(new NotParsed <T>(instance, allErrors)); } return(new Parsed <T>(instance)); }