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); }
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; } } }
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(); } } } }
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 }; } } } }