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