saqut-compiler/docs/transkript-frontend-tasarim.md

215 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# saQut Frontend Tasarım Oturumu — Transkript
> Bu belge, frontend (symbol table + semantic analiz + optimizasyon) mimarisinin
> kararlaştırıldığı tasarım oturumunun **sadık bir transkriptidir.** Alınan
> kararların gerekçeleri ADR formatında `docs/adr-frontend-analiz.md`'de,
> uygulama planı `docs/roadmap-frontend.md`'de yer alır. Bu belge ise tartışmanın
> **akışını ve düşünce sürecini** korur — bir kararın nasıl olgunlaştığı, hangi
> itirazların nasıl çözüldüğü buradadır.
---
## 0. Başlangıç durumu
Oturum öncesi tamamlananlar:
- Aşama 0 (SourceLocation / konum takibi) bitirildi: her token ve AST node'u
dosya/satır/sütun/offset taşıyor.
- İki bug giderildi: (1) `location.file` boş geliyordu → `Tokenizer::scan` artık
dosya yolu alıyor; (2) `"kind": true` bug'ı`JsonObject::add`'a `const char*`
overload'u eklendi.
- AST JSON çıktısındaki fazla boşluk/girinti hataları temizlendi.
- Bu işler commit'lendi, master'a merge edildi ve push edildi.
---
## 1. "Rotamız ne? IR/JIT'e geçebilir miyiz?"
**Kullanıcı:** AST ve parser hazır mı? IR ve JIT adımına geçebilir miyiz?
**Asistan (özet):** Henüz değil, doğrudan atlamak riskli. Roadmap durumu:
- Aşama 0 (konum) ✅
- Aşama 1 (CLI/REPL) 🟡 yarım
- Aşama 2 (AST bellek canavarı) 🟡 yarım
- Aşama 3 (Symbol Table) ❌ yok (`src/symbol/` klasörü bile yok)
- Aşama 4 (Feature Toggle) ❌ yok
- Aşama 5 (IR + Backend) ❌ embriyonik (IR'de sadece 5 opcode: mathadd/sub/mul/div,
declare; backend yok)
JIT'e atlamamak için iki engel: (1) Symbol table yok — IR üretimi değişken
çözümlemesi ister; (2) IR'de kontrol akışı/fonksiyon/bellek opcode'ları yok, yani
if/while/fonksiyon derlenemez. Ayrıca ADR-001'e göre strateji: C transpile →
QBE → custom/JIT. JIT "uzun vade".
Önerilen sıra: Symbol Table → IR güçlendirme → C transpile → sonra JIT/QBE.
---
## 2. Kullanıcının vizyonu: 2-pass parser ve AST'yi derinleştirme
**Kullanıcı (özet):** Parser 2 aşamalı olacak. İlk pass syntax'ı çözüp basit
AST'yi bırakacak (tokenler, yerleri, türleri). İkinci pass'te symbol table
kurulacak (değişkenler, türleri, yerleri, kapsamları, kaç kez/nerede kullanıldıkları).
Sonraki tüm operasyonlar AST üzerinden döneceği için AST'de çok fazla ham/işlenmiş
veri olmalı; optimizasyon ve analizler tamamen burada olacak. 2. pass'te ilk AST
ve symbol table kullanılarak: kullanılmayan değişkenler, return sonrası kod,
bir kez atanıp bir kez kullanılan değişkenler, literal-operatör-literal (`1+2`)
kapatılacak (constant folding). Yorumlar/eleştiriler isteniyor.
**Asistan — 4 itiraz/uyarı:**
1. **"AST'yi derinleştirmek" felsefeyle çelişebilir.** "Hiçbir bilgi atılmaz"
prensibi var. `1+2`'yi yıkıcı şekilde `3` yaparsan orijinali silersin →
`saqut ast` artık kullanıcının yazdığını göstermez. Çözüm: **annotation**
(node'a `foldedValue:3` ekle, ağacı bozma) vs **transformation** (asıl silmeyi
AST→IR indirmede yap).
2. **"2. pass" tek pass değil, içine 3 iş tıkıyorsun:** (a) sembol toplama/isim
çözümleme, (b) semantik doğrulama, (c) optimizasyon. Bunlar farklı bağımlılık
sırasına sahip; optimizasyon semantik analiz bitince anlamlı; optimizasyonlar
birbirini tetikler (fixpoint gerekir); ayrı test edilmeli.
3. **"Bir kez atanıp bir kez kullanılan" optimizasyonu ağır.** Def-use chain /
dataflow ister; basit tree-walk değil. Ertele, IR'de yap.
4. **Tip kontrolünü atlamamış ol.** Symbol table tip tutacaksa, `int x = "..."`
hatasını kim yakalar? Her expression node'una sonuç tipi annotate etmek değerli.
İki soru soruldu: constant folding yıkıcı mı annotation mı? Scope kuralı
(forward reference) ne?
---
## 3. Kullanıcının netleştirmesi: pass = derleyici aşaması; optimizasyon nerede?
**Kullanıcı (özet):** "2-pass" sadece parser içindi, optimizasyonu kastetmedim.
Sıralama: 1. pass AST kur, 2. pass symbol table, 3. pass AST'yi derinleştir.
Ölü kodu 3'te sadece işaretleyelim demiştim ama haklısın, optimizasyon kendi
içinde tekrar çalışmalı — belki 5, belki 10 pass; her pass öncekinden rahat.
**Önemli soru:** Optimizasyonları tam derleme/IR üretme zamanından önce
yapmamız gerekmiyor mu? Neden AST aşamasında optimize edeceğimizi düşündün?
Parametre olarak AST isteniyorsa optimizasyon halini isteğe bağlı vermeliyiz;
kullanıcı AST'nin/symbol table'ın optimizasyon öncesi/sonrası halini görmek
isteyebilir.
**Scope:** Bunu JIT veya compiler frontend olarak düşünüyorum; arka planda Java
gibi forward reference olan ama C syntax'lı bir dil. Başta OOP yok, JS gibi düşün.
**Asistan:**
- "Pass" düzeltmesi kabul: "5-10 pass" değil **fixpoint** (değişiklik durana
kadar). Her **tur** daha az iş yapar; analiz pass'leri bir kez çalışır.
- "Neden AST'de optimize?" sorusuna dürüst cevap: Ben "optimize" değil
"annotate" demiştim. **Analiz (gerçekler) vs optimizasyon (değişiklik)** ayrımı.
Frontend/middle-end/backend katmanlaması tanıtıldı. Basit kaynak-seviyesi
optimizasyonlar AST'de (backend-bağımsız, incelenebilir); ağır dataflow
optimizasyonları IR'de. Backend'e koyarsak 3 backend'de 3 kez yazarız.
- **Kullanıcının "öncesi/sonrası görebilmeli" gereksinimi mimariyi belirledi:**
optimizasyon orijinali ASLA bozmamalı → klon üret. `saqut ast` öncesi,
`saqut ast --optimized` sonrası.
- Scope kararı önerildi: üst seviye tam forward reference (2 alt-geçiş), lokal
declare-before-use. "Local hoisting istiyor musun?" sorusu soruldu.
---
## 4. Tipli dil, hoisting yok; kalan tasarım sorunları
**Kullanıcı (özet):** JS'i sadece syntax basitliği için örnek verdim, kötü
yanlarını almıyoruz — null/undefined karmaşası yok. Lokal'de hoisting olmasın,
tipli dil olacak. Pass = derleyicinin kendi aşamaları (lexing/parsing/optimizing/
compiling), bunları çoğaltabiliriz. Scope: tam forward reference olsun.
Başka sorun var mı?
**Asistan — "pass = aşama" doğrulandı,** her aşama bağımsız çalışan modül; CLI
komutları bunun yansıması. Sonra **3 gerçek mesele + küçük kararlar:**
1. **Tip sistemi hiç tanımlanmadı.** `varType` şu an sadece string. Minimal ama
genişletilebilir `Type` sınıfı gerek. Tip çıkarımı (auto)? Implicit conversion?
2. **Diagnostic altyapısı şimdi gelmeli.** Semantik analiz hata üretecek ama
koyacak yer yok. Aşama 6'nın tamamı değil ama minimal `Diagnostic` toplayıcı
bu işle birlikte gelmeli.
3. **Annotation'lar node'larda nerede yaşayacak?** `ExpressionNode`/`StatementNode`
ara tabanları önerisi.
Küçük kararlar: overloading yok; scope granülerliği (Program/FunctionDecl/Block/
for-while); recursive struct → pointer gelince; aritmetik semantiği (5/2 int mi).
---
## 5. Kullanıcının kapsam kararları + sorular
**Kullanıcı (özet):** En baştan: pointer sistemi yok, tipleme basit, tuple
(`<T,U>`) yok, class yok struct var, array'ler define sırasında `[]` ile —
ama dinamik mi statik bellek mi karar veremedim. Fonksiyonlar tipli. `class`
gibi keyword'leri dikkate alma, `auto` yok. Otomatik float↔int dönüşümü yok,
her şey açık; gizli dönüşüm istemiyorum, sadece constant'larda (`5/2`→`2`).
Minimal Type sınıfına katılıyorum ama ileride geliştirilebilir olmalı — bu dilin
geleceğini bilmiyorum, popüler de olabilir, tozlanabilir de. Diagnostic için tüm
hataları baştan belirlemeliyiz; sistemi durdurup tüm hataları kullanıcıya
söylemeliyiz; hata raporlama fonksiyonları ayrı bir yerde olsun. Recursive struct
define yok ama `struct StructA { StructB BVar }` olabilir. Scope granülerliği
onaylandı. Duplicate'i tamamen yok et. For döngüsü içindeki objeler dışında
silinebilir — ama symbol table'ı karmaşıklaştırır, her katmanda namespace
tutmalıyız; üst katmanda hem öncesi hem sonrası aranacak — symbol table da mı 2
geçiş olacak? AST'nin temiz kalması neyi zorlaştırır bilmiyorum, sen karar ver.
AST node cpp dosyaları neredeyse boş, oraları kullanalım, o class'ları dolduralım.
**ExpressionNode konusunu tam anlamadım, açar mısın?** Ben tüm analizi AST'de
yapar, her node'da anlamlı veri tutar, ref'leri kendi içimde pointer olarak
tutarım diye düşünüyordum.
**Asistan cevapları:**
- **Array:** Pointer yoksa dinamik array kuramazsın (heap+gizli pointer ister).
Öneri: statik sabit boyut. *(Bu karar bir sonraki turda revize edildi — bkz. §6.)*
- **ExpressionNode = aslında aynı fikirdeyiz.** Sorum felsefi değil, C++ detayı:
`resolvedType`'ı hangi node'a koyacağız? Tipli dilde sadece ifadelerin tipi var
(`5+3`→int; `if`→tipsiz). İki ara taban (`ExpressionNode`/`StatementNode`)
alanları doğru yere koyar + "burası ifade olmalı" kontrolü sağlar. Analiz yine
AST'de yaşar; bu sadece alanları doğru sınıflara dağıtmak.
- **Symbol table 2 geçiş?** Evet ama sadece üst seviyede. Geçiş 1: global'leri
hoist et. Geçiş 2: gövdelere in, çöz. Fonksiyon içi tek geçiş (lokal'de forward
ref yok). Öncesi/sonrası derdi sadece global'ler için, onu Geçiş 1 çözer.
- **AST temiz vs her şey AST'de → karar: her şey AST'de** (senin modelin).
Optimizasyon klonda dönüştürür. **Önemli:** "kaç kez kullanıldı" Symbol'da
yaşar (değişkene ait), node'da değil; IdentifierNode Symbol'a pointer tutar.
- **Hoisting açıklaması** (kullanıcı "local hoisting ne demek, global=local değil
mi?" diye sordu): Hoisting = tanımın yazıldığı satırdan önce de görünmesi.
Global'de forward ref güvenli (gövde tanımda çalışmaz, çağrılınca çalışır).
Lokal'de declare-before-use (değişkenin sırası/değeri var). Asimetri =
tutarsızlık değil, tam olarak Java'nın davranışı.
---
## 6. Pointer netleştirmesi + son onaylar
**Kullanıcı (özet):** Yanlış anlama düzeltmesi: pointer derleyici **içinde** tabii
ki var; programlama **dilinde** `*`/`&` yok. Pointer sadece derleyicinin içinde.
Bu, değişken listelerini destekler — JS'te pointer syntax'ı yok ama array var.
Kullanıcıya pointer yok, arka planda A'dan Z'ye pointer var. Ayrıca: local
hoisting senin dediğin gibi (declare-before-use). Array'ler `int[]` olsun.
**Ama bu backend'de dinamik bellek zorunluluğu getirmez mi? JIT'te?**
ExpressionNode → evet ekle. Her şey temiz, anlaşılır, yorum satırlarıyla
takip edilebilir olsun yeter.
**Asistan:**
- **Array kararı revize edildi:** Pointer arka planda olduğuna göre dinamik
array mümkün. Frontend için `Type` sadece "array of T" temsil etsin, boyut
tipte olmasın. Runtime bellek modeli (statik/heap/free) backend kararı, ertelendi.
- **Dinamik bellek/JIT yükümlülüğü cevabı:** Evet ileride yükümlülük getirir ama
frontend'i bloklamaz. C transpile'da malloc/realloc/free ile neredeyse bedava;
JIT'te minik runtime kütüphanesine call emit edilir; yönetim stratejisi en
basiti scope-tabanlı ownership, GC gerekmez.
- Tüm kararlar kilitlendi; dosya-dosya yol haritası sunuldu (Faz 0…4).
---
## 7. Belgeleme talebi
**Kullanıcı:** Konuştuklarımızı ve kararları ADR formatında, neden öyle yaptığımızı
da belgele; hiçbir şey boş geçmesin; transkript de yazabilirsin; en son yol
haritasını oluştur; her şeyden önce yeni bir branch çık.
**Asistan:** `feature/frontend-analysis` branch'i açıldı. Üç belge üretildi:
- `docs/adr-frontend-analiz.md` (ADR-006…014)
- `docs/transkript-frontend-tasarim.md` (bu belge)
- `docs/roadmap-frontend.md` (uygulama planı)