File: RedNodes\SyntaxFactsWriter.vb
Web Access
Project: src\src\Tools\Source\CompilerGeneratorTools\Source\VisualBasicSyntaxGenerator\VisualBasicSyntaxGenerator.vbproj (VisualBasicSyntaxGenerator)
' 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.
 
'-----------------------------------------------------------------------------------------------------------
' This is the code that actually outputs the VB code that defines the tree. It is passed a read and validated
' ParseTree, and outputs the code to defined the node classes for that tree, and also additional data
' structures like the kinds, visitor, etc.
'-----------------------------------------------------------------------------------------------------------
 
Imports System.IO
 
' Class to write out the code for the code tree.
Public Class SyntaxFactsWriter
    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 factory class to the given file.
    Public Sub GenerateFile(writer As TextWriter)
 
        _writer = writer
 
        _writer.WriteLine()
        _writer.WriteLine("Namespace {0}", Ident(_parseTree.NamespaceName))
        _writer.WriteLine()
 
        _writer.WriteLine("    Partial Public Class SyntaxFacts")
        GenerateAllFactoryMethods()
        _writer.WriteLine("    End Class")
        _writer.WriteLine()
 
        _writer.WriteLine("    Public Module GeneratedExtensionSyntaxFacts")
        GenerateAllExtensionFactoryMethods()
        _writer.WriteLine("    End Module")
 
        _writer.WriteLine()
        _writer.WriteLine("End Namespace")
 
    End Sub
 
    Public Sub GenerateGetText(writer As TextWriter)
 
        _writer = writer
 
        _writer.WriteLine()
        _writer.WriteLine("Namespace {0}", Ident(_parseTree.NamespaceName))
        _writer.WriteLine("    Partial Public Class SyntaxFacts")
        GenerateGetText()
        _writer.WriteLine("    End Class")
        _writer.WriteLine("End Namespace")
 
    End Sub
 
    ' Generate all factory methods for all node structures.
    Private Sub GenerateAllFactoryMethods()
        For Each nodeStructure In _parseTree.NodeStructures.Values
            GenerateFactoryMethodsForStructure(nodeStructure)
        Next
 
        GenerateGetText()
    End Sub
 
    Private Sub GenerateAllExtensionFactoryMethods()
        GenerateExtensionGetText()
    End Sub
 
    Private Sub GenerateGetText()
 
        _writer.WriteLine("        ''' <summary>")
        _writer.WriteLine("        ''' Return keyword or punctuation text based on SyntaxKind")
        _writer.WriteLine("        ''' </summary>")
        _writer.WriteLine("        Public Shared Function GetText(kind As SyntaxKind) As String")
        _writer.WriteLine("            Select Case kind")
 
        For Each nodeStructure In _parseTree.NodeStructures.Values
            For Each kind In nodeStructure.NodeKinds
                Dim tokenText = kind.TokenText
 
                If tokenText IsNot Nothing AndAlso tokenText.Contains("""") Then
                    tokenText = tokenText.Replace("""", """""")
                End If
 
                If tokenText IsNot Nothing AndAlso tokenText.Contains(vbCrLf) Then
                    tokenText = tokenText.Replace(vbCrLf, Environment.NewLine)
                End If
 
                If tokenText <> Nothing Then
                    _writer.WriteLine("                Case SyntaxKind.{0}", kind.Name)
 
                    If tokenText.Contains("vbCrLf") Then
                        _writer.WriteLine("                    Return {0}", tokenText)
                    Else
                        _writer.WriteLine("                    Return ""{0}""", tokenText)
                    End If
                End If
            Next
        Next
 
        _writer.WriteLine("                Case Else")
        _writer.WriteLine("                    Return String.Empty")
        _writer.WriteLine("            End Select")
        _writer.WriteLine("        End Function")
 
    End Sub
 
    Private Sub GenerateExtensionGetText()
 
        _writer.WriteLine("        ''' <summary>")
        _writer.WriteLine("        ''' Return keyword or punctuation text based on SyntaxKind")
        _writer.WriteLine("        ''' </summary>")
        _writer.WriteLine("        <Extension()>")
        _writer.WriteLine("        Public Function GetText(kind As SyntaxKind) As String")
        _writer.WriteLine("            Return SyntaxFacts.GetText(kind)")
        _writer.WriteLine("        End Function")
 
    End Sub
 
    ' Generate all factory methods for a node structure.
    ' If a nodeStructure has 0 kinds, it is abstract and no factory method is generator
    ' If a nodeStructure has 1 kind, a factory method for that kind is generator
    ' If a nodestructure has >=2 kinds, a factory method for each kind is generated, plus one for the structure as a whole, unless name would conflict.
    Private Sub GenerateFactoryMethodsForStructure(nodeStructure As ParseNodeStructure)
        If _parseTree.IsAbstract(nodeStructure) Then Return ' abstract structures don't have factory methods
 
        GenerateSyntaxFacts(nodeStructure)
 
    End Sub
 
    ' Generate the factory method for a node structure, possibly customized to a particular kind.
    ' If kind is Nothing, generate a factory method that takes a Kind parameter, and can create any kind.
    ' If kind is not Nothing, generator a factory method customized to that particular kind.
    Private Sub GenerateSyntaxFacts(nodeStructure As ParseNodeStructure)
        'GenerateSyntaxFact(nodeStructure.Name, nodeStructure.NodeKinds)
        GenerateSyntaxFact(SyntaxFactName(nodeStructure), nodeStructure.NodeKinds, Not nodeStructure.InternalSyntaxFacts)
 
        For Each child In GetAllChildrenOfStructure(nodeStructure)
            Dim kinds = child.ChildKind(nodeStructure.NodeKinds)
            Dim childKindStruct = KindTypeStructure(child.ChildKind)
            If kinds IsNot Nothing AndAlso childKindStruct.IsToken AndAlso Not child.IsList Then
                GenerateSyntaxFact(FactoryName(nodeStructure) + child.Name, kinds, Not child.InternalSyntaxFacts)
            End If
        Next
    End Sub
 
    ' Generate the factory method for a node structure, possibly customized to a particular kind.
    ' If kind is Nothing, generate a factory method that takes a Kind parameter, and can create any kind.
    ' If kind is not Nothing, generator a factory method customized to that particular kind.
    ' The simplified form is:
    '   Defaults the text for any token with token-text defined
    '   Defaults the trivia to a single trailing space for any token
    Private Sub GenerateSyntaxFact(name As String, nodeKinds As IList(Of ParseNodeKind), Optional publicAccessibility As Boolean = True)
 
        'Dim factoryFunctionName As String       ' name of the factory method.
        Dim needComma = False
        If nodeKinds.Count >= 2 Then
 
            _writer.WriteLine("        {1} Shared Function Is{0}(kind As SyntaxKind) As Boolean", name, If(publicAccessibility, "Public", "Friend"))
            _writer.WriteLine("            Select Case kind")
 
            _writer.WriteLine("                Case _")
            For Each kind In nodeKinds
                If needComma Then
                    _writer.WriteLine(",")
                End If
                _writer.Write("                SyntaxKind.{0}", kind.Name)
                needComma = True
            Next
            _writer.WriteLine()
            _writer.WriteLine("                    Return True")
 
            _writer.WriteLine("            End Select")
            _writer.WriteLine("            Return False")
            _writer.WriteLine("        End Function")
            _writer.WriteLine()
        End If
 
    End Sub
 
End Class