/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Tools/CompilerGeneratorTools/Source/VisualBasicSyntaxGenerator/Util/WriteUtils.vb
956 строк
36 KB
Copilot
Remove superfluous `src/Tools/Source` directory level (#83484)
30 апр 2026, 06:54
Не верифицирован
30 апр 2026, 06:54
2933275
Код
Авторство
О чём код?
' Licensed to the .NET Foundation under one or more agreements. ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. '----------------------------------------------------------------------------------------------------------- ' Defines a base class that is inherited by the writing classes that defines a bunch of utility ' functions for building up names of constructs. Basically anything that we want to shared between different ' output classes is defined here. '----------------------------------------------------------------------------------------------------------- Imports System.IO Imports System.Text ' Utility functions for writing out the parse tree. Basically name generation and various simply utility functions ' that are shared by different writing classes. This is typically inherited by a writing class. Public MustInherit Class WriteUtils Protected _parseTree As ParseTree ' the tree to output #If OLDSTYLE Then Protected Const NodeKindString = "NodeKind" Protected Const NodeListString = "NodeList" Protected Const SeparatedNodeListString = "SeparatedNodeList" Protected Const NodeFactoryListString = "NodeFactory" #Else Protected Const NodeKindString = "SyntaxKind" Protected Const NodeListString = "SyntaxList" Protected Const SeparatedNodeListString = "SeparatedSyntaxList" Protected Const NodeFactoryListString = "Syntax" #End If Public Sub New(parseTree As ParseTree) _parseTree = parseTree End Sub ' Name generation ' Get the base type name (no namespace) for a node structure. Protected Function StructureTypeName(nodeStructure As ParseNodeStructure) As String Return Ident(nodeStructure.Name) End Function ' Get the base type name (no namespace) for an enumeration. Protected Function EnumerationName(enumeration As ParseEnumeration) As String Return Ident(enumeration.Name) End Function 'Get a factory name from a kind Protected Function FactoryName(nodeKind As ParseNodeKind) As String Return nodeKind.Name End Function 'Get a factory name from a structure Protected Function FactoryName(nodeStructure As ParseNodeStructure) As String #If OLDSTYLE Then Return nodeStructure.Name #Else If nodeStructure.Name.EndsWith("Syntax", StringComparison.Ordinal) Then Return nodeStructure.Name.Substring(0, nodeStructure.Name.Length - 6) Else Return nodeStructure.Name End If #End If End Function Protected Function SyntaxFactName(nodeStructure As ParseNodeStructure) As String Dim name = FactoryName(nodeStructure) If name = "Keyword" Then name = "KeywordKind" End If Return name End Function ' Get the name for a field private variable Protected Function FieldVarName(nodeField As ParseNodeField) As String Dim name As String = nodeField.Name Return "_" + LowerFirstCharacter(name) End Function ' Get the name for a child private variable Protected Function ChildVarName(nodeChild As ParseNodeChild) As String Dim name As String = nodeChild.Name Return "_" + LowerFirstCharacter(name) End Function ' Get the name for a child private variable cache (not in the builder, but in the actual node) Protected Function ChildCacheVarName(nodeChild As ParseNodeChild) As String Dim name As String = nodeChild.Name Return "_" + LowerFirstCharacter(name) + "Cache" End Function ' Get the name for a new child variable is the visitor Protected Function ChildNewVarName(nodeChild As ParseNodeChild) As String Dim name As String = nodeChild.Name Return Ident("new" + UpperFirstCharacter(name)) End Function #If False Then ' Get the name for a new child variable is the visitor, but for the separators Protected Function ChildNewVarSeparatorsName(ByVal nodeChild As ParseNodeChild) As String Dim name As String = ChildSeparatorsName(nodeChild) Return Ident(LowerFirstCharacter(name) + "New") End Function #End If ' Get the name for a field parameter. ' If conflictName is not nothing, make sure the name doesn't conflict with that name. Protected Function FieldParamName(nodeField As ParseNodeField, Optional conflictName As String = Nothing) As String Dim name As String = nodeField.Name If String.Equals(name, conflictName, StringComparison.OrdinalIgnoreCase) Then name += "Parameter" End If Return Ident(LowerFirstCharacter(name)) End Function ' Get the name for a child parameter ' If conflictName is not nothing, make sure the name doesn't conflict with that name. Protected Function ChildParamName(nodeChild As ParseNodeChild, Optional conflictName As String = Nothing) As String Dim name As String = OptionalChildName(nodeChild) If String.Equals(name, conflictName, StringComparison.OrdinalIgnoreCase) Then name += "Parameter" End If Return Ident(LowerFirstCharacter(name)) End Function #If False Then ' Get the name for a child separator list parameter Protected Function ChildSeparatorsParamName(ByVal nodeChild As ParseNodeChild) As String Return Ident(LowerFirstCharacter(ChildSeparatorsName(nodeChild))) End Function #End If ' Get the name for a field property Protected Function FieldPropertyName(nodeField As ParseNodeField) As String Return Ident(UnescapedFieldPropertyName(nodeField)) End Function Protected Function UnescapedFieldPropertyName(nodeField As ParseNodeField) As String Dim name As String = nodeField.Name Return UpperFirstCharacter(name) End Function ' Get the name for a child property Protected Function ChildWithFunctionName(nodeChild As ParseNodeChild) As String Return Ident("With" + UpperFirstCharacter(nodeChild.Name)) End Function ' Get the name for a child property Protected Function ChildPropertyName(nodeChild As ParseNodeChild) As String Return Ident(UnescapedChildPropertyName(nodeChild)) End Function Protected Function UnescapedChildPropertyName(nodeChild As ParseNodeChild) As String Return UpperFirstCharacter(OptionalChildName(nodeChild)) End Function ' Get the name for a child separators property Protected Function ChildSeparatorsPropertyName(nodeChild As ParseNodeChild) As String Return Ident(UpperFirstCharacter(ChildSeparatorsName(nodeChild))) End Function ' If a child is optional and isn't a list, add "Optional" to the name. Protected Function OptionalChildName(nodeChild As ParseNodeChild) As String Dim name As String = nodeChild.Name If nodeChild.IsOptional AndAlso Not nodeChild.IsList Then #If OLDSTYLE Then Return "Optional" + UpperFirstCharacter(name) #Else Return UpperFirstCharacter(name) #End If Else Return UpperFirstCharacter(name) End If End Function ' If a child is a separated list, return the name of the separators. Protected Function ChildSeparatorsName(nodeChild As ParseNodeChild) As String If nodeChild.IsList AndAlso nodeChild.IsSeparated Then If String.IsNullOrEmpty(nodeChild.SeparatorsName) Then _parseTree.ReportError(nodeChild.Element, "separator-name was not found, but is required for separated lists") End If Return UpperFirstCharacter(nodeChild.SeparatorsName) Else Throw New InvalidOperationException("Shouldn't get here") End If End Function ' Get the type reference for a field property Protected Function FieldTypeRef(nodeField As ParseNodeField) As String Dim fieldType As Object = nodeField.FieldType If TypeOf fieldType Is SimpleType Then Return SimpleTypeName(CType(fieldType, SimpleType)) ElseIf TypeOf fieldType Is ParseEnumeration Then Return EnumerationTypeName(CType(fieldType, ParseEnumeration)) End If nodeField.ParseTree.ReportError(nodeField.Element, "Bad type for field") Return "UNKNOWNTYPE" End Function ' Get the type reference for a child property Protected Function ChildPropertyTypeRef(nodeStructure As ParseNodeStructure, nodeChild As ParseNodeChild, Optional isGreen As Boolean = False, Optional denyOverride As Boolean = False) As String Dim isOverride = nodeChild.ContainingStructure IsNot nodeStructure AndAlso Not denyOverride Dim result As String If nodeChild.IsList Then If nodeChild.IsSeparated Then result = String.Format(If(isGreen, "SeparatedSyntaxList(Of {0})", "SeparatedSyntaxList(Of {0})"), BaseTypeReference(nodeChild)) ElseIf KindTypeStructure(nodeChild.ChildKind).IsToken Then If isGreen Then result = String.Format("SyntaxList(Of {0})", BaseTypeReference(nodeChild)) Else result = "SyntaxTokenList" End If Else result = String.Format("SyntaxList(Of {0})", BaseTypeReference(nodeChild)) End If Else If Not isGreen AndAlso KindTypeStructure(nodeChild.ChildKind).IsToken Then Return String.Format("SyntaxToken") End If If Not isGreen AndAlso isOverride Then Dim childKindStructure As ParseNodeStructure = Nothing If nodeStructure.NodeKinds.Count = 1 Then Dim childNodeKind = GetChildNodeKind(nodeStructure.NodeKinds(0), nodeChild) childKindStructure = KindTypeStructure(childNodeKind) Else Dim childKinds As New HashSet(Of ParseNodeKind)() For Each kind In nodeStructure.NodeKinds Dim childNodeKind = GetChildNodeKind(kind, nodeChild) If childNodeKind IsNot Nothing Then childKinds.Add(GetChildNodeKind(kind, nodeChild)) Else childKinds = Nothing Exit For End If Next If childKinds IsNot Nothing Then If childKinds.Count = 1 Then childKindStructure = KindTypeStructure(childKinds.First) Else childKindStructure = GetCommonStructure(childKinds.ToList()) End If End If End If If childKindStructure IsNot Nothing Then Return childKindStructure.Name End If End If result = BaseTypeReference(nodeChild) End If If isGreen Then If nodeChild.IsList Then Return String.Format("Global.Microsoft.CodeAnalysis.Syntax.InternalSyntax.{0}", result) Else Return String.Format("InternalSyntax.{0}", result) End If End If Return result End Function Protected Function ChildFieldTypeRef(nodeChild As ParseNodeChild, Optional isGreen As Boolean = False) As String If nodeChild.IsList Then If nodeChild.IsSeparated Then Return String.Format(If(isGreen, "GreenNode", "SeparatedSyntaxList(Of {0})"), BaseTypeReference(nodeChild)) Else Return String.Format(If(isGreen, "GreenNode", "SyntaxList(Of {0})"), BaseTypeReference(nodeChild)) End If Else Return BaseTypeReference(nodeChild) End If End Function Protected Function ChildPrivateFieldTypeRef(nodeChild As ParseNodeChild) As String If nodeChild.IsList Then Return "SyntaxNode" Else Return BaseTypeReference(nodeChild) End If End Function ' Get the type reference for a child separators property Protected Function ChildSeparatorsTypeRef(nodeChild As ParseNodeChild) As String Return String.Format("SyntaxList(Of {0})", SeparatorsBaseTypeReference(nodeChild)) End Function ' Get the type reference for a child constructor Protected Function ChildConstructorTypeRef(nodeChild As ParseNodeChild, Optional isGreen As Boolean = False) As String If nodeChild.IsList Then If isGreen OrElse KindTypeStructure(nodeChild.ChildKind).IsToken Then Return "GreenNode" Else Return "SyntaxNode" End If Else Dim name = BaseTypeReference(nodeChild) If KindTypeStructure(nodeChild.ChildKind).IsToken Then Return "InternalSyntax." + name End If Return name End If End Function ' Get the type reference for a child constructor Protected Function ChildFactoryTypeRef(nodeStructure As ParseNodeStructure, nodeChild As ParseNodeChild, Optional isGreen As Boolean = False, Optional internalForm As Boolean = False) As String If nodeChild.IsList Then If nodeChild.IsSeparated Then If isGreen Then Return String.Format("Global.Microsoft.CodeAnalysis.Syntax.InternalSyntax.SeparatedSyntaxList(of GreenNode)", BaseTypeReference(nodeChild)) Else Return String.Format("SeparatedSyntaxList(Of {0})", BaseTypeReference(nodeChild)) End If Else If isGreen Then Return String.Format("Global.Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(of GreenNode)", StructureTypeName(_parseTree.RootStructure)) Else If KindTypeStructure(nodeChild.ChildKind).IsToken Then Return String.Format("SyntaxTokenList") Else Return String.Format("SyntaxList(of {0})", BaseTypeReference(nodeChild)) End If End If End If Else If Not internalForm AndAlso KindTypeStructure(nodeChild.ChildKind).IsToken Then Return String.Format("SyntaxToken", BaseTypeReference(nodeChild)) End If If Not isGreen Then Return ChildPropertyTypeRef(nodeStructure, nodeChild, isGreen) Else Return BaseTypeReference(nodeChild) End If End If End Function #If False Then ' Get the type reference for a child separators constructor Protected Function ChildSeparatorConstructorTypeRef(ByVal nodeChild As ParseNodeChild) As String If nodeChild.IsList AndAlso nodeChild.IsSeparated Then Return String.Format("SeparatedNodeList(Of {0})", SeparatorsBaseTypeReference(nodeChild)) Else Throw New ApplicationException("shouldn't get here") End If End Function #End If ' Is this type reference a list structure kind? Protected Function IsListStructureType(nodeField As ParseNodeChild) As Boolean Return nodeField.IsList AndAlso (TypeOf nodeField.ChildKind Is ParseNodeKind OrElse TypeOf nodeField.ChildKind Is List(Of ParseNodeKind)) End Function ' Is this type reference a non-list structure kind? Protected Function IsNodeStructureType(nodeField As ParseNodeChild) As Boolean Return Not nodeField.IsList AndAlso (TypeOf nodeField.ChildKind Is ParseNodeKind OrElse TypeOf nodeField.ChildKind Is List(Of ParseNodeKind)) End Function ' Get the type reference for a child private variable, ignoring lists Protected Function BaseTypeReference(nodeChild As ParseNodeChild) As String Return KindTypeReference(nodeChild.ChildKind, nodeChild.Element) End Function ' Get the type reference for separators, ignoring lists Protected Function SeparatorsBaseTypeReference(nodeChild As ParseNodeChild) As String Return KindTypeReference(nodeChild.SeparatorsKind, nodeChild.Element) End Function ' Get the type reference for a kind Private Function KindTypeReference(kind As Object, element As XNode) As String If TypeOf kind Is ParseNodeKind Then Return StructureTypeName(CType(kind, ParseNodeKind).NodeStructure) ElseIf TypeOf kind Is List(Of ParseNodeKind) Then Dim commonStructure = GetCommonStructure(CType(kind, List(Of ParseNodeKind))) If commonStructure Is Nothing Then Return "Object" Else Return StructureTypeName(commonStructure) End If End If _parseTree.ReportError(element, "Invalid kind specified") Return "UNKNOWNTYPE" End Function ' Get the type reference for a kind Protected Function KindTypeStructure(kind As Object) As ParseNodeStructure If TypeOf kind Is ParseNodeKind Then Return CType(kind, ParseNodeKind).NodeStructure ElseIf TypeOf kind Is List(Of ParseNodeKind) Then Return GetCommonStructure(CType(kind, List(Of ParseNodeKind))) End If Return Nothing End Function ' Get the type name of a simple type Protected Function SimpleTypeName(simpleType As SimpleType) As String Select Case simpleType Case SimpleType.Bool Return "Boolean" Case SimpleType.Text Return "String" Case SimpleType.Character Return "Char" Case SimpleType.Int32 Return "Integer" Case SimpleType.UInt32 Return "UInteger" Case SimpleType.Int64 Return "Long" Case SimpleType.UInt64 Return "ULong" Case SimpleType.Float32 Return "Single" Case SimpleType.Float64 Return "Double" Case SimpleType.Decimal Return "System.Decimal" Case SimpleType.DateTime Return "DateTime" Case SimpleType.TextSpan Return "TextSpan" Case SimpleType.NodeKind Return NodeKindString Case Else Throw New InvalidOperationException("Unexpected simple type") End Select End Function ' Get the type name of an enumeration type Protected Function EnumerationTypeName(enumType As ParseEnumeration) As String Return Ident(enumType.Name) End Function ' The name of the node kind enumeration Protected Function NodeKindType() As String Return NodeKindString End Function ' The name of the visitor method for a structure type Protected Function VisitorMethodName(nodeStructure As ParseNodeStructure) As String Dim nodeName = nodeStructure.Name If nodeName.EndsWith("Syntax", StringComparison.Ordinal) Then nodeName = nodeName.Substring(0, nodeName.Length - 6) Return "Visit" + nodeName End Function ' Is this structure the root? Protected Function IsRoot(nodeStructure As ParseNodeStructure) As Boolean Return String.IsNullOrEmpty(nodeStructure.ParentStructureId) End Function ' Given a list of ParseNodeKinds, find the common structure that encapsulates all ' of them, or else return Nothing if there is no common structure. Protected Function GetCommonStructure(kindList As List(Of ParseNodeKind)) As ParseNodeStructure Dim structList = kindList.Select(Function(kind) kind.NodeStructure).ToList() ' list of the structures. ' Any candidate ancestor is an ancestor (or same) of the first element Dim candidate As ParseNodeStructure = structList(0) Do If IsAncestorOfAll(candidate, structList) Then Return candidate End If candidate = candidate.ParentStructure Loop While (candidate IsNot Nothing) Return Nothing ' no ancestor End Function ' Is this structure an ancestorOrSame of all Protected Function IsAncestorOfAll(parent As ParseNodeStructure, children As List(Of ParseNodeStructure)) As Boolean Return children.TrueForAll(Function(child) _parseTree.IsAncestorOrSame(parent, child)) End Function ' Get all of the fields of a structure, including inherited fields, in the right order. ' TODO: need way to get the ordering right. Protected Function GetAllFieldsOfStructure(struct As ParseNodeStructure) As List(Of ParseNodeField) Dim fullList As New List(Of ParseNodeField) ' For now, just put inherited stuff at the beginning, until we design a real ordering solution Do While struct IsNot Nothing fullList.InsertRange(0, struct.Fields) struct = struct.ParentStructure Loop Return fullList End Function ' Get all of the children of a structure, including inherited children, in the right order. ' The ordering is defined first by order attribute, then by declared order (base before derived) Protected Function GetAllChildrenOfStructure(struct As ParseNodeStructure) As List(Of ParseNodeChild) Dim fullList As New List(Of Tuple(Of ParseNodeChild, Integer)) ' For now, just put inherited stuff at the beginning, until we design a real ordering solution Dim baseLevel = 0 ' 0 for this structure, 1 for base, 2 for grandbase, ... Do While struct IsNot Nothing For i = 0 To struct.Children.Count - 1 ' Add each child with an integer giving default sort order. fullList.Add(New Tuple(Of ParseNodeChild, Integer)(struct.Children(i), i - baseLevel * 100)) Next struct = struct.ParentStructure baseLevel += 1 Loop ' Return a new list in order. Return (From n In fullList Order By n.Item1.Order, n.Item2 Select n.Item1).ToList() End Function ' Get all of the children of a structure, including inherited children, in the right order. ' that can be passed to the factory method. ' The ordering is defined first by order attribute, then by declared order (base before derived) Protected Function GetAllFactoryChildrenOfStructure(struct As ParseNodeStructure) As IEnumerable(Of ParseNodeChild) Return From child In GetAllChildrenOfStructure(struct) Where Not child.NotInFactory Select child End Function ' String utility functions ' Lowercase the first character o a string Protected Function LowerFirstCharacter(s As String) As String If s Is Nothing OrElse s.Length = 0 Then Return s Else Return Char.ToLowerInvariant(s(0)) + s.Substring(1) End If End Function ' Uppercase the first character o a string Protected Function UpperFirstCharacter(s As String) As String If s Is Nothing OrElse s.Length = 0 Then Return s Else Return Char.ToUpperInvariant(s(0)) + s.Substring(1) End If End Function ' Word wrap a string into lines Protected Function WordWrap(text As String) As List(Of String) Const LineLength As Integer = 80 Dim lines As New List(Of String) ' Remove newlines, consecutive spaces. text = text.Replace(vbCr, " ") text = text.Replace(vbLf, " ") Do Dim newText = text.Replace(" ", " ") If newText = text Then Exit Do text = newText Loop text = text.Trim() While text.Length >= LineLength Dim split As Integer = text.Substring(0, LineLength).LastIndexOf(" "c) If split < 0 Then split = LineLength Dim line As String = text.Substring(0, split).Trim() lines.Add(line) text = text.Substring(split).Trim() End While If text.Length > 0 Then lines.Add(text) End If Return lines End Function ' Create a description XML comment with the given tag, indented the given number of characters Private Sub GenerateXmlCommentPart(writer As TextWriter, text As String, xmlTag As String, indent As Integer, Optional escape As Boolean = True) If String.IsNullOrWhiteSpace(text) Then Return Dim lines As List(Of String) If escape Then text = XmlEscape(text) lines = WordWrap(text) Else lines = text.Replace(vbCrLf, vbLf).Replace(vbCr, vbLf).Split(vbLf).ToList() End If lines.Insert(0, "<" & xmlTag & ">") lines.Add("</" & xmlTag & ">") Dim prefix = New String(" "c, indent) & "''' " For Each line In lines writer.WriteLine(prefix & line) Next End Sub Protected Shared Function XmlEscape(value As String) As String Return value.Replace("&", "&").Replace("<", "<").Replace(">", ">") End Function Protected Shadows Function XmlEscapeAndWrap(value As String) As List(Of String) Return WordWrap(XmlEscape(value)) End Function Public Sub GenerateSummaryXmlComment(writer As TextWriter, text As String, Optional indent As Integer = 8) GenerateXmlCommentPart(writer, text, "summary", indent) End Sub Public Sub GenerateParameterXmlComment(writer As TextWriter, parameterName As String, text As String, Optional escapeText As Boolean = False, Optional indent As Integer = 8) If String.IsNullOrWhiteSpace(text) Then Return If escapeText Then text = XmlEscape(text) Else ' Ensure the text does not require escaping. Dim filtered = text.Replace("<see ", "").Replace("/>", "").Replace("&", "").Replace("<", "").Replace(">", "") Debug.Assert(filtered = XmlEscape(filtered)) End If Dim prefix = New String(" "c, indent) & "''' " writer.WriteLine(prefix & "<param name=""{0}"">", parameterName) For Each line In WordWrap(text) writer.WriteLine(prefix & line) Next writer.WriteLine(prefix & "</param>") End Sub Public Sub GenerateTypeParameterXmlComment(writer As TextWriter, typeParameterName As String, text As String, Optional indent As Integer = 4) If String.IsNullOrWhiteSpace(text) Then Return text = XmlEscape(text) Dim prefix = New String(" "c, indent) & "''' " writer.WriteLine(prefix & "<typeparam name=""{0}"">", typeParameterName) For Each line In WordWrap(text) writer.WriteLine(prefix & line) Next writer.WriteLine(prefix & "</typeparam>") End Sub ' Generate and XML comment with the given description and remarks sections. If empty, the sections are omitted. Protected Sub GenerateXmlComment(writer As TextWriter, descriptionText As String, remarksText As String, indent As Integer) GenerateXmlCommentPart(writer, descriptionText, "summary", indent) GenerateXmlCommentPart(writer, remarksText, "remarks", indent, escape:=False) End Sub ' Generate XML comment for a structure Protected Sub GenerateXmlComment(writer As TextWriter, struct As ParseNodeStructure, indent As Integer, includeRemarks As Boolean) Dim descriptionText As String = struct.Description Dim remarksText As String = Nothing If includeRemarks AndAlso struct.NodeKinds.Any() Then remarksText += "<para>This node is associated with the following syntax kinds:</para>" & vbCrLf & "<list type=""bullet"">" & vbCrLf For Each kind In struct.NodeKinds remarksText += $"<item><description><see cref=""SyntaxKind.{kind.Name}""/></description></item>" & vbCrLf Next remarksText += "</list>" End If GenerateXmlComment(writer, descriptionText, remarksText, indent) End Sub ' Generate XML comment for a child Protected Sub GenerateXmlComment(writer As TextWriter, child As ParseNodeChild, indent As Integer) Dim descriptionText As String = child.Description Dim remarksText As String = Nothing If child.IsOptional Then If child.IsList Then remarksText = "If nothing is present, an empty list is returned." Else remarksText = "This child is optional. If it is not present, then Nothing is returned." End If End If GenerateXmlComment(writer, descriptionText, remarksText, indent) End Sub ' Generate XML comment for a child Protected Sub GenerateWithXmlComment(writer As TextWriter, child As ParseNodeChild, indent As Integer) Dim descriptionText As String = "Returns a copy of this with the " + ChildPropertyName(child) + " property changed to the specified value. Returns this instance if the specified value is the same as the current value." Dim remarksText As String = Nothing GenerateXmlComment(writer, descriptionText, remarksText, indent) End Sub ' Generate XML comment for a field Protected Sub GenerateXmlComment(writer As TextWriter, field As ParseNodeField, indent As Integer) Dim descriptionText As String = field.Description Dim remarksText As String = Nothing GenerateXmlComment(writer, descriptionText, remarksText, indent) End Sub ' Generate XML comment for a kind Protected Sub GenerateXmlComment(writer As TextWriter, kind As ParseNodeKind, indent As Integer) Dim descriptionText As String = kind.Description Dim remarksText As String = Nothing GenerateXmlComment(writer, descriptionText, remarksText, indent) End Sub ' Generate XML comment for an enumeration Protected Sub GenerateXmlComment(writer As TextWriter, enumerator As ParseEnumeration, indent As Integer) Dim descriptionText As String = enumerator.Description Dim remarksText As String = Nothing GenerateXmlComment(writer, descriptionText, remarksText, indent) End Sub ' Generate XML comment for an enumerator Protected Sub GenerateXmlComment(writer As TextWriter, enumerator As ParseEnumerator, indent As Integer) Dim descriptionText As String = enumerator.Description Dim remarksText As String = Nothing GenerateXmlComment(writer, descriptionText, remarksText, indent) End Sub Private ReadOnly _VBKeywords As String() = { "ADDHANDLER", "ADDRESSOF", "ALIAS", "AND", "ANDALSO", "AS", "BOOLEAN", "BYREF", "BYTE", "BYVAL", "CALL", "CASE", "CATCH", "CBOOL", "CBYTE", "CCHAR", "CDATE", "CDBL", "CDEC", "CHAR", "CINT", "CLASS", "CLNG", "COBJ", "CONST", "CONTINUE", "CSBYTE", "CSHORT", "CSNG", "CSTR", "CTYPE", "CUINT", "CULNG", "CUSHORT", "DATE", "DECIMAL", "DECLARE", "DEFAULT", "DELEGATE", "DIM", "DIRECTCAST", "DO", "DOUBLE", "EACH", "ELSE", "ELSEIF", "END", "ENDIF", "ENUM", "ERASE", "ERROR", "EVENT", "EXIT", "FALSE", "FINALLY", "FOR", "FRIEND", "FUNCTION", "GET", "GETTYPE", "GETXMLNAMESPACE", "GLOBAL", "GOSUB", "GOTO", "HANDLES", "IF", "IMPLEMENTS", "IMPORTS", "IN", "INHERITS", "INTEGER", "INTERFACE", "IS", "ISNOT", "LET", "LIB", "LIKE", "LONG", "LOOP", "ME", "MOD", "MODULE", "MUSTINHERIT", "MUSTOVERRIDE", "MYBASE", "MYCLASS", "NAMESPACE", "NARROWING", "NEW", "NEXT", "NOT", "NOTHING", "NOTINHERITABLE", "NOTOVERRIDABLE", "OBJECT", "OF", "ON", "OPERATOR", "OPTION", "OPTIONAL", "OR", "ORELSE", "OVERLOADS", "OVERRIDABLE", "OVERRIDES", "PARAMARRAY", "PARTIAL", "PRIVATE", "PROPERTY", "PROTECTED", "PUBLIC", "RAISEEVENT", "READONLY", "REDIM", "REM", "REMOVEHANDLER", "RESUME", "RETURN", "SBYTE", "SELECT", "SET", "SHADOWS", "SHARED", "SHORT", "SINGLE", "STATIC", "STEP", "STOP", "STRING", "STRUCTURE", "SUB", "SYNCLOCK", "THEN", "THROW", "TO", "TRUE", "TRY", "TRYCAST", "TYPEOF", "UINTEGER", "ULONG", "USHORT", "USING", "VARIANT", "WEND", "WHEN", "WHILE", "WIDENING", "WITH", "WITHEVENTS", "WRITEONLY", "XOR"} ' If the string is a keyword, escape it. Otherwise just return it. Protected Function Ident(id As String) As String If _VBKeywords.Contains(id.ToUpperInvariant()) Then Return "[" + id + "]" Else Return id End If End Function Public Function EscapeQuotes(s As String) As String If s.IndexOf(""""c) <> -1 Then Dim sb As New StringBuilder Dim parts = s.Split(""""c) Dim last = parts.Length - 1 For i = 0 To last - 1 sb.Append(parts(i)) sb.Append("""""") Next sb.Append(parts(last)) s = sb.ToString End If Return s End Function Public Function GetChildNodeKind(nodeKind As ParseNodeKind, child As ParseNodeChild) As ParseNodeKind Dim childNodeKind = TryCast(child.ChildKind, ParseNodeKind) Dim childNodeKinds = TryCast(child.ChildKind, List(Of ParseNodeKind)) If childNodeKinds IsNot Nothing AndAlso nodeKind IsNot Nothing Then childNodeKind = child.ChildKind(nodeKind.Name) End If If childNodeKind Is Nothing AndAlso child.DefaultChildKind IsNot Nothing Then childNodeKind = child.DefaultChildKind End If Return childNodeKind End Function Public Function IsAutoCreatableToken(node As ParseNodeStructure, nodeKind As ParseNodeKind, child As ParseNodeChild) As Boolean Dim childNodeKind = GetChildNodeKind(nodeKind, child) If childNodeKind IsNot Nothing Then Dim childNodeStructure = KindTypeStructure(childNodeKind) If childNodeStructure.IsToken AndAlso childNodeKind.Name <> "IdentifierToken" Then Return True End If End If Return False End Function Public Function IsAutoCreatableNodeOfAutoCreatableTokens(node As ParseNodeStructure, nodeKind As ParseNodeKind, child As ParseNodeChild) As Boolean Dim childNodeKind = GetChildNodeKind(nodeKind, child) ' Node contains only auto-creatable tokens If childNodeKind IsNot Nothing Then Dim childNodeStructure = KindTypeStructure(childNodeKind) If Not childNodeStructure.IsToken Then Dim allChildren = GetAllChildrenOfStructure(childNodeStructure) For Each childNodeChild In allChildren If Not IsAutoCreatableToken(childNodeStructure, childNodeKind, childNodeChild) Then Return False End If Next Return True End If End If Return False End Function Public Function IsAutoCreatableChild(node As ParseNodeStructure, nodeKind As ParseNodeKind, child As ParseNodeChild) As Boolean Return IsAutoCreatableToken(node, nodeKind, child) OrElse IsAutoCreatableNodeOfAutoCreatableTokens(node, nodeKind, child) End Function End Class