Пример #1
0
        private static IEnumerable <Pattern> ParseShorts(Tokens tokens, ICollection <Option> options)
        {
            // shorts ::= '-' ( chars )* [ [ ' ' ] chars ] ;

            var token = tokens.Move();

            Debug.Assert(token.StartsWith("-") && !token.StartsWith("--"));
            var left   = token.TrimStart(new[] { '-' });
            var parsed = new List <Pattern>();

            while (left != "")
            {
                var shortName = "-" + left[0];
                left = left.Substring(1);
                var    similar = options.Where(o => o.ShortName == shortName).ToList();
                Option option  = null;
                if (similar.Count > 1)
                {
                    throw tokens.CreateException(string.Format("{0} is specified ambiguously {1} times", shortName,
                                                               similar.Count));
                }
                if (similar.Count < 1)
                {
                    option = new Option(shortName, null, 0);
                    options.Add(option);
                    if (tokens.ThrowsInputError)
                    {
                        option = new Option(shortName, null, 0, new ValueObject(true));
                    }
                }
                else
                {
                    // why is copying necessary here?
                    option = new Option(shortName, similar[0].LongName, similar[0].ArgCount, similar[0].Value);
                    ValueObject value = null;
                    if (option.ArgCount != 0)
                    {
                        if (left == "")
                        {
                            if (tokens.Current() == null || tokens.Current() == "--")
                            {
                                throw tokens.CreateException(shortName + " requires argument");
                            }
                            value = new ValueObject(tokens.Move());
                        }
                        else
                        {
                            value = new ValueObject(left);
                            left  = "";
                        }
                    }
                    if (tokens.ThrowsInputError)
                    {
                        option.Value = value ?? new ValueObject(true);
                    }
                }
                parsed.Add(option);
            }
            return(parsed);
        }
Пример #2
0
        private static IEnumerable <Pattern> ParseAtom(Tokens tokens, ICollection <Option> options)
        {
            // atom ::= '(' expr ')' | '[' expr ']' | 'options'
            //  | long | shorts | argument | command ;

            var token  = tokens.Current();
            var result = new List <Pattern>();

            switch (token)
            {
            case "[":
            case "(":
            {
                tokens.Move();
                string matching;
                if (token == "(")
                {
                    matching = ")";
                    result.Add(new Required(ParseExpr(tokens, options).ToArray()));
                }
                else
                {
                    matching = "]";
                    result.Add(new Optional(ParseExpr(tokens, options).ToArray()));
                }
                if (tokens.Move() != matching)
                {
                    throw tokens.CreateException("unmatched '" + token + "'");
                }
            }
            break;

            case "options":
                tokens.Move();
                result.Add(new OptionsShortcut());
                break;

            default:
                if (token.StartsWith("--") && token != "--")
                {
                    return(ParseLong(tokens, options));
                }
                if (token.StartsWith("-") && token != "-" && token != "--")
                {
                    return(ParseShorts(tokens, options));
                }
                if (token.StartsWith("<") && token.EndsWith(">") || token.All(char.IsUpper))
                {
                    result.Add(new Argument(tokens.Move()));
                }
                else
                {
                    result.Add(new Command(tokens.Move()));
                }
                break;
            }
            return(result);
        }
Пример #3
0
        private static ICollection <Pattern> ParseSeq(Tokens tokens, ICollection <Option> options)
        {
            // seq ::= ( atom [ '...' ] )* ;
            var result = new List <Pattern>();

            while (!new[] { null, "]", ")", "|" }.Contains(tokens.Current()))
            {
                var atom = ParseAtom(tokens, options);

                if (tokens.Current() == "...")
                {
                    result.Add(new OneOrMore(atom.ToArray()));
                    tokens.Move();
                    return(result);
                }
                result.AddRange(atom);
            }
            return(result);
        }
Пример #4
0
        private static IEnumerable <Pattern> ParseExpr(Tokens tokens, ICollection <Option> options)
        {
            // expr ::= seq ( '|' seq )* ;
            var seq = ParseSeq(tokens, options);

            if (tokens.Current() != "|")
            {
                return(seq);
            }
            var result = new List <Pattern>();

            if (seq.Count() > 1)
            {
                result.Add(new Required(seq.ToArray()));
            }
            else
            {
                result.AddRange(seq);
            }
            while (tokens.Current() == "|")
            {
                tokens.Move();
                seq = ParseSeq(tokens, options);
                if (seq.Count() > 1)
                {
                    result.Add(new Required(seq.ToArray()));
                }
                else
                {
                    result.AddRange(seq);
                }
            }
            result = result.Distinct().ToList();
            if (result.Count > 1)
            {
                return new[] { new Either(result.ToArray()) }
            }
            ;
            return(result);
        }
Пример #5
0
        /// <summary>
        ///     Parse command-line argument vector.
        /// </summary>
        /// <param name="tokens"></param>
        /// <param name="options"></param>
        /// <param name="optionsFirst"></param>
        /// <returns></returns>
        internal static IList <Pattern> ParseArgv(Tokens tokens, ICollection <Option> options,
                                                  bool optionsFirst = false)
        {
            //    If options_first:
            //        argv ::= [ long | shorts ]* [ argument ]* [ '--' [ argument ]* ] ;
            //    else:
            //        argv ::= [ long | shorts | argument ]* [ '--' [ argument ]* ] ;

            var parsed = new List <Pattern>();

            while (tokens.Current() != null)
            {
                if (tokens.Current() == "--")
                {
                    parsed.AddRange(tokens.Select(v => new Argument(null, new ValueObject(v))));
                    return(parsed);
                }

                if (tokens.Current().StartsWith("--"))
                {
                    parsed.AddRange(ParseLong(tokens, options));
                }
                else if (tokens.Current().StartsWith("-") && tokens.Current() != "-")
                {
                    parsed.AddRange(ParseShorts(tokens, options));
                }
                else if (optionsFirst)
                {
                    parsed.AddRange(tokens.Select(v => new Argument(null, new ValueObject(v))));
                    return(parsed);
                }
                else
                {
                    parsed.Add(new Argument(null, new ValueObject(tokens.Move())));
                }
            }
            return(parsed);
        }
Пример #6
0
        private static IEnumerable <Pattern> ParseLong(Tokens tokens, ICollection <Option> options)
        {
            // long ::= '--' chars [ ( ' ' | '=' ) chars ] ;
            var p        = new StringPartition(tokens.Move(), "=");
            var longName = p.LeftString;

            Debug.Assert(longName.StartsWith("--"));
            var value   = (p.NoSeparatorFound) ? null : new ValueObject(p.RightString);
            var similar = options.Where(o => o.LongName == longName).ToList();

            if (tokens.ThrowsInputError && similar.Count == 0)
            {
                // If not exact match
                similar =
                    options.Where(o => !string.IsNullOrEmpty(o.LongName) && o.LongName.StartsWith(longName)).ToList();
            }
            if (similar.Count > 1)
            {
                // Might be simply specified ambiguously 2+ times?
                throw tokens.CreateException($"{longName} is not a unique prefix: {string.Join(", ", similar.Select(o => o.LongName))}?");
            }
            Option option = null;

            if (similar.Count < 1)
            {
                var argCount = p.Separator == "=" ? 1 : 0;
                option = new Option(null, longName, argCount);
                options.Add(option);
                if (tokens.ThrowsInputError)
                {
                    option = new Option(null, longName, argCount, argCount != 0 ? value : new ValueObject(true));
                }
            }
            else
            {
                option = new Option(similar[0].ShortName, similar[0].LongName, similar[0].ArgCount, similar[0].Value);
                if (option.ArgCount == 0)
                {
                    if (value != null)
                    {
                        throw tokens.CreateException(option.LongName + " must not have an argument");
                    }
                }
                else
                {
                    if (value == null)
                    {
                        if (tokens.Current() == null || tokens.Current() == "--")
                        {
                            throw tokens.CreateException(option.LongName + " requires an argument");
                        }
                        value = new ValueObject(tokens.Move());
                    }
                }
                if (tokens.ThrowsInputError)
                {
                    option.Value = value ?? new ValueObject(true);
                }
            }
            return(new[] { option });
        }