/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Tools/CompilerGeneratorTools/Source/VisualBasicSyntaxGenerator/RedNodes/RedNodeWriter.vb
1 030 строк
46 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. Imports System.IO ' Class to write out the code for the code tree. Friend Class RedNodeWriter Inherits WriteUtils Private _writer As TextWriter 'output is sent here. ' Initialize the class with the parse tree to write. Public Sub New(parseTree As ParseTree) MyBase.New(parseTree) End Sub ' Write out the code defining the tree to the give file. Public Sub WriteMainTreeAsCode(writer As TextWriter) _writer = writer GenerateMainNamespace() End Sub Public Sub WriteSyntaxTreeAsCode(writer As TextWriter) _writer = writer GenerateSyntaxNamespace() End Sub Private Sub GenerateMainNamespace() If Not String.IsNullOrEmpty(_parseTree.NamespaceName) Then _writer.WriteLine() _writer.WriteLine("Namespace {0}", Ident(_parseTree.NamespaceName)) _writer.WriteLine() End If If Not String.IsNullOrEmpty(_parseTree.VisitorName) Then GenerateVisitorClass(True) GenerateVisitorClass(False) End If If Not String.IsNullOrEmpty(_parseTree.RewriteVisitorName) Then GenerateRewriteVisitorClass() End If If Not String.IsNullOrEmpty(_parseTree.NamespaceName) Then _writer.WriteLine("End Namespace") End If End Sub Private Sub GenerateSyntaxNamespace() If Not String.IsNullOrEmpty(_parseTree.NamespaceName) Then _writer.WriteLine() _writer.WriteLine("Namespace {0}", Ident(_parseTree.NamespaceName & ".Syntax")) _writer.WriteLine() End If GenerateEnumTypes() _writer.WriteLine() _writer.WriteLine() GenerateNodeStructures() If Not String.IsNullOrEmpty(_parseTree.NamespaceName) Then _writer.WriteLine("End Namespace") End If End Sub Private Sub GenerateEnumTypes() For Each enumerationType In _parseTree.Enumerations.Values GenerateEnumerationType(enumerationType) Next End Sub Private Sub GenerateNodeStructures() For Each nodeStructure In _parseTree.NodeStructures.Values If Not (nodeStructure.IsToken OrElse nodeStructure.IsTrivia) Then GenerateNodeStructureClass(nodeStructure) End If Next End Sub ' Generate an enumeration type Private Sub GenerateEnumerationType(enumeration As ParseEnumeration) ' XML comment GenerateXmlComment(_writer, enumeration, 4) If enumeration.IsFlags Then _writer.WriteLine(" <Flags()> _") End If _writer.WriteLine(" Public Enum {0}", EnumerationTypeName(enumeration)) For Each enumerator In enumeration.Enumerators GenerateEnumeratorVariable(enumerator, enumeration.IsFlags) Next _writer.WriteLine(" End Enum") _writer.WriteLine() End Sub ' Generate a public enumerator declaration for a enumerator. ' If generateValue is true, generate the value also Private Sub GenerateEnumeratorVariable(enumerator As ParseEnumerator, generateValue As Boolean) _writer.WriteLine() ' XML comment GenerateXmlComment(_writer, enumerator, 8) _writer.Write(" {0}", Ident(enumerator.Name)) If generateValue Then _writer.Write(" = {0}", GetConstantValue(enumerator.Value)) End If _writer.WriteLine() End Sub ' Generate a constant value Private Function GetConstantValue(val As Long) As String Return val.ToString() End Function ' Generate a class declaration for a node structure. Private Sub GenerateNodeStructureClass(nodeStructure As ParseNodeStructure) ' SyntaxNode lives in the root namespace now, unlike the other unwashed node types. If nodeStructure.IsPredefined Then Return ' XML comment GenerateXmlComment(_writer, nodeStructure, 4, includeRemarks:=True) ' Class name _writer.Write(" ") If (nodeStructure.PartialClass) Then _writer.Write("Partial ") End If If _parseTree.IsAbstract(nodeStructure) Then _writer.WriteLine("Public MustInherit Class {0}", StructureTypeName(nodeStructure)) ElseIf Not nodeStructure.HasDerivedStructure Then _writer.WriteLine("Public NotInheritable Class {0}", StructureTypeName(nodeStructure)) Else Throw New InvalidOperationException("Not reachable") End If ' Base class If Not IsRoot(nodeStructure) Then _writer.WriteLine(" Inherits {0}", StructureTypeName(nodeStructure.ParentStructure)) End If _writer.WriteLine() 'Create members GenerateNodeStructureMembers(nodeStructure) ' Create the constructor. GenerateNodeStructureConstructor(nodeStructure) ' Create the IsTerminal property Dim parentStructure = nodeStructure.ParentStructure If parentStructure IsNot Nothing AndAlso nodeStructure.IsTerminal <> parentStructure.IsTerminal Then GenerateIsTerminal(nodeStructure) End If ' Create the property accessor for each of the fields Dim allFields = GetAllFieldsOfStructure(nodeStructure) For i = 0 To allFields.Count - 1 GenerateNodeFieldProperty(allFields(i), StructureTypeName(nodeStructure), allFields(i).ContainingStructure IsNot nodeStructure) Next ' Create the property accessor for each of the children Dim allChildren = GetAllChildrenOfStructure(nodeStructure) For i = 0 To allChildren.Count - 1 Dim child = allChildren(i) If child.IsList AndAlso child.IsSeparated Then GenerateNodeSeparatedListChildProperty(nodeStructure, child, i, child.ContainingStructure IsNot nodeStructure) Else GenerateNodeChildProperty(nodeStructure, child, i, child.ContainingStructure IsNot nodeStructure) End If GenerateNodeWithChildProperty(child, i, nodeStructure) If child.IsList Then GenerateChildListAccessor(nodeStructure, child) ElseIf HasNestedList(nodeStructure, child) Then GeneratedNestedChildListAccessor(nodeStructure, child) End If Next If allChildren.Count > 0 Then GenerateGetCachedSlot(nodeStructure, allChildren) GenerateGetNodeSlot(nodeStructure, allChildren) End If ' Visitor accept method If Not String.IsNullOrEmpty(_parseTree.VisitorName) Then GenerateAccept(nodeStructure) End If GenerateUpdate(nodeStructure) ' Special methods for the root node. If IsRoot(nodeStructure) Then GenerateRootNodeSpecialMethods(nodeStructure) End If ' End the class _writer.WriteLine(" End Class") _writer.WriteLine() End Sub Private Sub GenerateChildListAccessor(nodeStructure As ParseNodeStructure, child As ParseNodeChild) Dim kindType = KindTypeStructure(child.ChildKind) Dim itemType = If(kindType.IsToken, "SyntaxToken", kindType.Name) If _parseTree.IsAbstract(nodeStructure) Then If nodeStructure.Children.Contains(child) Then _writer.WriteLine(" Public Shadows Function Add{0}(ParamArray items As {1}()) As {2}", child.Name, itemType, nodeStructure.Name) _writer.WriteLine(" Return Add{0}Core(items)", child.Name) _writer.WriteLine(" End Function") _writer.WriteLine(" Friend MustOverride Function Add{0}Core(ParamArray items As {1}()) As {2}", child.Name, itemType, nodeStructure.Name) End If Else _writer.WriteLine(" Public Shadows Function Add{0}(ParamArray items As {1}()) As {2}", child.Name, itemType, nodeStructure.Name) _writer.WriteLine(" Return Me.With{0}(Me.{0}.AddRange(items))", child.Name) _writer.WriteLine(" End Function") _writer.WriteLine() If Not nodeStructure.Children.Contains(child) AndAlso nodeStructure.ParentStructure.Children.Contains(child) Then _writer.WriteLine(" Friend Overrides Function Add{0}Core(ParamArray items As {1}()) As {2}", child.Name, itemType, nodeStructure.ParentStructure.Name) _writer.WriteLine(" Return Add{0}(items)", child.Name) _writer.WriteLine(" End Function") _writer.WriteLine() End If End If End Sub Private Function HasNestedList(nodeStructure As ParseNodeStructure, child As ParseNodeChild) As Boolean Dim nestedList = GetNestedList(nodeStructure, child) Return nestedList IsNot Nothing End Function ' The nested list of a structure is the one and only list child ' The structure's other children must be auto-creatable. Private Function GetNestedList(nodeStructure As ParseNodeStructure, child As ParseNodeChild) As ParseNodeChild Dim childStructure = KindTypeStructure(child.ChildKind) If childStructure.IsToken Then Return Nothing Dim children = GetAllChildrenOfStructure(childStructure).ToList() Dim listChild As ParseNodeChild = Nothing For Each childNodeChild In children If childNodeChild.IsList Then If listChild Is Nothing Then listChild = childNodeChild Else ' More than one list! Return Nothing End If ElseIf Not IsAutoCreatableChild(childStructure, Nothing, childNodeChild) Then Return Nothing End If Next Return listChild End Function Private Sub GeneratedNestedChildListAccessor(nodeStructure As ParseNodeStructure, child As ParseNodeChild) Dim childStructure = KindTypeStructure(child.ChildKind) If _parseTree.IsAbstract(childStructure) Then Return End If Dim nestedList = GetNestedList(nodeStructure, child) Dim nestedListStructure = KindTypeStructure(nestedList.ChildKind) Dim itemType = If(nestedListStructure.IsToken, "SyntaxToken", nestedListStructure.Name) If _parseTree.IsAbstract(nodeStructure) Then If nodeStructure.Children.Contains(child) Then _writer.WriteLine(" Public Shadows Function Add{0}{1}(ParamArray items As {2}()) As {3}", child.Name, nestedList.Name, itemType, nodeStructure.Name) _writer.WriteLine(" Return Add{0}{1}Core(items)", child.Name, nestedList.Name) _writer.WriteLine(" End Function") _writer.WriteLine(" Friend MustOverride Function Add{0}{1}Core(ParamArray items As {2}()) As {3}", child.Name, nestedList.Name, itemType, nodeStructure.Name) _writer.WriteLine() End If Else _writer.WriteLine(" Public Shadows Function Add{0}{1}(ParamArray items As {2}()) As {3}", child.Name, nestedList.Name, itemType, nodeStructure.Name) _writer.WriteLine(" Dim _child = If(Me.{0} IsNot Nothing, Me.{0}, SyntaxFactory.{1}())", child.Name, FactoryName(childStructure)) _writer.WriteLine(" Return Me.With{0}(_child.Add{1}(items))", child.Name, nestedList.Name) _writer.WriteLine(" End Function") _writer.WriteLine() If Not nodeStructure.Children.Contains(child) AndAlso nodeStructure.ParentStructure.Children.Contains(child) Then _writer.WriteLine(" Friend Overrides Function Add{0}{1}Core(ParamArray items As {2}()) As {3}", child.Name, nestedList.Name, itemType, nodeStructure.ParentStructure.Name) _writer.WriteLine(" Return Add{0}{1}(items)", child.Name, nestedList.Name) _writer.WriteLine(" End Function") _writer.WriteLine() End If End If End Sub ' Generate IsTerminal property. Private Sub GenerateIsTerminal(nodeStructure As ParseNodeStructure) _writer.WriteLine(" Public Overrides ReadOnly Property IsTerminal As Boolean") _writer.WriteLine(" Get") _writer.WriteLine(" Return {0}", If(nodeStructure.IsTerminal, "True", "False")) _writer.WriteLine(" End Get") _writer.WriteLine(" End Property") _writer.WriteLine() End Sub Private Sub GenerateNodeStructureMembers(nodeStructure As ParseNodeStructure) Dim children = nodeStructure.Children For Each child In children If Not KindTypeStructure(child.ChildKind).IsToken Then _writer.WriteLine(" Friend {0} as {1}", ChildVarName(child), ChildPrivateFieldTypeRef(child)) End If Next _writer.WriteLine() End Sub ' Generate constructor for a node structure Private Sub GenerateNodeStructureConstructor(nodeStructure As ParseNodeStructure) If Not IsRoot(nodeStructure) AndAlso nodeStructure.Name <> "StructuredTriviaSyntax" Then _writer.WriteLine(" Friend Sub New(ByVal green As GreenNode, ByVal parent as SyntaxNode, ByVal startLocation As Integer)") _writer.WriteLine(" MyBase.New(green, parent, startLocation)") _writer.WriteLine(" Debug.Assert(green IsNot Nothing)") _writer.WriteLine(" Debug.Assert(startLocation >= 0)") _writer.WriteLine(" End Sub") _writer.WriteLine() End If Dim allFields = GetAllFieldsOfStructure(nodeStructure) If Not _parseTree.IsAbstract(nodeStructure) AndAlso StructureTypeName(nodeStructure) <> "IdentifierSyntax" Then _writer.Write(" Friend Sub New(") ' Generate each of the field parameters _writer.Write("ByVal kind As {0}, ByVal errors as DiagnosticInfo(), ByVal annotations as SyntaxAnnotation()", NodeKindType()) If nodeStructure.IsTerminal Then ' terminals have a text _writer.Write(", text as String") End If If nodeStructure.IsToken Then ' tokens have trivia _writer.Write(", precedingTrivia As SyntaxTriviaList, followingTrivia As SyntaxTriviaList", StructureTypeName(_parseTree.RootTrivia)) End If For Each field In allFields _writer.Write(", ") GenerateNodeStructureFieldParameter(field) Next For Each child In GetAllChildrenOfStructure(nodeStructure) _writer.Write(", ") GenerateNodeStructureChildParameter(child, Nothing) Next _writer.WriteLine(")") ' Generate call to create new builder, and pass result to my private constructor. _writer.Write(" Me.New(New Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax.{0}(", StructureTypeName(nodeStructure)) ' Generate each of the field parameters _writer.Write("kind", NodeKindType()) _writer.Write(", errors, annotations") If nodeStructure.IsTerminal Then ' nonterminals have text. _writer.Write(", text") End If If nodeStructure.IsToken AndAlso Not nodeStructure.IsTrivia Then ' tokens havetrivia, but only if they are not trivia. _writer.Write(", precedingTrivia.Node, followingTrivia.Node") End If If allFields.Count > 0 Then For i = 0 To allFields.Count - 1 _writer.Write(", {0}", FieldParamName(allFields(i))) Next End If For Each child In GetAllChildrenOfStructure(nodeStructure) If KindTypeStructure(child.ChildKind).IsToken Then _writer.Write(", {0}", ChildParamName(child)) ElseIf child.IsList Then _writer.Write(", if({0} IsNot Nothing, {0}.Green, Nothing)", ChildParamName(child)) Else If child.IsOptional Then ' optional normal child. _writer.Write(", if({0} IsNot Nothing", ChildParamName(child)) End If ' non-optional normal child. _writer.Write(", DirectCast({0}.Green, Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax.{1})", ChildParamName(child), BaseTypeReference(child)) If child.IsOptional Then ' optional normal child. _writer.Write(", Nothing)") End If End If Next _writer.WriteLine("), Nothing, 0)") ' Generate contracts If nodeStructure.IsTerminal Then ' tokens and trivia have a text _writer.WriteLine(" Debug.Assert(text IsNot Nothing)") End If ' Generate End Sub _writer.WriteLine(" End Sub") _writer.WriteLine() End If End Sub ' Generate a parameter corresponding to a node structure field Private Sub GenerateNodeStructureFieldParameter(field As ParseNodeField, Optional conflictName As String = Nothing) _writer.Write("{0} As {1}", FieldParamName(field, conflictName), FieldTypeRef(field)) End Sub ' Generate a parameter corresponding to a node structure child Private Sub GenerateNodeStructureChildParameter(child As ParseNodeChild, Optional conflictName As String = Nothing) _writer.Write("{0} As {1}", ChildParamName(child, conflictName), ChildConstructorTypeRef(child)) End Sub ' Generate a parameter corresponding to a node structure child Private Sub GenerateFactoryChildParameter(node As ParseNodeStructure, child As ParseNodeChild, Optional conflictName As String = Nothing) _writer.Write("{0} As {1}", ChildParamName(child, conflictName), ChildFactoryTypeRef(node, child, False, False)) End Sub ' Get modifiers Private Function GetModifiers(containingStructure As ParseNodeStructure, isOverride As Boolean, name As String) As String ' Is this overridable or an override? Dim modifiers = "" If isOverride Then modifiers = "Overrides " ElseIf containingStructure.HasDerivedStructure Then modifiers = "Overridable " End If ' Put Shadows modifier on if useful. ' Object has Equals and GetType ' root name has members for every kind and structure (factory methods) If (name = "Equals" OrElse name = "GetType") Then ' OrElse _parseTree.NodeKinds.ContainsKey(name) OrElse _parseTree.NodeStructures.ContainsKey(name)) Then modifiers = "Shadows " + modifiers End If Return modifiers End Function ' Generate a public property for a node field Private Sub GenerateNodeFieldProperty(field As ParseNodeField, TypeName As String, isOverride As Boolean) ' XML comment GenerateXmlComment(_writer, field, 8) _writer.WriteLine(" Public {2}ReadOnly Property {0} As {1}", FieldPropertyName(field), FieldTypeRef(field), GetModifiers(field.ContainingStructure, False, field.Name)) _writer.WriteLine(" Get") _writer.WriteLine(" Return DirectCast(Green, Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax.{0}).{1}", TypeName, FieldPropertyName(field)) _writer.WriteLine(" End Get") _writer.WriteLine(" End Property") _writer.WriteLine("") End Sub ' Generate a public property for a child Private Sub GenerateNodeChildProperty(nodeStructure As ParseNodeStructure, child As ParseNodeChild, childIndex As Integer, isOverride As Boolean) ' XML comment GenerateXmlComment(_writer, child, 8) If nodeStructure.HasDerivedStructure Then _writer.WriteLine(" Public ReadOnly Property {0} As {1}", ChildPropertyName(child), ChildPropertyTypeRef(nodeStructure, child)) _writer.WriteLine(" Get") _writer.WriteLine(" Return Me.Get{0}Core()", child.Name, ChildPropertyTypeRef(nodeStructure, child)) _writer.WriteLine(" End Get") _writer.WriteLine(" End Property") _writer.WriteLine("") _writer.WriteLine(" Friend {0}Function Get{1}Core() As {2}", GetModifiers(child.ContainingStructure, isOverride, child.Name), child.Name, ChildPropertyTypeRef(nodeStructure, child, denyOverride:=True)) Me.GenerateNodeChildPropertyRedAccessLogic(nodeStructure, child, childIndex, isOverride, extraIndent:="") _writer.WriteLine(" End Function") _writer.WriteLine() ElseIf isOverride Then _writer.WriteLine(" Public {0}ReadOnly Property {1} As {2}", If(isOverride, "Shadows ", ""), ChildPropertyName(child), ChildPropertyTypeRef(nodeStructure, child)) _writer.WriteLine(" Get") Me.GenerateNodeChildPropertyRedAccessLogic(nodeStructure, child, childIndex, isOverride, extraIndent:=" ") _writer.WriteLine(" End Get") _writer.WriteLine(" End Property") _writer.WriteLine("") _writer.WriteLine(" Friend {0}Function Get{1}Core() As {2}", GetModifiers(child.ContainingStructure, isOverride, child.Name), child.Name, ChildPropertyTypeRef(nodeStructure, child, denyOverride:=True)) _writer.WriteLine(" Return Me.{0}", ChildPropertyName(child), ChildPropertyTypeRef(nodeStructure, child)) _writer.WriteLine(" End Function") _writer.WriteLine() Else _writer.WriteLine(" Public {0}ReadOnly Property {1} As {2}", GetModifiers(child.ContainingStructure, isOverride, child.Name), ChildPropertyName(child), ChildPropertyTypeRef(nodeStructure, child)) _writer.WriteLine(" Get") Me.GenerateNodeChildPropertyRedAccessLogic(nodeStructure, child, childIndex, isOverride, extraIndent:=" ") _writer.WriteLine(" End Get") _writer.WriteLine(" End Property") _writer.WriteLine("") End If End Sub Private Sub GenerateNodeChildPropertyRedAccessLogic(nodeStructure As ParseNodeStructure, child As ParseNodeChild, childIndex As Integer, isOverride As Boolean, extraIndent As String) If KindTypeStructure(child.ChildKind).IsToken Then If child.IsList Then _writer.WriteLine($" {extraIndent}Dim slot = DirectCast(Me.Green, Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax.{{0}}).{{1}}", StructureTypeName(nodeStructure), ChildVarName(child)) _writer.WriteLine($" {extraIndent}If slot IsNot Nothing") _writer.WriteLine($" {extraIndent} return new SyntaxTokenList(Me, slot, {{0}}, {{1}})", Me.GetChildPosition(childIndex), Me.GetChildIndex(childIndex)) _writer.WriteLine($" {extraIndent}End If") _writer.WriteLine($" {extraIndent}Return Nothing") Else If child.IsOptional Then _writer.WriteLine($" {extraIndent}Dim slot = DirectCast(Me.Green, Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax.{{0}}).{{1}}", StructureTypeName(nodeStructure), ChildVarName(child)) _writer.WriteLine($" {extraIndent}If slot IsNot Nothing") _writer.WriteLine($" {extraIndent} return new SyntaxToken(Me, slot, {{0}}, {{1}})", Me.GetChildPosition(childIndex), Me.GetChildIndex(childIndex)) _writer.WriteLine($" {extraIndent}End If") _writer.WriteLine($" {extraIndent}Return Nothing") Else _writer.WriteLine($" {extraIndent}return new SyntaxToken(Me, DirectCast(Me.Green, Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax.{{0}}).{{1}}, {{2}}, {{3}})", StructureTypeName(nodeStructure), ChildVarName(child), Me.GetChildPosition(childIndex), Me.GetChildIndex(childIndex)) End If End If ElseIf IsListStructureType(child) Then If childIndex = 0 Then _writer.WriteLine($" {extraIndent}Dim listNode = GetRedAtZero({{0}})", ChildVarName(child)) Else _writer.WriteLine($" {extraIndent}Dim listNode = GetRed({{0}}, {{1}})", ChildVarName(child), childIndex) End If _writer.WriteLine($" {extraIndent}Return new {{0}}(listNode)", ChildPropertyTypeRef(nodeStructure, child, False)) Else Dim type = ChildPropertyTypeRef(nodeStructure, child) Dim baseType = ChildPropertyTypeRef(nodeStructure, child, denyOverride:=True) If childIndex = 0 Then If type = baseType Then _writer.WriteLine($" {extraIndent}Return GetRedAtZero({{0}})", ChildVarName(child)) Else _writer.WriteLine($" {extraIndent}Return DirectCast(GetRedAtZero({{0}}), {{1}})", ChildVarName(child), type) End If Else If type = baseType Then _writer.WriteLine($" {extraIndent}Return GetRed({{0}}, {{1}})", ChildVarName(child), childIndex) Else _writer.WriteLine($" {extraIndent}Return DirectCast(GetRed({{0}}, {{1}}), {{2}})", ChildVarName(child), childIndex, type) End If End If End If End Sub Private Function GetChildPosition(i As Integer) As String If (i = 0) Then Return "Me.Position" Else Return "Me.GetChildPosition(" & i & ")" End If End Function Private Function GetChildIndex(i As Integer) As String If (i = 0) Then Return "0" Else Return "Me.GetChildIndex(" & i & ")" End If End Function ' Generate a public property for a child Private Sub GenerateNodeWithChildProperty(withChild As ParseNodeChild, childIndex As Integer, nodeStructure As ParseNodeStructure) 'Dim isOverride As Boolean = withChild.ContainingStructure IsNot nodeStructure Dim hasPrevious As Boolean If True Then ' withChild.GenerateWith Then Dim isAbstract As Boolean = _parseTree.IsAbstract(nodeStructure) If isAbstract Then If nodeStructure.Children.Contains(withChild) Then ' +WriteLine($" public {node.Name} With{field.Name}({fieldType} {CamelCase(field.Name)}) => With{field.Name}Core({CamelCase(field.Name)});"); '+ WriteLine($" internal abstract {node.Name} With{field.Name}Core({fieldType} {CamelCase(field.Name)});"); GenerateWithXmlComment(_writer, withChild, 8) _writer.WriteLine($" Public Function {ChildWithFunctionName(withChild)}({ChildParamName(withChild)} As {ChildPropertyTypeRef(nodeStructure, withChild)}) As {StructureTypeName(nodeStructure)}") _writer.WriteLine($" Return {ChildWithFunctionName(withChild)}Core({ChildParamName(withChild)})") _writer.WriteLine($" End Function") _writer.WriteLine($" Friend MustOverride Function {ChildWithFunctionName(withChild)}Core({ChildParamName(withChild)} As {ChildPropertyTypeRef(nodeStructure, withChild)}) As {StructureTypeName(nodeStructure)}") End If Else If Not nodeStructure.Children.Contains(withChild) AndAlso nodeStructure.ParentStructure.Children.Contains(withChild) Then _writer.WriteLine($" Friend Overrides Function {ChildWithFunctionName(withChild)}Core({ChildParamName(withChild)} As {ChildPropertyTypeRef(nodeStructure, withChild)}) As {StructureTypeName(nodeStructure.ParentStructure)}") _writer.WriteLine($" Return {ChildWithFunctionName(withChild)}({ChildParamName(withChild)})") _writer.WriteLine($" End Function") _writer.WriteLine() End If ' XML comment GenerateWithXmlComment(_writer, withChild, 8) _writer.WriteLine(" Public Shadows Function {0}({1} as {2}) As {3}", ChildWithFunctionName(withChild), ChildParamName(withChild), ChildPropertyTypeRef(nodeStructure, withChild), StructureTypeName(nodeStructure)) _writer.Write(" return Update(") If nodeStructure.NodeKinds.Count >= 2 Then _writer.Write("Me.Kind") hasPrevious = True End If Dim allFields = GetAllFieldsOfStructure(nodeStructure) If allFields.Count > 0 Then For i = 0 To allFields.Count - 1 If hasPrevious Then _writer.Write(", ") End If _writer.Write("{0}", FieldParamName(allFields(i))) hasPrevious = True Next End If For Each child In GetAllChildrenOfStructure(nodeStructure) If hasPrevious Then _writer.Write(", ") End If If child Is withChild Then _writer.Write("{0}", ChildParamName(child)) Else _writer.Write("Me.{0}", UpperFirstCharacter(child.Name)) End If hasPrevious = True Next _writer.WriteLine(")") _writer.WriteLine(" End Function") End If _writer.WriteLine("") End If End Sub ' Generate two public properties for a child that is a separated list Private Sub GenerateNodeSeparatedListChildProperty(node As ParseNodeStructure, child As ParseNodeChild, childIndex As Integer, isOverride As Boolean) ' XML comment GenerateXmlComment(_writer, child, 8) _writer.WriteLine(" Public {2}ReadOnly Property {0} As {1}", ChildPropertyName(child), ChildPropertyTypeRef(node, child), GetModifiers(child.ContainingStructure, isOverride, child.Name)) _writer.WriteLine(" Get") If childIndex = 0 Then _writer.WriteLine(" Dim listNode = GetRedAtZero({0})", ChildVarName(child), childIndex) Else _writer.WriteLine(" Dim listNode = GetRed({0}, {1})", ChildVarName(child), childIndex) End If _writer.WriteLine(" If listNode IsNot Nothing") _writer.WriteLine(" Return new {0}(listNode, {1})", ChildPropertyTypeRef(node, child), GetChildIndex(childIndex)) _writer.WriteLine(" End If") _writer.WriteLine(" Return Nothing") _writer.WriteLine(" End Get") _writer.WriteLine(" End Property") _writer.WriteLine("") End Sub Private Sub GenerateAccept(nodeStructure As ParseNodeStructure) If _parseTree.IsAbstract(nodeStructure) Then Return End If _writer.WriteLine(" Public {0} Function Accept(Of TResult)(ByVal visitor As {1}(Of TResult)) As TResult", If(IsRoot(nodeStructure), "Overridable", "Overrides"), _parseTree.VisitorName) _writer.WriteLine(" Return visitor.{0}(Me)", VisitorMethodName(nodeStructure)) _writer.WriteLine(" End Function") _writer.WriteLine() _writer.WriteLine(" Public {0} Sub Accept(ByVal visitor As {1})", If(IsRoot(nodeStructure), "Overridable", "Overrides"), _parseTree.VisitorName) _writer.WriteLine(" visitor.{0}(Me)", VisitorMethodName(nodeStructure)) _writer.WriteLine(" End Sub") _writer.WriteLine() End Sub ' Generate Update method . But only for non terminals Private Sub GenerateUpdate(nodeStructure As ParseNodeStructure) If _parseTree.IsAbstract(nodeStructure) OrElse nodeStructure.IsToken OrElse nodeStructure.IsTrivia Then Return End If Dim structureName = StructureTypeName(nodeStructure) Dim factory = FactoryName(nodeStructure) Dim needComma = False Dim isMultiKind As Boolean = (nodeStructure.NodeKinds.Count >= 2) _writer.WriteLine() GenerateSummaryXmlComment(_writer, String.Format("Returns a copy of this with the specified changes. Returns this instance if there are no actual changes.", nodeStructure.Name)) If isMultiKind Then GenerateParameterXmlComment(_writer, "kind", String.Format("The new kind.", nodeStructure.Name)) End If For Each child In GetAllChildrenOfStructure(nodeStructure) GenerateParameterXmlComment(_writer, LowerFirstCharacter(OptionalChildName(child)), String.Format("The value for the {0} property.", child.Name)) Next _writer.Write(" Public ") If nodeStructure.ParentStructure IsNot Nothing AndAlso Not nodeStructure.ParentStructure.Abstract Then _writer.Write("Shadows ") End If _writer.Write("Function Update(") If isMultiKind Then _writer.Write("kind As SyntaxKind") needComma = True End If For Each child In GetAllChildrenOfStructure(nodeStructure) If needComma Then _writer.Write(", ") End If GenerateFactoryChildParameter(nodeStructure, child, Nothing) needComma = True Next _writer.WriteLine(") As {0}", structureName) needComma = False _writer.Write(" If ") If isMultiKind Then _writer.Write("kind <> Me.Kind") needComma = True End If For Each child In GetAllChildrenOfStructure(nodeStructure) If needComma Then _writer.Write(" OrElse ") End If If child.IsList Then _writer.Write("{0} <> Me.{1}", ChildParamName(child), ChildPropertyName(child)) ElseIf KindTypeStructure(child.ChildKind).IsToken Then _writer.Write("{0} <> Me.{1}", ChildParamName(child), ChildPropertyName(child)) Else _writer.Write("{0} IsNot Me.{1}", ChildParamName(child), ChildPropertyName(child)) End If needComma = True Next _writer.WriteLine(" Then") needComma = False _writer.Write(" Dim newNode = SyntaxFactory.{0}(", factory) If isMultiKind Then _writer.Write("kind, ") End If For Each child In GetAllChildrenOfStructure(nodeStructure) If needComma Then _writer.Write(", ") End If _writer.Write("{0}", ChildParamName(child)) needComma = True Next _writer.WriteLine(")") _writer.WriteLine(" Dim annotations = Me.GetAnnotations()") _writer.WriteLine(" If annotations IsNot Nothing AndAlso annotations.Length > 0") _writer.WriteLine(" return newNode.WithAnnotations(annotations)") _writer.WriteLine(" End If") _writer.WriteLine(" Return newNode") _writer.WriteLine(" End If") _writer.WriteLine(" Return Me") _writer.WriteLine(" End Function") _writer.WriteLine() End Sub ' Generate special methods and properties for the root node. These only appear in the root node. Private Sub GenerateRootNodeSpecialMethods(nodeStructure As ParseNodeStructure) _writer.WriteLine() End Sub ' Generate GetChild, GetChildrenCount so members can be accessed by index Private Sub GenerateGetNodeSlot(nodeStructure As ParseNodeStructure, allChildren As List(Of ParseNodeChild)) If _parseTree.IsAbstract(nodeStructure) OrElse nodeStructure.IsToken Then Return End If Dim childrenCount = allChildren.Count If childrenCount = 0 Then Return End If _writer.WriteLine(" Friend Overrides Function GetNodeSlot(i as Integer) as SyntaxNode") ' Create the property accessor for each of the children Dim children = allChildren If childrenCount <> 1 Then _writer.WriteLine(" Select case i") For i = 0 To childrenCount - 1 Dim child = children(i) If KindTypeStructure(child.ChildKind).IsToken Then Continue For End If _writer.WriteLine(" Case {0}", i) If child.IsList Then If i = 0 Then _writer.WriteLine(" Return GetRedAtZero({0})", ChildVarName(child)) Else _writer.WriteLine(" Return GetRed({0}, {1})", ChildVarName(child), i) End If Else _writer.WriteLine(" Return Me.{0}", ChildPropertyName(child)) End If Next _writer.WriteLine(" Case Else") _writer.WriteLine(" Return Nothing") _writer.WriteLine(" End Select") ElseIf Not KindTypeStructure(children(0).ChildKind).IsToken Then _writer.WriteLine(" If i = 0 Then") Dim child = children(0) If child.IsList Then _writer.WriteLine(" Return GetRedAtZero({0})", ChildVarName(child)) Else _writer.WriteLine(" Return Me.{0}", ChildPropertyName(child)) End If _writer.WriteLine(" Else") _writer.WriteLine(" Return Nothing") _writer.WriteLine(" End If") Else _writer.WriteLine(" Return Nothing") End If _writer.WriteLine(" End Function") _writer.WriteLine() End Sub ' Generate GetChild, GetChildrenCount so members can be accessed by index Private Sub GenerateGetCachedSlot(nodeStructure As ParseNodeStructure, allChildren As List(Of ParseNodeChild)) If _parseTree.IsAbstract(nodeStructure) OrElse nodeStructure.IsToken Then Return End If Dim childrenCount = allChildren.Count If childrenCount = 0 Then Return End If _writer.WriteLine(" Friend Overrides Function GetCachedSlot(i as Integer) as SyntaxNode") ' Create the property accessor for each of the children Dim children = allChildren If childrenCount <> 1 Then _writer.WriteLine(" Select case i") For i = 0 To childrenCount - 1 Dim child = children(i) If Not KindTypeStructure(child.ChildKind).IsToken Then _writer.WriteLine(" Case {0}", i) _writer.WriteLine(" Return Me.{0}", ChildVarName(child), i) End If Next _writer.WriteLine(" Case Else") _writer.WriteLine(" Return Nothing") _writer.WriteLine(" End Select") Else _writer.WriteLine(" If i = 0 Then") Dim child = children(0) If KindTypeStructure(child.ChildKind).IsToken Then _writer.WriteLine(" Return Nothing") Else _writer.WriteLine(" Return Me.{0}", ChildVarName(child)) End If _writer.WriteLine(" Else") _writer.WriteLine(" Return Nothing") _writer.WriteLine(" End If") End If _writer.WriteLine(" End Function") _writer.WriteLine() End Sub ' Generate the Visitor class definition Private Sub GenerateVisitorClass(withResult As Boolean) _writer.WriteLine(" Public MustInherit Class {0}{1}", Ident(_parseTree.VisitorName), If(withResult, "(Of TResult)", "")) For Each nodeStructure In _parseTree.NodeStructures.Values If Not nodeStructure.Abstract Then GenerateVisitorMethod(nodeStructure, withResult) End If Next _writer.WriteLine(" End Class") _writer.WriteLine() End Sub ' Generate a method in the Visitor class Private Sub GenerateVisitorMethod(nodeStructure As ParseNodeStructure, withResult As Boolean) If nodeStructure.IsToken OrElse nodeStructure.IsTrivia Then Return End If _writer.WriteLine(" Public Overridable {2} {0}(ByVal node As {1}){3}", VisitorMethodName(nodeStructure), StructureTypeName(nodeStructure), If(withResult, "Function", "Sub"), If(withResult, " As TResult", "")) _writer.WriteLine(" {0}Me.DefaultVisit(node){1}", If(withResult, "Return ", ""), If(withResult, "", " : Return")) _writer.WriteLine(" End {0}", If(withResult, "Function", "Sub")) End Sub ' Generate the RewriteVisitor class definition Private Sub GenerateRewriteVisitorClass() _writer.WriteLine(" Public MustInherit Class {0}", Ident(_parseTree.RewriteVisitorName)) _writer.WriteLine(" Inherits {0}(Of SyntaxNode)", Ident(_parseTree.VisitorName)) _writer.WriteLine() For Each nodeStructure In _parseTree.NodeStructures.Values GenerateRewriteVisitorMethod(nodeStructure) Next _writer.WriteLine(" End Class") _writer.WriteLine() End Sub ' Generate a method in the RewriteVisitor class Private Sub GenerateRewriteVisitorMethod(nodeStructure As ParseNodeStructure) If nodeStructure.IsToken OrElse nodeStructure.IsTrivia Then Return End If If nodeStructure.Abstract Then ' do nothing for abstract nodes Return End If Dim methodName = VisitorMethodName(nodeStructure) Dim structureName = StructureTypeName(nodeStructure) _writer.WriteLine(" Public Overrides Function {0}(ByVal node As {1}) As SyntaxNode", methodName, structureName) ' non-abstract non-terminals need to rewrite their children and recreate as needed. Dim allFields = GetAllFieldsOfStructure(nodeStructure) Dim allChildren = GetAllChildrenOfStructure(nodeStructure) ' create anyChanges variable _writer.WriteLine(" Dim anyChanges As Boolean = False") _writer.WriteLine() ' visit all children For i = 0 To allChildren.Count - 1 Dim child = allChildren(i) If child.IsList Then _writer.WriteLine(" Dim {0} = VisitList(node.{1})", ChildNewVarName(child), ChildPropertyName(child)) If KindTypeStructure(child.ChildKind).IsToken Then _writer.WriteLine(" If node.{0}.Node IsNot {1}.Node Then anyChanges = True", ChildPropertyName(child), ChildNewVarName(child)) Else _writer.WriteLine(" If node.{0} IsNot {1}.Node Then anyChanges = True", ChildVarName(child), ChildNewVarName(child)) End If ElseIf KindTypeStructure(child.ChildKind).IsToken Then _writer.WriteLine(" Dim {0} = DirectCast(VisitToken(node.{2}).Node, {3})" + Environment.NewLine + " If node.{2}.Node IsNot {0} Then anyChanges = True", ChildNewVarName(child), BaseTypeReference(child), ChildPropertyName(child), ChildConstructorTypeRef(child)) Else _writer.WriteLine(" Dim {0} = DirectCast(Visit(node.{2}), {1})" + Environment.NewLine + " If node.{2} IsNot {0} Then anyChanges = True", ChildNewVarName(child), ChildPropertyTypeRef(nodeStructure, child), ChildPropertyName(child)) End If Next _writer.WriteLine() ' check if any changes. _writer.WriteLine(" If anyChanges Then") _writer.Write(" Return New {0}(node.Kind", StructureTypeName(nodeStructure)) _writer.Write(", node.Green.GetDiagnostics, node.Green.GetAnnotations") For Each field In allFields _writer.Write(", node.{0}", FieldPropertyName(field)) Next For Each child In allChildren If child.IsList Then If KindTypeStructure(child.ChildKind).IsToken Then _writer.Write(", {0}.Node", ChildNewVarName(child)) Else _writer.Write(", {0}.Node", ChildNewVarName(child)) End If ElseIf KindTypeStructure(child.ChildKind).IsToken Then _writer.Write(", {0}", ChildNewVarName(child), ChildFieldTypeRef(child)) Else _writer.Write(", {0}", ChildNewVarName(child)) End If Next _writer.WriteLine(")") _writer.WriteLine(" Else") _writer.WriteLine(" Return node") _writer.WriteLine(" End If") _writer.WriteLine(" End Function") _writer.WriteLine() End Sub End Class