/// <summary>
 /// Parse a VB file and get the first class name, fully qualified with namespace.
 /// </summary>
 /// <param name="binaryStream"></param>
 /// <returns></returns>
 static internal ExtractedClassName GetFirstClassNameFullyQualified(Stream binaryStream)
 {
     try
     {
         VisualBasicTokenizer tokens = new VisualBasicTokenizer(binaryStream, /* forceANSI */ false);
         return Extract(tokens);
     }
     catch (DecoderFallbackException)
     {
         // There was no BOM and there are non UTF8 sequences. Fall back to ANSI.
         VisualBasicTokenizer tokens = new VisualBasicTokenizer(binaryStream, /* forceANSI */ true);
         return Extract(tokens);
     }
 }
        /*
        * Method:  AssertTokenize
        * 
        * Tokenize a string ('source') and compare it to the expected set of tokens.
        * Also compare the source that is regenerated by concatenating all of the tokens
        * to 'expectedSource'.
        */
        static private void AssertTokenize
        (
           string source,
           string expectedSource,
           string expectedTokenKey,
           int expectedLastLineNumber
        )
        {
            VisualBasicTokenizer tokens = new VisualBasicTokenizer
            (
                StreamHelpers.StringToStream(source),
                false
            );
            string results = "";
            string tokenKey = "";
            int lastLine = 0;
            bool syntaxError = false;
            foreach (Token t in tokens)
            {
                results += t.InnerText;
                lastLine = t.Line;

                if (!syntaxError)
                {
                    // Its not really a file name, but GetExtension serves the purpose of getting the class name without
                    // the namespace prepended.
                    string tokenClass = t.ToString();
                    int pos = tokenClass.LastIndexOfAny(new char[] { '+', '.' });

                    if (t is VisualBasicTokenizer.LineTerminatorToken)
                    {
                        tokenKey += "eol";
                    }
                    else if (t is WhitespaceToken)
                    {
                        tokenKey += ".";
                    }
                    else
                    {
                        tokenKey += tokenClass.Substring(pos + 1);
                        tokenKey += "(";
                        tokenKey += t.InnerText;
                        tokenKey += ")";
                    }
                }

                if (t is SyntaxErrorToken)
                {
                    // Stop processing after the first syntax error because
                    // the order of tokens after this is an implementation detail and
                    // shouldn't be encoded into the unit tests.
                    syntaxError = true;
                }
            }
            tokenKey = tokenKey.Replace("Token", "");

            if (expectedSource != results || expectedTokenKey != tokenKey)
            {
                Console.WriteLine(tokenKey);
            }

            Assert.AreEqual(expectedSource, results);
            Assert.AreEqual(expectedTokenKey, tokenKey);
            Assert.AreEqual(expectedLastLineNumber, lastLine);
        }
        /// <summary>
        /// Extract the class name.
        /// </summary>
        /// <param name="tokens"></param>
        /// <returns></returns>
        private static ExtractedClassName Extract(VisualBasicTokenizer tokens)
        {
            ParseState state = new ParseState();
            ExtractedClassName result = new ExtractedClassName();

            foreach (Token t in tokens)
            {
                // Search first for keywords that we care about.
                if (t is KeywordToken)
                {
                    state.Reset();

                    if (t.EqualsIgnoreCase("namespace"))
                    {
                        state.ResolvingNamespace = true;
                        if (state.InsideConditionalDirective)
                        {
                            result.IsInsideConditionalBlock = true;
                        }
                    }
                    else if (t.EqualsIgnoreCase("class"))
                    {
                        state.ResolvingClass = true;
                        if (state.InsideConditionalDirective)
                        {
                            result.IsInsideConditionalBlock = true;
                        }
                    }
                    else if (t.EqualsIgnoreCase("end"))
                    {
                        state.PopNamespacePart();
                    }
                }
                else if (t is VisualBasicTokenizer.LineTerminatorToken)
                {
                    if (state.ResolvingNamespace)
                    {
                        state.PushNamespacePart(state.Namespace);
                    }
                    state.Reset();
                }
                else if (t is VisualBasicTokenizer.SeparatorToken)
                {
                    if (state.ResolvingNamespace)
                    {
                        if (t.InnerText == ".")
                        {
                            state.Namespace += ".";
                        }
                    }
                }
                else if (t is IdentifierToken)
                {
                    // If we're resolving a namespace, then this is part of the namespace.
                    if (state.ResolvingNamespace)
                    {
                        state.Namespace += t.InnerText;
                    }
                    // If we're resolving a class, then we're done. We found the class name.
                    else if (state.ResolvingClass)
                    {
                        // We're done.
                        result.Name = state.ComposeQualifiedClassName(t.InnerText);
                        return result;
                    }
                }
                else if (t is OpenConditionalDirectiveToken)
                {
                    state.OpenConditionalDirective();
                }
                else if (t is CloseConditionalDirectiveToken)
                {
                    state.CloseConditionalDirective();
                }
            }

            return result;
        }