Derinlemesine yazılım eğitimleri için kanalımı takip edebilirsiniz...

Roslyn Syntax Tree API’sine Göz Atalım

Merhaba,

Bu makalemizde .NET Framework Compiler’ının derinlerine ulaşmamızı sağlayan Roslyn yapısındaki Syntax Tree API’sine değineceğiz.

.NET çatısı altında hangi dilde olursa olsun yazdığımız kodlar öncelikle derleyici tarafından ayrıştırılır(parse) ardından bu işlem neticesinde Syntax Tree(Sözdizimi Ağacı) oluşur. Bu ağaç içerisinde, yazmış olduğumuz kodla ilgili tüm bilgiler hiyerarşik bir vaziyette tutulacaktır.

Roslyn Syntax Tree API'sine Göz Atalım

Yukarıdaki görüntüyü incelersek eğer görüldüğü gibi komutlar arasına yazdığımız her şey bir anlam ifade etmektedir. Haliyle bu anlamları izah edebilmek için karşımıza Syntax Node, Syntax Token ve Syntax Trivia terimleri gelmektedir.

  • Syntax Node
    Kod içerisindeki yapıları ifade ederler. Class yapısı, metod yapısı, değişken yapısı vs… Roslyn’da her yapıya özel bir SyntaxNode sınıfı mevcuttur.
  • Syntax Token
    Kod içerisindeki komutları ifade eder.
  • Syntax Trivia(Önemsiz Şeyler – Ivır Zıvır)
    Kod içerisindeki yorumlar, boşluklar ve yapı isimleridir. Doğal olarak Syntax Trivia’lar, Syntax Token’lara bağlıdırlar. Her Syntax Token’da bulunan LeadingTrivia ve TrailingTrivia koleksiyonları aracılığıyla ilgili Token’a bağlı Trivia’lara erişilebilir.

Roslyn Syntax Tree API’sini kullanabilmek için Microsoft.CodeAnalysis Nuget paketini projeye entegre etmeniz gerekmektedir.

Install-Package Microsoft.CodeAnalysis -Version 1.2.1

Eğer yukarıdaki kod çalışmazsa çalışır halini buradan bulabilirsiniz.

Şimdi Microsoft.CodeAnalysis’in entegrasyonunu varsayarak, örnek bir kodun Syntax Tree’sini çıkaralım. Tabi bu işlemler için çalışırken ilgili kod sayfasına ‘Microsoft.CodeAnalysis.CSharp‘ ve ‘Microsoft.CodeAnalysis‘ kütüphanelerini using ettiğimize dikkatinizi çekerim.

using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis;

namespace RoslynSyntaxTree
{
    class Program
    {
        static void Main(string[] args)
        {
            SyntaxTree Tree = CSharpSyntaxTree.ParseText
                            (@"class OrnekClass
                                {
                                    public int OrnekProperty { get; set; }
                                    public void OrnekMetod()
                                    {

                                    }
                                    public void OrnekMetod(int x)
                                    {

                                    }

                                    public void OrnekMetod2()
                                    {

                                    }
                                }");
        }
    }
}

Yukarıdaki gördüğünüz gibi CSharpSyntaxTree.ParseText metodu içerisine verilen komutların Syntax Tree’sini verecektir.

Elde ettiğimiz bu Syntax Tree sayesinde istediğimiz elemanlara ulaşabilmekteyiz. Tabi burada ağaç üzerinden elemanlara erişebileceğimiz için öncelikle ağacın ilk elemanı olan root’a ulaşmamız gerekmektedir.

        static void Main(string[] args)
        {
            SyntaxTree Tree = CSharpSyntaxTree.ParseText
                            (@"class OrnekClass
                                {
                                    public int OrnekProperty { get; set; }
                                    public void OrnekMetod()
                                    {

                                    }
                                    public void OrnekMetod(int x)
                                    {

                                    }

                                    public void OrnekMetod2()
                                    {

                                    }
                                }");

            SyntaxNode Root = Tree.GetRoot();
        }

Evet, root elemanına ulaştıktan sonra bu root üzerinden diğer tüm elemanlara rahatça ulaşabiliriz.

        static void Main(string[] args)
        {
            SyntaxTree Tree = CSharpSyntaxTree.ParseText
                            (@"class OrnekClass
                                {
                                    public int OrnekProperty { get; set; }
                                    public void OrnekMetod()
                                    {

                                    }
                                    public void OrnekMetod(int x)
                                    {

                                    }

                                    public void OrnekMetod2()
                                    {

                                    }
                                }");

            SyntaxNode Root = Tree.GetRoot();
            var Methods = Root.DescendantNodes().OfType<MethodDeclarationSyntax>();
            var Propertys = Root.DescendantNodes().OfType<PropertyDeclarationSyntax>();
            Console.WriteLine("Methods...");
            foreach (var Method in Methods)
            {
                Console.WriteLine(Method.ToString());
            }
            Console.WriteLine("*********\nPropertys...");
            foreach (var Property in Propertys)
            {
                Console.WriteLine(Property.ToString());
            }


            Console.Read();
        }

Yukarıdaki örnek kodu derleyip çalıştırdığımız zaman aşağıdaki sonucu vermektedir.
Roslyn Syntax Tree API'sine Göz Atalım
Bunların yanında elemanlara filtre uygulayabilir söz gelimi sadece parametresiz metodlara ulaşabiliriz.

.
.
.
            SyntaxNode Root = Tree.GetRoot();
            var Methods = Root.DescendantNodes().OfType<MethodDeclarationSyntax>().Where(m => !m.ParameterList.Parameters.Any());
            Console.WriteLine("Methods...");
            foreach (var Method in Methods)
            {
                Console.WriteLine(Method.ToString());
            }
.
.
.

Roslyn Syntax Tree API'sine Göz Atalım

Yukarıdaki örneklendirmelerimizde metodlar için ‘MethodDeclarationSyntax‘ tipini, propertyler içinse ‘PropertyDeclarationSyntax‘ tipini kullandık. Örneklendirmede olan elemanlarla vermediğimiz diğer elemanlar için bu tarz tipleri nereden biliyorsun(bileceğim) diye sorarsanız eğer Syntax Visualizer isimli araçtan işimizi görmektedir.

Syntax Visualizer aracını Visual Studio platformunda kullanabilmek için .NET Compiler Platform SDK’sını yüklememiz gerekmektedir. (Bu işlem için buraya tıklayarak ilgili SDK’yı indirip, kurabilirsiniz.)

Yükleme işlemini yaptıktan sonra “View” -> “Other Windows” -> “Syntax Visualizer” kombinasyonuyla ilgili pencereyi açabilirsiniz.
Syntax Visualizer

Aşağıdaki videoda da gördüğünüz gibi Syntax Visualizer aracı sayesinde üzerine tıkladığımız yapının hangi tipten temsil edildiğini ve bunun dışında içinde hangi özelliklerin barındığınıda net bir şekilde analiz etmekteyiz.

Bu yazımızında sonuna gelmiş bulunmaktayız. Okuduğunuz için teşekkür ederim…
Sonraki yazılarımda görüşmek üzere…
İyi çalışmalar…

Bunlar da hoşunuza gidebilir...

1 Cevap

  1. 14 Temmuz 2016

    […] Önceki yazılarımdan Roslyn Syntax Tree API’sine Göz Atalım başlıklı yazımda SyntaxTree sınıfı ile Syntax Tree üzerinde gezinmiştik. Bu içeriğimizde […]

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

*