saqut-compiler/docs/roadmap-frontend.md

227 lines
14 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 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…019).
> Tartışma akışı: `docs/transkript-frontend-tasarim.md`.
>
> **İlke:** Sıralama katıdır — her faz bir öncekine dayanır. Her faz sonunda
> geçerli örnekle (`examples/fibonacci.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).
>
> ⚠️ **Yapılan vs planlanan:** Bugün çalışan = lexer, tokenizer, Pratt parser,
> AST, AST'nin JSON serileştirmesi, CLI iskeleti, konum takibi, basit aritmetiği
> düşüren minimal IR deneyi. Bu yol haritasındaki **her şey planlıdır** (sembol
> tablosu, semantik analiz, tip sistemi, diagnostic, optimizasyon).
>
> 🎯 **Bu haftanın işi:** **sembol tablosu + iki-geçişli toplayıcı** (Faz 2),
> hedef **"fibonacci'yi derle ve çalıştır"** (`examples/fibonacci.sqt`). Faz 01
> bunun önkoşuludur.
>
> 🧭 **Önce dikey dilim, sonra çerçeve.** Bir şey çalışmadan önce genel pass
> manager / evrensel config / ağır soyutlama inşa etme. Uçtan uca tek bir dilim
> (kaynak → IR → çalıştır; tamsayı + değişken + kontrol akışı + tek `print`)
> önce çalışsın. Faz 4'ün framework'ü (OptimizationManager, fixpoint, config)
> ancak Faz 03 fibonacci'yi geçirdikten **sonra** anlam kazanır — erken
> soyutlama daha az değil, daha çok karmaşıklıktır.
---
## 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 03
- **Middle-end:** Faz 4
- **Backend:** bu yol haritasının dışında (birincil: IR + bytecode VM, ADR-015;
ileride: C transpile; makine kodu uzak gelecek — "JIT" kapsam dışı)
---
## 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 (declare-before-use ihlali dahil — lokal ve **global başlatıcı**, ADR-011) | Faz 2/3 |
| `E002` | Aynı scope'ta çift tanım | Faz 2 |
| `E003` | Tip uyuşmazlığı (gizli dönüşüm yok; literal için bağlama-göre kural, ADR-010) | 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 |
| `E010` | **Özyinelemeli/döngüsel struct tanımı** (by-value çevrim → sonsuz boyut, ADR-011) | Faz 2/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.)*
**Literal / başlatıcı kuralları (ADR-010/011) hata kataloğunu nasıl etkiler:**
- `float x = 1;`**hata değil** (tamsayı literali bağlama-göre tiplenir,
kayıpsız). `int y = 1.5;``E003` (kayıp). `float x = anInt;``E003`
(değişken→değişken gizli dönüşüm yok).
- `int a = b; int b = 5;` (global) → `E001` (global başlatıcı declare-before-use).
### 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/fibonacci.sqt` hâlâ geçerli JSON (regresyon yok,
`python3 -m json.tool` ile). Parser regresyonu için ayrıca
`examples/parser-stress/Final.sqt` de geçerli JSON üretmeye devam etmeli (bu
dosya **geçerli program değildir**, yalnızca parser/AST stres fixture'ıdır —
semantik fazlarda fixture olarak kullanılmaz).
- 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`; çift tanım → `E002`.
- **Döngüsel struct kontrolü (`E010`):** Geçiş 1'den sonra struct'lar düğüm,
"alanı olarak içerir" kenarıyla bir çevrim-arama (DFS) çalıştır; çevrim →
`E010` (ADR-011). Pointer olmadığı için tüm kapsama by-value'dur; çevrim =
sonsuz boyut.
- **Global başlatıcı declare-before-use (ADR-011):** fonksiyon/struct tam hoist
edilir, global değişken **ismi** hoist edilir, ama global değişken
**başlatıcısı** kendinden önce tanımlı isimleri kullanabilir; aksi → `E001`.
### Doğrulama
- `saqut symbols examples/fibonacci.sqt` → zengin tablo (her sembolün tipi, tanım
yeri, referansları). Forward reference çalışır (sonra tanımlı fonksiyon
çağrılabilir — `main`, `fibonacci`'yi çağırır).
- Hatalı örnekler → `E001`/`E002`/`E007`/`E010` 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 **değişken→değişken** dönüşüm yok (ADR-010) → uyuşmazlıkta `E003`. **Tamsayı literali bağlama-göre tiplenir** (kayıpsızsa beklenen tipe uyar; `float x = 1;` geçerli, `int y = 1.5;``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 + **sert iterasyon tavanı** `maxFixpointRounds`, ADR-009). **Sonlanma değişmezi:** havuzdaki pass'ler monoton (yalnızca küçültür); büyüten pass (inlining) eklenirse tavan zorunlu. Çalışmadan önce AST'yi **klonlar**`ASTNode::clone()` **merkezi bir bileşendir** (ADR-007): parent pointer'lar yeniden bağlanır, sembol tablosu klonlanıp `IdentifierNode→Symbol` bağları **remap** edilir. **Her turda**, klon üzerinde akışa-bağlı analiz (`isReachable`, ref-count) **yeniden hesaplanır** (ADR-009); aksi halde zincirleme fırsatlar bayat veriyle kaçar. |
| `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ı + **FFI seam** `callhost`, ADR-016) → **bytecode VM ile
çalıştırma** (ADR-015) → hedef: **`examples/fibonacci.sqt` derlenir ve çalışır.**
- **Çalıştırma modeli IR + bytecode VM'dir** (ADR-015). **Makine-kodu JIT
ıkça kapsam dışıdır;** öncelik determinizm + incelenebilirlik, ham hız değil.
- **C transpile**, ileride geçerli bir **ikinci** backend olarak kalır (frontend
backend-bağımsız). Makine kodu gerçekten istenirse libgccjit/LLVM'e bağlanılır
— çok uzak gelecek.
- IR/VM tasarlanırken **FFI seam'i şimdiden bırak** (ADR-016); `print` ilk
müşteridir. Bellek host (C++) heap'idir; özel allocator yok. Dinamik array'in
runtime modeli (ADR-014) bu fazda netleşir.
> Çerçeve uyarısı: bu sonraki adım da **önce dikey dilim** ilkesine tabidir —
> genel VM/optimizasyon altyapısı kurmadan önce fibonacci uçtan uca çalışsın.