private void ReportUnrecognizedArgument(TokenParseResult result, string argument)
        {
            switch (result.State)
            {
            case TokenParseResultState.UnknownNamedArgument:
                ReportLine(Strings.UnrecognizedArgument, argument);

                if (!string.IsNullOrEmpty(result.NamedArg))
                {
                    var possibleArgs = GetSimilarNamedArguments(result.NamedArgType, result.NamedArg).ToList();
                    if (possibleArgs.Count > 0)
                    {
                        ReportLine(
                            "  " + Strings.PossibleIntendedNamedArguments,
                            string.Join(", ", possibleArgs.Select(a => "'" + a + "'")));
                    }
                }

                break;

            case TokenParseResultState.UnknownPositionalArgument:
                ReportLine(Strings.UnrecognizedArgument, argument);
                break;

            case TokenParseResultState.RequiresOptionArgument:
                ReportLine(Strings.MissingRequiredOptionArgument, argument);
                break;
            }
        }
Example #2
0
        public TokenParseResult ParseRule(Grouping group, Token startToken, ParserSettings settings)
        {
            List <SyntaxNode> nodes       = new List <SyntaxNode>();
            TokenParseResult  groupResult = TokenParseResult.Failed(startToken);
            Token             token;
            TokenParseResult  ruleResult;

            token = startToken;

            foreach (Rule rule in group)
            {
                ruleResult = rule.Parse(token, settings);
                if (ruleResult)
                {
                    if (!groupResult || settings.AlternateCritera == ParserSettings.SelectionCriteria.First ||
                        (groupResult.Node.GetTokenCount() < ruleResult.Node.GetTokenCount()))
                    {
                        groupResult           = ruleResult;
                        groupResult.Node.Rule = group;
                        if (settings.AlternateCritera == ParserSettings.SelectionCriteria.First)
                        {
                            break;
                        }
                    }
                }
            }

            return(groupResult);
        }
Example #3
0
        /// <summary>
        /// Calls Rule's Parse and adds as child result if succesful.
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        public TokenParseResult ParseRule(Token token, ParserSettings settings)
        {
            TokenParseResult result = Rule.Parse(token, settings);

            if (result.IsSuccesful)
            {
                SyntaxNode parentNode = new SyntaxNode(Source, token);
                parentNode.Add(result.Node);
                result.Node = parentNode;
            }
            return(result);
        }
Example #4
0
        public TokenParseResult ParseRule(Token token, ParserSettings settings)
        {
            TokenParseResult result;

            if (TokenType.Name == token.TokenType.Name)
            {
                result = TokenParseResult.Success(new SyntaxNode(Source, token), token.Next);
            }
            else
            {
                result = TokenParseResult.Failed(token);
            }

            return(result);
        }
Example #5
0
        public override TokenParseResult Parse(Token token, ParserSettings settings)
        {
            TokenParseResult result;

            if (Text == token.Text)
            {
                result = TokenParseResult.Success(new SyntaxNode(this, token), token.Next);
            }
            else
            {
                result = TokenParseResult.Failed(token);
            }

            return(result);
        }
            /// <summary>
            /// Executes a parse.  When this method is called, the parsing engine
            /// reads information from the source text (either a string or a file)
            /// and then reports what action was taken. This ranges from a token
            /// being read and recognized from the source, a parse reduction, or a type of error.
            /// </summary>
            /// <returns>ParseMessage indicating parser state.</returns>
            public ParseMessage Parse()
            {
                if (m_grammar == null)
                {
                    return(ParseMessage.NotLoadedError);
                }
                while (true)
                {
                    Token readToken;
                    if (m_inputTokens.Count == 0)
                    {
                        //We must read a token
                        readToken = m_tokenReader.ReadToken();
                        if (readToken == null)
                        {
                            return(ParseMessage.InternalError);
                        }
                        else if (readToken.SymbolType != SymbolType.Whitespace)
                        {
                            m_inputTokens.Push(readToken);
                            if (m_commentLevel == 0 &&
                                readToken.SymbolType != SymbolType.CommentLine &&
                                readToken.SymbolType != SymbolType.CommentStart)
                            {
                                return(ParseMessage.TokenRead);
                            }
                        }
                    }
                    else if (m_commentLevel > 0)
                    {
                        //We are in a block comment
                        readToken = m_inputTokens.PopToken();
                        if (readToken != null)
                        {
                            switch (readToken.SymbolType)
                            {
                            case SymbolType.CommentStart:
                                m_commentLevel++;
                                break;

                            case SymbolType.CommentEnd:
                                m_commentLevel--;
                                break;

                            case SymbolType.End:
                                return(ParseMessage.CommentError);

                            default:
                                //Do nothing, ignore
                                //The 'comment line' symbol is ignored as well
                                break;
                            }
                        }
                    }
                    else
                    {
                        readToken = m_inputTokens.PeekToken();
                        if (readToken != null)
                        {
                            switch (readToken.SymbolType)
                            {
                            case SymbolType.CommentStart:
                                m_commentLevel++;
                                m_inputTokens.Pop();                                         //Remove it
                                break;

                            case SymbolType.CommentLine:
                                m_inputTokens.Pop();                                         //Remove it and rest of line
                                string comment = m_tokenReader.ReadToLineEnd();
                                m_comments[LineNumber] = comment;
                                break;

                            case SymbolType.Error:
                                return(ParseMessage.LexicalError);

                            default:
                                //FINALLY, we can parse the token
                                TokenParseResult parseResult = ParseToken(readToken);
                                switch (parseResult)
                                {
                                case TokenParseResult.Accept:
                                    return(ParseMessage.Accept);

                                case TokenParseResult.InternalError:
                                    return(ParseMessage.InternalError);

                                case TokenParseResult.ReduceNormal:
                                    return(ParseMessage.Reduction);

                                case TokenParseResult.Shift:
                                    m_inputTokens.Pop();                                                     //A simple shift, we must continue
                                    //Okay, remove the top token, it is on the stack
                                    break;

                                case TokenParseResult.SyntaxError:
                                    return(ParseMessage.SyntaxError);
                                }
                                break;
                            }
                        }
                    }
                }
            }
Example #7
0
        /// <summary>
        /// Executes next step of parser and returns parser state.
        /// </summary>
        /// <returns>Parser current state.</returns>
        public ParseMessage Parse()
        {
            if (m_token.m_symbol != null)
            {
                switch (m_token.m_symbol.m_symbolType)
                {
                case SymbolType.CommentLine:
                    DiscardInputToken();                             //Remove it
                    MoveToLineEnd();
                    break;

                case SymbolType.CommentStart:
                    ProcessBlockComment();
                    break;
                }
            }
            while (true)
            {
                if (m_token.m_symbol == null)
                {
                    //We must read a token
                    Symbol     readTokenSymbol = ReadToken();
                    SymbolType symbolType      = readTokenSymbol.m_symbolType;
                    if (m_commentLevel == 0 &&
                        symbolType != SymbolType.CommentLine &&
                        symbolType != SymbolType.CommentStart &&
                        symbolType != SymbolType.WhiteSpace)
                    {
                        return(ParseMessage.TokenRead);
                    }
                }
                else
                {
                    //==== Normal parse mode - we have a token and we are not in comment mode
                    switch (m_token.m_symbol.m_symbolType)
                    {
                    case SymbolType.WhiteSpace:
                        DiscardInputToken();                                  // Discard Whitespace
                        break;

                    case SymbolType.CommentStart:
                        m_commentLevel = 1;                                 // Switch to block comment mode.
                        return(ParseMessage.CommentBlockRead);

                    case SymbolType.CommentLine:
                        return(ParseMessage.CommentLineRead);

                    case SymbolType.Error:
                        return(ParseMessage.LexicalError);

                    default:
                        //Finally, we can parse the token
                        TokenParseResult parseResult = ParseToken();
                        switch (parseResult)
                        {
                        case TokenParseResult.Accept:
                            return(ParseMessage.Accept);

                        case TokenParseResult.InternalError:
                            return(ParseMessage.InternalError);

                        case TokenParseResult.ReduceNormal:
                            return(ParseMessage.Reduction);

                        case TokenParseResult.Shift:
                            //A simple shift, we must continue
                            DiscardInputToken();                                     // Okay, remove the top token, it is on the stack
                            break;

                        case TokenParseResult.SyntaxError:
                            return(ParseMessage.SyntaxError);

                        default:
                            //Do nothing
                            break;
                        }
                        break;
                    }
                }
            }
        }
        private TokenParseResult TryParseNamedArgument(string argument, string argumentPrefix, NamedArgumentType namedArgType, out IReadOnlyList <ArgumentAndValue> parsedArgs)
        {
            var prefixLength = argumentPrefix.Length;

            Debug.Assert(argument.Length >= prefixLength);

            // Figure out where the argument name ends.
            var endIndex = argument.IndexOfAny(_argumentSet.Attribute.ArgumentValueSeparators, prefixLength);

            // Special case: check for '+' and '-' for booleans.
            if (endIndex < 0 && argument.Length >= 2)
            {
                var lastArgumentChar = argument[argument.Length - 1];
                if (ArgumentNameTerminators.Any(t => lastArgumentChar.Equals(t)))
                {
                    endIndex = argument.Length - 1;
                }
            }

            // If we don't have a separator or terminator, then consume the full string.
            if (endIndex < 0)
            {
                endIndex = argument.Length;
            }

            // Extract the argument name(s), separate from the prefix
            // or optional argument value.
            var options = argument.Substring(prefixLength, endIndex - prefixLength);

            // Extract the option argument (a.k.a. value), if there is one.
            string optionArgument = null;

            if (argument.Length > prefixLength + options.Length)
            {
                // If there's an argument value separator, then extract the value after the separator.
                if (_argumentSet.Attribute.ArgumentValueSeparators.Any(sep => argument[prefixLength + options.Length] == sep))
                {
                    optionArgument = argument.Substring(prefixLength + options.Length + 1);
                }

                // Otherwise, it might be a terminator; extract the rest of the string.
                else
                {
                    optionArgument = argument.Substring(prefixLength + options.Length);
                }
            }

            // Now try to figure out how many names are present.
            if (namedArgType == NamedArgumentType.ShortName &&
                (_argumentSet.Attribute.AllowMultipleShortNamesInOneToken || _argumentSet.Attribute.AllowElidingSeparatorAfterShortName))
            {
                Debug.Assert(_argumentSet.Attribute.ShortNamesAreOneCharacterLong);

                // Since short names are one character long, we parse them one at a
                // time, preparing for multiple arguments in this one token.
                var args = new List <ArgumentAndValue>();
                for (var index = 0; index < options.Length; ++index)
                {
                    // Try parsing it as a short name; bail immediately if we find an invalid
                    // one.
                    var possibleShortName = new string(options[index], 1);
                    if (!_argumentSet.TryGetNamedArgument(possibleShortName, out ArgumentDefinition arg))
                    {
                        parsedArgs = null;
                        return(TokenParseResult.UnknownNamedArgument(namedArgType, possibleShortName));
                    }

                    // If this parsed as a short name that takes a required option argument,
                    // and we didn't see an option argument, and we allow mushing together
                    // short names and their option arguments, then try parsing the rest of
                    // this token as an option argument.
                    var lastChar = index == options.Length - 1;
                    if (arg.RequiresOptionArgument &&
                        _argumentSet.Attribute.AllowElidingSeparatorAfterShortName &&
                        optionArgument == null &&
                        !lastChar)
                    {
                        optionArgument = options.Substring(index + 1);
                        index          = options.Length - 1;
                        lastChar       = true;
                    }

                    if (!_argumentSet.Attribute.AllowMultipleShortNamesInOneToken &&
                        args.Count > 0)
                    {
                        parsedArgs = null;
                        return(TokenParseResult.UnknownNamedArgument());
                    }

                    args.Add(new ArgumentAndValue
                    {
                        Arg   = arg,
                        Value = lastChar ? optionArgument : null
                    });
                }

                parsedArgs = args;
            }
            else
            {
                // Try to look up the argument by name.
                if (!_argumentSet.TryGetNamedArgument(options, out ArgumentDefinition arg))
                {
                    parsedArgs = null;
                    return(TokenParseResult.UnknownNamedArgument(namedArgType, options));
                }

                parsedArgs = new[] { new ArgumentAndValue
                                     {
                                         Arg   = arg,
                                         Value = optionArgument
                                     } };
            }

            // If the last named argument we saw in this token required an
            // option argument to go with it, then yield that information
            // so it can be used by the caller (e.g. in completion generation).
            var lastArg = parsedArgs.GetLastOrDefault();

            if (lastArg != null &&
                lastArg.Arg.RequiresOptionArgument &&
                string.IsNullOrEmpty(lastArg.Value))
            {
                return(TokenParseResult.RequiresOptionArgument(lastArg.Arg));
            }

            return(TokenParseResult.Ready);
        }
        private TokenParseResult TryParseNextNamedArgument(IReadOnlyList <string> args, int index, string longNameArgumentPrefix, string shortNameArgumentPrefix, object destination, out int argsConsumed)
        {
            argsConsumed = 1;

            var argument = args[index];
            var result   = TokenParseResult.UnknownNamedArgument();

            IReadOnlyList <ArgumentAndValue> parsedArgs = null;

            if (result.IsUnknown && longNameArgumentPrefix != null)
            {
                result = TryParseNamedArgument(argument, longNameArgumentPrefix, NamedArgumentType.LongName, out parsedArgs);
            }
            if (result.IsUnknown && shortNameArgumentPrefix != null)
            {
                result = TryParseNamedArgument(argument, shortNameArgumentPrefix, NamedArgumentType.ShortName, out parsedArgs);
            }

            // If our policy allows a named argument's value to be placed
            // in the following token, and if we're missing a required
            // value, and if there's at least one more token, then try
            // to parse the next token as the current argument's value.
            if (result.State == TokenParseResultState.RequiresOptionArgument &&
                _argumentSet.Attribute.AllowNamedArgumentValueAsSucceedingToken &&
                index + 1 < args.Count)
            {
                var lastParsedArg = parsedArgs.GetLast();

                Debug.Assert(lastParsedArg.Arg.RequiresOptionArgument);
                Debug.Assert(!lastParsedArg.Arg.TakesRestOfLine);
                Debug.Assert(string.IsNullOrEmpty(parsedArgs.GetLast().Value));

                ++index;
                ++argsConsumed;

                lastParsedArg.Value = args[index];
                result = TokenParseResult.Ready;
            }

            if (!result.IsReady)
            {
                ReportUnrecognizedArgument(result, argument);
                return(result);
            }

            foreach (var parsedArg in parsedArgs)
            {
                // TODO: Obviate the need to use string.Empty here.
                var argValue = parsedArg.Value ?? string.Empty;

                if (parsedArg.Arg.TakesRestOfLine)
                {
                    if (!parsedArg.Arg.TrySetRestOfLine(argValue, args.Skip(index + 1), destination))
                    {
                        result = TokenParseResult.FailedParsing;
                        continue;
                    }

                    argsConsumed = args.Count - index; // skip the rest of the line
                }
                else
                {
                    if (!TryParseAndStore(parsedArg.Arg, argValue, destination))
                    {
                        result = TokenParseResult.FailedParsing;
                        continue;
                    }
                }
            }

            return(result);
        }
Example #10
0
        /// <summary>
        /// Parses a Group who's children are part of a chain and do not alternate
        /// </summary>
        /// <param name="group"></param>
        /// <param name="token"></param>
        /// <returns></returns>
        public TokenParseResult ParseRule(Grouping group, Token startToken, ParserSettings settings)
        {
            List <SyntaxNode> nodes       = new List <SyntaxNode>();
            TokenParseResult  groupResult = TokenParseResult.Failed(startToken);

            TokenParseResult ruleResult;
            int   ruleIdx;
            Rule  rule;
            Token token;
            // got the minimum results and wasn't an exception
            bool lastRuleOK;
            List <SyntaxNode> ruleNodes = new List <SyntaxNode>();

            ruleIdx    = 0;
            token      = startToken;
            lastRuleOK = true;

            while (lastRuleOK && ruleIdx < group.Count && token != null)
            {
                // every rule has its own scope
                rule = group[ruleIdx];
                ruleNodes.Clear();
                lastRuleOK = false;
                while (token != null)
                {
                    if (ruleResult = rule.Parse(token, settings))
                    {
                        ruleNodes.Add(ruleResult);
                        token = ruleResult.NextToken;
                        if (ruleNodes.Count >= rule.Quantifier.MaxValue)
                        {
                            break;
                        }
                    }
                    else
                    {
                        break;
                    }
                }

                lastRuleOK = (rule.Quantifier.MinValue <= ruleNodes.Count) ^ rule.IsException;


                // if we achieved min qty then add to nodes.
                if (lastRuleOK)
                {
                    nodes.AddRange(ruleNodes);
                    ruleIdx++;
                }
            }

            if (lastRuleOK && ruleIdx >= group.LastRequiredRuleIndex && nodes.Count > 0)
            {
                SyntaxNode parent = new SyntaxNode(group, startToken);
                parent.AddRange(nodes);
                // token should be set to the last succesful nextToken
                groupResult = TokenParseResult.Success(parent, token);
            }

            return(groupResult);
        }
Example #11
0
 public override TokenParseResult Parse(Token token, ParserSettings settings)
 {
     return(TokenParseResult.Success(this, null, null, token));
 }