public void Dispose()
 {
     TokenStreamReader.Dispose();
     TokenStreamReader = null;
     LanguageTokens    = null;
     CurrentTokenBuffer?.Clear();
 }
예제 #2
0
        /// <summary>
        /// Reads and reflects the given VB Classic text file into a usable form.
        /// </summary>
        /// <param name="partitionedFile">An instance of <see cref="VbPartitionedFile"/> representing the VB Classic module to reflect.</param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"><paramref name="partitionedFile"/> was null.</exception>
        /// <exception cref="InvalidOperationException">There was no analyzer considered fitting for the underlying file.</exception>
        public static IVbModule GetReflectedModule(VbPartitionedFile partitionedFile)
        {
            if (partitionedFile == null)
            {
                throw new ArgumentNullException("partitionedFile");
            }

            if (Tokenizer == null)
            {
                throw new InvalidOperationException("No tokenizer defined for analyzing the file!");
            }

            IReadOnlyList <IToken> tokens = Tokenizer.GetTokens(partitionedFile.GetMergedContent());

            TokenStreamReader reader = new TokenStreamReader(tokens);

            IAnalyzer analyzer = null;

            if (!AnalyzerFactory.TryGetAnalyzerForFile(reader, out analyzer))
            {
                // TODO: Dedicated exception for this.
                throw new InvalidOperationException("Could not analyze the given file!");
            }

            reader.Rewind();

            return(analyzer.Analyze(reader));
        }
예제 #3
0
        bool IAnalyzer.CanAnalyze(TokenStreamReader reader)
        {
            /* This is very simple here. Modules only got this only line at the beginning
             *  and right after that, user code begins.
             */

            return(reader.Peek().Content.StartsWith(AnalyzerConstants.Attribute_TokenName, StringComparison.Ordinal));
        }
        public bool MoveNext()
        {
            InitlializeTokenBufferIfEmpty();
            if (CurrentSymbol == LexiconSymbol.SkipMaterial ||
                CurrentSymbol == LexiconSymbol.NA)
            {
                CurrentTokenBuffer.Clear();
            }

            while (!TokenStreamReader.EndOfStream)
            {
                var rawCharacter       = TokenStreamReader.Read();
                var convertedCharacter = Convert.ToChar(rawCharacter);
                var singleToken        = LanguageTokens.FindLexiconSymbol(convertedCharacter);

                CurrentTokenBuffer.Add(convertedCharacter);

                var validTokenBuffer = LanguageTokens.FindLexiconSymbol(CurrentTokenBuffer);

                var tempValidTokenBuffer = validTokenBuffer;
                var rulesToApply         = validTokenBuffer;
                rulesToApply = Rules.Select(appliedRule => rulesToApply = appliedRule(singleToken, rulesToApply, CurrentSymbol))
                               .Where(ls => ls != LexiconSymbol.NA)
                               .LastOrDefault();
                if (rulesToApply != tempValidTokenBuffer)
                {
                    validTokenBuffer = rulesToApply;
                }



                if (CurrentTokenBuffer.Count > 0 && validTokenBuffer == LexiconSymbol.Assign)
                {
                    CurrentTokenBuffer.RemoveAt(CurrentTokenBuffer.Count - 1);
                }



                CurrentSymbol = validTokenBuffer;

                var mayStopSymbol = LanguageTokens.FindLexiconSymbol(new List <char>()
                {
                    convertedCharacter
                });
                if (mayStopSymbol == LexiconSymbol.SkipMaterial)
                {
                    CurrentSymbol = mayStopSymbol;
                }

                if (CurrentSymbol != LexiconSymbol.NA)
                {
                    return(true);
                }
            }
            return(false);
        }
예제 #5
0
        bool IAnalyzer.CanAnalyze(TokenStreamReader reader)
        {
            IToken[] firstLine = reader.GetUntilEOL().ToArray();
            if (firstLine.Length == 2)
            {
                return(firstLine[0].EqualsStringInvariant("VERSION") &&
                       firstLine[1].EqualsStringInvariant("5.00"));
            }

            return(false);
        }
예제 #6
0
        internal static bool TryGetAnalyzerForFile(TokenStreamReader reader, out IAnalyzer analyzer)
        {
            var best = _analyzers.FirstOrDefault(_ => _.CanAnalyze(reader.Rewind()));

            if (best != null)
            {
                analyzer = best;
                return(true);
            }

            analyzer = null;
            return(false);
        }
예제 #7
0
        internal static IEnumerable <IVbAttribute> GetAttributes(TokenStreamReader reader)
        {
            bool didEncounterAttributes = false;

            while (!reader.IsEOF)
            {
                IToken token = reader.Read();

                switch (token.Type)
                {
                case TokenType.Word:
                {
                    if (token.EqualsStringInvariant(AnalyzerConstants.Attribute_TokenName))
                    {
                        didEncounterAttributes = true;

                        List <IToken> lineTokens = new List <IToken>();
                        lineTokens.Add(token);
                        lineTokens.AddRange(reader.GetUntilEOL());

                        if (lineTokens.Count == 4)
                        {
                            yield return(new VbAttribute()
                                {
                                    Location = lineTokens[0].Location,
                                    Name = lineTokens[1].Content,
                                    Value = lineTokens[3].Content.Replace("\"", ""),
                                });
                        }
                    }
                    else
                    {
                        /* If we had attributes previously, it is now valid to break execution here.
                         * VB Classic files always end their "preamble" or "header" with an "Attribute" block.
                         * After that block, the user code is starting.
                         */
                        if (didEncounterAttributes)
                        {
                            yield break;
                        }
                    }
                }
                break;

                default:
                case TokenType.EOL:
                case TokenType.EOF:
                    continue;
                }
            }
        }
예제 #8
0
        internal static IEnumerable <IVbField> GetFields(TokenStreamReader reader)
        {
            /* TODO: Field declarations á la "Var1, Var2, Var3 As Integer" are not supported right now.
             */

            while (!reader.IsEOF)
            {
                List <IToken> tokens = reader.GetUntilEOL().ToList();
                if (tokens.Count < 2)
                {
                    continue;
                }

                IVbField field = null;

                if (TryParseFieldDeclaration(tokens, out field))
                {
                    yield return(field);
                }
            }
        }
예제 #9
0
        IVbModule IAnalyzer.Analyze(TokenStreamReader reader)
        {
            var attributes = AnalyzerTools.GetAttributes(reader).ToDictionary(_ => _.Name);

            GlobalModule mod = new GlobalModule();

            mod.Visibility = MemberVisibility.Default;
            mod.Name       = attributes[AnalyzerConstants.AttributeName_Name].Value;

            foreach (IVbAttribute attribute in attributes.Values)
            {
                mod.AddMember(attribute);
            }
            foreach (IVbField field in AnalyzerTools.GetFields(reader.Rewind()))
            {
                mod.AddMember(field);
            }
            foreach (IVbMethod method in AnalyzerTools.GetMethods(reader.Rewind()))
            {
                mod.AddMember(method);
            }

            return(mod);
        }
예제 #10
0
        internal static IEnumerable <IVbMethod> GetMethods(TokenStreamReader reader)
        {
            bool         isInMethod = false;
            VbMethodType methodType = VbMethodType.Sub;

            // Remembers the complete signature for easier construction later.
            List <IToken> signatureTokens = new List <IToken>();

            IToken   previous = null;
            VbMethod method   = null;

            while (!reader.IsEOF)
            {
                if (!reader.IsBOF)
                {
                    previous = reader.GetPrevious();
                }

                IToken token = reader.Read();

                if (token.Type == TokenType.Word)
                {
                    if (token.EqualsStringInvariant(AnalyzerConstants.Method_Sub) ||
                        token.EqualsStringInvariant(AnalyzerConstants.Method_Function) ||
                        token.EqualsStringInvariant(AnalyzerConstants.Method_Property))
                    {
                        if (isInMethod)
                        {
                            if (previous.EqualsStringInvariant(AnalyzerConstants.End))
                            {
                                method.EndStatementLocation = token.Location;
                                isInMethod = false;
                            }

                            continue;
                        }

                        isInMethod = true;

                        methodType = (VbMethodType)Enum.Parse(typeof(VbMethodType), token.Content, true);

                        method = new VbMethod();

                        // Properties have Let/Get/Set next... eat that and store it.
                        if (methodType == VbMethodType.Property)
                        {
                            IToken propertyAcc = reader.Read();

                            method = new VbProperty()
                            {
                                Accessor = (VbPropertyAccessor)Enum.Parse(typeof(VbPropertyAccessor), propertyAcc.Content, true),
                            };
                        }

                        method.Visibility = MemberVisibility.Default;
                        method.Location   = token.Location;
                        method.MethodKind = methodType;

                        /* Check if there was a visibility-modifier preceeding this method. If so, add it to our signature and correct source location to point to that token.
                         */
                        MemberVisibility visibility = MemberVisibility.Default;
                        if (TryGetMemberVisibility(previous, out visibility))
                        {
                            // Set method location to the previous token (start of line).
                            method.Location = previous.Location;
                        }

                        method.Visibility = visibility;
                        method.Name       = reader.GetUntil(false, null, TokenType.Symbol).GetString();

                        signatureTokens.AddRange(reader.GetUntilEOL());

                        bool success = false;
                        try
                        {
                            ParseSignatureIntoMethod(method, signatureTokens);
                            success = true;
                        }
                        catch (Exception)
                        {
                            // FIXME: The parser may peek() too far beyond EOF. Need to handle that!
                        }

                        if (success)
                        {
                            yield return(method);
                        }

                        signatureTokens.Clear();
                    }
                }
            }
        }
예제 #11
0
 private static string ReadUntilEOLIntoString(TokenStreamReader tokenReader, string[] tokensToIgnore)
 {
     return(string.Concat(tokenReader.GetUntilEOL(true, tokensToIgnore).Select(_ => _.Content)));
 }
예제 #12
0
        private static void ParseSignatureIntoMethod(VbMethod method, IReadOnlyList <IToken> signatureTokens)
        {
            TokenStreamReader tokenReader = new TokenStreamReader(signatureTokens);

            if (tokenReader.Peek().Type == TokenType.Symbol)
            {
                tokenReader.Read();
            }

            VbParameter parameter = new VbParameter();

            while (!tokenReader.IsEOF)
            {
                // If it's already the end of the signature, leave the loop.
                if (tokenReader.Peek().EqualsStringInvariant(")"))
                {
                    tokenReader.Read();
                    break;
                }

                IToken token = tokenReader.Read();

                if (IsParameterOptional(token))
                {
                    parameter.IsOptional = true;
                    continue;
                }

                VbParameterAccess access = VbParameterAccess.Default;
                if (IsParamaterAccessToken(token, out access))
                {
                    parameter.Access = access;
                    continue;
                }

                /* Assume that if the next parameter is "As", then this is a parameter name.
                 * Also watch out for implicit parameters, which are parameters that don't declare a type (variant).
                 */
                IToken peek = tokenReader.Peek();
                if (peek == null)
                {
                    break;
                }

                if (peek.EqualsStringInvariant("As") ||
                    peek.Type == TokenType.Symbol)
                {
                    parameter.Name     = token.Content;
                    parameter.Location = token.Location;

                    if (peek.Type == TokenType.Symbol)
                    {
                        parameter.Type = VbTypes.Variant;

                        // Eat token.
                        tokenReader.Read();
                    }
                    else
                    {
                        // Eat token.
                        tokenReader.Read();

                        parameter.Type = new VbType()
                        {
                            TypeName = ReadUntilEOLIntoString(tokenReader, Delimiters)
                        };
                    }

                    /* Look ahead for an optional value declaration if this parameter is optional.
                     */
                    if (parameter.IsOptional)
                    {
                        if (tokenReader.GetPrevious().Content == "=")
                        {
                            parameter.OptionalDefaultValue = ReadUntilEOLIntoString(tokenReader, Delimiters);
                        }
                    }

                    /* Add parameter and reset instance.
                     */
                    method.AddParameter(parameter);

                    parameter = new VbParameter();

                    continue;
                }
            }

            /* Specify "void" return "type" in advance; may be overridden.
             */
            method.ReturnType = VbTypes.Void;

            bool canHaveReturnType = false;

            if (method.MethodKind == VbMethodType.Function)
            {
                canHaveReturnType = true;
            }
            else if (method.MethodKind == VbMethodType.Property)
            {
                IVbProperty property = (IVbProperty)method;
                if (property.Accessor == VbPropertyAccessor.Get)
                {
                    canHaveReturnType = true;
                }
            }

            /* Look for a return type.
             */
            if (canHaveReturnType)
            {
                method.ReturnType = VbTypes.Variant;

                if (!tokenReader.IsEOF)
                {
                    var returnTokens = tokenReader.GetUntilEOL().ToArray();
                    if (returnTokens[0].EqualsStringInvariant("As"))
                    {
                        string typeName = string.Concat(returnTokens.Skip(1).Select(_ => _.Content));
                        method.ReturnType = new VbType()
                        {
                            TypeName = typeName
                        };
                    }
                }
            }
        }