11 KiB
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 <noreply@anthropic.com>; dal0.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_ptrile nesne sahipliği. DüzObject*+ intrusive liste.
Adım 1.1 — Nesne modeli temeli (src/vm/object.hpp veya benzeri)
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 nesneyinextzincirine 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ı buradanile işaretle.
Adım 1.2 — Value'yu referans taşıyacak şekilde genişlet (src/vm/value.hpp)
ValueKind'aRefekle (array/struct nesnelerineObject*).Value'yaObject* ref = nullptr;alanı +static Value fromRef(Object*).Nilkind 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
struct ArrayObject : Object { // type = ObjectType::Array
std::vector<Value> 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,elementsdoldur,Value::fromRefile 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çindekiObject*) kopyalanır ama nesne paylaşılır →func(arr)içindekiARRAY_SETçağıranı etkiler. (Bu, kararın doğrulandığı kritik testtir.) ==(ADR-023): array'de kimlik → ikiValue'nunref'i aynıObject*mı? (İçerik DEĞİL.) Mevcut EQ opcode'unu tip-bazlı dallandır veyaREF_EQekle.
Adım 1.5 — Sınır kontrolü (kafes felsefesi)
ARRAY_GET/ARRAY_SETindex sınır dışıysa → temiz runtime hatası (sessiz UB değil). saQut "cage" — koruma şart.
Doğrulama (golden test — tests/ veya examples/)
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)
- Struct runtime. Alanlar (isimli),
StructObject : Object { std::vector<Value> 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). - 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.) - Null akış-analizi (ADR-021 — REVİZE). Ayrı frontend görevi:
Type?tip sistemi +T <: T?atama kuralı + katı operand kuralı + akış-duyarlı narrowing (nestedif+ sıralı guard +&&). ⚠️a!/??/?.YASAK — null yalnızca görünürifile aklanır.T?üstünde doğrudan erişim → derleme hatası. Frontend kesin çözer (backend yeniden analiz etmez). Detay: TODO Bölüm "SIRADAKİ İŞ" + ADR-021. - Hata yönetimi (ADR-025, #57). Struct-tabanlı yakalanabilir hata (Swift-tarzı):
- Önkoşul: IR'a satır tablosu (komut index → kaynak konum) — stacktrace için. Şu an taşıyor mu doğrula.
- Standart built-in
struct Error { int line; int char; string message; string trace; string code; }. - Klasik
try { ... } catch (e) { ... }bloğu (unwind + en yakın handler'a zıpla);catch (e)→e : Error.throwile kullanıcı da kaldırır. - Runtime null-deref (NPE analoğu), array OOB, /0,
a!patlaması → yakalanabilir hata;message/code= derleyicinin W/E kataloğu. - UNCHECKED (Java/C#/JS usulü): fonksiyon işaretlenmez (
noexcept/constexprtarzı YOK), çağrıdatry f()YOK. İmza-işaretli Swift/Zig modeli KULLANMA. - Stacktrace = frame stack'ten en içten dışa; insan + JSON; deterministik (adım indeksi/replay handle).
- float/double (#44). Bağımsız;
Value::Float+ FADD… opcode + tip denetleyici. - 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_ptrsahiplik 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 (tipint[]). 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; nullableint[]?.- #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) + Null 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.
6. ⚠️ TERMİNOLOJİ KİLİDİ — isimleri değiştirme/icat etme
Bu oturumda null yerine nil yazıldı; bu tür sapmalar olmamalı. Anlaşılan
isimler aynen kullanılır. İsmi belirsiz bir şeyle karşılaşırsan icat etme —
Opus'a sor.
| Kavram | DOĞRU | YANLIŞ (kullanma) |
|---|---|---|
| Null anahtar sözcüğü / literal | null |
nilnonevoid |
| Nullable tip işareti | Type? (ör. int?, Node?) |
Optional<T>Type | null |
| Non-null iddiası / elvis / safe-call | YASAK — if narrowing kullan |
a!a ?? xa?.f |
| Array literal | [1, 2, 3] |
{1,2,3} |
| Array tip | int[] |
array<int>[]int |
| Hata tipi | Error ({line,char,message,trace,code}) |
ExceptionErr |
| Hata kaldırma / yakalama | throw / try / catch |
raiserescue |
| Fonksiyon | func |
fnfunctiondef |
| C++ ValueKind null'u | ValueKind::Null |
Nil |
Genel kural: ADR'lerde/handoff'ta yazan tam ismi kullan. Yeni bir isim gerekiyorsa ve ADR'de yoksa, kendin karar verme — TODO'ya not düş veya Opus'a sor. Kod identifier'ları İngilizce (dil sözdizimi), yorum/commit Türkçe.