|
' 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
|