/* Function: TryToGetFirstBlockLine * If the iterator is on a line that starts with one of the <BlockTags>, extracts the components and returns true. * Use <GetBlockTag()> to get the complete block since it may span multiple lines. */ protected bool TryToGetFirstBlockLine(LineIterator lineIterator, out string tag, out TokenIterator startOfContent) { tag = null; startOfContent = default(TokenIterator); TokenIterator tokenIterator = lineIterator.FirstToken(LineBoundsMode.CommentContent); if (tokenIterator.Character != '@') { return(false); } tokenIterator.Next(); if (tokenIterator.FundamentalType != FundamentalType.Text) { return(false); } string possibleTag = tokenIterator.String; if (BlockTags.Contains(possibleTag) == false) { return(false); } tokenIterator.Next(); tokenIterator.NextPastWhitespace(); tag = possibleTag; startOfContent = tokenIterator; return(true); }
/* Function: GetColumn * Returns the bounds of a parameter's column and what type it is, which depends on <ColumnOrder>. You *must* call * <CalculateColumns()> beforehand. Returns false if the column index is out of bounds or the contents are empty for * that particular slot. */ public bool GetColumn(int columnIndex, out TokenIterator start, out TokenIterator end, out ColumnType type) { if (columnIndex >= columnIndexes.Length) { start = parsedPrototype.Tokenizer.LastToken; end = parsedPrototype.Tokenizer.LastToken; type = ColumnType.Name; return(false); } int startIndex = columnIndexes[columnIndex]; int endIndex = (columnIndex + 1 >= columnIndexes.Length ? endOfColumnsIndex : columnIndexes[columnIndex + 1]); start = parsedPrototype.Tokenizer.FirstToken; if (startIndex > 0) { start.Next(startIndex); } end = start; if (endIndex > startIndex) { end.Next(endIndex - startIndex); } type = ColumnOrder[columnIndex]; end.PreviousPastWhitespace(PreviousPastWhitespaceMode.EndingBounds, start); start.NextPastWhitespace(end); return(end > start); }
/* Function: TryToSkipSubstitutionDefinition * * If the iterator is on a valid substitution definition, advances it past it, determines its properties, and returns true. Otherwise the * iterator will be left alone and it will return false. * * identifier - "$identifier" in "$identifier = value;" * value - "value" in "$identifier = value;" * declaration - "$identifier = value;" in "$identifier = value;" */ protected bool TryToSkipSubstitutionDefinition(ref TokenIterator iterator, out string identifier, out string value, out string declaration) { identifier = null; value = null; declaration = null; TokenIterator lookahead = iterator; if (TryToSkipSubstitutionIdentifier(ref lookahead, out identifier) == false) { return(false); } lookahead.NextPastWhitespace(); if (lookahead.Character != ':' && lookahead.Character != '=') { identifier = null; return(false); } lookahead.Next(); lookahead.NextPastWhitespace(); TokenIterator startOfValue = lookahead; while (lookahead.IsInBounds && lookahead.Character != ';' && lookahead.FundamentalType != FundamentalType.LineBreak) { GenericSkip(ref lookahead); } value = startOfValue.TextBetween(lookahead); if (lookahead.Character == ';') { lookahead.Next(); } declaration = iterator.TextBetween(lookahead); iterator = lookahead; return(true); }
/* Function: CalculateColumns * Fills in <columnIndexes> for the passed parameter. If the parameter doesn't exist it will return false. */ protected bool CalculateColumns(int parameterIndex) { TokenIterator startParam, endParam; if (parsedPrototype.GetParameter(parameterIndex, out startParam, out endParam) == false) { return(false); } if (columnIndexes == null) { columnIndexes = new int[NumberOfColumns]; } TokenIterator iterator = startParam; iterator.NextPastWhitespace(endParam); PrototypeParsingType type = iterator.PrototypeParsingType; if (parsedPrototype.Style == ParsedPrototype.ParameterStyle.C) { // ModifierQualifier int currentColumn = 0; columnIndexes[currentColumn] = iterator.TokenIndex; // Null covers whitespace and any random symbols we encountered that went unmarked. while (iterator < endParam && (type == PrototypeParsingType.TypeModifier || type == PrototypeParsingType.TypeQualifier || type == PrototypeParsingType.Null)) { iterator.Next(); type = iterator.PrototypeParsingType; } // Type currentColumn++; columnIndexes[currentColumn] = iterator.TokenIndex; int typeNesting = 0; while (iterator < endParam && (type == PrototypeParsingType.Type || type == PrototypeParsingType.TypeSuffix || type == PrototypeParsingType.OpeningTypeSuffix || type == PrototypeParsingType.ClosingTypeSuffix || type == PrototypeParsingType.Null || typeNesting > 0)) { if (type == PrototypeParsingType.OpeningTypeSuffix) { typeNesting++; } else if (type == PrototypeParsingType.ClosingTypeSuffix) { typeNesting--; } iterator.Next(); type = iterator.PrototypeParsingType; } // NamePrefix currentColumn++; columnIndexes[currentColumn] = iterator.TokenIndex; while (iterator < endParam && type == PrototypeParsingType.NamePrefix_PartOfType) { iterator.Next(); type = iterator.PrototypeParsingType; } // Name currentColumn++; columnIndexes[currentColumn] = iterator.TokenIndex; // Include the parameter separator because there may not be a default value while (iterator < endParam && (type == PrototypeParsingType.Name || type == PrototypeParsingType.NameSuffix_PartOfType || type == PrototypeParsingType.ParamSeparator || type == PrototypeParsingType.Null)) { iterator.Next(); type = iterator.PrototypeParsingType; } // DefaultValueSeparator currentColumn++; columnIndexes[currentColumn] = iterator.TokenIndex; while (iterator < endParam && type == PrototypeParsingType.DefaultValueSeparator) { iterator.Next(); type = iterator.PrototypeParsingType; } // DefaultValue currentColumn++; columnIndexes[currentColumn] = iterator.TokenIndex; } else if (parsedPrototype.Style == ParsedPrototype.ParameterStyle.Pascal) { // NameModifier int currentColumn = 0; columnIndexes[currentColumn] = iterator.TokenIndex; // Null covers whitespace and any random symbols we encountered that went unmarked. while (iterator < endParam && (type == PrototypeParsingType.NameModifier_PartOfType || type == PrototypeParsingType.Null)) { iterator.Next(); type = iterator.PrototypeParsingType; } // Name currentColumn++; columnIndexes[currentColumn] = iterator.TokenIndex; // Null covers whitespace and any random symbols we encountered that went unmarked. // Include the parameter separator because there may not be a type while (iterator < endParam && (type == PrototypeParsingType.Name || type == PrototypeParsingType.NamePrefix_PartOfType || type == PrototypeParsingType.NameSuffix_PartOfType || type == PrototypeParsingType.ParamSeparator || type == PrototypeParsingType.Null)) { iterator.Next(); type = iterator.PrototypeParsingType; } // TypeNameSeparator currentColumn++; columnIndexes[currentColumn] = iterator.TokenIndex; while (iterator < endParam && type == PrototypeParsingType.NameTypeSeparator) { iterator.Next(); type = iterator.PrototypeParsingType; } // Type currentColumn++; columnIndexes[currentColumn] = iterator.TokenIndex; int typeNesting = 0; // Include the parameter separator because there may not be a default value while (iterator < endParam && (type == PrototypeParsingType.TypeModifier || type == PrototypeParsingType.TypeQualifier || type == PrototypeParsingType.Type || type == PrototypeParsingType.TypeSuffix || type == PrototypeParsingType.OpeningTypeSuffix || type == PrototypeParsingType.ClosingTypeSuffix || type == PrototypeParsingType.ParamSeparator || type == PrototypeParsingType.Null || typeNesting > 0)) { if (type == PrototypeParsingType.OpeningTypeSuffix) { typeNesting++; } else if (type == PrototypeParsingType.ClosingTypeSuffix) { typeNesting--; } iterator.Next(); type = iterator.PrototypeParsingType; } // DefaultValueSeparator currentColumn++; columnIndexes[currentColumn] = iterator.TokenIndex; while (iterator < endParam && type == PrototypeParsingType.DefaultValueSeparator) { iterator.Next(); type = iterator.PrototypeParsingType; } // DefaultValue currentColumn++; columnIndexes[currentColumn] = iterator.TokenIndex; } // End of parameter endOfColumnsIndex = endParam.TokenIndex; return(true); }
/* Function: MarkAnnotationParameter * * Applies types to an annotation parameter, such as ""String"" in "@Copynight("String")" or "id = 12" in * "@RequestForEnhancement(id = 12, engineer = "String")". * * Supported Modes: * * - <ParseMode.ParsePrototype> * - The contents will be marked with parameter tokens. * - Everything else has no effect. */ protected void MarkAnnotationParameter(TokenIterator start, TokenIterator end, ParseMode mode = ParseMode.IterateOnly) { if (mode != ParseMode.ParsePrototype) { return; } start.NextPastWhitespace(end); end.PreviousPastWhitespace(PreviousPastWhitespaceMode.EndingBounds, start); if (start >= end) { return; } // Find and mark the equals sign, if there is one TokenIterator equals = start; while (equals < end) { if (equals.Character == '=') { equals.PrototypeParsingType = PrototypeParsingType.PropertyValueSeparator; break; } else if (TryToSkipComment(ref equals) || TryToSkipString(ref equals) || TryToSkipBlock(ref equals, true)) { } else { equals.Next(); } } // The equals sign will be at or past the end if it doesn't exist. if (equals >= end) { start.SetPrototypeParsingTypeBetween(end, PrototypeParsingType.PropertyValue); } else { TokenIterator iterator = equals; iterator.PreviousPastWhitespace(PreviousPastWhitespaceMode.EndingBounds, start); if (start < iterator) { start.SetPrototypeParsingTypeBetween(iterator, PrototypeParsingType.Name); } iterator = equals; iterator.Next(); iterator.NextPastWhitespace(end); if (iterator < end) { iterator.SetPrototypeParsingTypeBetween(end, PrototypeParsingType.PropertyValue); } } }
/* Function: CalculateSections */ protected void CalculateSections() { sections = new List <Section>(); Section section = null; TokenIterator iterator = tokenizer.FirstToken; iterator.NextPastWhitespace(); // Pre-Prototype Lines while (iterator.IsInBounds && iterator.ClassPrototypeParsingType == ClassPrototypeParsingType.StartOfPrePrototypeLine) { section = new Section(); section.Type = SectionType.PrePrototypeLine; section.StartIndex = iterator.TokenIndex; do { iterator.Next(); }while (iterator.IsInBounds && iterator.ClassPrototypeParsingType == ClassPrototypeParsingType.PrePrototypeLine); section.EndIndex = iterator.TokenIndex; sections.Add(section); iterator.NextPastWhitespace(); } // Before Parents TokenIterator startOfSection = iterator; section = new Section(); section.Type = SectionType.BeforeParents; section.StartIndex = startOfSection.TokenIndex; while (iterator.IsInBounds && iterator.ClassPrototypeParsingType != ClassPrototypeParsingType.StartOfParents && iterator.ClassPrototypeParsingType != ClassPrototypeParsingType.StartOfPostPrototypeLine && iterator.ClassPrototypeParsingType != ClassPrototypeParsingType.StartOfBody) { iterator.Next(); } TokenIterator lookbehind = iterator; lookbehind.PreviousPastWhitespace(PreviousPastWhitespaceMode.EndingBounds, startOfSection); section.EndIndex = lookbehind.TokenIndex; sections.Add(section); // Parents if (iterator.ClassPrototypeParsingType == ClassPrototypeParsingType.StartOfParents) { do { iterator.Next(); }while (iterator.ClassPrototypeParsingType == ClassPrototypeParsingType.StartOfParents); iterator.NextPastWhitespace(); while (iterator.IsInBounds && iterator.ClassPrototypeParsingType != ClassPrototypeParsingType.EndOfParents && iterator.ClassPrototypeParsingType != ClassPrototypeParsingType.StartOfPostPrototypeLine && iterator.ClassPrototypeParsingType != ClassPrototypeParsingType.StartOfBody) { startOfSection = iterator; section = new Section(); section.Type = SectionType.Parent; section.StartIndex = startOfSection.TokenIndex; while (iterator.IsInBounds && iterator.ClassPrototypeParsingType != ClassPrototypeParsingType.ParentSeparator && iterator.ClassPrototypeParsingType != ClassPrototypeParsingType.EndOfParents && iterator.ClassPrototypeParsingType != ClassPrototypeParsingType.StartOfPostPrototypeLine && iterator.ClassPrototypeParsingType != ClassPrototypeParsingType.StartOfBody) { iterator.Next(); } lookbehind = iterator; lookbehind.PreviousPastWhitespace(PreviousPastWhitespaceMode.EndingBounds, startOfSection); section.EndIndex = lookbehind.TokenIndex; sections.Add(section); if (iterator.ClassPrototypeParsingType == ClassPrototypeParsingType.ParentSeparator) { do { iterator.Next(); }while (iterator.ClassPrototypeParsingType == ClassPrototypeParsingType.ParentSeparator); iterator.NextPastWhitespace(); } } } // After Parents if (iterator.IsInBounds && iterator.ClassPrototypeParsingType != ClassPrototypeParsingType.StartOfPostPrototypeLine && iterator.ClassPrototypeParsingType != ClassPrototypeParsingType.StartOfBody) { startOfSection = iterator; section = new Section(); section.Type = SectionType.AfterParents; section.StartIndex = iterator.TokenIndex; do { iterator.Next(); }while (iterator.IsInBounds && iterator.ClassPrototypeParsingType != ClassPrototypeParsingType.StartOfPostPrototypeLine && iterator.ClassPrototypeParsingType != ClassPrototypeParsingType.StartOfBody); lookbehind = iterator; lookbehind.PreviousPastWhitespace(PreviousPastWhitespaceMode.EndingBounds, startOfSection); section.EndIndex = lookbehind.TokenIndex; sections.Add(section); } // Post-Prototype Lines while (iterator.IsInBounds && iterator.ClassPrototypeParsingType == ClassPrototypeParsingType.StartOfPostPrototypeLine) { section = new Section(); section.Type = SectionType.PostPrototypeLine; section.StartIndex = iterator.TokenIndex; do { iterator.Next(); }while (iterator.IsInBounds && iterator.ClassPrototypeParsingType == ClassPrototypeParsingType.PostPrototypeLine); section.EndIndex = iterator.TokenIndex; sections.Add(section); iterator.NextPastWhitespace(); } }
// Group: Support Functions // __________________________________________________________________________ /* Function: CalculateParameterTable * Fills in <parameterTableTokenIndexes>, <parameterTableColumnUsed>, and <symbolColumnWidth> for the * passed section. */ protected void CalculateParameterTable(Prototypes.ParameterSection section) { // // Check if this is a raw section with nothing other than parameter separators, meaning no name, type, etc. tokens // TokenIterator iterator = section.Start; TokenIterator endOfSection = section.End; bool isRaw = true; while (iterator < endOfSection) { var type = iterator.PrototypeParsingType; if (type != PrototypeParsingType.Null && type != PrototypeParsingType.StartOfPrototypeSection && type != PrototypeParsingType.StartOfParams && type != PrototypeParsingType.ParamSeparator && type != PrototypeParsingType.EndOfParams && type != PrototypeParsingType.EndOfPrototypeSection) { isRaw = false; break; } iterator.Next(); } // // Now fill in parameterTableTokenIndexes // parameterTableTokenIndexes = new int[section.NumberOfParameters, NumberOfColumns + 1]; for (int parameterIndex = 0; parameterIndex < section.NumberOfParameters; parameterIndex++) { TokenIterator startOfParam, endOfParam; section.GetParameterBounds(parameterIndex, out startOfParam, out endOfParam); iterator = startOfParam; iterator.NextPastWhitespace(endOfParam); // C-Style Parameters if (section.ParameterStyle == ParsedPrototype.ParameterStyle.C) { while (iterator < endOfParam && iterator.PrototypeParsingType == PrototypeParsingType.Null && iterator.FundamentalType == FundamentalType.Whitespace) { iterator.Next(); } // ModifierQualifier int currentColumn = 0; parameterTableTokenIndexes[parameterIndex, currentColumn] = iterator.TokenIndex; TokenIterator startOfType = iterator; if (!isRaw) { while (iterator < endOfParam) { PrototypeParsingType type = iterator.PrototypeParsingType; // Null covers whitespace and any random symbols we encountered that went unmarked. if (type == PrototypeParsingType.TypeModifier || type == PrototypeParsingType.TypeQualifier || type == PrototypeParsingType.ParamModifier || type == PrototypeParsingType.Null) { iterator.Next(); } else if (type == PrototypeParsingType.OpeningTypeModifier || type == PrototypeParsingType.OpeningParamModifier) { SkipModifierBlock(ref iterator, endOfParam); } else { break; } } } // Type currentColumn++; parameterTableTokenIndexes[parameterIndex, currentColumn] = iterator.TokenIndex; // Allow this column to claim the contents of a raw prototype. They should all be null tokens. // We use the type column instead of the name column because the name column isn't fully syntax highlighted. while (iterator < endOfParam) { PrototypeParsingType type = iterator.PrototypeParsingType; // The previous loop already got any modifiers before the type, so this will only cover the type // plus any modifiers following it. if (type == PrototypeParsingType.Type || type == PrototypeParsingType.TypeModifier || type == PrototypeParsingType.ParamModifier || (isRaw && type == PrototypeParsingType.ParamSeparator) || type == PrototypeParsingType.Null) { iterator.Next(); } else if (type == PrototypeParsingType.OpeningTypeModifier || type == PrototypeParsingType.OpeningParamModifier) { SkipModifierBlock(ref iterator, endOfParam); } else { break; } } // Symbols currentColumn++; parameterTableTokenIndexes[parameterIndex, currentColumn] = iterator.TokenIndex; if (!isRaw) { // All symbols are part of the type column right now because they're marked as type or param // modifiers. Walk backwards to claim the symbols from the type column. if (iterator > startOfType) { TokenIterator lookbehind = iterator; lookbehind.Previous(); if (lookbehind.FundamentalType == FundamentalType.Symbol && lookbehind.Character != '_' && lookbehind.PrototypeParsingType != PrototypeParsingType.ClosingTypeModifier && lookbehind.PrototypeParsingType != PrototypeParsingType.ClosingParamModifier) { parameterTableTokenIndexes[parameterIndex, currentColumn] = lookbehind.TokenIndex; lookbehind.Previous(); while (lookbehind >= startOfType) { if (lookbehind.FundamentalType == FundamentalType.Symbol && lookbehind.Character != '_' && lookbehind.PrototypeParsingType != PrototypeParsingType.ClosingTypeModifier && lookbehind.PrototypeParsingType != PrototypeParsingType.ClosingParamModifier) { parameterTableTokenIndexes[parameterIndex, currentColumn] = lookbehind.TokenIndex; lookbehind.Previous(); } else { break; } } // Fix up any columns we stole from for (int i = 0; i < currentColumn; i++) { if (parameterTableTokenIndexes[parameterIndex, i] > parameterTableTokenIndexes[parameterIndex, currentColumn]) { parameterTableTokenIndexes[parameterIndex, i] = parameterTableTokenIndexes[parameterIndex, currentColumn]; } } } } } // Name currentColumn++; parameterTableTokenIndexes[parameterIndex, currentColumn] = iterator.TokenIndex; if (!isRaw) { while (iterator < endOfParam) { PrototypeParsingType type = iterator.PrototypeParsingType; // Include the parameter separator because there may not be a default value. // Include modifiers because there still may be some after the name. if (type == PrototypeParsingType.Name || type == PrototypeParsingType.TypeModifier || type == PrototypeParsingType.ParamModifier || type == PrototypeParsingType.ParamSeparator || type == PrototypeParsingType.Null) { iterator.Next(); } else if (type == PrototypeParsingType.OpeningTypeModifier || type == PrototypeParsingType.OpeningParamModifier) { SkipModifierBlock(ref iterator, endOfParam); } else { break; } } } // PropertyValueSeparator currentColumn++; parameterTableTokenIndexes[parameterIndex, currentColumn] = iterator.TokenIndex; if (!isRaw) { while (iterator < endOfParam) { PrototypeParsingType type = iterator.PrototypeParsingType; if (type == PrototypeParsingType.PropertyValueSeparator || type == PrototypeParsingType.Null) { iterator.Next(); } else { break; } } } // PropertyValue currentColumn++; parameterTableTokenIndexes[parameterIndex, currentColumn] = iterator.TokenIndex; if (!isRaw) { while (iterator < endOfParam) { PrototypeParsingType type = iterator.PrototypeParsingType; if (type == PrototypeParsingType.PropertyValue || type == PrototypeParsingType.ParamSeparator || type == PrototypeParsingType.Null) { iterator.Next(); } else { break; } } } // DefaultValueSeparator currentColumn++; parameterTableTokenIndexes[parameterIndex, currentColumn] = iterator.TokenIndex; if (!isRaw) { while (iterator < endOfParam) { PrototypeParsingType type = iterator.PrototypeParsingType; if (type == PrototypeParsingType.DefaultValueSeparator || type == PrototypeParsingType.Null) { iterator.Next(); } else { break; } } } // DefaultValue currentColumn++; parameterTableTokenIndexes[parameterIndex, currentColumn] = iterator.TokenIndex; // End of param currentColumn++; parameterTableTokenIndexes[parameterIndex, currentColumn] = endOfParam.TokenIndex; } // Pascal-Style Parameters else if (section.ParameterStyle == ParsedPrototype.ParameterStyle.Pascal) { while (iterator < endOfParam && iterator.PrototypeParsingType == PrototypeParsingType.Null && iterator.FundamentalType == FundamentalType.Whitespace) { iterator.Next(); } // ModifierQualifier int currentColumn = 0; parameterTableTokenIndexes[parameterIndex, currentColumn] = iterator.TokenIndex; if (!isRaw) { while (iterator < endOfParam) { PrototypeParsingType type = iterator.PrototypeParsingType; if (type == PrototypeParsingType.TypeModifier || type == PrototypeParsingType.ParamModifier || type == PrototypeParsingType.ParamSeparator || type == PrototypeParsingType.Null) { iterator.Next(); } else if (type == PrototypeParsingType.OpeningTypeModifier || type == PrototypeParsingType.OpeningParamModifier) { SkipModifierBlock(ref iterator, endOfParam); } else { break; } } } // Do we have a name-type separator? We may not, such as for SQL. bool hasNameTypeSeparator = false; TokenIterator lookahead = iterator; if (!isRaw) { while (lookahead < endOfParam) { if (lookahead.PrototypeParsingType == PrototypeParsingType.NameTypeSeparator) { hasNameTypeSeparator = true; break; } lookahead.Next(); } } // Name currentColumn++; parameterTableTokenIndexes[parameterIndex, currentColumn] = iterator.TokenIndex; if (!isRaw) { while (iterator < endOfParam) { PrototypeParsingType type = iterator.PrototypeParsingType; // Include the parameter separator because there may not be a type. if (type == PrototypeParsingType.Name || type == PrototypeParsingType.ParamSeparator || type == PrototypeParsingType.Null) { iterator.Next(); } // Include modifiers because there still may be some after the name, but only if there's a name-type separator. else if (hasNameTypeSeparator && (type == PrototypeParsingType.TypeModifier || type == PrototypeParsingType.ParamModifier)) { iterator.Next(); } else if (type == PrototypeParsingType.OpeningTypeModifier || type == PrototypeParsingType.OpeningParamModifier) { SkipModifierBlock(ref iterator, endOfParam); } else { break; } } } // TypeNameSeparator currentColumn++; parameterTableTokenIndexes[parameterIndex, currentColumn] = iterator.TokenIndex; if (!isRaw) { while (iterator < endOfParam) { PrototypeParsingType type = iterator.PrototypeParsingType; if (type == PrototypeParsingType.NameTypeSeparator || type == PrototypeParsingType.Null) { iterator.Next(); } else { break; } } } // Symbols currentColumn++; parameterTableTokenIndexes[parameterIndex, currentColumn] = iterator.TokenIndex; if (!isRaw) { if (iterator < endOfParam && iterator.FundamentalType == FundamentalType.Symbol && iterator.Character != '_') { while (iterator < endOfParam) { PrototypeParsingType type = iterator.PrototypeParsingType; if (( (iterator.FundamentalType == FundamentalType.Symbol && iterator.Character != '_') || (iterator.FundamentalType == FundamentalType.Whitespace) ) && (type == PrototypeParsingType.TypeModifier || type == PrototypeParsingType.ParamModifier || type == PrototypeParsingType.Null)) { iterator.Next(); } else { break; } } } } // Type currentColumn++; parameterTableTokenIndexes[parameterIndex, currentColumn] = iterator.TokenIndex; // Allow this column to claim the contents of a raw prototype. They should all be null tokens. // We use the type column instead of the name column because the name column isn't syntax highlighted. while (iterator < endOfParam) { PrototypeParsingType type = iterator.PrototypeParsingType; // Include the parameter separator because there may not be a default value. if (type == PrototypeParsingType.Type || type == PrototypeParsingType.TypeModifier || type == PrototypeParsingType.TypeQualifier || type == PrototypeParsingType.ParamModifier || type == PrototypeParsingType.ParamSeparator || type == PrototypeParsingType.Null) { iterator.Next(); } else if (type == PrototypeParsingType.OpeningTypeModifier || type == PrototypeParsingType.OpeningParamModifier) { SkipModifierBlock(ref iterator, endOfParam); } else { break; } } // PropertyValueSeparator currentColumn++; parameterTableTokenIndexes[parameterIndex, currentColumn] = iterator.TokenIndex; if (!isRaw) { while (iterator < endOfParam) { PrototypeParsingType type = iterator.PrototypeParsingType; if (type == PrototypeParsingType.PropertyValueSeparator || type == PrototypeParsingType.Null) { iterator.Next(); } else { break; } } } // PropertyValue currentColumn++; parameterTableTokenIndexes[parameterIndex, currentColumn] = iterator.TokenIndex; if (!isRaw) { while (iterator < endOfParam) { PrototypeParsingType type = iterator.PrototypeParsingType; if (type == PrototypeParsingType.PropertyValue || type == PrototypeParsingType.ParamSeparator || type == PrototypeParsingType.Null) { iterator.Next(); } else { break; } } } // DefaultValueSeparator currentColumn++; parameterTableTokenIndexes[parameterIndex, currentColumn] = iterator.TokenIndex; if (!isRaw) { while (iterator < endOfParam) { PrototypeParsingType type = iterator.PrototypeParsingType; if (type == PrototypeParsingType.DefaultValueSeparator || type == PrototypeParsingType.Null) { iterator.Next(); } else { break; } } } // DefaultValue currentColumn++; parameterTableTokenIndexes[parameterIndex, currentColumn] = iterator.TokenIndex; // End of param currentColumn++; parameterTableTokenIndexes[parameterIndex, currentColumn] = endOfParam.TokenIndex; } } // // Next fill in parameterTableColumnsUsed // // There's a very high likelihood of this array always being the same length so it's worth it to try to reuse the // memory and avoid a reallocation. if (parameterTableColumnsUsed != null && parameterTableColumnsUsed.Length == NumberOfColumns) { Array.Clear(parameterTableColumnsUsed, 0, NumberOfColumns); } else { parameterTableColumnsUsed = new bool[NumberOfColumns]; } for (int parameterIndex = 0; parameterIndex < section.NumberOfParameters; parameterIndex++) { for (int columnIndex = 0; columnIndex < NumberOfColumns; columnIndex++) { if (parameterTableTokenIndexes[parameterIndex, columnIndex] != parameterTableTokenIndexes[parameterIndex, columnIndex + 1]) { parameterTableColumnsUsed[columnIndex] = true; } } } // // Next determine the symbol column's width // symbolColumnWidth = 0; if (parameterTableColumnsUsed[SymbolsColumnIndex]) { for (int parameterIndex = 0; parameterIndex < section.NumberOfParameters; parameterIndex++) { int startTokenIndex = parameterTableTokenIndexes[parameterIndex, SymbolsColumnIndex]; int endTokenIndex = parameterTableTokenIndexes[parameterIndex, SymbolsColumnIndex + 1]; if (endTokenIndex > startTokenIndex) { TokenIterator start, end; section.GetParameterBounds(parameterIndex, out start, out end); start.Next(startTokenIndex - start.TokenIndex); end.Previous(end.TokenIndex - endTokenIndex); int paramColumnWidth = end.RawTextIndex - start.RawTextIndex; if (paramColumnWidth > symbolColumnWidth) { symbolColumnWidth = paramColumnWidth; } } } } }
/* Function: RecalculateSections * * Recalculates the <Sections> list. If you've set <MainSectionIndex> manually, it will have to be set again after calling this * function. * * Sections are delimited with <PrototypeParsingType.StartOfPrototypeSection> and <PrototypeParsingType.EndOfPrototypeSection>. * Neither of these token types are required to appear, and if they do not the entire prototype will be in one section. Also, they are * not required to appear together. Sections can be delimited by only start tokens or only end tokens, whichever is most convenient * to the language parser and won't interfere with marking other types. * * Each section containing <PrototypeParsingType.StartOfParams> will generate a <ParameterSection>. All others will generate a * regular <Section>. */ public void RecalculateSections() { if (sections == null) { sections = new List <Section>(1); } else { sections.Clear(); } TokenIterator startOfSection = tokenizer.FirstToken; TokenIterator endOfSection = startOfSection; int firstSectionWithName = -1; int firstSectionWithParams = -1; for (;;) { // Find the section bounds bool sectionIsEmpty = true; bool sectionHasName = false; bool sectionHasParams = false; while (endOfSection.IsInBounds) { // Break if we hit the beginning of the next section, but not if it's the start of the current section if (endOfSection.PrototypeParsingType == PrototypeParsingType.StartOfPrototypeSection && endOfSection > startOfSection) { break; } if (endOfSection.FundamentalType != FundamentalType.Whitespace) { sectionIsEmpty = false; } if (endOfSection.PrototypeParsingType == PrototypeParsingType.Name) { sectionHasName = true; } else if (endOfSection.PrototypeParsingType == PrototypeParsingType.StartOfParams) { sectionHasParams = true; } else if (endOfSection.PrototypeParsingType == PrototypeParsingType.EndOfPrototypeSection) { endOfSection.Next(); break; } endOfSection.Next(); } // Process the section if (!sectionIsEmpty) { endOfSection.PreviousPastWhitespace(PreviousPastWhitespaceMode.EndingBounds, startOfSection); startOfSection.NextPastWhitespace(endOfSection); if (sectionHasParams) { sections.Add(new ParameterSection(startOfSection, endOfSection, supportsImpliedTypes)); } else { sections.Add(new Section(startOfSection, endOfSection)); } if (sectionHasName && firstSectionWithName == -1) { firstSectionWithName = sections.Count - 1; } if (sectionHasParams && firstSectionWithParams == -1) { firstSectionWithParams = sections.Count - 1; } } // Continue? if (endOfSection.IsInBounds) { startOfSection = endOfSection; } else { break; } } // Sanity check. This should only happen if all the sections were whitespace, which shouldn't normally happen but I // suppose could with a manual prototype. if (sections.Count < 1) { sections.Add(new Section(tokenizer.FirstToken, tokenizer.LastToken)); } // Determine main section if (sections.Count == 1) { mainSectionIndex = 0; } else if (firstSectionWithName != -1) { mainSectionIndex = firstSectionWithName; } else if (firstSectionWithParams != -1) { mainSectionIndex = firstSectionWithParams; } else { mainSectionIndex = 0; } }
/* Function: GetSimpleText * Converts a stretch of text to NDMarkup, ignoring the formatting. Unlike <GetText()> this will not surround the output * in paragraph tags. */ protected void GetSimpleText(ref JavadocIterator iterator, StringBuilder output) { while (iterator.IsInBounds) { if (iterator.IsOn(JavadocElementType.Text)) { output.EntityEncodeAndAppend(iterator.String); iterator.Next(); } else if (iterator.IsOn(JavadocElementType.EntityChar)) { output.EntityEncodeAndAppend(iterator.EntityValue); iterator.Next(); } else if (iterator.IsOn(JavadocElementType.LineBreak)) { output.Append('\n'); iterator.Next(); } else if (iterator.IsOnJavadocTag("code") || iterator.IsOnJavadocTag("literal")) { output.EntityEncodeAndAppend(iterator.JavadocTagValue); iterator.Next(); } else if (iterator.IsOnJavadocTag("link") || iterator.IsOnJavadocTag("linkPlain")) { Tokenizer linkContent = new Tokenizer(iterator.JavadocTagValue); TokenIterator linkIterator = linkContent.FirstToken; string symbol = GetJavadocLinkSymbol(ref linkIterator); linkIterator.NextPastWhitespace(); string description = GetSimpleText(linkIterator, linkContent.LastToken); description = Normalize(description); if (description == null || description == "") { output.EntityEncodeAndAppend(symbol); } else { output.EntityEncodeAndAppend(description); } iterator.Next(); } else if (iterator.IsOnJavadocTag("value")) { string symbol = iterator.JavadocTagValue; if (symbol == null || symbol == "") { output.EntityEncodeAndAppend( Locale.Get("NaturalDocs.Engine", "Javadoc.Substitution.value") ); } else { output.EntityEncodeAndAppend( Locale.Get("NaturalDocs.Engine", "Javadoc.Substitution.value(symbol)", symbol) ); } iterator.Next(); } else { // Ignore indent. Spaces between words will be handled by line breaks. // Ignore HTML comments. // Ignore HTML tags. iterator.Next(); } } }
/* Function: GetText * * Converts a stretch of formatted text to NDMarkup. * * Modes: * * Normal - The iterator continues until it goes out of bounds. * ListItem - The iterator continues until it reaches a closing li tag. It also skips certain formatting that is not supported * in list items in NDMarkup. */ protected void GetText(ref JavadocIterator iterator, StringBuilder output, GetTextMode mode = GetTextMode.Normal) { output.Append("<p>"); TagStack tagStack = new TagStack(); tagStack.OpenTag(null, "</p>"); while (iterator.IsInBounds) { if (iterator.IsOn(JavadocElementType.Text)) { output.EntityEncodeAndAppend(iterator.String); iterator.Next(); } else if (iterator.IsOn(JavadocElementType.EntityChar)) { output.EntityEncodeAndAppend(iterator.EntityValue); iterator.Next(); } else if (iterator.IsOn(JavadocElementType.LineBreak)) { // Add a literal line break. We'll replace these with spaces or double spaces later. Right now we can't decide // which it should be because you can't run a regex directly on a StringBuilder and it would be inefficient to convert // it to a string on every line break. output.Append('\n'); iterator.Next(); } else if (iterator.IsOnHTMLTag("p")) { // Text can appear both inside and outside of <p> tags, whitespace can appear between <p> tags that can be // mistaken for content, and people can use <p> tags as standalone rather than opening tags. Rather than put in // logic to try to account for all of this we handle it in a very dirty but simple way. Every <p> tag--opening, closing, // or standalone--causes a paragraph break. Normalize() will clean it up for us afterwards. tagStack.CloseTag(1, output); // Reuse our surrounding tag output.Append("</p><p>"); iterator.Next(); } else if (iterator.IsOnHTMLTag("b") || iterator.IsOnHTMLTag("strong")) { if (iterator.HTMLTagForm == TagForm.Opening) { tagStack.OpenTag(iterator.TagType, "</b>"); output.Append("<b>"); } else if (iterator.HTMLTagForm == TagForm.Closing) { tagStack.CloseTag(iterator.TagType, output); } iterator.Next(); } else if (iterator.IsOnHTMLTag("i") || iterator.IsOnHTMLTag("em")) { if (iterator.HTMLTagForm == TagForm.Opening) { tagStack.OpenTag(iterator.TagType, "</i>"); output.Append("<i>"); } else if (iterator.HTMLTagForm == TagForm.Closing) { tagStack.CloseTag(iterator.TagType, output); } iterator.Next(); } else if (iterator.IsOnHTMLTag("u")) { if (iterator.HTMLTagForm == TagForm.Opening) { tagStack.OpenTag(iterator.TagType, "</u>"); output.Append("<u>"); } else if (iterator.HTMLTagForm == TagForm.Closing) { tagStack.CloseTag(iterator.TagType, output); } iterator.Next(); } else if (iterator.IsOnHTMLTag("pre", TagForm.Opening) && mode == GetTextMode.Normal) // Ignore pre's in list items { output.Append("</p>"); GetPre(ref iterator, output); output.Append("<p>"); } else if (iterator.IsOnHTMLTag("ul") || iterator.IsOnHTMLTag("ol")) { if (iterator.HTMLTagForm == TagForm.Opening) { output.Append("</p>"); GetList(ref iterator, output); output.Append("<p>"); } else if (iterator.HTMLTagForm == TagForm.Closing && mode == GetTextMode.ListItem) { break; } else { iterator.Next(); } } else if (iterator.IsOnHTMLTag("li", TagForm.Closing) && mode == GetTextMode.ListItem) { break; } else if (iterator.IsOnHTMLTag("a", TagForm.Opening)) { string href = iterator.HTMLTagProperty("href"); if (href == null || href == "" || href == "#" || href.StartsWith("{@docRoot}") || href.StartsWith("javascript:", StringComparison.OrdinalIgnoreCase)) { iterator.Next(); } else { GetHTMLLink(ref iterator, output); } } else if (iterator.IsOnJavadocTag("code") || iterator.IsOnJavadocTag("literal")) { // These get added without searching the contents for nested tags output.EntityEncodeAndAppend(iterator.JavadocTagValue); iterator.Next(); } else if (iterator.IsOnJavadocTag("link") || iterator.IsOnJavadocTag("linkPlain")) { Tokenizer linkContent = new Tokenizer(iterator.JavadocTagValue); TokenIterator linkIterator = linkContent.FirstToken; string symbol = GetJavadocLinkSymbol(ref linkIterator); linkIterator.NextPastWhitespace(); string description = GetSimpleText(linkIterator, linkContent.LastToken); description = Normalize(description); if (description == null || description == "") { output.Append("<link type=\"naturaldocs\" originaltext=\""); output.EntityEncodeAndAppend(symbol); output.Append("\">"); } else { output.Append("<link type=\"naturaldocs\" originaltext=\""); output.EntityEncodeAndAppend(description); output.Append(" at "); output.EntityEncodeAndAppend(symbol); output.Append("\">"); } iterator.Next(); } else if (iterator.IsOnJavadocTag("value")) { string symbol = iterator.JavadocTagValue; if (symbol == null || symbol == "") { output.EntityEncodeAndAppend( Locale.Get("NaturalDocs.Engine", "Javadoc.Substitution.value") ); } else { string substitution = Locale.Get("NaturalDocs.Engine", "Javadoc.Substitution.value(symbol)", '\x1F'); int substitutionIndex = substitution.IndexOf('\x1F'); if (substitutionIndex == -1) { output.EntityEncodeAndAppend(substitution); } else { if (substitutionIndex > 0) { output.EntityEncodeAndAppend(substitution, 0, substitutionIndex); } output.Append("<link type=\"naturaldocs\" originaltext=\""); output.EntityEncodeAndAppend(symbol); output.Append("\">"); if (substitutionIndex < substitution.Length - 1) { output.EntityEncodeAndAppend(substitution, substitutionIndex + 1, substitution.Length - (substitutionIndex + 1)); } } } iterator.Next(); } else { // Ignore indent. Spaces between words will be handled by line breaks. // Ignore HTML comments. // Ignore unrecognized HTML tags. iterator.Next(); } } tagStack.CloseAllTags(output); }
/* Function: TryToGetBlock * If the iterator is on a line that starts with one of the <BlockTags>, parses it, adds its content to the comment, * moves the iterator past it, and returns true. If it is not at the start of a tag block it will return false and change * nothing. */ protected bool TryToGetBlock(ref LineIterator lineIterator, LineIterator limit, JavadocComment comment) { if (lineIterator >= limit) { return(false); } // Get the complete content across multiple lines. string tag; TokenIterator startOfContent; if (TryToGetFirstBlockLine(lineIterator, out tag, out startOfContent) == false) { return(false); } for (;;) { lineIterator.Next(); if (lineIterator >= limit || IsFirstBlockLine(lineIterator)) { break; } } TokenIterator endOfContent = lineIterator.FirstToken(LineBoundsMode.Everything); // Any "@tag item description", possibly in a list if (tag == "exception" || tag == "param" || tag == "throws") { TokenIterator iterator = startOfContent; string symbol = null; TryToGetBlockSymbol(ref iterator, endOfContent, out symbol); iterator.NextPastWhitespace(); string description = GetText(iterator, endOfContent); description = Normalize(description); if (symbol == null || symbol == "" || description == null || description == "") { return(false); } var commentBlock = comment.GetListBlock(tag); commentBlock.Add(symbol, description); return(true); } // Any "@tag description", possibly in a list else if (tag == "author" || tag == "deprecated" || tag == "since" || tag == "version") { string description = GetText(startOfContent, endOfContent); description = Normalize(description); if (description == null || description == "") { return(false); } if (tag == "deprecated") { if (comment.Deprecated == null) { comment.Deprecated = description; } else { comment.Deprecated += description; } } else { var commentBlock = comment.GetListBlock(tag); commentBlock.Add(null, description); } return(true); } // Any "@tag description" that can't be in a list else if (tag == "return") { string description = GetText(startOfContent, endOfContent); description = Normalize(description); if (description == null || description == "") { return(false); } var commentBlock = comment.GetTextBlock(tag); commentBlock.Text.Append(description); return(true); } else if (tag == "see") { string description = null; TokenIterator iterator = startOfContent; // @see "Description" // @see <a href="link">Description</a> if (iterator.Character == '"' || iterator.Character == '<') { // There's not symbol so interpret the whole thing as the description. We'll let GetText() handle the HTML link. description = GetText(iterator, endOfContent); description = Normalize(description); } // @see Class.Class#Member // @see Class.Class#Member Description else { string symbol = GetJavadocLinkSymbol(ref iterator); iterator.NextPastWhitespace(); description = GetSimpleText(iterator, endOfContent); description = Normalize(description); if (description == null || description == "") { description = "<p><link type=\"naturaldocs\" originaltext=\"" + symbol.EntityEncode() + "\"></p>"; } else { description = "<p><link type=\"naturaldocs\" originaltext=\"" + description.EntityEncode() + " at " + symbol.EntityEncode() + "\"></p>"; } } if (description == null || description == "") { return(false); } var commentBlock = comment.GetListBlock(tag); commentBlock.Add(null, description); return(true); } // Ignored blocks // - serial // - serialField // - serialData else { return(true); } }
/* Function: CalculateSections */ protected void CalculateSections() { sections = new List <Section>(); Section section = null; TokenIterator iterator = tokenizer.FirstToken; iterator.NextPastWhitespace(); // Pre-Prototype Lines while (iterator.IsInBounds && iterator.PrototypeParsingType == PrototypeParsingType.StartOfPrePrototypeLine) { section = new Section(); section.Type = SectionType.PrePrototypeLine; section.StartIndex = iterator.TokenIndex; do { iterator.Next(); }while (iterator.IsInBounds && iterator.PrototypeParsingType == PrototypeParsingType.PrePrototypeLine); section.EndIndex = iterator.TokenIndex; sections.Add(section); iterator.NextPastWhitespace(); } // Before Parameters section = new Section(); section.Type = SectionType.BeforeParameters; section.StartIndex = iterator.TokenIndex; while (iterator.IsInBounds && iterator.PrototypeParsingType != PrototypeParsingType.StartOfParams && iterator.PrototypeParsingType != PrototypeParsingType.StartOfPostPrototypeLine) { iterator.Next(); } if (iterator.PrototypeParsingType == PrototypeParsingType.StartOfParams) { // Include the StartOfParams symbol in the section iterator.Next(); section.EndIndex = iterator.TokenIndex; sections.Add(section); iterator.NextPastWhitespace(); // Parameters while (iterator.IsInBounds && iterator.PrototypeParsingType != PrototypeParsingType.EndOfParams && iterator.PrototypeParsingType != PrototypeParsingType.StartOfPostPrototypeLine) { section = new Section(); section.Type = SectionType.Parameter; section.StartIndex = iterator.TokenIndex; while (iterator.IsInBounds && iterator.PrototypeParsingType != PrototypeParsingType.EndOfParams && iterator.PrototypeParsingType != PrototypeParsingType.ParamSeparator && iterator.PrototypeParsingType != PrototypeParsingType.StartOfPostPrototypeLine) { iterator.Next(); } // Include the separator in the parameter block if (iterator.PrototypeParsingType == PrototypeParsingType.ParamSeparator) { iterator.Next(); section.EndIndex = iterator.TokenIndex; } else { TokenIterator lookbehind = iterator; lookbehind.PreviousPastWhitespace(PreviousPastWhitespaceMode.Iterator, iterator); section.EndIndex = lookbehind.TokenIndex; } sections.Add(section); iterator.NextPastWhitespace(); } // After Parameters if (iterator.IsInBounds && iterator.PrototypeParsingType != PrototypeParsingType.StartOfPostPrototypeLine) { section = new Section(); section.Type = SectionType.AfterParameters; section.StartIndex = iterator.TokenIndex; do { iterator.Next(); }while (iterator.IsInBounds && iterator.PrototypeParsingType != PrototypeParsingType.StartOfPostPrototypeLine); TokenIterator lookbehind = iterator; lookbehind.PreviousPastWhitespace(PreviousPastWhitespaceMode.Iterator, iterator); section.EndIndex = lookbehind.TokenIndex; sections.Add(section); } } else // there was no StartOfParams { // We still have to finish the BeforeParameters section. TokenIterator lookbehind = iterator; lookbehind.PreviousPastWhitespace(PreviousPastWhitespaceMode.Iterator, iterator); section.EndIndex = lookbehind.TokenIndex; sections.Add(section); } // Post-Prototype Lines while (iterator.IsInBounds && iterator.PrototypeParsingType == PrototypeParsingType.StartOfPostPrototypeLine) { section = new Section(); section.Type = SectionType.PostPrototypeLine; section.StartIndex = iterator.TokenIndex; do { iterator.Next(); }while (iterator.IsInBounds && iterator.PrototypeParsingType == PrototypeParsingType.PostPrototypeLine); section.EndIndex = iterator.TokenIndex; sections.Add(section); iterator.NextPastWhitespace(); } }
/* Function: MarkParameter * Marks the tokens in the parameter specified by the bounds with <PrototypeParsingTypes>. */ protected void MarkParameter(TokenIterator start, TokenIterator end) { // Pass 1: Count the number of "words" in the parameter prior to the default value and mark the default value // separator. We'll figure out how to interpret the words in the second pass. int words = 0; TokenIterator iterator = start; while (iterator < end) { // Default values if (iterator.Character == '=') { iterator.PrototypeParsingType = PrototypeParsingType.DefaultValueSeparator; iterator.Next(); iterator.NextPastWhitespace(end); TokenIterator endOfDefaultValue = end; TokenIterator lookbehind = endOfDefaultValue; lookbehind.Previous(); while (lookbehind >= iterator && lookbehind.PrototypeParsingType == PrototypeParsingType.ParamSeparator) { endOfDefaultValue = lookbehind; lookbehind.Previous(); } endOfDefaultValue.PreviousPastWhitespace(PreviousPastWhitespaceMode.EndingBounds, iterator); if (iterator < endOfDefaultValue) { iterator.SetPrototypeParsingTypeBetween(endOfDefaultValue, PrototypeParsingType.DefaultValue); } break; } // Param separator else if (iterator.PrototypeParsingType == PrototypeParsingType.ParamSeparator) { break; } // "Words" we're interested in else if (TryToSkipTypeOrVarName(ref iterator, end) || TryToSkipComment(ref iterator) || TryToSkipString(ref iterator) || TryToSkipBlock(ref iterator, true)) { // If there was a comment in the prototype, that means it specifically wasn't filtered out because it was something // significant like a Splint comment or /*out*/. Treat it like a modifier. // Strings don't really make sense in the prototype until the default value, but we need the parser to handle it anyway // just so it doesn't lose its mind if one occurs. // If we come across a block that doesn't immediately follow an identifier, it may be something like a C# property so // treat it as a modifier. words++; } // Whitespace and any unexpected random symbols else { iterator.Next(); } } // Pass 2: Mark the "words" we counted from the first pass. The order of words goes [modifier] [modifier] [type] [name], // starting from the right. Typeless languages that only have one word will have it correctly interpreted as the name. iterator = start; TokenIterator wordStart, wordEnd; while (iterator < end) { wordStart = iterator; bool foundWord = false; bool foundBlock = false; if (iterator.PrototypeParsingType == PrototypeParsingType.DefaultValueSeparator || iterator.PrototypeParsingType == PrototypeParsingType.ParamSeparator) { break; } else if (TryToSkipTypeOrVarName(ref iterator, end)) { foundWord = true; } else if (TryToSkipComment(ref iterator) || TryToSkipString(ref iterator) || TryToSkipBlock(ref iterator, true)) { foundWord = true; foundBlock = true; } else { iterator.Next(); } // Process the word we found if (foundWord) { wordEnd = iterator; if (words >= 3) { if (foundBlock && wordEnd.TokenIndex - wordStart.TokenIndex >= 2) { wordStart.PrototypeParsingType = PrototypeParsingType.OpeningTypeModifier; TokenIterator lookbehind = wordEnd; lookbehind.Previous(); lookbehind.PrototypeParsingType = PrototypeParsingType.ClosingTypeModifier; } else { wordStart.SetPrototypeParsingTypeBetween(wordEnd, PrototypeParsingType.TypeModifier); } } else if (words == 2) { MarkType(wordStart, wordEnd); } else if (words == 1) { MarkName(wordStart, wordEnd); // Change the $ at the beginning of the name from a param modifier to part of the name if (wordStart.Character == '$') { wordStart.PrototypeParsingType = PrototypeParsingType.Name; } } words--; } } }