· 3 dk okuma
AST olmadan GDScript karmaşıklığını ölçmek
yazan: Furkan Durna · Proje: gdmetrics
#godot #gdscript #tooling
Godot projeleri de diğer codebase'lerle aynı şekilde büyüyor: birkaç fonksiyon sessizce kimsenin dokunmak istemediği fonksiyonlara dönüşüyor. gdmetrics, her GDScript fonksiyonunu ölçen ve önce neyin refactor edilmesi gerektiğini sıralayan bir editör eklentisi ve komut satırı aracı. Script'leri yalnızca okuyor, asla değiştirmiyor.
Ödünç alınacak bir parser yok
Çoğu karmaşıklık aracı bir soyut sözdizimi ağacı (AST) üzerinde dolaşır. Godot eklentilere böyle bir şey sunmuyor; bu yüzden gdmetrics'in GDScript ile yazılmış kendi tokenizer'ı var. Dosyaları regular expression kullanmadan satır satır okuyor ve keyword'ler, identifier'lar, operatörler, string'ler ve yorumlar üretiyor.
Bunun üzerinde birkaç küçük aşama çalışıyor:
- Fonksiyonlar
func,static funcya dasignalile başlıyor ve girinti kendi seviyelerine döndüğünde bitiyor. - Kontrol akışı, girinti, bloklar ve lambda'lar için stack'lerle takip ediliyor; iç içe geçme derinliği, girinti stack'inin boyutu.
- Cyclomatic complexity 1'den başlıyor ve her
if,elif,for,while,match, match kolu ve ternary için bir puan ekliyor; etkinleştirildiğinde mantıksal operatörler için de. - Cognitive complexity çoğu yapı için 1 artı mevcut iç içe geçme derinliği kadar ekliyor; yani aynı
ifne kadar derinde olursa o kadar pahalıya geliyor. Lambda'lar sabit bir puan tutuyor ve gövdeleri, onları içeren fonksiyonun hesabına katılmıyor.
Cognitive puan, yayımlanmış cognitive complexity fikrini model alıyor ama kendi tercihlerini yapıyor. Örneğin kontrol akışı içindeki erken return, break ve continue bir puan ekliyor.
İşin büyük kısmı edge case'lerdi
Gerçek bir parser'ı olmayan, girintiye dayalı bir dilin keskin köşeleri var:
- Ternary mi, statement mı?
x if cond else yile statement olanifaynı keyword'ü kullanıyor. Satırdaif'ten önce herhangi bir token varsa, bu bir ternary. - Match kollarının keyword'ü yok. Bir kol,
matchaltındaki ilk girinti seviyesinde bulunan ve en üst seviyede iki nokta içeren bir satır. Pattern'lerdeki virgüller vewhenguard'ları yalnızca parantezlerin dışında sayılıyor;text.match(...)ise öncesinde bir nokta olduğu için reddediliyor. - Satır devamları. Sondaki bir ters eğik çizgi satırları birleştiriyor; ardından boş satırlar ya da yorum satırları gelse bile. Bu, Godot parser'ının bilinen bir davranışıyla örtüşüyor.
- String'ler. Çok satırlı string'ler, raw string'ler ve
&"...",^"..."ve@"..."literal biçimleri destekleniyor; dosyanın başındaki byte-order mark da temizleniyor. - Karışık tab ve boşluklar girintiyi belirsiz hâle getiriyor. Bu satırlar tahmin edilmek yerine işaretleniyor.
Her edge case'in bir fixture dosyası ve beklenen bir JSON sonucu var; headless bir test ikisini karşılaştırıyor.
Editörde
Dock'ta tek bir ana buton var: Find what to fix. Sonuçlar üç listede geliyor: öncelikli düzeltmeler, en büyük dosyalar ve hepsi. Her fonksiyon, yapılandırılabilir eşiklere göre sade bir etiket alıyor (OK, Hard to read, Fix soon). Bir satıra çift tıklamak, script'i o satırda açıyor.
Birkaç ek özellik sıralamayı daha kullanışlı hâle getiriyor:
- Yakın zamanda git'te sık değişen dosyalar işaretleniyor, çünkü sık değişen karmaşık kod pahalıya patlayan türden koddur.
- Yorum direktifleri bir fonksiyonu yok sayabiliyor ya da görünür kalması için sabitleyebiliyor.
- Başarısızlık eşiğini aşan fonksiyonlar script editöründe işaretlenebiliyor; bu özellik config dosyasından açılıyor.
CI'da
Aynı analiz komut satırından headless olarak çalışıyor. JSON, CSV ve HTML raporları yazıyor, her çalıştırmada bir geçmiş dosyasına bir satır ekliyor ve regression'ları yakalamak için bir baseline ile karşılaştırma yapabiliyor. Exit code'lar basit:
- 0: her şey eşiklerin içinde.
- 1: bir fonksiyon başarısızlık eşiğini aştı ya da diff geriledi.
- 2: aracın kendisi başarısız oldu. Ayrıca
project.godotgibi korunan dosyaların üzerine yazmayı reddediyor.
Bir GitHub Actions şablonu Godot'yu kuruyor, kontrolü çalıştırıyor ve raporları yüklüyor.
İki sürüm, tek çekirdek
Godot 3 ve 4 birbirinden, tek bir eklentinin ikisine birden hizmet edemeyeceği kadar farklı. Analiz çekirdeği Godot 4 sürümünde duruyor ve bir sync script'iyle Godot 3 sürümüne kopyalanıyor; tokenizer ve arayüz ise her sürüm için ayrı kalıyor. Godot 3 küçük geçici çözümler gerektirdi: ilk 3.x sürümleri quit(code) ifadesini parse edemiyor, bu yüzden CLI exit code'u başka bir yolla ayarlıyor.
Sınırlar
Bu bir compiler değil, sezgisel bir parser. README beklenen doğruluğu belirtiyor (Godot 4'te yaklaşık %90–93, Godot 3'te %85–90) ve her sonuç bir güven değeri taşıyor; böylece düşük güvenli fonksiyonlar elle kontrol edilebiliyor. Planlanan eklemeler arasında Halstead metrikleri ve bir maintainability index var.
Godot 4 sürümü itch.io üzerinde, her iki sürüm de GitHub'da (Godot 4, Godot 3).