/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Tools/CompilerGeneratorTools/Source/VisualBasicSyntaxGenerator/XML/ParseTreeDescription.vb
713 строк
25 KB
Miha Zupan
Replace string.Compare == 0 patterns with Equals/StartsWith calls (#84036)
16 июн 2026, 19:27
Не верифицирован
16 июн 2026, 19:27
6128161
Код
Авторство
О чём код?
' 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 the in-memory format of the parse tree description. Many of the structures also ' contain some of the code for reading themselves from the input file. '----------------------------------------------------------------------------------------------------------- Imports System.Globalization Imports System.Text Imports System.Xml Imports <xmlns="http://schemas.microsoft.com/VisualStudio/Roslyn/Compiler"> ' Root class of the parse tree. All information about the parse tree is in ' stuff accessible from here. In particular, contains dictionaries of all ' the various parts (structures, node kinds, enumerations, etc.) Public Class ParseTree Public FileName As String ' my file name Public NamespaceName As String ' name of the namespace to put stuff in Public VisitorName As String ' name of the visitor class Public RewriteVisitorName As String ' name of the rewriting visitor class Public FactoryClassName As String ' name of the factory class Public ContextualFactoryClassName As String ' name of the contextual factory class ' Dictionary of all node-structure's, indexed by name Public NodeStructures As New Dictionary(Of String, ParseNodeStructure) ' Dictionary of all node-kinds, indexed by name Public NodeKinds As New Dictionary(Of String, ParseNodeKind) ' Dictionary of all enumerations, indexed by name Public Enumerations As New Dictionary(Of String, ParseEnumeration) ' Dictionary of all node-kind-alias's, indexed by name Public Aliases As New Dictionary(Of String, ParseNodeKindAlias) ' Determines which structures are abstract Public IsAbstract As New Dictionary(Of ParseNodeStructure, Boolean) ' Get the root structure. Public RootStructure As ParseNodeStructure ' Get the root structure for Tokens, Trivia Public RootToken, RootTrivia As ParseNodeStructure ' Remember nodes with errors so we only report one error per node. Private ReadOnly _elementsWithErrors As New Dictionary(Of XNode, Boolean) ' Report an error. Public Sub ReportError(referencingNode As XNode, message As String, ParamArray args As Object()) Dim fullMessage As String = FileName If referencingNode IsNot Nothing Then If _elementsWithErrors.ContainsKey(referencingNode) Then ' We already reported an error on this node. Exit Sub End If _elementsWithErrors(referencingNode) = True ' remember this so we only report errors on this node once. Dim lineInfo = CType(referencingNode, IXmlLineInfo) fullMessage += String.Format("({0})", lineInfo.LineNumber) End If fullMessage += String.Format(": " + message, args) Console.WriteLine(fullMessage) End Sub ' Does this struct have any children (including parents? Public Function HasAnyChildren(struct As ParseNodeStructure) As Boolean Return struct.Children.Count > 0 OrElse (struct.ParentStructure IsNot Nothing AndAlso HasAnyChildren(struct.ParentStructure)) End Function ' We finished reading the tree. Do a bit of pre-processing. Public Sub FinishedReading() ' Go through each node-structure and check for the root. RootStructure = Nothing For Each struct In NodeStructures.Values If struct.IsRoot Then If RootStructure IsNot Nothing Then ReportError(RootStructure.Element, "More than one root node specified.") ReportError(struct.Element, "More than one root node specified.") End If RootStructure = struct Else ' this node is derived from something else. Remember that. struct.ParentStructure.HasDerivedStructure = Not String.IsNullOrEmpty(struct.ParentStructureId) End If ' Check for token root. If struct.IsTokenRoot Then If RootToken IsNot Nothing Then ReportError(struct.Element, "More than one token root specified.") RootToken = struct End If ' Check for trivia root. If struct.IsTriviaRoot Then If RootTrivia IsNot Nothing Then ReportError(struct.Element, "More than one trivia root specified.") RootTrivia = struct End If IsAbstract(struct) = True ' Determine "tokens" and trivia by walking the hierarchy SetIsTokenAndIsTrivia(struct) Next ' Figure out abstract nodes - they have no kinds associated with them. For Each kind In NodeKinds.Values IsAbstract(kind.NodeStructure) = False Next End Sub ' Set the IsToken and IsTrivia flags on a struct Private Sub SetIsTokenAndIsTrivia(struct As ParseNodeStructure) ' Walk the hierarchy. Dim parent = struct While parent IsNot Nothing If parent.IsTokenRoot Then struct.IsToken = True Return End If If parent.IsTriviaRoot Then struct.IsTrivia = True End If parent = parent.ParentStructure End While End Sub Public Function ParseEnumType(enumString As String, referencingElement As XNode) As Object If (Enumerations.ContainsKey(enumString)) Then Return Enumerations(enumString) End If ReportError(referencingElement, "{0} is not a valid field type. You should add a node-kind entry in the syntax.xml.", enumString) Return Nothing End Function Public Function ParseOneNodeKind(typeString As String, referencingNode As XNode) As ParseNodeKind If (NodeKinds.ContainsKey(typeString)) Then Return NodeKinds(typeString) End If ReportError(referencingNode, "{0} is not a valid node kind", typeString) Return Nothing End Function Public Function ParseNodeKind(typeParts As IList(Of String), referencingNode As XNode) As Object Dim typeList As New List(Of ParseNodeKind) For Each typePart In typeParts Dim foundType = ParseNodeKind(typePart, referencingNode) If (TypeOf foundType Is List(Of ParseNodeKind)) Then typeList.AddRange(CType(foundType, List(Of ParseNodeKind))) Else If Not TypeOf foundType Is ParseNodeKind Then ReportError(referencingNode, "{0} cannot be used in a alternation of types; it is not a node kind", typePart) Else typeList.Add(CType(foundType, ParseNodeKind)) End If End If Next If typeList.Count = 1 Then Return typeList(0) End If Return typeList End Function Public Function ParseNodeKind(typeString As String, referencingNode As XNode) As Object If (typeString.Contains("|")) Then Dim typeList As New List(Of ParseNodeKind) For Each typePart As String In typeString.Split("|"c) Dim foundType = ParseNodeKind(typePart, referencingNode) If (TypeOf foundType Is List(Of ParseNodeKind)) Then typeList.AddRange(CType(foundType, List(Of ParseNodeKind))) Else If Not TypeOf foundType Is ParseNodeKind Then ReportError(referencingNode, "{0} cannot be used in a alternation of types; it is not a node kind", typePart) Else typeList.Add(CType(foundType, ParseNodeKind)) End If End If Next Return typeList End If If typeString.StartsWith("@", StringComparison.Ordinal) Then Dim nodeTypeString = typeString.Substring(1) Dim nodeStructure As ParseNodeStructure = Nothing If Not NodeStructures.TryGetValue(nodeTypeString, nodeStructure) Then ReportError(referencingNode, "Unknown structure '@{0}'", nodeTypeString) Return Nothing End If Return nodeStructure.GetAllKinds() End If Dim nodeKindAlias As ParseNodeKindAlias = Nothing If Aliases.TryGetValue(typeString, nodeKindAlias) Then Return ParseNodeKind(nodeKindAlias.AliasKinds, referencingNode) End If Return ParseOneNodeKind(typeString, referencingNode) End Function ' Is this structure some base structure of another, or the same Public Function IsAncestorOrSame(parent As ParseNodeStructure, child As ParseNodeStructure) As Boolean Do If (parent Is child) Then Return True End If child = child.ParentStructure Loop While (child IsNot Nothing) Return False End Function End Class ' Base class for things in the parse trees. Each one has a reference back ' to the containing parse tree, and also the XML element it was loaded from. Public MustInherit Class ParseTreeDefinition Private _parseTree As ParseTree Public Overridable Property ParseTree() As ParseTree Get Return Me._parseTree End Get Set(value As ParseTree) Me._parseTree = value End Set End Property ' The element this was loaded from. Primarily useful for getting line/col info for errors. Public Element As XElement End Class ' Information defined in a node-structure element. Defines a node class in the parse tree. Public Class ParseNodeStructure Inherits ParseTreeDefinition ' name of the structure. Public Name As String ' parent as a string. Public ParentStructureId As String Public ReadOnly Property ParentStructure() As ParseNodeStructure Get If String.IsNullOrEmpty(ParentStructureId) Then Return Nothing Else Dim nodeStructure As ParseNodeStructure = Nothing If Not ParseTree.NodeStructures.TryGetValue(ParentStructureId, nodeStructure) Then ParseTree.ReportError(Element, "Unknown parent structure '{0}' for node-structure '{1}'", ParentStructureId, Name) Return Nothing End If Return nodeStructure End If End Get End Property ' Information about the structure. Public Description As String Public Abstract As Boolean Public PartialClass As Boolean Public IsPredefined As Boolean Public IsRoot As Boolean Public IsTokenRoot, IsTriviaRoot As Boolean ' is this the root of tokens, trivia? Public NoFactory As Boolean ' if true, don't create factory method Public NodeKinds As List(Of ParseNodeKind) Public Fields As List(Of ParseNodeField) Public Children As List(Of ParseNodeChild) Public HasDerivedStructure As Boolean ' does this node have any nodes derived from it? Public ReadOnly InternalSyntaxFacts As Boolean Public ReadOnly HasDefaultFactory As Boolean Public IsToken As Boolean ' true if node derives from token root Public IsTrivia As Boolean ' true if node derives from trivia root Public ReadOnly Property IsTerminal As Boolean Get Return IsToken OrElse (Not ParseTree.HasAnyChildren(Me) AndAlso Not Me.Abstract) End Get End Property Public DefaultTrailingTrivia As String ' default trailing trivia for the simplified factory. ' Create a new structure in the give tree and load it from the give XElement. Public Sub New(el As XElement, tree As ParseTree) Me.ParseTree = tree Me.Element = el Name = el.@name ParentStructureId = el.@parent Description = el.<description>.Value DefaultTrailingTrivia = el.@<default-trailing-trivia> Abstract = If(CType(el.Attribute("abstract"), Boolean?), False) PartialClass = If(CType(el.Attribute("partial"), Boolean?), False) IsPredefined = If(CType(el.Attribute("predefined"), Boolean?), False) IsRoot = If(CType(el.Attribute("root"), Boolean?), False) IsTokenRoot = If(CType(el.Attribute("token-root"), Boolean?), False) IsTriviaRoot = If(CType(el.Attribute("trivia-root"), Boolean?), False) NoFactory = If(CType(el.Attribute("no-factory"), Boolean?), False) HasDefaultFactory = If(CType(el.Attribute("has-default-factory"), Boolean?), False) InternalSyntaxFacts = If(CType(el.Attribute("syntax-facts-internal"), Boolean?), False) NodeKinds = (From nk In el.<node-kind> Select New ParseNodeKind(nk, Me)).ToList() For Each nk In NodeKinds If tree.NodeKinds.ContainsKey(nk.Name) Then tree.ReportError(Element, "node-kind ""{0}"" already defined.", nk.Name) Else tree.NodeKinds.Add(nk.Name, nk) End If Next Fields = (From f In el.<field> Select New ParseNodeField(f, Me)).ToList() Children = (From c In el.<child> Select New ParseNodeChild(c, Me)).ToList() End Sub Public Function GetAllKinds() As List(Of ParseNodeKind) Return New List(Of ParseNodeKind)(From kvPair In ParseTree.NodeKinds Where ParseTree.IsAncestorOrSame(Me, kvPair.Value.NodeStructure) Select kvPair.Value) End Function Public Function DerivesFrom(baseClassName As String) As Boolean Dim nodeStructure As ParseNodeStructure = Me While nodeStructure IsNot Nothing If String.Equals(nodeStructure.Name, baseClassName, StringComparison.OrdinalIgnoreCase) Then Return True End If nodeStructure = nodeStructure.ParentStructure End While Return False End Function Public Overrides Function ToString() As String Return Name End Function End Class ' Defines a single node kind in the tree. Every node kind is associated with a structure, but ' a structure can have multiple node kinds. Kinds must be unique in the whole tree. Public Class ParseNodeKind Inherits ParseTreeDefinition Public Name As String Public StructureId As String Public TokenText As String Public NoFactory As Boolean ' if true, don't create factory method for this kind. Public ReadOnly Property NodeStructure() As ParseNodeStructure Get If String.IsNullOrEmpty(StructureId) Then Return Nothing Else Dim parseNodeStructure As ParseNodeStructure = Nothing If Not ParseTree.NodeStructures.TryGetValue(StructureId, parseNodeStructure) Then ParseTree.ReportError(Element, "Unknown structure '{0}' for node-kind '{1}'", StructureId, Name) Return Nothing End If Return parseNodeStructure End If End Get End Property Public Description As String Public Sub New(el As XElement, struct As ParseNodeStructure) Me.ParseTree = struct.ParseTree Me.Element = el Name = el.@name TokenText = el.@<token-text> NoFactory = If(CType(el.Attribute("no-factory"), Boolean?), False) StructureId = struct.Name Description = If(el.<description>.Value, struct.Description) End Sub End Class ' Defines an alias for one or more node kinds. Public Class ParseNodeKindAlias Inherits ParseTreeDefinition Public Name As String Public AliasKinds As String Public Description As String Public Sub New(el As XElement, tree As ParseTree) ParseTree = tree Me.Element = el Name = el.@name AliasKinds = el.@alias Description = el.<description>.Value End Sub End Class ' A field in a node structure. A field is a property that stores data like integer, ' text, etc, not a child node. Its type can be a simple type or an enumeration type. Public Class ParseNodeField Inherits ParseTreeDefinition Public ReadOnly Name As String Public ReadOnly ContainingStructure As ParseNodeStructure Public ReadOnly IsOptional As Boolean Public ReadOnly FieldTypeId As String Public ReadOnly Description As String Public Sub New(el As XElement, struct As ParseNodeStructure) Me.ParseTree = struct.ParseTree Me.Element = el Me.ContainingStructure = struct Name = el.@name IsOptional = If(CType(el.Attribute("optional"), Boolean?), False) FieldTypeId = el.@type Description = el.<description>.Value End Sub ' Gets the field type. Could return a SimpleType, Enumeration Public ReadOnly Property FieldType() As Object Get Select Case FieldTypeId.ToLowerInvariant() Case "boolean" Return SimpleType.Bool Case "text" Return SimpleType.Text Case "character" Return SimpleType.Character Case "int32" Return SimpleType.Int32 Case "uint32" Return SimpleType.UInt32 Case "int64" Return SimpleType.Int64 Case "uint64" Return SimpleType.UInt64 Case "float32" Return SimpleType.Float32 Case "float64" Return SimpleType.Float64 Case "decimal" Return SimpleType.Decimal Case "datetime" Return SimpleType.DateTime Case "textspan" Return SimpleType.TextSpan Case "nodekind" Return SimpleType.NodeKind Case Else Return ParseTree.ParseEnumType(FieldTypeId, Element) End Select End Get End Property End Class ' Defines a child node with a node structure. A child can be a single child ' node of a list of child nodes. Public Class ParseNodeChild Inherits ParseTreeDefinition Public ReadOnly Name As String Public ReadOnly ContainingStructure As ParseNodeStructure Public ReadOnly IsOptional As Boolean Public ReadOnly MinCount As Integer Public ReadOnly IsList As Boolean Public ReadOnly IsSeparated As Boolean Public ReadOnly SeparatorsName As String Private ReadOnly _childKindNames As New Dictionary(Of String, List(Of String)) Private _childKind As Object Public ReadOnly SeparatorsTypeId As String Public ReadOnly Description As String Public ReadOnly Order As Single Public ReadOnly NotInFactory As Boolean Public ReadOnly GenerateWith As Boolean Public ReadOnly InternalSyntaxFacts As Boolean Public KindForNodeKind As Dictionary(Of String, ParseNodeKind) Private ReadOnly _defaultChildKindName As String Private _defaultChildKind As ParseNodeKind Public Sub New(el As XElement, struct As ParseNodeStructure) Me.ParseTree = struct.ParseTree Me.Element = el Me.ContainingStructure = struct Single.TryParse(el.@order, NumberStyles.Any, CultureInfo.InvariantCulture, Me.Order) Name = el.@name SeparatorsName = el.@<separator-name> SeparatorsTypeId = el.@<separator-kind> IsList = If(CType(el.Attribute("list"), Boolean?), False) IsSeparated = el.@<separator-kind> <> "" IsOptional = If(CType(el.Attribute("optional"), Boolean?), False) MinCount = If(CType(el.Attribute("min-count"), Integer?), 0) Description = el.<description>.Value NotInFactory = If(CType(el.Attribute("not-in-factory"), Boolean?), False) GenerateWith = If(CType(el.Attribute("generate-with"), Boolean?), False) InternalSyntaxFacts = If(CType(el.Attribute("syntax-facts-internal"), Boolean?), False) _defaultChildKindName = CType(el.Attribute("default-kind"), String) For Each kind In el.<kind> ' The kind may be duplicated Dim nodeKinds As List(Of String) = Nothing If _childKindNames.TryGetValue(kind.@name, nodeKinds) Then nodeKinds.Add(kind.@<node-kind>) Else nodeKinds = New List(Of String) nodeKinds.Add(kind.@<node-kind>) _childKindNames.Add(kind.@name, nodeKinds) End If Next If _childKindNames.Count = 0 Then Dim kindsString = el.@kind For Each kind As String In kindsString.Split("|"c) _childKindNames.Add(kind, Nothing) 'New List(Of String)(From nodeKind In struct.NodeKinds Select nodeKind.Name)) Next ElseIf el.@kind IsNot Nothing Then ParseTree.ReportError(el, "Cannot have both kind attribute on child and also have kind sub element in child.") End If End Sub Public ReadOnly Property ChildKind(kind As String) As ParseNodeKind Get If KindForNodeKind Is Nothing Then KindForNodeKind = New Dictionary(Of String, ParseNodeKind) For Each key In _childKindNames.Keys Dim nodeNames = _childKindNames(key) If nodeNames IsNot Nothing Then Dim child = ParseTree.ParseOneNodeKind(key, Element) For Each nodeName In nodeNames Dim node = ParseTree.ParseOneNodeKind(nodeName, Element) KindForNodeKind.Add(node.Name, child) Next End If Next End If Dim result As ParseNodeKind = Nothing KindForNodeKind.TryGetValue(kind, result) Return result End Get End Property Public ReadOnly Property ChildKind(containerKinds As IList(Of ParseNodeKind)) As List(Of ParseNodeKind) Get Dim allChildkinds As List(Of ParseNodeKind) = TryCast(ChildKind(), List(Of ParseNodeKind)) If allChildkinds Is Nothing Then Return Nothing End If Dim childkindsForContainer = New List(Of ParseNodeKind) For Each containerKind In containerKinds Dim propertyKind = ChildKind(containerKind.Name) If propertyKind IsNot Nothing Then childkindsForContainer.Add(propertyKind) End If Next If childkindsForContainer.Count > 0 Then Return childkindsForContainer End If Return allChildkinds End Get End Property ' Gets the child type. Could return a NodeKind, List(NodeKind) containing the allowable node kinds of the child. Public ReadOnly Property ChildKind() As Object Get If _childKind Is Nothing Then Dim names(_childKindNames.Count - 1) As String _childKindNames.Keys.CopyTo(names, 0) _childKind = ParseTree.ParseNodeKind(names, Element) End If Return _childKind End Get End Property Public Function WithChildKind(childKind As Object) As ParseNodeChild Dim copy = New ParseNodeChild(Me.Element, Me.ContainingStructure) copy._childKind = childKind Return copy End Function Public ReadOnly Property DefaultChildKind() As ParseNodeKind Get If _defaultChildKind Is Nothing AndAlso _defaultChildKindName IsNot Nothing Then _defaultChildKind = CType(ParseTree.ParseNodeKind(_defaultChildKindName, Element), ParseNodeKind) End If Return _defaultChildKind End Get End Property ' Gets the separators type. Could return a NodeKind, List(NodeKind) containing the allowable node kinds of the child. Public ReadOnly Property SeparatorsKind() As Object Get Return ParseTree.ParseNodeKind(SeparatorsTypeId, Element) End Get End Property Public Overrides Function ToString() As String Return Name End Function End Class ' Defines an enumeration type, so that fields of this type can be defined. Public Class ParseEnumeration Inherits ParseTreeDefinition Public Name As String Public IsFlags As Boolean Public Description As String Public Enumerators As List(Of ParseEnumerator) Public Sub New(el As XElement, tree As ParseTree) ParseTree = tree Me.Element = el Name = el.@name IsFlags = If(CType(el.Attribute("flags"), Boolean?), False) Description = el.<description>.Value Enumerators = (From en In el.<enumerators>.<enumerator> Select New ParseEnumerator(en, Me)).ToList() End Sub End Class ' Defines a single enumerator inside an enumeration type. Public Class ParseEnumerator Public Name As String Public ValueString As String Public Description As String Public Sub New(el As XElement, enumeration As ParseEnumeration) Name = el.@name ValueString = el.@hexvalue Description = el.<description>.Value End Sub Public ReadOnly Property Value() As Long Get Return Convert.ToInt64(ValueString, 16) End Get End Property End Class ' THe kinds of simple types for fields. Public Enum SimpleType Bool Text Character Int32 UInt32 Int64 UInt64 Float32 Float64 [Decimal] DateTime TextSpan NodeKind End Enum