docs: frontend tasarim kararlari, transkript ve yol haritasi
Symbol table + semantic analiz + optimizasyon framework tasarim oturumunun ciktilari: - adr-frontend-analiz.md: ADR-006..014 (cok-asamali frontend, analiz/ optimizasyon ayrimi, optimizasyon konumu, fixpoint, tip sistemi, scope/forward-reference, ExpressionNode/StatementNode, analiz verisi yeri, dil kapsami) — her karar gerekcesiyle. - transkript-frontend-tasarim.md: oturum akiscinin sadik transkripti. - roadmap-frontend.md: dosya-dosya uygulama plani (Faz 0..4).
This commit is contained in:
parent
b986f0cb26
commit
f7467f18b3
|
|
@ -0,0 +1,389 @@
|
||||||
|
# saQut Derleyici — Frontend & Semantic Analiz Karar Kaydı (ADR-006 …)
|
||||||
|
|
||||||
|
> Bu belge, `docs/fikirler.md`'deki ADR-001…005'in **devamıdır**. Orada backend
|
||||||
|
> stratejisi, parser mimarisi, header-only tercihi, token sistemi ve IR tasarımı
|
||||||
|
> kararlaştırılmıştı. Bu belge ise **frontend'in tamamlanması** — symbol table,
|
||||||
|
> semantic analiz ve optimizasyon framework'ü — etrafında alınan kararları,
|
||||||
|
> **neden** alındıklarını, elenen alternatifleri ve gelecekteki sonuçlarını kaydeder.
|
||||||
|
>
|
||||||
|
> Bu kararlar bir tasarım oturumunda (kullanıcı + asistan) tartışılarak alındı.
|
||||||
|
> Tartışmanın tam akışı için bkz. `docs/transkript-frontend-tasarim.md`.
|
||||||
|
> Uygulama planı için bkz. `docs/roadmap-frontend.md`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ADR-006: Çok-Aşamalı (Multi-Pass) Frontend Mimarisi
|
||||||
|
|
||||||
|
### Bağlam
|
||||||
|
|
||||||
|
Derleyici tek bir monolitik geçişle çalışmaz; lexing, parsing, analiz,
|
||||||
|
optimizasyon, kod üretimi gibi **birbirinden bağımsız aşamalardan** oluşur.
|
||||||
|
saQut'un "alet çantası" (toolbox) felsefesi gereği bu aşamaların her biri:
|
||||||
|
- bağımsız çalışabilmeli,
|
||||||
|
- net bir girdi/çıktı sözleşmesine sahip olmalı,
|
||||||
|
- gerektiğinde çoğaltılabilmeli (projenin amacına sadık kalarak).
|
||||||
|
|
||||||
|
CLI komutları (`tokens`, `ast`, `symbols`, …) zaten bu aşama-modülü
|
||||||
|
yapısının dışa vurumudur — her komut bir aşamanın çıktısını gösterir.
|
||||||
|
|
||||||
|
### Değerlendirilen Yaklaşımlar
|
||||||
|
|
||||||
|
#### Tek geçişli (single-pass) parser+analiz
|
||||||
|
- **+** Basit, hızlı.
|
||||||
|
- **−** Forward reference (ileri başvuru) imkânsızlaşır; her şey tanımdan
|
||||||
|
önce bilinmek zorunda kalır.
|
||||||
|
- **−** Analiz ve syntax iç içe girer, test edilemez, bakımı zor.
|
||||||
|
|
||||||
|
#### Çok geçişli (multi-pass) — net aşamalar
|
||||||
|
- **+** Her aşama tek bir iş yapar, ayrı ayrı test edilir.
|
||||||
|
- **+** Forward reference mümkün olur.
|
||||||
|
- **+** Aşamalar incelenebilir (`saqut ast`, `saqut symbols` …).
|
||||||
|
- **−** Daha fazla kod ve veri yapısı; aşamalar arası sözleşme tasarımı gerekir.
|
||||||
|
|
||||||
|
### Karar
|
||||||
|
|
||||||
|
✅ **Çok-aşamalı frontend.** Aşamalar şu üç katmana ayrılır (klasik derleyici
|
||||||
|
mimarisi):
|
||||||
|
|
||||||
|
```
|
||||||
|
FRONTEND MIDDLE-END BACKEND
|
||||||
|
lexer → token → optimizasyon IR lowering →
|
||||||
|
parser → AST → (opsiyonel, iteratif, kod üretimi
|
||||||
|
symbol table → toggle'lı, ortak (C transpile /
|
||||||
|
semantic analiz gösterim üstünde) QBE / JIT)
|
||||||
|
(annotated AST)
|
||||||
|
```
|
||||||
|
|
||||||
|
- **Pass 1 (Syntax):** token → ham AST. (Büyük ölçüde mevcut.)
|
||||||
|
- **Pass 2 (Symbol):** AST → SymbolTable (scope'lu, iki-geçişli — bkz. ADR-011).
|
||||||
|
- **Pass 3 (Semantic / "ASTyi derinleştir"):** symbol table + AST kullanılarak
|
||||||
|
her node zenginleştirilir (tip, symbol bağı, erişilebilirlik, reference sayısı).
|
||||||
|
|
||||||
|
"Parser ve symbol hikayesini bitirmek" = **frontend'i bitirmek.** Optimizasyon
|
||||||
|
ayrı bir katmandır (middle-end), backend'ler bu ortak çıktıdan beslenir.
|
||||||
|
|
||||||
|
**Neden bu katmanlama?** Birden çok backend (C transpile, QBE, JIT) planlandığı
|
||||||
|
için, ortak işler (analiz, optimizasyon) **bir kez** ortak katmanda yapılmalı;
|
||||||
|
yoksa her backend aynı optimizasyonu yeniden yazar.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ADR-007: Analiz (Annotation) ile Optimizasyon (Transformation) Ayrımı
|
||||||
|
|
||||||
|
### Bağlam
|
||||||
|
|
||||||
|
`docs/fikirler.md` ve `docs/todo.md`'nin temel prensibi: **"AST bellek canavarı.
|
||||||
|
Hiçbir bilgi atılmaz."** Aynı zamanda constant folding (`1+2` → `3`), dead code
|
||||||
|
elimination gibi optimizasyonlar isteniyor. Bu ikisi doğrudan çelişir gibi
|
||||||
|
görünür: optimizasyon AST'yi bozarsa, kaynak kodun izdüşümü kaybolur ve
|
||||||
|
`saqut ast` artık kullanıcının yazdığını değil, optimize edilmiş hali gösterir.
|
||||||
|
|
||||||
|
Ayrıca kritik bir kullanıcı gereksinimi belirlendi: **kullanıcı, AST'nin veya
|
||||||
|
sembol tablosunun optimizasyondan önceki ve sonraki halini ayrı ayrı görebilmeli.**
|
||||||
|
|
||||||
|
### İki Kavram
|
||||||
|
|
||||||
|
- **Analiz (annotation) = programın gerçekleri.** "Bu node sabit, değeri 3",
|
||||||
|
"bu kod erişilemez", "bu ifadenin tipi int", "bu değişken 2 kez kullanıldı".
|
||||||
|
Bunlar **değişiklik değil, tespittir.** Backend'den bağımsızdır.
|
||||||
|
- **Optimizasyon (transformation) = ağacı/IR'ı gerçekten değiştirmek.**
|
||||||
|
`1+2`'yi `3` ile değiştirmek, ölü kodu silmek.
|
||||||
|
|
||||||
|
### Karar
|
||||||
|
|
||||||
|
✅ **İki kavram net ayrılır:**
|
||||||
|
|
||||||
|
1. **Analiz, orijinal AST'nin üstüne yerinde işaretleme yapar** (node'lara tip,
|
||||||
|
symbol bağı, erişilebilirlik, constness ekler). Ağacı **bozmaz**, zenginleştirir.
|
||||||
|
Orijinal AST hâlâ kaynak kodun tam izdüşümüdür.
|
||||||
|
|
||||||
|
2. **Optimizasyon dönüşümü, ağacın bir KOPYASI (klon) üzerinde yapılır.**
|
||||||
|
Orijinal analizli AST = "öncesi"; klon + dönüştürülmüş AST = "sonrası".
|
||||||
|
Ağaç klonlamak ucuz ve basittir, yalnızca `--optimized` istendiğinde yapılır.
|
||||||
|
|
||||||
|
**Sonuç:** Hem "bellek canavarı" felsefesi korunur (orijinal AST her şeyi tutar),
|
||||||
|
hem optimizasyon yapılır, hem de öncesi/sonrası ayrı ayrı incelenebilir.
|
||||||
|
|
||||||
|
```
|
||||||
|
saqut ast file.sqt → ham + annotate edilmiş AST (1+2 burada durur)
|
||||||
|
saqut ast file.sqt --optimized → klon, folding uygulanmış (3 var)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ADR-008: Optimizasyon Konumu — AST mı, IR mı?
|
||||||
|
|
||||||
|
### Bağlam
|
||||||
|
|
||||||
|
"Optimizasyonu IR/derleme zamanında mı yapmalıyız, yoksa AST aşamasında mı?"
|
||||||
|
sorusu tartışıldı. İki uç yaklaşım var:
|
||||||
|
|
||||||
|
- **AST seviyesi:** kaynak-seviyesi, dile yakın, incelenebilir.
|
||||||
|
- **IR seviyesi:** açık kontrol-akış grafiği (CFG), dataflow analizi için uygun
|
||||||
|
(LLVM modeli).
|
||||||
|
|
||||||
|
### Karar
|
||||||
|
|
||||||
|
✅ **Hibrit, optimizasyon türüne göre bölünür:**
|
||||||
|
|
||||||
|
- **Kaynak-seviyesi, ağaç-yerel optimizasyonlar** (constant folding, ölü kod
|
||||||
|
işaretleme, unused variable) → **AST'de** yapılır. Çünkü:
|
||||||
|
1. Dil JS gibi basit; ağır optimizasyona ihtiyaç yok.
|
||||||
|
2. Backend-bağımsız → C transpile, QBE, JIT üçü birden faydalanır.
|
||||||
|
3. İncelenebilir kalır (`saqut ast --optimized`) — projenin varlık sebebi.
|
||||||
|
|
||||||
|
- **CFG/dataflow gerektiren optimizasyonlar** ("bir kez atanıp bir kez
|
||||||
|
kullanılan değişken" = copy propagation, common subexpression elimination,
|
||||||
|
loop optimizasyonları) → **IR'de** yapılır, IR olgunlaşınca ertelenir.
|
||||||
|
Çünkü bunlar açık kontrol akışı ister, ağaçta yapmak işkencedir.
|
||||||
|
|
||||||
|
**Neden backend'e bırakmıyoruz?** 3 backend varsa, optimizasyon backend'e
|
||||||
|
konulursa 3 kez yazılır. Ortak katmanda (middle-end) bir kez yazılır.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ADR-009: Optimizasyon Pass Yönetimi — Sabit Sayı Değil, Fixpoint
|
||||||
|
|
||||||
|
### Bağlam
|
||||||
|
|
||||||
|
Optimizasyon adımları birbirini tetikler: constant folding yeni ölü kod doğurur,
|
||||||
|
dead code elimination yeni kullanılmayan değişken doğurur. Tek geçişte zincirleme
|
||||||
|
fırsatlar kaçırılır. "5 pass mı, 10 pass mı çalıştıralım?" sorusu yanlış kurgu.
|
||||||
|
|
||||||
|
> **Not:** Buradaki "pass", ADR-006'daki derleyici aşamalarından (lexing/parsing
|
||||||
|
> gibi makro-aşamalar) farklıdır. Burada "pass" = tek bir optimizasyon adımının
|
||||||
|
> AST üzerindeki bir gezisidir.
|
||||||
|
|
||||||
|
### Karar
|
||||||
|
|
||||||
|
✅ **Fixpoint döngüsü.** Önceden belirlenmiş sayıda değil; bir pass havuzu,
|
||||||
|
**hiçbir pass değişiklik yapmayana kadar** döngüde çalışır. Belki 2 tur sürer,
|
||||||
|
belki 7 — kodun kendisi belirler.
|
||||||
|
|
||||||
|
- Her **tur** bir öncekinden daha az iş yapar (giderek azalan değişiklik), ta ki
|
||||||
|
sıfır değişiklikle stabilize olana kadar.
|
||||||
|
- Pass'ler `CompilerConfig` ile tek tek açılıp kapatılabilir.
|
||||||
|
- `OptimizationManager` pass listesini tutar, sırayı ve fixpoint döngüsünü yönetir.
|
||||||
|
|
||||||
|
> Düzeltme notu: "Her pass bir öncekinden daha kolay" sezgisi yanlıştır. Doğrusu:
|
||||||
|
> her **tur** daha az değişiklik yapar. Analiz pass'leri (symbol table, type check)
|
||||||
|
> "kolaylaşmaz"; onlar bir kez çalışır.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ADR-010: Tip Sistemi Tasarımı
|
||||||
|
|
||||||
|
### Bağlam
|
||||||
|
|
||||||
|
Dil **tipli** olacak. Şu anda `varType`/`returnType` AST'de yalnızca
|
||||||
|
`std::string`. Tip kontrolünü string karşılaştırmasıyla yazmak kırılgandır ve
|
||||||
|
`int[]`, `struct Point`, fonksiyon tipi gelince baştan yazmayı gerektirir.
|
||||||
|
|
||||||
|
### Alınan Kararlar
|
||||||
|
|
||||||
|
✅ **Minimal ama genişletilebilir `Type` sınıfı** (`src/core/type.hpp`):
|
||||||
|
- `kind`: `Primitive / Array / Struct / Function / Error`.
|
||||||
|
- Primitifler: `int, float, double, char, string, bool, void`.
|
||||||
|
- `Array` → eleman tipi (boyut tipin parçası DEĞİL — bkz. aşağı).
|
||||||
|
- `Function` → dönüş tipi + parametre tipleri.
|
||||||
|
- İleride `Pointer`, `Generic` eklenebilir.
|
||||||
|
|
||||||
|
✅ **`Error` tipi şart.** Tip hatası olduğunda node'a `Error` atanır; böylece
|
||||||
|
ardışık sahte hatalar üretilmez (tek hata, tek mesaj).
|
||||||
|
|
||||||
|
✅ **Gizli (implicit) dönüşüm YOK.** `int → float` otomatik olmaz; her şey açık.
|
||||||
|
- **Tek istisna:** sabit ifadelerde (constant folding) — `int a = 5 / 2;` → `2`.
|
||||||
|
Sabitler üzerinde küçük analiz/hesap yapılır.
|
||||||
|
|
||||||
|
✅ **Tip çıkarımı (auto/var) YOK.** Her şey açıkça tiplenir. `auto` keyword'ü
|
||||||
|
yok sayılır. Sebep: basitlik, öngörülebilirlik, kafa karışıklığını önlemek.
|
||||||
|
|
||||||
|
✅ **Array tip temsili: `int[]` (boyut tipte yok).** `int[]` sadece "int dizisi";
|
||||||
|
boyut tip eşitliğine girmez (JS gibi). Tip kontrolü basit kalır.
|
||||||
|
|
||||||
|
**Neden genişletilebilir?** "Bu dilin geleceğini bilmiyoruz; beklenenden popüler
|
||||||
|
de olabilir, yıllarca repolarda tozlanabilir de." Temel sağlam ve büyümeye açık
|
||||||
|
olmalı.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ADR-011: Scope ve Forward Reference Kuralları
|
||||||
|
|
||||||
|
### Bağlam
|
||||||
|
|
||||||
|
Dil "Java gibi forward reference, C gibi syntax, başta OOP yok" olarak
|
||||||
|
tasarlandı (JS yalnızca **syntax basitliği** örneği olarak verildi; JS'in kötü
|
||||||
|
yanları — null/undefined ikiliği, var hoisting — **alınmıyor**).
|
||||||
|
|
||||||
|
### "Hoisting" nedir?
|
||||||
|
|
||||||
|
Bir tanımın, yazıldığı satırdan **önce de** görünür olması (scope'un tepesine
|
||||||
|
"kaldırılmış" gibi).
|
||||||
|
|
||||||
|
### Karar
|
||||||
|
|
||||||
|
✅ **Asimetrik kurallar (tam olarak Java'nın davranışı):**
|
||||||
|
|
||||||
|
- **Üst seviye (global): tam forward reference (hoisting var).** Fonksiyonlar,
|
||||||
|
global değişkenler, struct'lar sırasından bağımsız her yerde görünür.
|
||||||
|
```
|
||||||
|
int main() { return kare(5); } // kare aşağıda ama görünür → OK
|
||||||
|
int kare(int n) { return n * n; }
|
||||||
|
```
|
||||||
|
**Neden güvenli?** `main`'in gövdesi tanımlandığı anda çalışmaz; çağrılınca
|
||||||
|
çalışır, o ana kadar `kare` zaten vardır. Tanımların çalışma sırası yoktur.
|
||||||
|
|
||||||
|
- **Lokal (fonksiyon içi): declare-before-use (hoisting YOK).**
|
||||||
|
```
|
||||||
|
int main() {
|
||||||
|
int x = y + 1; // HATA: y henüz tanımlı değil
|
||||||
|
int y = 5;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
**Neden?** Lokal değişkenin bir çalışma sırası ve değeri vardır; tanımdan önce
|
||||||
|
kullanmak, var olmayan/değeri olmayan bir şeyi kullanmaktır. Local hoisting
|
||||||
|
olsaydı isim olur ama değeri çöp/undefined olurdu (JS `var` derdi) — kaçınılan
|
||||||
|
durum.
|
||||||
|
|
||||||
|
**Asimetri tutarsızlık değildir:** global tanımlar yerinde çalışmaz (forward ref
|
||||||
|
güvenli), lokal değişkenlerin sırası ve değeri vardır (declare-before-use güvenli).
|
||||||
|
Bu, Java/C#'ın da davranışıdır.
|
||||||
|
|
||||||
|
✅ **Duplicate kesinlikle yasak.** Aynı scope'ta aynı isimli iki
|
||||||
|
değişken/fonksiyon tanımlanamaz → diagnostic. (Overloading yok.)
|
||||||
|
|
||||||
|
✅ **Shadowing serbest.** İç scope, dış scope'u gölgeleyebilir (hata değil).
|
||||||
|
|
||||||
|
✅ **Scope oluşturan node'lar:** `Program` (global), `FunctionDecl` (parametreler),
|
||||||
|
`Block`, `for`/`while` (init değişkeni döngüye ait; döngü dışında görünmez).
|
||||||
|
Her katman bir namespace tutar; değişken bulunamazsa bir üst katmanda aranır.
|
||||||
|
|
||||||
|
### Symbol Table'ın İki Geçişi
|
||||||
|
|
||||||
|
✅ **Sadece üst seviyede iki geçiş gerekir:**
|
||||||
|
- **Geçiş 1:** tüm üst-seviye tanımları (fonksiyon imzaları, struct isim+alanları,
|
||||||
|
global değişkenler) global scope'a hoist et.
|
||||||
|
- **Geçiş 2:** gövdelere in; lokal'leri declare-before-use ile topla, her
|
||||||
|
`Identifier`'ı çöz, reference ekle.
|
||||||
|
- **Fonksiyon içi tek geçiş yeter** (lokal'de forward ref yok). "Öncesi/sonrası"
|
||||||
|
derdi yalnızca global'ler içindir, onu da Geçiş 1 çözer (global'ler en baştan
|
||||||
|
tamamen doludur).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ADR-012: ExpressionNode / StatementNode Ara Tabanları
|
||||||
|
|
||||||
|
### Bağlam
|
||||||
|
|
||||||
|
Şu anda tüm AST node'ları doğrudan `ASTNode`'dan türüyor; "ifade" (değer üreten)
|
||||||
|
ve "deyim" (iş yapan ama değer olmayan) ayrımı yok. Tipli bir dilde yalnızca
|
||||||
|
**ifadelerin** tipi vardır: `5 + 3` → int; `if (...) {...}` → tipi yok.
|
||||||
|
|
||||||
|
`resolvedType` alanını nereye koyacağımız bir tasarım kararı. Seçenekler:
|
||||||
|
- (a) `ASTNode` tabanına koy → her node'da olur, `if`/`while`'da boşa durur.
|
||||||
|
- (b) `ExpressionNode`/`StatementNode` ara tabanları → alanlar doğru yere oturur.
|
||||||
|
- (c) Yan-tablo `map<ASTNode*, Annotation>` → AST temiz ama dolaylı/karmaşık.
|
||||||
|
|
||||||
|
### Karar
|
||||||
|
|
||||||
|
✅ **(b) İki ara taban eklenir:**
|
||||||
|
- `ExpressionNode : ASTNode` → `resolvedType`, `isConstant`, `foldedValue`.
|
||||||
|
- `StatementNode : ASTNode` → `isReachable` (ölü kod analizi için).
|
||||||
|
|
||||||
|
```
|
||||||
|
ASTNode
|
||||||
|
├─ ExpressionNode (resolvedType, isConstant, foldedValue)
|
||||||
|
│ ├─ LiteralNode / BinaryExpressionNode / IdentifierNode / CallExpressionNode …
|
||||||
|
└─ StatementNode (isReachable)
|
||||||
|
├─ IfStatementNode / WhileStatementNode / ReturnStatementNode / BlockNode …
|
||||||
|
```
|
||||||
|
|
||||||
|
**Kazanımlar:**
|
||||||
|
1. `resolvedType` yalnızca tip taşıyabilen node'larda olur.
|
||||||
|
2. Parser/analiz "burası ifade olmalı" diyebilir (örn. `if` koşulu bir
|
||||||
|
`ExpressionNode` olmalı, fonksiyon argümanı `ExpressionNode` olmalı).
|
||||||
|
|
||||||
|
**Önemli:** Bu karar, "her şey AST'de" felsefesini bozmaz (bkz. ADR-013); yalnızca
|
||||||
|
analiz alanlarını doğru node sınıflarına dağıtır. Node cpp dosyaları zaten boştu;
|
||||||
|
bu tabanlar onları doldururken ekleniyor. Maliyeti şimdi düşük, sonra yüksek
|
||||||
|
olurdu.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ADR-013: Analiz Verisi Nerede Yaşar — Her Şey AST'de
|
||||||
|
|
||||||
|
### Bağlam
|
||||||
|
|
||||||
|
İki model: (1) her şey AST node'larının üstünde; (2) AST temiz, analiz sonuçları
|
||||||
|
ayrı yan-tablolarda.
|
||||||
|
|
||||||
|
- **Her şey AST'de:** tek doğruluk kaynağı, gezinmesi kolay (`node->type`),
|
||||||
|
kullanıcının zihinsel modeli, boş node class'larını doldurur. Ancak öncesi/
|
||||||
|
sonrası için ağacı klonlamak gerekir.
|
||||||
|
- **Temiz AST + yan-tablolar:** AST sade kalır, çoklu bağımsız analiz mümkün;
|
||||||
|
ancak dolaylılık ve karmaşıklık artar, "node class'larını doldur" isteğine ters.
|
||||||
|
|
||||||
|
### Karar
|
||||||
|
|
||||||
|
✅ **Her şey AST node'larının üstünde** (kullanıcının modeli):
|
||||||
|
- **Analiz (tip, constness, erişilebilirlik) = node'lara yerinde işaretlenir.**
|
||||||
|
- **Optimizasyon dönüşümü = ağacın klonunda yapılır** (ADR-007), böylece
|
||||||
|
öncesi/sonrası korunur.
|
||||||
|
|
||||||
|
✅ **Önemli ayrım — "kaç kez kullanıldı" bilgisi node'da değil, Symbol'da:**
|
||||||
|
- `IdentifierNode` → işaret ettiği `Symbol`'a pointer tutar.
|
||||||
|
- `Symbol` → o değişkenin tüm referanslarının listesini + sayısını tutar.
|
||||||
|
- `ExpressionNode` → kendi sonuç tipini, sabit olup olmadığını tutar.
|
||||||
|
|
||||||
|
Sebep: kullanım sayısı **değişkene** aittir, tek bir kullanım node'una değil.
|
||||||
|
|
||||||
|
> **Pointer notu:** Burada ve genel olarak derleyici **içinde** pointer serbestçe
|
||||||
|
> kullanılır (Symbol bağları, parent pointer'lar vb.). Kullanıcıya sunulan
|
||||||
|
> **dilde** pointer syntax'ı (`*`, `&`) yoktur — bkz. ADR-014.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ADR-014: Dil Kapsamı ve Özellik Kararları
|
||||||
|
|
||||||
|
### Karar — Başlangıç Dili (v0)
|
||||||
|
|
||||||
|
| Özellik | Karar | Not |
|
||||||
|
|---|---|---|
|
||||||
|
| Pointer (kullanıcı syntax'ı `*`/`&`) | ❌ Yok | Ama derleyici/runtime **içeride** pointer'ı sonuna kadar kullanır |
|
||||||
|
| Tuple / Generic (`<T,U>`) | ❌ Yok | |
|
||||||
|
| Class / OOP | ❌ Yok (başta) | `class` keyword'ü yok sayılır |
|
||||||
|
| Struct | ✅ Var | `struct A { B bVar }` olur (B başka yerde tanımlı); recursive define yok |
|
||||||
|
| Array | ✅ `int[]` | Dinamik yönde; runtime bellek modeli ertelendi |
|
||||||
|
| Fonksiyonlar | ✅ Tipli | Dönüş + parametre tipleri zorunlu |
|
||||||
|
| `auto` / tip çıkarımı | ❌ Yok | Her şey açık tipli |
|
||||||
|
| Gizli int↔float dönüşümü | ❌ Yok | Sadece sabit folding'de istisna |
|
||||||
|
|
||||||
|
### Dinamik Array'in Bellek Yükümlülüğü (Gelecek Notu)
|
||||||
|
|
||||||
|
`int[]` büyüyebilen array = heap + bir yönetim stratejisi gerektirir. Bu gerçek
|
||||||
|
bir yükümlülüktür ama **frontend'i bloklamaz** ve kolay yolu vardır:
|
||||||
|
|
||||||
|
- **Frontend:** yalnızca "bu int dizisi" bilgisini ister; bellek modelinden habersiz.
|
||||||
|
- **C transpile backend (ilk backend):** `int[]` → C'de `struct {int* data; size_t len, cap;}`,
|
||||||
|
`malloc/realloc/free` ile yönetilir. Bellek yönetimi C'den hazır gelir.
|
||||||
|
- **JIT backend:** bellek yönetimini kendi yapmaz; minik bir runtime kütüphanesi
|
||||||
|
(`array_new`, `array_push`, `array_free`) olur, JIT bunlara **call** emit eder.
|
||||||
|
- **Yönetim stratejisi (ne zaman free):** en basiti scope-tabanlı ownership
|
||||||
|
(array'i tutan değişken scope'tan çıkınca free). GC gerekmez. Runtime'a
|
||||||
|
gelince kararlaştırılır.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kararların Özet Tablosu
|
||||||
|
|
||||||
|
| ADR | Konu | Karar |
|
||||||
|
|---|---|---|
|
||||||
|
| 006 | Frontend mimarisi | Çok-aşamalı; frontend/middle-end/backend katmanları |
|
||||||
|
| 007 | Analiz vs optimizasyon | Analiz yerinde işaretler; optimizasyon klonda dönüştürür |
|
||||||
|
| 008 | Optimizasyon konumu | Basitler AST'de, dataflow gerektirenler IR'de |
|
||||||
|
| 009 | Pass yönetimi | Fixpoint döngüsü, toggle'lı |
|
||||||
|
| 010 | Tip sistemi | Minimal+genişletilebilir Type; gizli dönüşüm yok; Error tipi |
|
||||||
|
| 011 | Scope/forward ref | Global'de forward ref, lokal'de declare-before-use (Java gibi) |
|
||||||
|
| 012 | Node hiyerarşisi | ExpressionNode / StatementNode ara tabanları |
|
||||||
|
| 013 | Analiz verisi yeri | Her şey AST'de; ref-count Symbol'da |
|
||||||
|
| 014 | Dil kapsamı | Pointer/class/generic yok; struct+array+tipli fonksiyon var |
|
||||||
|
|
@ -0,0 +1,179 @@
|
||||||
|
# saQut Frontend Yol Haritası — Symbol Table + Semantic Analiz + Optimizasyon
|
||||||
|
|
||||||
|
> Bu belge, frontend'i tamamlamaya yönelik dosya-dosya uygulama planıdır.
|
||||||
|
> Kararların gerekçeleri: `docs/adr-frontend-analiz.md` (ADR-006…014).
|
||||||
|
> Tartışma akışı: `docs/transkript-frontend-tasarim.md`.
|
||||||
|
>
|
||||||
|
> **İlke:** Sıralama katıdır — her faz bir öncekine dayanır. Her faz sonunda
|
||||||
|
> mevcut örneklerle (`examples/Final.sqt`, `examples/source.sqt`) ve CLI
|
||||||
|
> komutlarıyla doğrulama yapılır; regresyon olmamalıdır. Kod temiz, anlaşılır ve
|
||||||
|
> yorum satırlarıyla takip edilebilir olmalıdır (header-only tarzı korunur,
|
||||||
|
> bkz. ADR-003).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Genel Bakış
|
||||||
|
|
||||||
|
```
|
||||||
|
Faz 0 Temeller Type sınıfı + Diagnostic modülü + Hata kataloğu
|
||||||
|
Faz 1 AST Refactor ExpressionNode/StatementNode + analiz alanları
|
||||||
|
Faz 2 Symbol Table Symbol + Scope + SymbolTable + iki-geçişli toplama
|
||||||
|
Faz 3 Semantic Analiz Tip kontrolü + yapısal doğrulama (diagnostic'e basar)
|
||||||
|
Faz 4 Optimizasyon Pass manager (fixpoint) + constant folding + dead code
|
||||||
|
```
|
||||||
|
|
||||||
|
Katman eşlemesi (ADR-006):
|
||||||
|
- **Frontend:** Faz 0–3
|
||||||
|
- **Middle-end:** Faz 4
|
||||||
|
- **Backend:** bu yol haritasının dışında (C transpile → QBE → JIT, ADR-001)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Faz 0 — Temeller (Type + Diagnostic + Hata Kataloğu)
|
||||||
|
|
||||||
|
**Bağımlılık:** yok. **Hedef:** her şeyin üstüne kurulacağı temel veri yapıları.
|
||||||
|
İlgili ADR: 010 (Type), 013 (Diagnostic).
|
||||||
|
|
||||||
|
### Dosyalar
|
||||||
|
|
||||||
|
| Dosya | İçerik |
|
||||||
|
|---|---|
|
||||||
|
| `src/core/type.hpp` | `Type` sınıfı. `enum class TypeKind { Primitive, Array, Struct, Function, Error }`. Primitif alt-tipleri: `int, float, double, char, string, bool, void`. Alanlar: array için `elementType`, function için `returnType`+`paramTypes`, struct için `structName`. Metotlar: `equals(const Type&)`, `toString()`, `toJson()`, factory'ler (`Type::primitive(...)`, `Type::array(...)`, `Type::error()`). |
|
||||||
|
| `src/diagnostic/diagnostic.hpp` | `enum class DiagLevel { Error, Warning, Note, Hint }`. `struct Diagnostic { DiagLevel level; std::string code; SourceLocation loc; std::string message; std::string hint; }`. **Hata kataloğu** (sabitler/enum): bkz. aşağı. |
|
||||||
|
| `src/diagnostic/diagnostic_engine.hpp` | `DiagnosticEngine`: `report(Diagnostic)`, `hasErrors()`, `errorCount()`, `printAll(std::ostream&)`, `toJson()`. Diagnostic'leri biriktirir; durdurma kararını pipeline verir (tüm hatalar toplanır, sonra raporlanır — ADR-013). |
|
||||||
|
|
||||||
|
### Hata Kataloğu (baştan belirlenir)
|
||||||
|
|
||||||
|
| Kod | Anlam | Hangi fazda üretilir |
|
||||||
|
|---|---|---|
|
||||||
|
| `E001` | Tanımsız değişken/isim | Faz 2/3 |
|
||||||
|
| `E002` | Aynı scope'ta çift tanım | Faz 2 |
|
||||||
|
| `E003` | Tip uyuşmazlığı | Faz 3 |
|
||||||
|
| `E004` | Döngü/switch dışı `break`/`continue` | Faz 3 |
|
||||||
|
| `E005` | Fonksiyon dışı `return` | Faz 3 |
|
||||||
|
| `E006` | Return tipi imzaya uymuyor | Faz 3 |
|
||||||
|
| `E007` | Tanımsız tip (bilinmeyen tip adı) | Faz 2/3 |
|
||||||
|
| `E008` | Fonksiyon çağrısı argüman sayısı/tipi uyuşmuyor | Faz 3 |
|
||||||
|
| `E009` | Array boyutu sabit değil / geçersiz | Faz 3 |
|
||||||
|
| `W001` | Kullanılmayan değişken | Faz 4 |
|
||||||
|
| `W002` | Sıfıra bölme (sabit folding) | Faz 4 |
|
||||||
|
| `W003` | Erişilemez (ölü) kod | Faz 4 |
|
||||||
|
|
||||||
|
*(Liste uygulamada genişleyebilir; yeni hatalar buraya eklenir.)*
|
||||||
|
|
||||||
|
### Doğrulama
|
||||||
|
- `Type::equals` / `toString` birim testleri.
|
||||||
|
- `DiagnosticEngine` topla → `printAll` çıktısı doğru sıralı.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Faz 1 — AST Refactor (ExpressionNode / StatementNode + analiz alanları)
|
||||||
|
|
||||||
|
**Bağımlılık:** Faz 0 (Type). **Hedef:** node hiyerarşisini ifade/deyim olarak
|
||||||
|
ayır, analiz alanlarını ekle. İlgili ADR: 012, 013.
|
||||||
|
|
||||||
|
### Dosyalar
|
||||||
|
|
||||||
|
| Dosya | Değişiklik |
|
||||||
|
|---|---|
|
||||||
|
| `src/parser/ast_node.hpp` | İki ara taban ekle: `class ExpressionNode : public ASTNode { Type resolvedType; bool isConstant=false; /* foldedValue */ }` ve `class StatementNode : public ASTNode { bool isReachable=true; }`. |
|
||||||
|
| `src/parser/nodes/literal.hpp` · `binary_expr.hpp` · `identifier.hpp` · `expressions.hpp` (Call/Member/Index/Postfix) | Bu node'ları `ExpressionNode`'dan türet. |
|
||||||
|
| `src/parser/nodes/statements.hpp` (Block/If/While/For/DoWhile/Return/Break/Continue/ExpressionStatement) · `declarations.hpp`? | Statement'ları `StatementNode`'dan türet. (VariableDecl/FunctionDecl/StructDecl tartışmalı — declaration; şimdilik `StatementNode` veya doğrudan `ASTNode` altında değerlendirilir.) |
|
||||||
|
| `src/parser/nodes/identifier.hpp` | `IdentifierNode`'a `Symbol* resolvedSymbol = nullptr;` (Faz 2'de bağlanır). |
|
||||||
|
| `src/parser/nodes/*.cpp` | `toJson()`/`log()`'a yeni alanları (tip, isReachable) ekle — boş cpp'ler doluyor. |
|
||||||
|
|
||||||
|
### Doğrulama
|
||||||
|
- `saqut ast examples/Final.sqt` hâlâ geçerli JSON (regresyon yok, `python3 -m json.tool` ile).
|
||||||
|
- Derleme uyarısız (`-Wall -Wextra`).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Faz 2 — Symbol Table (scope'lu, iki-geçişli toplama)
|
||||||
|
|
||||||
|
**Bağımlılık:** Faz 0, 1. **Hedef:** isim çözümleme + scope + referans toplama.
|
||||||
|
İlgili ADR: 011, 013.
|
||||||
|
|
||||||
|
### Dosyalar
|
||||||
|
|
||||||
|
| Dosya | İçerik |
|
||||||
|
|---|---|
|
||||||
|
| `src/symbol/symbol.hpp` | `enum class SymbolKind { Variable, Function, Parameter, Struct, Field }`. `struct Symbol { std::string name; SymbolKind kind; Type type; SourceLocation definitionLoc; std::vector<SourceLocation> references; Scope* scope; }`. |
|
||||||
|
| `src/symbol/scope.hpp` | `class Scope { Scope* parent; std::unordered_map<std::string, Symbol*> symbols; ... }`. `defineLocal()`, `lookupLocal()`. Her katman bir namespace. |
|
||||||
|
| `src/symbol/symbol_table.hpp` | Scope yığını yönetimi: `enterScope()`, `exitScope()`, `define(Symbol)` (aynı scope'ta duplicate → false + `E002`), `resolve(name)` (içten dışa), `addReference(name, loc)`, `getAllSymbols()`, `toJson()`. |
|
||||||
|
| `src/symbol/symbol_collector.hpp/.cpp` | **İki geçiş** (ADR-011): **Geçiş 1** → tüm üst-seviye tanımlarını (fonksiyon imzaları, struct isim+alan tipleri, global değişkenler) global scope'a hoist et. **Geçiş 2** → fonksiyon gövdelerine in; lokal'leri declare-before-use ile topla; her `IdentifierNode`'u `resolve()` edip `resolvedSymbol`'a bağla + `addReference`. |
|
||||||
|
|
||||||
|
### Notlar
|
||||||
|
- Scope oluşturan node'lar: Program, FunctionDecl (parametreler), Block, for/while.
|
||||||
|
- `src/json.hpp`'deki eski `collectSymbolsRecursive` bu sistemle değiştirilir.
|
||||||
|
- Tanımsız isim → `E001`; bilinmeyen tip → `E007`.
|
||||||
|
|
||||||
|
### Doğrulama
|
||||||
|
- `saqut symbols examples/Final.sqt` → zengin tablo (her sembolün tipi, tanım yeri,
|
||||||
|
referansları). Forward reference çalışır (sonra tanımlı fonksiyon çağrılabilir).
|
||||||
|
- Hatalı örnekler → `E001`/`E002`/`E007` diagnostic'leri.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Faz 3 — Semantic Analiz (Tip Kontrolü + Yapısal Doğrulama)
|
||||||
|
|
||||||
|
**Bağımlılık:** Faz 2. **Hedef:** tipleri ata/kontrol et, yapısal kuralları
|
||||||
|
doğrula. İlgili ADR: 010, 013.
|
||||||
|
|
||||||
|
### Dosyalar
|
||||||
|
|
||||||
|
| Dosya | İçerik |
|
||||||
|
|---|---|
|
||||||
|
| `src/sema/type_checker.hpp/.cpp` | İfadeleri alttan üste gez, her `ExpressionNode`'a `resolvedType` ata. Gizli dönüşüm yok (ADR-010) → uyuşmazlıkta `E003`. Kontrol noktaları: atama (`=`), binary op operand tipleri, fonksiyon çağrısı argümanları (`E008`), array index, return değeri (`E006`), variable init tip uyumu. Hata olunca node'a `Type::error()` → ardışık sahte hata yok. |
|
||||||
|
| `src/sema/structural_validator.hpp/.cpp` | Parent pointer ile ağaç-tırmanma kontrolleri: `break`/`continue` döngü/switch içinde mi (`E004`), `return` fonksiyon içinde mi (`E005`), array boyutu sabit mi (`E009`). |
|
||||||
|
|
||||||
|
### Notlar
|
||||||
|
- Bu iki modül + Faz 2'nin collector'ı birlikte "semantic analiz" fazını oluşturur.
|
||||||
|
- Tüm hatalar toplanır, ilk hatada durulmaz; faz sonunda `DiagnosticEngine`
|
||||||
|
hepsini raporlar, pipeline durur (ADR-013).
|
||||||
|
|
||||||
|
### Doğrulama
|
||||||
|
- Doğru `.sqt` → temiz geçer, her expression node'unun tipi JSON'da görünür.
|
||||||
|
- Hatalı `.sqt` örnekleri → tüm semantik hatalar tek seferde listelenir.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Faz 4 — Optimizasyon Framework
|
||||||
|
|
||||||
|
**Bağımlılık:** Faz 3. **Hedef:** opsiyonel, iteratif, toggle'lı kaynak-seviyesi
|
||||||
|
optimizasyon. **Orijinali bozmaz — klon üstünde** (ADR-007). İlgili ADR: 007, 008, 009.
|
||||||
|
|
||||||
|
### Dosyalar
|
||||||
|
|
||||||
|
| Dosya | İçerik |
|
||||||
|
|---|---|
|
||||||
|
| `src/core/config.hpp` | `CompilerConfig`: pass toggle'ları (`optConstantFolding`, `optDeadCodeElim`, …), `outputFormat`, `mode`, `optimized` bayrağı. |
|
||||||
|
| `src/opt/optimization_pass.hpp` | Soyut `OptimizationPass`: `virtual bool run(ASTNode* root, SymbolTable* table) = 0;` (değişiklik yaptıysa true). `name()`. |
|
||||||
|
| `src/opt/optimization_manager.hpp` | Pass listesi; `CompilerConfig`'e göre seçim; **fixpoint döngüsü** (hiçbir pass değişiklik yapmayana kadar). Çalışmadan önce AST'yi **klonlar** (`ASTNode::clone()` gerekebilir). |
|
||||||
|
| `src/opt/constant_folding.hpp/.cpp` | `BinaryExpression` operandları sabitse hesapla, sonucu sabit `Literal` ile değiştir (klonda). Tipe saygılı (`5/2`→int `2`, ADR-010). Sıfıra bölme → `W002`, katlama yapma. |
|
||||||
|
| `src/opt/dead_code_elim.hpp/.cpp` | `isReachable` (Faz 3) işaretine göre: `return`/`break`/`continue` sonrası statement'lar, `if(false)`, sıfır-referanslı değişken (`W001`/`W003`). |
|
||||||
|
|
||||||
|
### CLI Entegrasyonu
|
||||||
|
|
||||||
|
| Dosya | Değişiklik |
|
||||||
|
|---|---|
|
||||||
|
| `src/cli/args.hpp` | `--optimized` ve `--opt-all`/`--opt-none`/`--skip-*` bayrakları → `CompilerConfig`. |
|
||||||
|
| `src/cli/commands/ast.hpp` · `symbols.hpp` | `--optimized` verilince klon+optimize edilmiş hali göster; verilmezse orijinal. |
|
||||||
|
|
||||||
|
### Doğrulama
|
||||||
|
- `saqut ast file --optimized` → `1+2` katlanmış, ölü kod elenmiş.
|
||||||
|
- `saqut ast file` (bayraksız) → orijinal, **değişmemiş** (öncesi/sonrası ayrımı).
|
||||||
|
- Fixpoint: zincirleme optimizasyon (folding → yeni dead code → DCE) yakalanır.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tamamlanınca
|
||||||
|
|
||||||
|
Bu yol haritası bittiğinde frontend tamamlanmış olur:
|
||||||
|
- Parser → analizli, tipli, sembol-çözümlü AST + zengin symbol table.
|
||||||
|
- Tam hata raporlama (toplu, kataloglu).
|
||||||
|
- Opsiyonel, incelenebilir optimizasyon.
|
||||||
|
|
||||||
|
Sonraki adım (ayrı yol haritası): **IR güçlendirme** (kontrol akışı/fonksiyon/
|
||||||
|
bellek opcode'ları, ADR-005/Issue 5.1) → **C transpile backend** → QBE → JIT
|
||||||
|
(ADR-001 sırası). Dinamik array'in runtime bellek modeli (ADR-014) backend
|
||||||
|
fazında kararlaştırılır.
|
||||||
|
|
@ -0,0 +1,214 @@
|
||||||
|
# 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ı)
|
||||||
Loading…
Reference in New Issue