Roslyn SyntaxNodes yeniden kullanılıyor mu?


124

Roslyn CTP'ye bir göz atıyorum ve İfade ağacı API'sine benzer bir sorunu çözerken her ikisi de değişmez, ancak Roslyn bunu oldukça farklı bir şekilde yapıyor:

  • Expressiondüğümlerin ana düğüme referansı yoktur, a kullanılarak değiştirilir ExpressionVisitorve bu nedenle büyük parçalar yeniden kullanılabilir.

  • Roslyn'in SyntaxNodediğer tarafta ebeveynine bir referansı vardır, bu nedenle tüm düğümler etkili bir şekilde yeniden kullanılması imkansız bir blok haline gelir. Yöntemler gibi Update, ReplaceNodevb, modifikasyonları yapmak için temin edilmiştir.

Bu nerede bitiyor? Document? Project? ISolution? API, ağacın adım adım değiştirilmesini teşvik eder (düğme yukarı yerine), ancak her adım tam bir kopya oluşturur mu?

Neden böyle bir seçim yaptılar? Kaçırdığım ilginç bir numara var mı?

Yanıtlar:


181

GÜNCELLEME: Bu soru blogumun 8 Haziran 2012 tarihli konusuydu . Bu mükemmel soru için teşekkürler!


Harika soru. Ortaya koyduğunuz konuları çok uzun süre tartıştık.

Aşağıdaki özelliklere sahip bir veri yapısına sahip olmak istiyoruz:

  • Immutable.
  • Bir ağacın şekli.
  • Alt düğümlerden üst düğümlere ucuz erişim.
  • Ağaçtaki bir düğümden metindeki bir karakter ofsetine eşlemek mümkündür.
  • Kalıcı .

By kalıcılık I yeteneği anlamına ağacında mevcut düğümlerin çoğunu yeniden bir düzenleme metin tamponuna yapıldığında. Düğümler değişmez olduğundan, onları yeniden kullanmanın önünde bir engel yoktur. Performans için buna ihtiyacımız var; Bir tuşa her bastığınızda dosyanın büyük kısımlarını yeniden ayrıştıramayız. Ağacın yalnızca düzenlemeden etkilenen kısımlarını yeniden tanımlamalı ve yeniden ayrıştırmalıyız.

Şimdi bunların beşini tek bir veri yapısına koymaya çalıştığınızda hemen sorunlarla karşılaşırsınız:

  • İlk etapta nasıl bir düğüm oluşturursunuz? Ebeveyn ve çocuk, her ikisi de birbirlerine atıfta bulunur ve değişmezdir, öyleyse hangisi önce inşa edilir?
  • Bu sorunu çözmeyi başardığınızı varsayarsak: nasıl kalıcı hale getirirsiniz? Bir alt düğümü farklı bir ebeveynde yeniden kullanamazsınız çünkü bu, çocuğa yeni bir ebeveyni olduğunu söylemeyi içerir. Ancak çocuk değişmezdir.
  • Bu sorunu çözmeyi başardığınızı varsayarsak: düzenleme arabelleğine yeni bir karakter eklediğinizde, o noktadan sonra bir konuma eşlenen her düğümün mutlak konumu değişir. Bu, kalıcı bir veri yapısı oluşturmayı çok zorlaştırır, çünkü herhangi bir düzenleme, düğümlerin çoğunun kapsamını değiştirebilir!

Ancak Roslyn ekibinde rutin olarak imkansız şeyler yapıyoruz. Aslında imkansız olanı iki ayrıştırma ağacını tutarak yapıyoruz . "Yeşil" ağaç değişmez, kalıcıdır, üst referansları yoktur, "aşağıdan yukarıya" oluşturulmuştur ve her düğüm genişliğini izler ancak mutlak konumunu takip etmez . Bir düzenleme gerçekleştiğinde, yeşil ağacın yalnızca düzenlemeden etkilenen kısımlarını yeniden oluştururuz, bu tipik olarak ağaçtaki toplam ayrıştırma düğümlerinin yaklaşık O (log n) kadarıdır.

"Kırmızı" ağaç bir değişmez cephe yeşil ağacın etrafında inşa edilmiştir; istek üzerine "yukarıdan aşağıya" oluşturulur ve her düzenlemede atılır. Siz ağaçtan yukarıdan aşağıya inerken talep üzerine bunları üreterek ana referansları hesaplar . Siz aşağı indikçe yine genişliklerden hesaplayarak mutlak konumları üretir.

Siz, kullanıcı, yalnızca kırmızı ağacı görürsünüz; yeşil ağaç bir uygulama detayıdır. Bir ayrıştırma düğümünün dahili durumuna bakarsanız, aslında orada farklı türde başka bir ayrıştırma düğümüne bir referans olduğunu görürsünüz ; bu yeşil ağaç düğümüdür.

Bu arada, bunlara "kırmızı / yeşil ağaçlar" denir çünkü bunlar, tasarım toplantısında veri yapısını çizmek için kullandığımız beyaz tahta kalemi renkleriydi. Renklerin başka bir anlamı yok.

Bu stratejinin yararı, tüm bu harika şeyleri elde etmemizdir: değişmezlik, kalıcılık, ebeveyn referansları vb. Maliyet, bu sistemin karmaşık olması ve "kırmızı" cepheler büyürse çok fazla bellek tüketebilmesidir. Şu anda, bazı maliyetleri, faydalarını kaybetmeden düşürüp azaltamayacağımızı görmek için deneyler yapıyoruz.


3
Ve sorunuzun IProjects ve IDocuments ile ilgili kısmını ele almak için: hizmetler katmanında benzer bir model kullanıyoruz. Dahili olarak, sözdizimi ağacının yeşil düğümlerine ahlaki açıdan eşdeğer olan "DocumentState" ve "ProjectState" türleri vardır. Aldığınız IProject / IDocument nesneleri, bunların kırmızı düğüm cepheleridir. Bir derleyicide Roslyn.Services.Project uygulamasına bakarsanız, neredeyse tüm çağrıların dahili durum nesnelerine yönlendirildiğini görürsünüz.
Jason Malinowski

@Eric yorum için üzgünüm ama kendinizle çelişiyorsunuz. The expense and difficulty of building a complex persistent data structure doesn't pay for itself.ref: stackoverflow.com/questions/6742923/… Eğer yüksek performans hedefleriniz varsa, neden ilk etapta onu değiştirilemez hale getirdiniz? Bariz olanlardan başka bir sebep var mı? örneğin konuların güvenli olmasını sağlamak, akıl
Lukasz Madon

2
@lukas Bu alıntıyı bağlamdan çıkarıyorsun. Önceki cümle "Çünkü .NET programlarında tipik olarak dizeler üzerinde yapılan işlemlere baktığınızda, tamamen yeni bir dizge yapmak her yönden hiç de kötü değildir." OTOH, tipik olarak bir ifade ağacında yapılan işlemlere baktığınızda - örneğin, kaynak dosyaya birkaç karakter yazmak - tamamen yeni bir ifade ağacı oluşturmak önemli ölçüde daha kötüdür. Yani sadece yarısını inşa ediyorlar.
Timbo

1
@lukas Tahminim: Roslyn'in arka plan iş parçacıkları üzerinde çalışması gerektiği düşünüldüğünde, değişmezlik birden çok iş parçacığının aynı kaynak kodunu aynı anda, kullanıcı bir tuşa bastığında değişeceğinden endişe etmeden analiz etmesine izin veriyor. Kullanıcı girdisine yanıt olarak, değişmez ağaçlar, çalışan analiz görevlerini durdurmadan güncellenebilir. Bu yüzden, değişmezliğin ana amacının Roslyn'i yazmayı kolaylaştırmak (ve belki de müşterilerin kullanması için daha kolay) yapmak olduğunu hayal ediyorum.
Qwertie

3
@lukas Kalıcı veri yapıları, veri yapısı tipik olarak değişikliklerden çok daha büyük olduğunda kopyalamadan daha verimlidir. Demek istediğin, eğer varsa, benim için kaybolur.
Qwertie
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.