From cf6f70644945ebab6505b31038b703ac6f87eaf8 Mon Sep 17 00:00:00 2001 From: abdussamedulutas Date: Sun, 14 Jun 2026 19:53:12 +0300 Subject: [PATCH] docs: belgeleri yeniden hizala (IR+VM modeli, kilitli kararlar) - Calistirma modeli: "JIT" terimi birakildi -> IR + bytecode VM birincil; makine-kodu JIT kapsam disi (ADR-015). C-transpile ikinci backend. - readme.md bastan yazildi: toolbox cercevesi, yapilan vs planlanan ayrimi. - ADR amend: 007 (klon yuk tasir), 009 (fixpoint degismezi + analiz yeniden hesabi), 010 (literal baglama-gore tipleme), 011 (global baslatici uc-parcali kural + dongusel struct E010), 014 (bellek gerekcesi). - Yeni ADR: 015 (IR+VM), 016 (FFI seam), 017 (batteries=sinir), 018 (interface ertelendi), 019 (frontend<->runtime ayrimi). - roadmap: bu hafta sembol tablosu->fibonacci; once dikey dilim; E010. - examples: Final.sqt -> parser-stress/ (gecersiz fixture); yeni gecerli fibonacci.sqt eklendi. Co-Authored-By: Claude Opus 4.8 --- docs/adr-frontend-analiz.md | 339 +++++++++++++++++++++++-- docs/fikirler.md | 17 ++ docs/roadmap-frontend.md | 77 ++++-- examples/fibonacci.sqt | 33 +++ examples/{ => parser-stress}/Final.sqt | 0 examples/parser-stress/README.md | 21 ++ readme.md | 268 +++++++++++-------- 7 files changed, 612 insertions(+), 143 deletions(-) create mode 100644 examples/fibonacci.sqt rename examples/{ => parser-stress}/Final.sqt (100%) create mode 100644 examples/parser-stress/README.md diff --git a/docs/adr-frontend-analiz.md b/docs/adr-frontend-analiz.md index f0194fb..17ece89 100644 --- a/docs/adr-frontend-analiz.md +++ b/docs/adr-frontend-analiz.md @@ -9,6 +9,13 @@ > 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`. +> +> ⚠️ **Yapılan vs planlanan:** Bu belgedeki ADR-006…019 **tasarım kararlarıdır**; +> tarif edilen makine (sembol tablosu, semantik analiz, tip sistemi, diagnostic, +> optimizasyon, IR+VM) **henüz kodlanmamıştır.** Bugün çalışan: lexer, tokenizer, +> Pratt parser, AST, AST'nin JSON serileştirmesi, CLI iskeleti, konum takibi ve +> basit aritmetiği düşüren minimal bir IR deneyi. Hiçbir ADR, var olmayan bir +> mekanizmayı varmış gibi anlatmaz. --- @@ -48,10 +55,10 @@ 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) +parser → AST → (opsiyonel, iteratif, bytecode VM (birincil) +symbol table → toggle'lı, ortak + ileride C transpile +semantic analiz gösterim üstünde) (makine kodu = uzak +(annotated AST) gelecek; ADR-015) ``` - **Pass 1 (Syntax):** token → ham AST. (Büyük ölçüde mevcut.) @@ -62,9 +69,10 @@ semantic analiz gösterim üstünde) QBE / JIT) "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. +**Neden bu katmanlama?** Birden çok backend (birincil: IR+bytecode VM, ADR-015; +ileride: C transpile; çok uzak: makine kodu) hedeflendiği için, ortak işler +(analiz, optimizasyon) **bir kez** ortak katmanda yapılmalı; yoksa her backend +aynı optimizasyonu yeniden yazar. --- @@ -109,6 +117,35 @@ saqut ast file.sqt → ham + annotate edilmiş AST (1+2 burada duru saqut ast file.sqt --optimized → klon, folding uygulanmış (3 var) ``` +### Güncelleme — Klon maliyeti yük taşır (load-bearing) + +İlk metin "ağaç klonlamak ucuz ve basittir" diyordu; bu **klon maliyetini hafife +alıyor** ve bir **tutarlılık (coherence) problemini** atlıyordu. Düzeltme: + +`ASTNode::clone()` "belki gerekir" değil, **merkezi ve spesifiye edilmesi +zorunlu** bir bileşendir; tüm öncesi/sonrası hikâyesi ona dayanır (bkz. roadmap +Faz 4'te clone() yükseltildi). + +**Klonlanırken karar verilmesi gereken iki nokta (açıkça belgele):** + +1. **Parent pointer'lar yeniden bağlanmalı.** Klon node'larının `parent`'ı + orijinali değil, klonu göstermeli; yoksa yapısal doğrulama ve dönüşümler + yanlış ağaçta gezinir. + +2. **`IdentifierNode → Symbol` bağları: paylaş mı, yeniden eşle mi?** + - **Paylaş** (klon ve orijinal aynı sembol tablosuna işaret eder): ucuz, ama + klonu optimize etmek orijinalin **referans sayımlarını bozar** (DCE klonda + bir kullanımı silince orijinalin Symbol ref-count'u da düşer). + - **Yeniden eşle** (klona ait bir sembol tablosu kopyası): doğru, ama ucuz + değil. + - **Karar:** `--optimized` istendiğinde sembol tablosu da **klonlanır ve + yeniden eşlenir** (remap). Doğruluk, ucuzluğa tercih edilir; klon zaten + yalnızca optimizasyon istendiğinde üretilir, sıcak yol değildir. "Ucuz" + iddiası kaldırıldı. + +Bu, ADR-013'teki "ref-count Symbol'da yaşar" kararıyla tutarlıdır: ref-count +Symbol'da olduğu için, klonun kendi Symbol'larına sahip olması şarttır. + --- ## ADR-008: Optimizasyon Konumu — AST mı, IR mı? @@ -129,7 +166,7 @@ sorusu tartışıldı. İki uç yaklaşım var: - **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. + 2. Backend-bağımsız → bytecode VM ve ileride C transpile birden faydalanır. 3. İncelenebilir kalır (`saqut ast --optimized`) — projenin varlık sebebi. - **CFG/dataflow gerektiren optimizasyonlar** ("bir kez atanıp bir kez @@ -169,6 +206,39 @@ belki 7 — kodun kendisi belirler. > her **tur** daha az değişiklik yapar. Analiz pass'leri (symbol table, type check) > "kolaylaşmaz"; onlar bir kez çalışır. +### Güncelleme — Sonlanma değişmezi (termination invariant) + +Fixpoint döngüsünün **sonlanacağı garanti edilmeli**. İki seçenekten en az biri +zorunludur: + +1. **Monotonluk:** havuzdaki tüm pass'ler **monoton** olmalı — yalnızca + küçültür/sadeleştirir, asla büyütmez. Constant folding ve dead code + elimination bugün monotondur, dolayısıyla fixpoint sonlanır. +2. **Sert iterasyon tavanı (cap):** bir üst sınır (örn. `maxFixpointRounds`). + +**Neden gerekli:** ileride **büyüten** pass'ler (inlining, loop unrolling) +eklenirse, naif fixpoint **salınabilir** (A büyütür, B küçültür, sonsuz döngü). +Büyüten bir pass eklendiği an, monotonluk bozulur ve **iterasyon tavanı zorunlu +hale gelir.** Bu değişmez şimdiden yazıya geçirildi ki ileride unutulmasın. + +### Güncelleme — "Analiz bir kez çalışır" çelişkisinin çözümü + +ADR-013 "analiz bir kez çalışır" diyor; ama folding **erişilebilirliği** +(`if(false)`) ve **referans sayımlarını** değiştirir, DCE de tam bunlara +dayanır. Eğer analiz gerçekten yalnızca bir kez çalışırsa, fixpoint'in ikinci +turundaki DCE **bayat (stale) veriyle** çalışır ve zincirleme fırsatları kaçırır. + +**Çözüm — iki analiz sınıfını ayır:** + +- **Kaynağa-bağlı analiz** (her ifadenin tipi, sembol bağları): kaynak değişmediği + sürece sabittir → **bir kez** çalışır, klona taşınır. +- **Türetilmiş/akışa-bağlı analiz** (erişilebilirlik `isReachable`, referans + sayıları): bir dönüşüm bunları geçersizleştirir → **fixpoint döngüsünün her + turunda, klon üzerinde yeniden hesaplanır.** + +Yani "analiz bir kez çalışır" ifadesi yalnızca **kaynağa-bağlı** analiz için +geçerlidir; akışa-bağlı analiz tur başına tazelenir. ADR-013 buna göre okunmalı. + --- ## ADR-010: Tip Sistemi Tasarımı @@ -205,6 +275,33 @@ boyut tip eşitliğine girmez (JS gibi). Tip kontrolü basit kalır. de olabilir, yıllarca repolarda tozlanabilir de." Temel sağlam ve büyümeye açık olmalı. +### Güncelleme — Sayısal literal tipleme kuralı + +"Gizli dönüşüm yok + tip çıkarımı yok" altında `float x = 1;` ifadesi +**tanımsızdı**. Bu açıkça karara bağlanmalı, çünkü tip denetleyicisini (Faz 3) +doğrudan yönlendirir. + +**Değerlendirilen iki kural:** + +- **(a) Literal her zaman `int`:** `1` daima `int`'tir. `float x = 1;` bir tip + hatasıdır; `float x = 1.0;` yazmak zorunludur. En katı, en öngörülebilir; ama + rahatsız edici ve "gizli dönüşüm yok" ilkesini literallere kadar gereksiz yere + zorlar. +- **(b) Tamsayı literali bağlama-göre tiplenir (context-typed / polymorphic):** + tipsiz bir tamsayı sabiti, beklenen tip ona **kayıpsız** sığıyorsa o tipe + uyarlanır. `float x = 1;` çalışır (`1` → `1.0`); `int y = 1.5;` ise hata + (kayıp olur). + +**Karar:** ✅ **(b) Bağlama-göre tiplenen tamsayı literalleri.** + +- Gerekçe: bu bir **değişken-değer dönüşümü değil, bir derleme-zamanı sabitinin + uygun tipte yorumlanmasıdır** — tam olarak ADR-010'un zaten tanıdığı "sabit + istisnası" (`int a = 5/2 → 2`) ruhuyla aynı kapıya çıkar. Çalışma zamanı + `int` değişkenini `float`'a gizlice çevirmek hâlâ **yasaktır**; istisna + yalnızca **literal/sabit** içindir. +- Kural net: *değişken→değişken* gizli dönüşüm yok; *literal→beklenen tip* + kayıpsızsa serbest. `float x = anInt;` hata; `float x = 1;` serbest. + --- ## ADR-011: Scope ve Forward Reference Kuralları @@ -269,6 +366,44 @@ Her katman bir namespace tutar; değişken bulunamazsa bir üst katmanda aranır derdi yalnızca global'ler içindir, onu da Geçiş 1 çözer (global'ler en baştan tamamen doludur). +### Güncelleme — Global "tam forward reference" çok genişti: üç-parçalı kural + +İlk metin "global = her zaman forward-reference güvenli" diyordu; bu **fazla +geniş**. Global bir değişkenin **başlatıcısının (initializer) bir çalışma +sırası vardır** (tıpkı lokaller gibi). Düzeltme — üç ayrı kural: + +1. **Global fonksiyonlar / struct'lar → tam hoisting.** Tanım anında çalışmazlar, + sıradan bağımsız her yerde görünür. (Güvenli; değişmedi.) +2. **Global değişken isimleri → hoist edilir.** İsim her yerde görünür. +3. **Global değişken başlatıcıları → değer sırasına tabidir** (lokaller gibi) → + **declare-before-use** VEYA bir **definite-assignment (kesin-atama) analizi** + gerektirir. + +**Neden:** `int a = b; int b = 5;` global scope'ta, isim-hoisting'e güvenilirse, +`a`'ya **sessizce çöp değer** verir — kaçınmaya çalıştığımız tam o JS `var` +durumu. Java da aynı sebeple bunu kısıtlar. Karar: global başlatıcılar için de +**declare-before-use** uygulanır (en basit, definite-assignment'a gerek +bırakmaz). Yani isim görünür ama **kendinden önceki** bir global başlatıcıda +kullanılabilir. + +### Güncelleme — Döngüsel / karşılıklı-özyinelemeli struct tespiti + +Pointer olmadığı için tüm struct iç içeliği **değer (by-value)** ile olur → +herhangi bir kapsama döngüsü sonsuz boyut demektir: + +``` +struct A { B b } // A, B'yi değer olarak içerir +struct B { A a } // B, A'yı değer olarak içerir → sonsuz boyut +``` + +Bu **derleme hatası olmak zorunda** ve hata kataloğunda **eksikti**. Eklendi: +**`E010` — özyinelemeli/döngüsel struct tanımı.** Symbol toplama sonrası bir +**topolojik / kapsama-döngüsü kontrolü** çalışır (struct'ları düğüm, "alan +olarak içerir" kenarını çevrim arayan bir DFS ile). Çevrim bulunursa `E010`. + +(Karşılaştır: `struct A { B b }` + `struct B { int x }` geçerlidir; yalnızca +**çevrim** yasaktır. Pointer olsaydı çevrim mümkün olurdu — ama pointer yok.) + --- ## ADR-012: ExpressionNode / StatementNode Ara Tabanları @@ -351,12 +486,14 @@ Sebep: kullanım sayısı **değişkene** aittir, tek bir kullanım node'una de |---|---|---| | Pointer (kullanıcı syntax'ı `*`/`&`) | ❌ Yok | Ama derleyici/runtime **içeride** pointer'ı sonuna kadar kullanır | | Tuple / Generic (``) | ❌ 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 | +| Class / OOP / kalıtım | ❌ Yok (başta) | `class` keyword'ü yok sayılır | +| Closure | ❌ Yok | Bkz. ADR-019 (bellek bağımlılığı) | +| Struct | ✅ Var | `struct A { B bVar }` olur (B başka yerde tanımlı); **çevrim yasak → `E010`** | +| `interface` | ⏸️ Ertelendi | Reddedilmedi; v0 değil — gerekçe aşağıda + ADR-018 | | 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 | +| Gizli int↔float dönüşümü | ❌ Yok | Sadece sabit/literal folding'de istisna (ADR-010) | ### Dinamik Array'in Bellek Yükümlülüğü (Gelecek Notu) @@ -364,13 +501,164 @@ Sebep: kullanım sayısı **değişkene** aittir, tek bir kullanım node'una de 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. +- **IR + bytecode VM (ilk çalıştırma modeli, ADR-015):** bellek host (C++) + heap'idir; array'ler host tarafında `std::vector` benzeri bir yapıyla tutulur. + VM, array işlemleri için **host fonksiyonlarına** (FFI seam, ADR-016) çağrı + yapar. v0 için özel allocator gerekmez. +- **C transpile backend (ileride, ikinci backend):** `int[]` → C'de + `struct {int* data; size_t len, cap;}`, `malloc/realloc/free` ile yönetilir. +- **Yönetim stratejisi (ne zaman free):** scope-tabanlı ownership (array'i tutan + değişken scope'tan çıkınca free). GC gerekmez — **neden gerekmediği aşağıda + gerekçelendirildi.** + +### Güncelleme — Scope-tabanlı bellek artık GEREKÇELİ (bağımlılığı belgele) + +Önceki kaygı ("scope çıkışında free, aliasing/escape altında bozulur") kilitli +dil kimliğiyle **lehte çözüldü:** + +> prosedürel + value semantics + kullanıcı pointer'ı yok + closure yok + kaçan +> referans yok → array/string'ler tanımlandıkları scope'tan **kaçamaz** → +> scope-tabanlı ownership (scope çıkışında free) **gerçekten çalışır, GC +> gerekmez.** + +**Bağımlılık açıkça yazılır:** scope-tabanlı bellek, *yalnızca* no-pointer / +value-semantics seçimi sayesinde geçerlidir. `interface` değerleri veya kaçan +referanslar eklenirse bu sorun **yeniden açılır**. (Bu, `interface`'i ertelemenin +ikinci sebebidir — bkz. ADR-018, ADR-019.) + +--- + +## ADR-015: Çalıştırma Modeli — IR + Bytecode VM (Makine-Kodu JIT Kapsam Dışı) + +### Bağlam + +Daha önceki belge/konuşmalarda çalıştırma için "JIT" terimi geçiyordu. Hangi +çalıştırma modeli? Üç uç var: tree-walker, bytecode VM, gerçek makine-kodu JIT. + +### Değerlendirilen Yaklaşımlar + +- **Tree-walker (AST'yi doğrudan gez-çalıştır):** en basit, ama **çok yavaş**; + her çalıştırmada ağaç gezilir. +- **Makine-kodu JIT** (register allocation, ABI/çağırma sözleşmeleri, + çalıştırılabilir `mmap` bellek): en hızlı; ama **tek faydası ham hızdır**, ki + burada öncelik değil. Determinizmi ve incelenebilirliği zorlaştırır, devasa + mühendislik yükü getirir. +- **IR + bytecode VM** (kendi IR'imize derle, yorumlayıcı döngü ile çalıştır): + determinizm ve incelenebilirliği **doğrudan** sağlar; tree-walker'dan hızlı; + bellek host heap'iyle kolay. + +### Karar + +✅ **IR + bytecode VM.** saQut kendi IR'sine derler ve bir yorumlayıcı döngüyle +çalıştırır. + +- ❌ **Makine-kodu JIT kapsam dışıdır** (terminoloji düzeltmesi: "JIT" demeyi + bırak). Öncelikler **determinizm + incelenebilirlik** (toolbox), ham hız değil. +- **Bellek kolaydır:** host (C++) heap'i; özel runtime allocator yok (v0). +- **C'ye transpile, geçerli bir İKİNCİ backend olarak ileride kalır** (frontend + backend-bağımsız, ADR-006). +- İleride makine kodu **gerçekten** istenirse: elle code generator yazmak yerine + **libgccjit / LLVM'e bağlan** (ADR-001'deki QBE/custom değerlendirmeleri o gün + için geçerli). Bu **çok uzak gelecektir.** + +--- + +## ADR-016: FFI Seam — Host Fonksiyon Çağırma Deliği + +### Bağlam + +`print` bile bir "dış dünya" çağrısıdır; VM tek başına ekrana yazamaz, host'tan +bir fonksiyon çağırmalıdır. Bu ihtiyaç ya **kaza eseri** tek bir özel-durum +olarak gömülür, ya da **kasıtlı bir mekanizma** olarak tasarlanır. + +### Karar + +✅ **IR/runtime tasarımına bilinçli bir FFI seam konur:** "host fonksiyonu çağır" +için tek, genel bir IR mekanizması (örn. `callhost , args...`). + +- `print` bu seam'in **ilk müşterisidir**, özel-durum değil. +- İleride tüm "batteries" (bkz. ADR-017) bu sınır üzerinden gelir: sıkıştırma/ + kripto C kütüphaneleri buraya bağlanır. +- **Neden şimdi:** seam'i sonradan eklemek IR ve VM'i baştan değiştirmeyi + gerektirir; deliği bir kez doğru açmak ucuzdur. Mekanizmayı **şimdi** doğru + tasarla, içini sonra doldur. + +--- + +## ADR-017: Batteries / Stdlib — Sınır Problemi (Ertelendi) + +### Bağlam + +Gerçek bir genel sürüm pil ile gelmeli (sıralama, sıkıştırma, kripto, +JSON/XML/HTML, ileride runtime/donanım, ses/görüntü/video). JSON/string +ergonomisi olmayan bir dil benimsenmez — bu doğru. Ama korku: pilleri çekirdeğe +gömmek **monolit** yaratır. + +### Karar + +✅ **Pil = sınır (boundary) problemi, "zlib'i yeniden yaz" problemi değil.** + +- Çekirdek: **küçük bir gerçek builtin kümesi** (`print`, temel zorunlular) + + **gerisi kütüphane/FFI.** +- **JSON/XML/HTML ayrıştırıcıları saQut'ta yazılabilir** (string + struct + + fonksiyon + kontrol akışı yeter) — ilk "gerçek program" demoları. +- **Sıkıştırma/kripto:** denenmiş C kütüphanelerine **FFI** ile bağlan. **Kripto + asla elle yazılmaz.** +- **Bugüne tek yansıması:** FFI seam'i (ADR-016) bırak. Gerisi **v0 kapsamı + dışıdır.** Sınır bir kez çizilir, piller üstünde sonsuza dek birikir. + +--- + +## ADR-018: `interface` Ertelemesi (Reddedilmedi) + +### Bağlam + +Kullanıcı struct'ın yanında `interface` de istedi (crypto, compression, custom +data types, JSON, string için). `interface` alınmalı mı, ne zaman? + +### Karar + +✅ **Şimdi `struct`, `interface` ise ertelenir (reddedilmez).** + +**Neden ertelendi:** `interface`, `struct`'tan kategorik olarak ağırdır. +- Struct yalnızca alan yerleşimidir (field layout). +- Interface "bu metotları sağlayan herhangi bir tip" demektir → çağrı yerinde + somut tip **bilinmez** → **dinamik dispatch** → vtable / fat pointer (içsel + pointer, izinli) → ve bir interface değeri **herhangi bir tipi tutabilir**, bu + da **kaçma/yaşam-süresi (escape/lifetime) problemini yeniden açar** (ADR-019). +- Go bunu fat pointer + GC ile çözer; saQut **GC istemiyor.** + +Kullanıcının saydığı her şey (crypto, compression, custom data, JSON, string) +**yalnızca struct + fonksiyonla** yapılabilir (C bunu kanıtlar). Dolayısıyla: +şimdi struct'ı al, interface'i ertele. + +**Metot-çağrı şekeri** (`list.push(5)` → `push(list, 5)`) ileride **parser +seviyesinde, sıfır semantik maliyetli** bir desugaring olarak eklenebilir — +şimdi değil. + +--- + +## ADR-019: Frontend ↔ Runtime Sorumluluk Ayrımı + +### Bağlam + +"Hangi CPU çekirdeği, hangi cihaz, ne zaman tetiklenir, hangi çıktı formatı" +gibi sorular nereye ait? Frontend'e mi, runtime'a mı? + +### Karar + +✅ **Net ayrım, frontend'i runtime kaygılarıyla yükleme:** + +- **Frontend:** **yapı ve anlam** — tip, scope, dataflow. (Bu yol haritasının + konusu.) +- **Runtime/backend:** çekirdek/cihaz/tetikleme/çıktı formatı. + +**Neden:** bu ayrım, kullanıcının önem verdiği **modülerliği korur**; frontend +backend-bağımsız kalır (ADR-006), böylece IR+VM ve ileride C-transpile aynı +frontend'den beslenir. Ayrıca **value-semantics + no-escape** kararının (kaçan +referans/closure yok) bağımlılığı buradadır: bu sayede scope-tabanlı bellek +çalışır (ADR-014). Closure veya interface değerleri eklemek bu ayrımı ve bellek +modelini birlikte zorlar — ikisi de bu yüzden ertelendi. --- @@ -379,11 +667,16 @@ bir yükümlülüktür ama **frontend'i bloklamaz** ve kolay yolu vardır: | 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 | +| 007 | Analiz vs optimizasyon | Analiz yerinde işaretler; optimizasyon klonda dönüştürür; `clone()` merkezi, sembol tablosu remap edilir | | 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) | +| 009 | Pass yönetimi | Fixpoint döngüsü, toggle'lı; monotonluk/iterasyon-tavanı değişmezi; akışa-bağlı analiz tur başına tazelenir | +| 010 | Tip sistemi | Minimal+genişletilebilir Type; gizli dönüşüm yok; Error tipi; tamsayı literali bağlama-göre tiplenir | +| 011 | Scope/forward ref | Global'de forward ref (fonksiyon/struct), ama global başlatıcı declare-before-use; lokal declare-before-use; döngüsel struct → `E010` | | 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 | +| 014 | Dil kapsamı | Pointer/class/generic/closure yok; struct+array+tipli fonksiyon var; scope-tabanlı bellek gerekçeli | +| 015 | Çalıştırma modeli | IR + bytecode VM; makine-kodu JIT kapsam dışı | +| 016 | FFI seam | Kasıtlı "host fonksiyonu çağır" mekanizması; `print` ilk müşteri | +| 017 | Batteries/stdlib | Sınır problemi; küçük builtin + FFI/kütüphane; ertelendi | +| 018 | `interface` | Ertelendi (reddedilmedi); struct+fonksiyon yeter | +| 019 | Frontend↔runtime | Frontend yapı+anlam; çekirdek/cihaz/çıktı runtime'a ait | diff --git a/docs/fikirler.md b/docs/fikirler.md index f667d67..e129375 100644 --- a/docs/fikirler.md +++ b/docs/fikirler.md @@ -4,6 +4,23 @@ > gelecek yol haritası hakkında kapsamlı analizleri içerir. > Her kararın **neden** alındığı, alternatiflerin neden elendiği ve > gelecekte hangi koşullarda tekrar değerlendirileceği belirtilmiştir. +> +> ⚠️ **Hizalama notu (sonraki oturum):** Aşağıdaki ADR-001 ve ADR-005, backend +> kod-üretimi seçeneklerini (LLVM/QBE/custom/C-transpile) ve "JIT" terimini +> tartışır. Sonradan **çalıştırma modeli netleşti** ve bazı ifadeler güncellendi: +> +> - **Birincil çalıştırma modeli = IR + bytecode VM** (yorumlayıcı döngü). +> Bkz. `docs/adr-frontend-analiz.md` **ADR-015**. +> - **Gerçek makine-kodu JIT kapsam DIŞIDIR** (tek faydası ham hız; öncelik +> determinizm + incelenebilirlik). Buradaki "JIT" geçişleri bu ışıkta okunmalı. +> - **C-transpile**, ileride geçerli bir **ikinci backend**'tir; QBE/custom/LLVM +> ise "makine kodu gerçekten gerekirse libgccjit/LLVM'e bağlan" çerçevesinde +> **çok uzak gelecektir**. ADR-001'deki karşılaştırmalar o gün için geçerli. +> - "HeavyIR/LightIR" ikiliği (ADR-005) bir **gelecek fikri** olarak durur; v0'ın +> IR+VM hedefi tek, basit bir IR'dir + **FFI seam** (ADR-016). +> - **Yapılan vs planlanan:** ADR-001'deki "mevcut durum" listesi hâlâ doğrudur +> (lexer/tokenizer/parser/AST + minimal IR deneyi çalışır); kod üretimi ve VM +> **henüz yoktur.** --- diff --git a/docs/roadmap-frontend.md b/docs/roadmap-frontend.md index 05479ca..897b73d 100644 --- a/docs/roadmap-frontend.md +++ b/docs/roadmap-frontend.md @@ -1,14 +1,30 @@ # 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). +> 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 -> mevcut örneklerle (`examples/Final.sqt`, `examples/source.sqt`) ve CLI +> 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. --- @@ -25,7 +41,8 @@ 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) +- **Backend:** bu yol haritasının dışında (birincil: IR + bytecode VM, ADR-015; + ileride: C transpile; makine kodu uzak gelecek — "JIT" kapsam dışı) --- @@ -46,21 +63,28 @@ Katman eşlemesi (ADR-006): | Kod | Anlam | Hangi fazda üretilir | |---|---|---| -| `E001` | Tanımsız değişken/isim | Faz 2/3 | +| `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ığı | Faz 3 | +| `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ı. @@ -83,7 +107,11 @@ ayır, analiz alanlarını ekle. İlgili ADR: 012, 013. | `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). +- `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`). --- @@ -105,12 +133,20 @@ ayır, analiz alanlarını ekle. İlgili ADR: 012, 013. ### 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`. +- 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/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. +- `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. --- @@ -123,7 +159,7 @@ doğrula. İlgili ADR: 010, 013. | 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/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 @@ -148,7 +184,7 @@ optimizasyon. **Orijinali bozmaz — klon üstünde** (ADR-007). İlgili ADR: 00 |---|---| | `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/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`). | @@ -174,6 +210,17 @@ Bu yol haritası bittiğinde frontend tamamlanmış olur: - 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. +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. diff --git a/examples/fibonacci.sqt b/examples/fibonacci.sqt new file mode 100644 index 0000000..c78b7f9 --- /dev/null +++ b/examples/fibonacci.sqt @@ -0,0 +1,33 @@ +// saQut — geçerli örnek program (semantik analiz + kod üretimi fixture'ı) +// +// Kilitlenmiş tasarıma uyar: prosedürel, value semantics, kullanıcıya açık +// pointer yok, tek main, struct/array gerektirmez. Birinci kilometre taşının +// ("fibonacci'yi derle ve çalıştır") referans programıdır. +// +// İlk ifade doğrudan bir fonksiyon tanımı olabilir; zorunlu class/main +// boilerplate'i yoktur (Java'nın aksine). + +int fibonacci(int n) { + if (n <= 1) { + return n; + } + return fibonacci(n - 1) + fibonacci(n - 2); +} + +int fibonacciIterative(int n) { + int first = 0; + int second = 1; + for (int i = 0; i < n; i = i + 1) { + int next = first + second; + first = second; + second = next; + } + return first; +} + +int main() { + int n = 10; + print(fibonacci(n)); // recursive + print(fibonacciIterative(n)); // iterative + return 0; +} diff --git a/examples/Final.sqt b/examples/parser-stress/Final.sqt similarity index 100% rename from examples/Final.sqt rename to examples/parser-stress/Final.sqt diff --git a/examples/parser-stress/README.md b/examples/parser-stress/README.md new file mode 100644 index 0000000..be4d031 --- /dev/null +++ b/examples/parser-stress/README.md @@ -0,0 +1,21 @@ +# Parser Stres Fixture'ları + +Buradaki dosyalar **yalnızca parser/AST'yi zorlamak** için yazılmıştır. +**Geçerli saQut programı değildirler** ve semantik analiz / kod üretimi için +fixture olarak **kullanılmamalıdır**. + +## `Final.sqt` + +Tarihsel olarak parser'ın token/AST kapsamını test etmek için kullanıldı +(289 token, 200+ AST node). Ancak kilitlenmiş dil tasarımını birden çok yerde +**ihlal eder**: + +- **Kullanıcıya açık pointer kullanımı** (`struct List*`, `->`) — dilde `*`/`&` + yoktur (bkz. ADR-014). +- **Sabit boyutlu array** (`int arr[100]`) — array tipi `int[]`'tir, boyut tipin + parçası değildir (bkz. ADR-010). +- **İki `int main()` tanımı** — aynı scope'ta çift tanım yasaktır (ADR-011, `E002`). +- `printf` format-string semantiği — dilin builtin'i `print`'tir; format'lı + çıktı bir kütüphane/FFI işidir (bkz. ADR-017). + +Geçerli, küçük bir örnek için `examples/fibonacci.sqt`'ye bakın. diff --git a/readme.md b/readme.md index b37f806..aa29342 100644 --- a/readme.md +++ b/readme.md @@ -1,127 +1,185 @@ -# Syntax +# saQut -Syntax modunda 2 seçenek bulunmaktadır - - JIR: Söz dizimi tamamen Java programlama diline uygun olarak parse edilmektedir. Compiling, transpiling desteklenir Interpreter desteklenmez - - CIR: Söz dizimi tamamen C programlama diline uygun olarak parse edilir. Compiling ve Interpreter desteklenir. transpiling desteklenmez +**Programlanabilir, incelenebilir bir derleyici — bir "alet çantası" (toolbox).** -# Compiler short options +saQut'un asıl varlık sebebi dilin kendisinden çok, **derleme sürecinin her +aşamasının dışarıdan görülebilir ve müdahale edilebilir olmasıdır.** Token'lar, +AST, sembol tablosu, optimizasyonun öncesi/sonrası ve IR — hepsi ayrı ayrı +incelenebilir. Dil, bu aletin üzerinde çalıştığı küçük, prosedürel bir +örnektir; vitrin değil, alet. + +Uygulama dili **C++**'tır (header-only eğilimli, bkz. `docs/fikirler.md` ADR-003). + +--- + +## Şu an ne çalışıyor, ne çalışmıyor + +Belgeler **planlanan** ile **yapılan**ı net ayırır. Bugünkü gerçek durum: + +### ✅ Çalışıyor (built) +- **Lexer** — karakter seviyesi tarama, konum takibi. +- **Tokenizer** — token üretimi (6 token tipi), yorum satırı desteği. +- **Pratt parser** — ifade (Pratt) + statement (recursive descent) ayrıştırma. +- **AST** — fonksiyon, blok, değişken tanımı, if/for/while/do-while/return, + ifade node'ları. +- **AST'nin JSON serileştirmesi** — `saqut ast` ile incelenebilir. +- **CLI komut yapısı** — `tokens`, `ast`, `symbols`, `run` iskeletleri. +- **Kaynak konum takibi** (SourceLocation) — offset → (satır, sütun). +- **Minimal IR deneyi** — basit aritmetiği düşürür (örn. `1 + (7/3)` → kısa + doğrusal komut dizisi). Henüz tam bir backend değil, bir deneydir. + +### 🚧 Henüz yok (planned) +- Sembol tablosu +- Semantik analiz +- Tip sistemi +- Diagnostic (hata raporlama) motoru +- Optimizasyon +- IR + bytecode VM ile çalıştırma + +> `feature/frontend-analysis` dalı şu an yalnızca bu yapılmamış işin **tasarım +> belgelerini** içerir, kodunu değil. + +**Birinci kilometre taşı ("bitti" tanımı):** derleyici **fibonacci'yi** +(recursive + iterative) ve basit matematik/döngü programlarını **derleyip +çalıştırabilmeli.** Referans program: `examples/fibonacci.sqt`. + +--- + +## Dil kimliği (kilitli) + +Prosedürel, **C ailesi sözdizimi**, **value semantics**. İlk ifade doğrudan bir +işlem/tanım olabilir; zorunlu class/`main` boilerplate'i yoktur (Java'nın aksine). + +| Özellik | Karar | +|---|---| +| Class / OOP / kalıtım | **Yok** | +| Closure | **Yok** | +| Generic | **Yok** | +| Kullanıcıya açık pointer (`*` / `&`) | **Yok** — derleyici/runtime içeride pointer'ı serbestçe kullanır | +| `struct` | **Var** | +| Tipli fonksiyonlar (dönüş + parametre) | **Var** | +| Array (`int[]`) | **Var** | +| `interface` | **Ertelendi** (v0 değil — gerekçe ADR-018) | +| `auto` / tip çıkarımı | **Yok** | +| Gizli int↔float dönüşümü | **Yok** (tek istisna: sabit folding) | + +Gerekçe: prosedürel tasarım semantik karmaşıklığı en aza indirir ve hedeflerle +(fibonacci, matematik, sıralama, ayrıştırma) örtüşür. Standart C'de `class` +yoktur (o C++'tır); C, struct + fonksiyonun yettiğini kanıtlar. + +--- + +## Çalıştırma modeli (kilitli): IR + bytecode VM + +saQut, kendi **IR**'sine derler ve bu IR'yi bir **yorumlayıcı döngü (bytecode +VM)** ile çalıştırır. + +- **Tree-walker DEĞİL** (çok yavaş). +- **Gerçek makine-kodu JIT DEĞİL.** Makine kodu üretimi (register allocation, + ABI/çağırma sözleşmeleri, çalıştırılabilir `mmap` bellek) **kapsam dışıdır** — + tek faydası ham hızdır ve hız burada öncelik değildir. Öncelikler + **determinizm** ve **incelenebilirliktir**; bytecode VM ikisini de doğrudan + sağlar. +- **Bellek bu modelde kolaydır:** host (C++) heap'i kullanılır; v0 için özel + runtime allocator gerekmez. +- **C'ye transpile, geçerli bir İKİNCİ backend olarak ileride kalır** (frontend + backend-bağımsızdır — middle-end ayrımının amacı budur, ADR-006). İleride + makine kodu istenirse elle code generator yazmak yerine **libgccjit / LLVM'e + bağlanılır** — ama bu çok uzak gelecektir. + +> Eski belge/konuşmalarda geçen "JIT" terimi yanlış yönlendiricidir; doğru +> çerçeve **IR + VM**'dir. + +--- + +## Mimari hatlar ``` -sqt kaynak kodunu çallıştırır -saqut file:sourcecode.sqt - -sqt kaynak kodunu C koduna sonrada makine koduna derler. GCC gereklidir -saqut compile file:sourcecode.sqt output:program.exe - -Derleyicinin olduğu gibi çalıştırılması interpreter moduna alır, konsola yazılan kodları alır çalıştırır outputu loglar -saqut - -Derleyici kodu alır ve IR üretir -saqut parse file:sourcecode.sqt output:program.ces - -Derleyici IRyi alır ve çalıştırır. Burda kaynak kodu veya IR olup olmadığını otomatik anlar -saqut file:sourcecode.ces - -Derleyici IRyi veya kaynak kodunu alır C diline çevirir -saqut transpile file:sourcecode.ces output:program.c - -Derleyici kaynak kodu ASTsini çıkarır ve kaydeder -saqut file:sourcecode.sqt ast:sourcecode.xml +KAYNAK KOD + │ lexer + ▼ +TOKEN'LAR ────────────── saqut tokens + │ parser (Pratt + recursive descent) + ▼ +AST ──────────────────── saqut ast + │ sembol toplama (iki geçişli) ┐ + ▼ │ +SEMBOL TABLOSU ───────── saqut symbols │ FRONTEND + │ semantik analiz (annotation) │ (yapı + anlam) + ▼ │ +ANNOTATE EDİLMİŞ AST ─── saqut ast ┘ + │ optimizasyon (opsiyonel, klon üstünde) ── MIDDLE-END + ▼ +IR ───────────────────── (planlanan) ┐ + │ bytecode VM / yorumlayıcı döngü │ BACKEND + ▼ │ (çalıştırma + FFI seam) +ÇALIŞTIRMA / ÇIKTI ───── saqut run ┘ ``` +- **Frontend** yapıyı ve anlamı modeller (tip, scope, dataflow). +- **"Hangi çekirdek, hangi cihaz, ne zaman, hangi çıktı formatı"** runtime/backend + meselesidir — frontend'e yüklenmez. +--- -# Compiler Structure +## CLI (mevcut + planlanan) -## 1 Source Code +``` +# --- çalışıyor --- +saqut tokens file:kaynak.sqt # token listesi +saqut ast file:kaynak.sqt # AST (JSON) +saqut symbols file:kaynak.sqt # sembol tablosu (iskelet) -- Yazılan kaynak kodun derleyiciye aktarılması -- Derleyici için belirlenen seçenekler ile derleyici yapısının yeniden yapılandırılması -- Derleyicinin outputlarının ayarlanması ve çıkışlarının aktarılması +# --- planlanan --- +saqut run file:kaynak.sqt # IR üret + bytecode VM ile çalıştır +saqut ast file:kaynak.sqt --optimized # klon, optimize edilmiş AST (öncesi/sonrası) +saqut transpile file:kaynak.sqt -o prog.c # ikinci backend (ileride) +``` -## 2 Lexing +Tasarım gereği her aşamanın çıktısı erken bir noktada dosyalanabilir/loglanabilir +(programlanabilir derleyici). Token, ham AST, optimize AST ve IR ayrı ayrı +kaydedilebilir. -Kaynak kodun içindeki tüm harflerin gezilip tek parça büyük bir token listesinin oluşturulması +--- -Bu işlemin sonucunda kaynak kodun içindeki tüm yapılar; semboller, sayılar, stringler ve operatörler olarak 4 kategoriye ayrılır +## Batteries / stdlib — kuzey yıldızı, ertelendi -## 3 Tokenning +Gerçek bir genel sürüm pil ile gelmeli (sıralama, sıkıştırma, kripto, +JSON/XML/HTML ayrıştırma). Ama bu **bugünün işi ve v0.1 değildir.** -Tüm tokenler gezilerek bir Abstract Syntax Tree ağacı (AST) oluşturulur. Tek düze tokenler bu aşamada hiyerarşik olarak +Mimari çerçeve (monolit korkusunu önler): derleyici pilleri çekirdeğine +gömmez. Bunun yerine **küçük bir gerçek builtin kümesi** (`print`, temel +zorunlular) + **gerisi kütüphane/FFI** ile gelir. "Batteries" sorunu aslında +bir **sınır (FFI/link seam) sorunudur**, "zlib'i yeniden yaz" sorunu değil. +Sınır bir kez çizilir, piller üstünde sonsuza dek birikir. -File -> Class -> Methods -> Expressions / Statements -> Volumes -> Values +- **JSON/XML/HTML ayrıştırıcıları saQut'un kendisinde yazılabilir** (string + + struct + fonksiyon + kontrol akışı yeter). İlk gerçek demo programları. +- **Sıkıştırma/kripto:** denenmiş C kütüphanelerine FFI ile bağlan. **Kripto + asla elle yazılmaz.** +- **Bugüne tek yansıması:** IR/runtime tasarlanırken **bilinçli bir FFI seam** + ("host fonksiyonu çağır" deliği) bırakılır. `print` bunu zaten zorlar — bunu + kaza değil, **kasıtlı bir mekanizma** yapıyoruz (ADR-016). -Şeklinde bir ağaç yapısına kavuşur. Böylece yazılan kaynak kodu anlaşılır ilk yapısına kavuşur +--- -## 4 Parsing +## Belge haritası -Oluşturulan AST ağacı anlamlaştırılır ve zenginleştirilir. Tanımlanan değerler, fonksiyonlar, classler ve değişkenler belirlenir. Tip kontrolleri ve Syntax hataları burada keşfedilir. Ayrıca Ulaşılamayan kod alanları, sınıfların ulaşılamayan (private) accessorları kontrol edilir, tüm bir kod boyunca class, tipleme, değişken ve döngülerin kullanım adetleri analiz edilir. Sistem içinde kullanılan tüm yapılar için geniş kapsamlı bir Symbol tablosu oluşturulur +| Belge | İçerik | +|---|---| +| `docs/fikirler.md` | ADR-001…005: backend stratejisi, parser, header-only, token, IR | +| `docs/adr-frontend-analiz.md` | ADR-006…019: frontend, analiz/optimizasyon, çalıştırma modeli, FFI, interface, bellek | +| `docs/roadmap-frontend.md` | Faz-faz uygulama planı (sembol tablosu → fibonacci) | +| `docs/transkript-frontend-tasarim.md` | Tasarım oturumunun transkripti | +| `examples/fibonacci.sqt` | Geçerli referans program (semantik + kod üretimi fixture'ı) | +| `examples/parser-stress/` | Yalnızca parser'ı zorlayan, **geçerli olmayan** fixture'lar | -## 5 Optimizing +--- -Zenginleştirilmiş AST üzerindeki analizler üzerinden bazı AST dalları silinir, değiştirilir veya yeni dallar eklenebilir +## İlke -- Constant Folding : 4 + 1 gibi sonucu belli olan ifadeler 5 olarak tutulur -- Dead Code Elimination : returnden sonraki kod bloğunun silinmesi veya if(false) ve dengi statementlerin yapıdan kaldırılması -- Matematiksel olarak değişmez kodların kaldırılması x * 1, x+0, x * 1 gibi valuelerin direkt x olarak değiştirilmesi -- Hiç kullanılmayan değişkenlerin kaldırılması -- Sabit (const) değerlerin döngülerin dışına çıkarılması veya programın globaline taşınması -- Null Check Elimination : Daha önce nullcheck yapılmış bir değişkenin tekrar nullcheck yapılan kontrollerini devredışı bırakmak -- Type Check Elimination : Daha önce typecheck yapılmış bir değişkenin tekrar typecheck yapılan kontrollerini devredışı bırakmak - -## 6 Compiling - -Oluşturulmuş tüm AST ağacını tamamen aynı işi yapan daha alt bir veri kümesine indirgeme işidir. Bellekteki AST yapısı ardışık komutlar dizisine çevrilir (Intermediate Representation) IR daha sonra tekrar okunup çalıştırılabilir. - -Daha sonra IR ile kurulacak yapı ile bazen HeavyIR bazende LightIR üretilir. -LightIR, en temiz ve hızlı ancak hiç bir ayrıntı içermeyen koddur. Kaynak kodun çalıştırılması için mükemmel veridir ancak debug verilerinden yoksundur -HeavyIR, kaynak kodu verilerinin yanı sıra orjinal AST üzerinde tanımlanmış değişken isimleri ayrıntıları ve tiplemeleride içerir. LightIRye göre daha ayrıntılı ve büyüktür ancak debugging ve kaynak kodun parça parça okunduğu durumlar için (örneğin interpreter) kullanışlıdır - -## 7 Interpreting - -Derleyici HeavyIR üretir ve Symbol tablosunu silmez. -Optimizasyonların çoğu kapatılır. -Oluşturulmuş HeavyIR kodu çalıştırılır çalışma bittikten sonra stackframe kapatılmaz yeni girişler beklenir. Yeni kaynak kodu girişleri yapıldığında yine derlenir ve anında çalıştırılır. Yeni çalıştırılan kaynak kodu bir önceki stackframe içersinde symbol tablosu dikkate alınarak output üretir böylece önceki değerler halen kullanılabilir - -## or 7 Executing - -Derleyici LightIR üretir IR oluşturulduktan sonra symbol tablosu silinir. -Üretilen IR otomatize edilmiş bellekte yüksek performans ile çalıştırılır. - -Derleyici o an ürettiği kaynak kodu anında çalıştırdığı (JIT) gibi -Daha önce üretilmiş ve depolanmış IR kodunuda çalıştırabilir - -## or 7 Transpiling - -Derleyici HeavyIR üretir ve Symbol tablosunu silmez. -Derleyici IR üretmez bunun yerine AST Üzerinden yeni bir dile çevrilir. -Duruma göre daha üst bir seviye dile dönüşüm yapıldığı gibi daha alt bir dile dönüşüm yapılabilir. IR üretilmez bunun yerine alınan kaynak kodu farklı bir kaynak koduna çevrilir - -# programmable compiler - -Derleyici tek seferde kaynak kodu alıp okuyup çalıştırabilir veya derleyebilir. -Ayrıca debug ortamlarında veya daha ayrıntılı projelerde derleme anına müdehale edilebilir - -## Stage Session - -Derleyiciye verilen bazı parametreler ile Lexer ve Tokenizer anında bazı işlemlerin yapılması engellenebilir -Örneğin accessorler kapatılabilir, hexedecimal sayılar kapatılabilir. Veya class olmadan globale yazılmış kodlar engellenebilir - -## AST Session - -Derleyiciye verilen bazı parametreler ile class yapılarına müdehale edilebilir, tipleme sistemleri sabitlenebilir, tek bir metot içerisine yazılacak kod sınırlanabilir veya for içerisinde for döngüsü kısıtlanabilir. Yazılan kod için analizler sonucunda bazı bloklar görmezden gelinebilir veya manipüle edilebilir - -## Optimizing Session - -Optimizasyon aşamaları parametreler ile tek tek açılabilir veya kapatılabilir - -## Output Session - -Derleyici ürettiği veriyi erken bir aşamada dosyalayabilir ve loglayabilir. -Derleyicinin oluşturduğui token, Pure AST, Optimized AST, LightIR veya HeavyIR ayrı ayrı kaydedilebilir - -## Compiling Session - -AST ağacını IRye dönüştürürken neleri aktaracağı derleyici parametre şeklinde verilebilir. -IR, yanlızca JIT ve Compiling modunda değiştirilebilir. Interpreter modunda değiştirilmesine izin verilmez -IR olarak tipleme, sınıflar, değişken isimleri, tekrarlama kayıtları, işlemler ve statementlerin hangilerinin eklenebileceği değiştirilebilir \ No newline at end of file +Bir şey çalışmadan önce çerçeve inşa etmekten kaçın. Önce **uçtan uca tek bir +dikey dilim** çalıştır (kaynak → IR → çalıştır; tamsayı aritmetiği + değişken + +kontrol akışı + tek bir `print`). Modülerlik bir kuzey yıldızıdır, v0.1 +gereksinimi değil; ihtiyaç doğmadan eklenen her soyutlama **daha az değil, daha +çok** karmaşıklıktır.