227 lines
14 KiB
Markdown
227 lines
14 KiB
Markdown
# 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 0–1
|
||
> 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 0–3 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 0–3
|
||
- **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
|
||
açı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.
|