# Sonnet Uygulama Promptu — Bileşik Tipler Runtime'ı (ADR-020…024) > Bu dosya bir **devir teslim promptu**. Opus ile yapılan mimari oturumda 5 karar > alındı (ADR-020…024). Bu plan o kararları **koda döker.** Kararları yeniden > sorma — uygula. İletişim Türkçe; commit sonu `Co-Authored-By: Claude Opus 4.8 > `; dal `0.1.0`. --- ## 0. Nerede kaldık (bağlam) Bu oturumda kilitlenen mimari kararlar (tümü `docs/adr-frontend-analiz.md`): | ADR | Karar (özet) | |---|---| | **020** | Primitive (`int`/`float`/`bool`) = **değer**; bileşik (`struct`/`array`/`string`) = **referans** (JS/Java/C# modeli). "Pointer yok" = kullanıcıya `&`/`*` *sözdizimi* yok; runtime referansı kullanır. | | **021** | Null güvenliği: varsayılan **non-null**; nullable açıkça `Type?`. Akış-duyarlı null analizi (compile-time, runtime sıfır). `a!` = runtime-kontrollü iddia. | | **022** | GC: basit **taşımasız, stop-the-world, deterministik mark-sweep**. Nesne modeli **baştan GC-hazır** (header + kök sayımı + çocuk sayımı). v1: toplama YOK. **`shared_ptr`'ı kalıcı sahiplik modeli YAPMA.** | | **023** | `==`: primitive değer; referans (struct/array) **kimlik** (aynı nesne); string **içerik**. Derin eşitlik asla `==`'e bağlanmaz → ayrı `deepEquals()`. | | **024** | String = **immutable değer-tipi, iç temsil UTF-8**. `s+"x"` yeni string üretir; `==` içerik. | Açık mimari borç: **#56** (döngüsel referans → mark-sweep GC v2). Şimdilik toplama yok, bilinçli. **Mevcut kod durumu:** - int-only pipeline uçtan uca çalışıyor (`examples/fibonacci.sqt`). - `src/vm/value.hpp` → `Value` = `{ ValueKind kind; int intValue; std::string stringValue; }`. String **inline** (immutable olduğu için yeterli — taşıma zorunlu değil). - `src/ir/` → 3-adresli IR, slot tabanlı. `instruction.hpp`, `ir_generator.cpp`, `ir_program.hpp`. - `src/vm/interpreter.cpp` → bytecode yorumlayıcı döngü. `call_frame.hpp` çağrı çerçevesi. - struct/array: parser + semantik **var**, IR/VM codegen **YOK**. --- ## 1. İlk görev — GC-hazır nesne modeli + ARRAY runtime (dikey dilim) **Neden array, string değil:** string zaten immutable-değer olarak inline çalışıyor; asıl kararları (referans semantiği + GC-hazır nesne modeli + kimlik eşitliği) **doğrulayan** ilk gerçek referans-tipi array'dir. Bu görev, struct'ın da oturacağı temeli atar. ### KAPSAM DIŞI (bu görevde YAPMA — sonraki görevler) - ❌ Gerçek çöp toplama (mark-sweep). ADR-022 v1 = toplama yok. Sadece header + all-objects listesi + kök-sayımı *kancasını* kur. - ❌ Tam null akış-analizi (ADR-021). `int[]?` parse edilebilir ama flow-narrowing bu görevde değil. - ❌ struct codegen, string UTF-8 cilası, builder. Ayrı görevler (Bölüm 2). - ❌ `shared_ptr` ile nesne sahipliği. Düz `Object*` + intrusive liste. ### Adım 1.1 — Nesne modeli temeli (`src/vm/object.hpp` veya benzeri) ```cpp enum class ObjectType { Array /*, Struct, String (ileride) */ }; struct Object { ObjectType type; bool marked = false; // mark-sweep için (v2); şimdilik kullanılmaz Object* next = nullptr; // intrusive "tüm nesneler" listesi (mark-sweep tarayışı için) }; ``` - Bir **Heap/allocator**: `Object* allocate(...)` her yeni nesneyi `next` zincirine ekler. **Free yok** (v1). Yıkıcıda/process exit'te toptan bırak. - **Kök sayımı kancası:** VM'in operand stack + frame local'leri + global slot'lar üstünden referansları gezebileceği bir yol bırak (şimdilik imza/TODO yeterli; içini doldurmak v2). `// TODO(#56): mark-sweep kök taraması buradan` ile işaretle. ### Adım 1.2 — `Value`'yu referans taşıyacak şekilde genişlet (`src/vm/value.hpp`) - `ValueKind`'a `Ref` ekle (array/struct nesnelerine `Object*`). - `Value`'ya `Object* ref = nullptr;` alanı + `static Value fromRef(Object*)`. - `Nil` kind ekle (ADR-021 null: `Type?` null değeri ve referans varsayılanı). - `isTruthy`/`toString`/`typeName`'i yeni kind'lar için genişlet. - String inline kalsın (`ValueKind::String`), dokunma. ### Adım 1.3 — ArrayObject ```cpp struct ArrayObject : Object { // type = ObjectType::Array std::vector elements; // homojen (int[] → hepsi Int) }; ``` - Array literali (`[1,2,3]` — **parser'ın mevcut sözdizimini doğrula**, Bölüm 4'e bak) → ArrayObject tahsis, `elements` doldur, `Value::fromRef` ile slot'a koy. ### Adım 1.4 — IR opcode'ları + IR üreteci - `ARRAY_NEW` (literal/boyuttan array oluştur), `ARRAY_GET dest, arr, idx`, `ARRAY_SET arr, idx, val`, `ARRAY_LEN dest, arr`. (`instruction.hpp` + üreteç.) - **Referans semantiği:** array bir fonksiyona geçince/atanınca `Value` (içindeki `Object*`) **kopyalanır ama nesne paylaşılır** → `func(arr)` içindeki `ARRAY_SET` çağıranı etkiler. (Bu, kararın doğrulandığı kritik testtir.) - **`==` (ADR-023):** array'de **kimlik** → iki `Value`'nun `ref`'i aynı `Object*` mı? (İçerik DEĞİL.) Mevcut EQ opcode'unu tip-bazlı dallandır veya `REF_EQ` ekle. ### Adım 1.5 — Sınır kontrolü (kafes felsefesi) - `ARRAY_GET`/`ARRAY_SET` index sınır dışıysa → **temiz runtime hatası** (sessiz UB değil). saQut "cage" — koruma şart. ### Doğrulama (golden test — `tests/` veya `examples/`) ```c func degistir(int[] a) { a[0] = 99; } func main() { int[] x = [1, 2, 3]; degistir(x); print(x[0]); // 99 ← referans semantiği (ADR-020) int[] y = x; print(y == x); // true ← kimlik (aynı nesne, ADR-023) int[] z = [1, 2, 3]; print(z == x); // false ← içerikçe aynı ama farklı nesne print(x[1]); // 2 // x[5] → runtime sınır hatası } ``` `saqut run` ile beklenen çıktı doğrulanmalı. `saqut ir` çıktısı yeni opcode'ları göstermeli. --- ## 2. Sonraki görevler (sıralı — ilk görev bitince) 1. **Struct runtime.** Alanlar (isimli), `StructObject : Object { std::vector fields; }`. `struct Node { Node next; }` artık **meşru** (referans → sonlu boyut). **E010 revizyonu:** referansla tutulan struct alanı için döngü artık hata DEĞİL (ADR-020). Bu görev #56'yı *canlı* hale getirir (döngü kurulabilir, henüz toplanmaz). 2. **String cilası (ADR-024).** İçerik `==`'i doğrula; UTF-8 çok-baytlı pass-through (`"şğü"` concat+print bozulmasın); bayt-uzunluğu vs karakter ayrımını açık API olarak işaretle. (İstege bağlı: string'i de Object modeline taşıyıp intern et — zorunlu değil.) 3. **Null akış-analizi (ADR-021).** Ayrı **frontend** görevi: `Type?` tip sistemi + akış-duyarlı narrowing (`if (a != null)`, guard, `&&`), `T?` üstünde doğrudan erişim → derleme hatası, `a!` runtime-kontrollü iddia. CFG/yapısal akış üstünde; SSA gerekmez. #20 (akıllı diagnostic) buradan beslenir. 4. **float/double (#44).** Bağımsız; `Value::Float` + FADD… opcode + tip denetleyici. 5. **mark-sweep GC v2 (#56).** Adım 1.1'de bırakılan header+kök kancası üstünde aç. --- ## 3. Uyman gereken kararlar (sorma, uygula) - Referans semantiği: bileşik = paylaşılan nesne; primitive = kopya (ADR-020). - Array/struct `==` = **kimlik**; string `==` = **içerik** (ADR-023). - Nesne modeli GC-hazır ama v1 toplama YOK (ADR-022); `shared_ptr` sahiplik modeli kurma. - Sınır kontrolü + temiz runtime hataları (kafes felsefesi). - Erken soyutlama yok: önce çalışan dikey dilim, framework sonra (CLAUDE.md ilkesi). ## 4. Bloklamayan açık noktalar (ilk göreve engel değil — gerekirse Opus'a sor) - **Array literal sözdizimi:** parser'da `[1,2,3]` mi `{0,1,2}` mi kabul ediliyor? Mevcut parser'ı **doğrula**; tutarsızsa `[...]` tercih (tip `int[]`). Karar gerekirse işaretle. - Array sabit-boyut mu büyüyebilir mi: readme "dinamik" der; ilk görevde literal+indeks yeter, büyütme API'si (`push`/`len`) sonra. - `int[]` non-null varsayılan (ADR-021) → `int[] a;` init zorunlu; nullable `int[]?`. - #42 (cast modeli) ve #41 (stdlib politikası) henüz karara bağlanmadı — ilk görevi bloklamaz; sıraları gelince Opus ile. --- ## 5. Özet — tek cümle GC-hazır basit nesne modelini kur (header + all-objects listesi, toplama yok), `Value`'ya referans (`Ref`) + `Nil` ekle, **array**'i referans semantiği + kimlik `==` + sınır kontrolüyle uçtan uca çalıştır; struct ve null-analizi sonraki görevler.