/* Function: GetAccessLevel * Returns the <Languages.AccessLevel> if it can be determined. This should only be used with basic language support * as it's not as reliable as the results from the dedicated language parsers. */ virtual public Languages.AccessLevel GetAccessLevel() { Languages.AccessLevel accessLevel = Languages.AccessLevel.Unknown; TokenIterator iterator = start; while (iterator < end) { if (iterator.FundamentalType == FundamentalType.Text && iterator.PrototypeParsingType == PrototypeParsingType.TypeModifier && IsStandaloneWord(iterator)) { if (iterator.MatchesToken("public")) { accessLevel = Languages.AccessLevel.Public; } else if (iterator.MatchesToken("private")) { if (accessLevel == Languages.AccessLevel.Protected) { accessLevel = Languages.AccessLevel.PrivateProtected; } else { accessLevel = Languages.AccessLevel.Private; } } else if (iterator.MatchesToken("protected")) { if (accessLevel == Languages.AccessLevel.Internal) { accessLevel = Languages.AccessLevel.ProtectedInternal; } else if (accessLevel == Languages.AccessLevel.Private) { accessLevel = Languages.AccessLevel.PrivateProtected; } else { accessLevel = Languages.AccessLevel.Protected; } } else if (iterator.MatchesToken("internal")) { if (accessLevel == Languages.AccessLevel.Protected) { accessLevel = Languages.AccessLevel.ProtectedInternal; } else { accessLevel = Languages.AccessLevel.Internal; } } } iterator.Next(); } return(accessLevel); }
/* Function: TryToSkipClassParent * * Tries to move the iterator past a single class parent declaration. * * Supported Modes: * * - <ParseMode.IterateOnly> * - <ParseMode.ParseClassPrototype> * - Everything else is treated as <ParseMode.IterateOnly>. */ protected bool TryToSkipClassParent(ref TokenIterator iterator, ParseMode mode = ParseMode.IterateOnly) { TokenIterator lookahead = iterator; if (lookahead.MatchesToken("metaclass")) { lookahead.Next(); TryToSkipWhitespace(ref lookahead); if (lookahead.Character == '=') { if (mode == ParseMode.ParseClassPrototype) { iterator.ClassPrototypeParsingType = ClassPrototypeParsingType.Modifier; } lookahead.Next(); TryToSkipWhitespace(ref lookahead); } else { // Nevermind, reset lookahead = iterator; } } TokenIterator startOfIdentifier = lookahead; if (TryToSkipIdentifier(ref lookahead) == false) { ResetTokensBetween(iterator, lookahead, mode); return(false); } if (mode == ParseMode.ParseClassPrototype) { lookahead.Tokenizer.SetClassPrototypeParsingTypeBetween(startOfIdentifier, lookahead, ClassPrototypeParsingType.Name); } iterator = lookahead; return(true); }
/* Function: ParsePrototype * Converts a raw text prototype into a <ParsedPrototype>. */ override public ParsedPrototype ParsePrototype(string stringPrototype, int commentTypeID) { Tokenizer tokenizedPrototype = new Tokenizer(stringPrototype, tabWidth: EngineInstance.Config.TabWidth); ParsedPrototype parsedPrototype; // Mark any leading annotations. TokenIterator iterator = tokenizedPrototype.FirstToken; TryToSkipWhitespace(ref iterator, true, ParseMode.ParsePrototype); if (TryToSkipAnnotations(ref iterator, ParseMode.ParsePrototype)) { TryToSkipWhitespace(ref iterator, true, ParseMode.ParsePrototype); } // Search for the first opening bracket or brace. char closingBracket = '\0'; while (iterator.IsInBounds) { if (iterator.Character == '(') { closingBracket = ')'; break; } else if (iterator.Character == '[') { // Only treat brackets as parameters if it's following "this", meaning it's an iterator. Ignore all others so we // don't get tripped up on metadata or array brackets on return values. TokenIterator lookbehind = iterator; lookbehind.Previous(); lookbehind.PreviousPastWhitespace(PreviousPastWhitespaceMode.Iterator); if (lookbehind.MatchesToken("this")) { closingBracket = ']'; break; } else { iterator.Next(); } } else if (iterator.Character == '{') { closingBracket = '}'; break; } else if (TryToSkipComment(ref iterator) || TryToSkipString(ref iterator)) { } else { iterator.Next(); } } // If we found brackets, it's either a function prototype or a class prototype that includes members. // Mark the delimiters. if (closingBracket != '\0') { iterator.PrototypeParsingType = PrototypeParsingType.StartOfParams; iterator.Next(); while (iterator.IsInBounds) { if (iterator.Character == ',') { iterator.PrototypeParsingType = PrototypeParsingType.ParamSeparator; iterator.Next(); } else if (iterator.Character == closingBracket) { iterator.PrototypeParsingType = PrototypeParsingType.EndOfParams; break; } // Unlike prototype detection, here we treat < as an opening bracket. Since we're already in the parameter list // we shouldn't run into it as part of an operator overload, and we need it to not treat the comma in "template<a,b>" // as a parameter divider. else if (TryToSkipComment(ref iterator) || TryToSkipString(ref iterator) || TryToSkipBlock(ref iterator, true)) { } else { iterator.Next(); } } // We have enough tokens marked to create the parsed prototype. This will also let us iterate through the parameters // easily. parsedPrototype = new ParsedPrototype(tokenizedPrototype); // Set the main section to the last one, since any annotations present will each be in their own section. Some can have // parameter lists and we don't want those confused for the actual parameter list. parsedPrototype.MainSectionIndex = parsedPrototype.Sections.Count - 1; // Mark the part before the parameters, which includes the name and return value. TokenIterator start, end; parsedPrototype.GetBeforeParameters(out start, out end); // Exclude the opening bracket end.Previous(); end.PreviousPastWhitespace(PreviousPastWhitespaceMode.EndingBounds, start); if (start < end) { MarkCParameter(start, end); } // If there are any parameters, mark the tokens in them. if (parsedPrototype.NumberOfParameters > 0) { for (int i = 0; i < parsedPrototype.NumberOfParameters; i++) { parsedPrototype.GetParameter(i, out start, out end); MarkCParameter(start, end); } } } // If there's no brackets, it's a variable, property, or class. else { parsedPrototype = new ParsedPrototype(tokenizedPrototype); TokenIterator start = tokenizedPrototype.FirstToken; TokenIterator end = tokenizedPrototype.LastToken; MarkCParameter(start, end); } return(parsedPrototype); }
// Group: Parsing Functions // __________________________________________________________________________ /* Function: TryToSkipClassDeclarationLine * * If the iterator is on a class's declaration line, moves it past it and returns true. It does not handle the class body. * * Supported Modes: * * - <ParseMode.IterateOnly> * - <ParseMode.ParseClassPrototype> * - Everything else is treated as <ParseMode.IterateOnly>. */ protected bool TryToSkipClassDeclarationLine(ref TokenIterator iterator, ParseMode mode = ParseMode.IterateOnly) { TokenIterator lookahead = iterator; // Decorators if (TryToSkipDecorators(ref lookahead, mode)) { TryToSkipWhitespace(ref lookahead); } // Keyword if (lookahead.MatchesToken("class") == false) { ResetTokensBetween(iterator, lookahead, mode); return(false); } if (mode == ParseMode.ParseClassPrototype) { lookahead.ClassPrototypeParsingType = ClassPrototypeParsingType.Keyword; } lookahead.Next(); TryToSkipWhitespace(ref lookahead); // Name TokenIterator startOfIdentifier = lookahead; if (TryToSkipIdentifier(ref lookahead) == false) { ResetTokensBetween(iterator, lookahead, mode); return(false); } if (mode == ParseMode.ParseClassPrototype) { iterator.Tokenizer.SetClassPrototypeParsingTypeBetween(startOfIdentifier, lookahead, ClassPrototypeParsingType.Name); } TryToSkipWhitespace(ref lookahead); // Base classes if (lookahead.Character == '(') { if (mode == ParseMode.ParseClassPrototype) { lookahead.ClassPrototypeParsingType = ClassPrototypeParsingType.StartOfParents; } lookahead.Next(); TryToSkipWhitespace(ref lookahead); for (;;) { if (lookahead.Character == ')') { if (mode == ParseMode.ParseClassPrototype) { lookahead.ClassPrototypeParsingType = ClassPrototypeParsingType.EndOfParents; } break; } if (TryToSkipClassParent(ref lookahead, mode) == false) { ResetTokensBetween(iterator, lookahead, mode); return(false); } TryToSkipWhitespace(ref lookahead); if (lookahead.Character == ',') { if (mode == ParseMode.ParseClassPrototype) { lookahead.ClassPrototypeParsingType = ClassPrototypeParsingType.ParentSeparator; } lookahead.Next(); TryToSkipWhitespace(ref lookahead); } } } iterator = lookahead; return(true); }
// Group: Parsing Functions // __________________________________________________________________________ /* Function: TryToSkipClassDeclarationLine * * If the iterator is on a class's declaration line, moves it past it and returns true. It does not handle the class body. * * Supported Modes: * * - <ParseMode.IterateOnly> * - <ParseMode.ParseClassPrototype> * - Everything else is treated as <ParseMode.IterateOnly>. */ protected bool TryToSkipClassDeclarationLine(ref TokenIterator iterator, ParseMode mode = ParseMode.IterateOnly) { TokenIterator lookahead = iterator; // Keyword if (lookahead.MatchesToken("class") == false) { return(false); } if (mode == ParseMode.ParseClassPrototype) { lookahead.ClassPrototypeParsingType = ClassPrototypeParsingType.Keyword; } lookahead.Next(); TryToSkipWhitespace(ref lookahead); // Name TokenIterator startOfIdentifier = lookahead; if (TryToSkipUnqualifiedIdentifier(ref lookahead) == false) { ResetTokensBetween(iterator, lookahead, mode); return(false); } if (mode == ParseMode.ParseClassPrototype) { startOfIdentifier.SetClassPrototypeParsingTypeBetween(lookahead, ClassPrototypeParsingType.Name); } TryToSkipWhitespace(ref lookahead); // Base class if (lookahead.Character == '<') { if (mode == ParseMode.ParseClassPrototype) { lookahead.ClassPrototypeParsingType = ClassPrototypeParsingType.StartOfParents; } lookahead.Next(); TryToSkipWhitespace(ref lookahead); TokenIterator startOfParent = lookahead; if (TryToSkipUnqualifiedIdentifier(ref lookahead) == false) { ResetTokensBetween(iterator, lookahead, mode); return(false); } if (mode == ParseMode.ParseClassPrototype) { startOfParent.SetClassPrototypeParsingTypeBetween(lookahead, ClassPrototypeParsingType.Name); } } iterator = lookahead; return(true); }