Inheritance: AttributeBase
Exemplo n.º 1
0
        public static Dictionary <int, ValueAttribute> GetValues(Type type)
        {
            var result = new Dictionary <int, ValueAttribute>();

            foreach (var prop in type.GetProperties())
            {
                foreach (var value in prop.GetCustomAttributes(typeof(ValueAttribute), true))
                {
                    ValueAttribute valueAttr = (ValueAttribute)value;
                    if (result.ContainsKey(valueAttr.Index))
                    {
                        throw new ParserException("There is more than one [Value] with the index " + valueAttr.Index);
                    }
                    if (valueAttr.Index < 0)
                    {
                        throw new ParserException("A [Value]'s index cannot be negative");
                    }
                    valueAttr.TargetProperty = prop;
                    VerifyAttribute(valueAttr);
                    result.Add(valueAttr.Index, valueAttr);
                }
            }
            if (!result.Keys.SequenceEqual(Enumerable.Range(0, result.Count)))
            {
                throw new ParserException("[Value] indices must be consecutive from 0 to N");
            }
            return(result);
        }
Exemplo n.º 2
0
        private ParseResult <object> Parse(Type type, string input)
        {
            // TODO Refactor this whole thing to use exception handling and store common objects in a class

            object instance = Activator.CreateInstance(type);

            Dictionary <string, OptionAttribute> options = OptionsClassProcessor.GetOptions(type);
            Dictionary <int, ValueAttribute>     values  = OptionsClassProcessor.GetValues(type);
            int             unsatisfiedCount             = options.Count + values.Count;
            int             nextValueToFill      = 0;
            OptionAttribute optionExpectingValue = null;
            Tokenizer       tokenizer            = new Tokenizer(input);

            while (!tokenizer.AtEnd && unsatisfiedCount > 0)
            {
                Token token = tokenizer.NextToken;
                switch (token.Kind)
                {
                case TokenKind.LongOption:
                case TokenKind.ShortOption:
                    if (optionExpectingValue != null)
                    {
                        return(ParseResult <object> .WithError("No value provided for option '" + optionExpectingValue.Option + "'"));
                    }
                    OptionAttribute optionAttr;
                    if (!options.TryGetValue(token.Value, out optionAttr))
                    {
                        return(ParseResult <object> .WithError("Unexpected option '" + token.Value + "'"));
                    }
                    if (optionAttr.Satisfied)
                    {
                        return(ParseResult <object> .WithError("Multiple values for option '" + token.Value + "' are not allowed"));
                    }

                    var alreadySatisfiedExclusiveOption = FirstAlreadySatisfiedMutuallyExclusiveOption(options, optionAttr);
                    if (alreadySatisfiedExclusiveOption != null)
                    {
                        return(ParseResult <object> .WithError("The option '" + token.Value + "' is mutually exclusive with the option '" + alreadySatisfiedExclusiveOption.Option + "' that was already satisfied"));
                    }

                    if (optionAttr.TargetProperty.PropertyType == typeof(bool))
                    {
                        optionAttr.TargetProperty.SetValue(instance, true);
                        optionAttr.Satisfied = true;
                        --unsatisfiedCount;
                    }
                    else
                    {
                        optionExpectingValue = optionAttr;
                    }
                    break;

                case TokenKind.Value:
                    if (optionExpectingValue != null)
                    {
                        string error = SetPropertyValue(optionExpectingValue, instance, token.Value);
                        if (error != null)
                        {
                            return(ParseResult <object> .WithError("Error setting option '" + optionExpectingValue.Option + "': " + error));
                        }
                        optionExpectingValue.Satisfied = true;
                        optionExpectingValue           = null;
                        --unsatisfiedCount;
                    }
                    else
                    {
                        if (nextValueToFill >= values.Count)
                        {
                            // There are no more values to fill, just options
                            return(ParseResult <object> .WithError("Unexpected plain value '" + token.Value + "'"));
                        }

                        ValueAttribute valueAttr = values[nextValueToFill];
                        string         error     = SetPropertyValue(valueAttr, instance, token.Value);
                        if (error != null)
                        {
                            return(ParseResult <object> .WithError("Error setting value #" + nextValueToFill + ": " + error));
                        }
                        valueAttr.Satisfied = true;
                        --unsatisfiedCount;
                        ++nextValueToFill;
                    }
                    break;

                case TokenKind.Error:
                    return(ParseResult <object> .WithError("Error parsing options: " + token.Value));
                }
            }

            SetDefaultValues(instance, options, values);

            var errorResult = FindUnsatisfiedOptionsAndValues(options, values);

            if (errorResult != null)
            {
                return(errorResult);
            }

            errorResult = SetRestOfInputPropertyIfAvailable(type, instance, tokenizer);
            if (errorResult != null)
            {
                return(errorResult);
            }

            return(ParseResult <object> .WithValue(instance));
        }