private static (IParseTree parseTree, TokenStreamRewriter rewriter) ParseInternal(ParserMode mode, VBAParser parser, CommonTokenStream tokenStream, ParserStartRule startRule)
        {
            if (mode == ParserMode.Ll)
            {
                parser.Interpreter.PredictionMode = PredictionMode.Ll;
            }
            else
            {
                parser.Interpreter.PredictionMode = PredictionMode.Sll;
            }
            var tree = startRule.Invoke(parser);

            return(tree, new TokenStreamRewriter(tokenStream));
        }
        /// <summary>
        /// Parses the supplied code.
        /// </summary>
        /// <param name="code">The code to parse.</param>
        /// <param name="startRule">The parser rule to begin the process with.</param>
        /// <param name="mode">(Optional) The parser mode to run.</param>
        public static (IParseTree parseTree, TokenStreamRewriter rewriter) Parse(string code, ParserStartRule startRule, ParserMode mode = ParserMode.Default)
        {
            var tokenStreamProvider = new SimpleVBAModuleTokenStreamProvider();
            var tokenStream         = tokenStreamProvider.Tokens(code ?? string.Empty);
            var parser = new VBAParser(tokenStream);

            try
            {
                return(ParseInternal(ParserMode.Sll, parser, tokenStream, startRule));
            }
            catch (ParsePassSyntaxErrorException exception)
            {
                var actualMode = parser.Interpreter.PredictionMode.ToString().ToUpperInvariant();
                System.Diagnostics.Debug.Assert(actualMode == ParserMode.Sll.ToString().ToUpperInvariant());

                var message = $"{actualMode} mode failed while parsing the code at symbol {exception.OffendingSymbol.Text} at L{exception.LineNumber}C{exception.Position}. Retrying using LL.";
                LogAndReset(message, exception, parser, tokenStream);

                if (parser.Interpreter.PredictionMode == PredictionMode.Sll)
                {
                    return(ParseInternal(ParserMode.Ll, parser, tokenStream, startRule));
                }
            }
            catch (Exception exception)
            {
                var actualMode = parser.Interpreter.PredictionMode.ToString().ToUpperInvariant();
                System.Diagnostics.Debug.Assert(actualMode == ParserMode.Sll.ToString().ToUpperInvariant());

                var message = $"{actualMode} mode threw an exception. Retrying LL mode.";
                LogAndReset(message, exception, parser, tokenStream);

                if (parser.Interpreter.PredictionMode == PredictionMode.Sll)
                {
                    return(ParseInternal(ParserMode.Ll, parser, tokenStream, startRule));
                }
            }

            return(null, null);
        }