Merge pull request 'feat: ADR-024/025/021 — string concat, try/catch/throw, nullable akış-analizi' (#115) from 0.1.0 into master

This commit is contained in:
saqut 2026-06-20 21:36:43 +03:00
commit fe8d73a13c
123 changed files with 4584 additions and 602 deletions

4
.gitignore vendored
View File

@ -17,6 +17,4 @@ scripts/gitea.py
__pycache__/
# CMake versiyona özgü dosyalar (otomatik üretilir, her güncellemede değişir)
build/CMakeFiles/[0-9]*/
build/.cmake/
build/compile_commands.json
build/*

View File

@ -20,37 +20,95 @@ git'te izlenir.
ham hız değil). C'ye transpile ileride geçerli 2. backend. İleride makine kodu
gerekirse libgccjit/LLVM'e bağlanılır (çok uzak). Bellek = host C++ heap; özel
allocator yok. (ADR-015)
- **Dil kimliği:** prosedürel, C-ailesi sözdizimi, value semantics, zorunlu
class/main boilerplate yok. **Yok:** class/OOP, closure, generic, kullanıcı
pointer'ı (`*`/`&`), auto/tip çıkarımı, gizli int↔float (tek istisna sabit
folding). **Var:** struct, tipli fonksiyonlar, array (`int[]`). `interface`
**ertelendi** (reddedilmedi, ADR-018).
- **Dil kimliği:** prosedürel, C-ailesi sözdizimi, zorunlu class/main boilerplate
yok. **Semantik (ADR-020):** primitive (`int`/`float`/`bool`) = **değer**;
bileşik (`struct`/`array`/`string`) = **referans** (JS/Java/C# modeli). "Pointer
yok" = kullanıcıya `&`/`*` **sözdizimi** verilmez; derleyici/runtime içeride ve
çalışma zamanında referansı sonuna kadar kullanır. **Yok:** OOP, closure,
generic, auto/tip çıkarımı, gizli int↔float (tek istisna sabit folding). **Var:**
struct, tipli fonksiyonlar, array (`int[]`). `class`/`function` sözdizimsel
**rezerve** (semantik ileride). `interface` **ertelendi** (ADR-018).
⚠️ Referans semantiği döngüsel-referans **sızıntısını** açtı → GC/döngü
toplayıcı borcu (**#56**, `karar-gerekli`).
- **Null güvenliği (ADR-021, REVİZE):** varsayılan non-null; nullable açıkça `Type?`
(Kotlin/Swift). `null` yalnızca `T?`'ye atanır; `T?` üstünde doğrudan erişim derleme
hatası. **Atama kuralı `T <: T?`** (notnull→nullable serbest, nullable→notnull yasak).
**Katı operand kuralı:** non-null bağlamda her operand statik non-null olmalı
(`int a=b+c+d`, biri nullable → hata). Aklama **yalnızca görünür `if` narrowing**
(nested + sıralı guard + `&&`; alias takibi yok). ⚠️ **`a!`/`??`/`?.` YASAK** (gizli
runtime null-aklama yok). Runtime maliyeti **sıfır**; frontend kesin çözer (backend
yeniden analiz etmez) → runtime null-deref esasen FFI backstop'u. SSA gerekmez (#2).
- **Bellek/GC (ADR-022):** **basit, taşımasız, stop-the-world, deterministik
mark-sweep** (döngüleri toplar, "cage" korunur). **`shared_ptr`'ı kalıcı model
YAPMA** (refcount döngüde sızar = topuğa-sıkma). Kural: nesne modelini **baştan
GC-hazır** kur (header: tip+mark biti+liste; VM kök sayar; nesne çocuk
referansları sayar). v1: toplamasız (arena); v2: aynı model üstünde mark-sweep.
Asıl perf-katili GC kararı → basit tutarak de-risk edildi.
- **Eşitlik (ADR-023):** `==` primitive'de değer, referans (struct/array) **kimlik**
(aynı nesne). Derin/yapısal eşitlik **asla** `==`'e bağlanmaz → ayrı görünür
`deepEquals()` (PHP `==`/`===`/`clone` ailesi gibi). **String istisnası:** `==`
**içerik** olmalı (Java gotcha'sından kaçın) → string'i immutable değer-tipi
modelle (#40). `obj==obj`'i hata yapmak + kullanıcı-tanımlı eşitlik = uzak gelecek.
- **String (ADR-024):** **immutable değer-tipi, iç temsil UTF-8.** `s = s + "x"`
yeni string üretir; `==` içerik (ADR-023). Bayt/scalar/grapheme erişimi açıkça
ayrı (sahte O(1) karakter indeksi YOK). Verimli birleştirme için ileride builder.
Çözdüğü: #40 (yüzey), #9 (iç temsil). Mevcut `Value` string'i inline tutuyor —
immutable olduğu için bu yeterli; heap/object-model'e taşımak zorunlu değil.
- **Hata yönetimi (ADR-025, #57):** **Swift-tarzı** yakalanabilir, **struct-tabanlı**
hata — OOP/extend YOK. Standart `Error { line; char; message; trace; code }`
(message=W/E metni, code=W/E kodu). **Klasik `try{}catch{}` bloğu, UNCHECKED**
(Java/C#/JS usulü): fonksiyon işaretlenmez (`noexcept`/`constexpr` tarzı YOK),
çağrıda `try f()` yok — developer'a güven, alışkanlık bozulmaz. Runtime null-deref
(NPE analoğu), array OOB, /0, `a!` patlaması → yakalanabilir hata (ADR-021'in runtime
backstop'u). `throw` ile kullanıcı da kaldırır. Deterministik stacktrace (IR satır
tablosu önkoşul). **Tuple → ertelendi** (ADR-014'teki "yok" gevşedi). `finally` yerine
ileride `defer`.
- **Tip dönüşümü (ADR-026, #42):**ık **`as`** (infix, sola-bağlı): `x as int`.
Yalnızca **skaler + string** arası; **struct/array cast YOK** (elle yapıcı fonksiyon —
derleyiciyi sade tutar, sessiz alan kaybı önlenir). Başarısızlık **hedef tipin
nullable'lığıyla:** `as int``Error` fırlatır; `as int?``null`. Ayrı `as?` YOK.
`float→int` sıfıra kırpar (NaN/Inf/taşma fallible). `int(x)` fonksiyon-stili reddedildi.
- **Analiz vs Optimizasyon:** Analiz orijinal AST üstünde annotation; optimizasyon
**klon** üstünde dönüşüm. `ASTNode::clone()` yük taşıyan merkezi bileşen
(parent pointer'lar + sembol tablosu remap edilir, ADR-007). Fixpoint döngüsü +
iterasyon tavanı (`maxFixpointRounds`, ADR-009).
- **Literal/tip kuralı:** tamsayı literali bağlama-göre tiplenir (`float x = 1;`
geçerli; `int y = 1.5;`→E003; değişken→değişken gizli dönüşüm yok). Döngüsel
by-value struct → E010. (ADR-010/011)
by-value struct → E010 (⚠️ ADR-020 ile revize: referansla tutulan struct alanı
artık döngü kurabilir, `Node next` meşru). (ADR-010/011)
- **FFI seam:** kasıtlı "host fonksiyonu çağır" mekanizması (`callhost`); `print`
ilk müşteri (ADR-016). Batteries = sınır/FFI problemi, "zlib'i yeniden yaz"
değil; kripto asla elle yazılmaz (ADR-017).
## Mevcut durum (yapılan vs planlanan)
- **Çalışıyor:** lexer, tokenizer, Pratt parser, AST, AST'nin JSON serileştirmesi,
CLI iskeleti (`tokens`/`ast`/`symbols`/`run`), konum takibi, basit aritmetiği
düşüren minimal IR deneyi.
- **Planlı (henüz YOK):** sembol tablosu, semantik analiz, tip sistemi, diagnostic
motoru, optimizasyon, IR+bytecode VM ile çalıştırma.
- **Birinci kilometre taşı ("bitti" tanımı):** `examples/fibonacci.sqt`
(recursive + iterative) derlenip çalıştırılabilmeli.
- **✅ Birinci kilometre taşı AŞILDI:** `examples/fibonacci.sqt`
(recursive + iterative) `saqut run` ile çalışıyor → `55\n55`.
- **Çalışıyor (tam pipeline):**
- Lexer, tokenizer, Pratt parser, AST + JSON serileştirmesi
- Sembol tablosu (iki-geçişli toplayıcı, döngüsel struct tespiti)
- Tip sistemi (`src/core/type.hpp`) + diagnostic motoru (`src/diagnostic/`)
- Tip denetleyici + yapısal doğrulayıcı (`src/semantic/`)
- Optimizasyon: constant folding (int/bool/logical) + dead code elimination
- IR üreteci (3-adresli, slot tabanlı) + bytecode VM (yorumlayıcı döngü)
- CLI: `tokens` / `ast` / `symbols` / `check` / `ir` / `run` (6 komut)
- **Henüz YOK (bilinen eksikler):**
- float/double codegen (tip sistemi var, IR opcode'u yok)
- struct IR (parse/semantik var, codegen yok)
- array IR (parse/semantik var, codegen yok)
- `%=` operatörü IR'da eksik (#37)
- Global değişken IR üretimi sessizce atlıyor (#38)
- W003 ölü kod uyarısı üretilmiyor (#36)
- DCE silinen düğümleri `delete` etmiyor — bellek sızıntısı (#35)
- **İlke:** Önce uçtan uca tek **dikey dilim**, sonra çerçeve. Erken soyutlamadan kaçın.
## Belge haritası
- `readme.md` — toolbox çerçevesi, built-vs-planned, dil kimliği, çalıştırma modeli.
- `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/adr-frontend-analiz.md` — ADR-006…026 (frontend, analiz/optimizasyon,
çalıştırma modeli, FFI, interface, bellek, **değer/referans semantiği, null
güvenliği, mark-sweep GC, eşitlik, string, hata yönetimi, tip dönüşümü**).
- `docs/sonnet-handoff.md`**Sonnet için uygulama promptu** (ADR-020…024'ü koda
döken sıralı görev planı; ilk görev: GC-hazır nesne modeli + array runtime).
- `docs/roadmap-frontend.md` — faz-faz uygulama planı (Faz 04 → fibonacci).
- `docs/transkript-frontend-tasarim.md` — tasarım oturumu transkripti.
- `examples/fibonacci.sqt` — geçerli referans program.
@ -97,6 +155,6 @@ git'te izlenir.
## Çalışma konvansiyonları
- Commit mesajları sonunda: `Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>`.
- Ana dal `master`; commit/push kullanıcı isteyince yapılır.
- Ana dal `0.1.0`; `master` branch yok. commit/push kullanıcı isteyince yapılır.
- Wiki API'si Gitea'da REST üzerinden çalışmadı; wiki içeriği `wiki.md`'ye yazılıp
kullanıcı tarafından elle yapıştırılıyor.

View File

@ -20,3 +20,99 @@ file(GLOB_RECURSE SOURCES "src/*.cpp")
add_executable(saqut ${SOURCES})
target_include_directories(saqut PRIVATE src)
# Testler
enable_testing()
set(SAQUT_BINARY "${CMAKE_BINARY_DIR}/saqut")
set(GOLDEN_SCRIPT "${CMAKE_SOURCE_DIR}/cmake/run_golden.cmake")
# Birim testleri (tests/run.sh)
add_test(
NAME unit_tests
COMMAND bash "${CMAKE_SOURCE_DIR}/tests/run.sh"
)
# Golden testleri tests/golden/**/*.sqt dosyalarını otomatik keşfet.
# Her .sqt için iki olası expected dosyası kontrol edilir:
# BASE.expected saqut run (siyah-kutu çıktı testi)
# BASE.ir_opt.expected saqut ir --optimized (beyaz-kutu IR testi)
file(GLOB_RECURSE ALL_GOLDEN_SQT CONFIGURE_DEPENDS
"${CMAKE_SOURCE_DIR}/tests/golden/*.sqt"
)
foreach(SQT_FILE ${ALL_GOLDEN_SQT})
file(RELATIVE_PATH REL "${CMAKE_SOURCE_DIR}/tests/golden" "${SQT_FILE}")
string(REPLACE ".sqt" "" BASE "${REL}")
string(REPLACE "/" "_" TNAME "${BASE}")
# Siyah-kutu: saqut run çıktısı
set(RUN_EXPECTED "${CMAKE_SOURCE_DIR}/tests/golden/${BASE}.expected")
if(EXISTS "${RUN_EXPECTED}")
add_test(
NAME "golden_${TNAME}"
COMMAND ${CMAKE_COMMAND}
-DBINARY=${SAQUT_BINARY}
-DSOURCE=${SQT_FILE}
-DEXPECTED=${RUN_EXPECTED}
-P "${GOLDEN_SCRIPT}"
)
endif()
# Beyaz-kutu: saqut ir --optimized çıktısı
set(IR_OPT_EXPECTED "${CMAKE_SOURCE_DIR}/tests/golden/${BASE}.ir_opt.expected")
if(EXISTS "${IR_OPT_EXPECTED}")
add_test(
NAME "golden_${TNAME}_ir_opt"
COMMAND ${CMAKE_COMMAND}
-DBINARY=${SAQUT_BINARY}
-DSOURCE=${SQT_FILE}
-DEXPECTED=${IR_OPT_EXPECTED}
-DCOMMAND=ir
-DOPTIMIZED=1
-P "${GOLDEN_SCRIPT}"
)
endif()
# Doğruluk kalkanı: saqut run --optimized çıktısı == beklenen golden değer
# "Optimizasyon oldu" değil, "optimize IR doğru sonuç verdi" testleri.
set(RUN_OPT_EXPECTED "${CMAKE_SOURCE_DIR}/tests/golden/${BASE}.run_opt.expected")
if(EXISTS "${RUN_OPT_EXPECTED}")
add_test(
NAME "golden_${TNAME}_run_opt"
COMMAND ${CMAKE_COMMAND}
-DBINARY=${SAQUT_BINARY}
-DSOURCE=${SQT_FILE}
-DEXPECTED=${RUN_OPT_EXPECTED}
-DOPTIMIZED=1
-P "${GOLDEN_SCRIPT}"
)
endif()
# Negatif test: .compile_error derleme hatası beklenen golden testler.
# Dosya içeriği stderr'de aranır (regex/düz dize).
set(COMPILE_ERROR_EXPECTED "${CMAKE_SOURCE_DIR}/tests/golden/${BASE}.compile_error")
if(EXISTS "${COMPILE_ERROR_EXPECTED}")
add_test(
NAME "golden_${TNAME}_compile_error"
COMMAND ${CMAKE_COMMAND}
-DBINARY=${SAQUT_BINARY}
-DSOURCE=${SQT_FILE}
-DEXPECTED=${COMPILE_ERROR_EXPECTED}
-P "${CMAKE_SOURCE_DIR}/cmake/run_golden_error.cmake"
)
endif()
# Negatif test: .runtime_error çalışma zamanı hatası beklenen golden testler.
# Aynı altyapı: exit code != 0 + stderr içeriği kontrolü.
set(RUNTIME_ERROR_EXPECTED "${CMAKE_SOURCE_DIR}/tests/golden/${BASE}.runtime_error")
if(EXISTS "${RUNTIME_ERROR_EXPECTED}")
add_test(
NAME "golden_${TNAME}_runtime_error"
COMMAND ${CMAKE_COMMAND}
-DBINARY=${SAQUT_BINARY}
-DSOURCE=${SQT_FILE}
-DEXPECTED=${RUNTIME_ERROR_EXPECTED}
-P "${CMAKE_SOURCE_DIR}/cmake/run_golden_error.cmake"
)
endif()
endforeach()

139
TODO.md Normal file
View File

@ -0,0 +1,139 @@
# TODO — Teknik Borçlar ve Ertelenen Kararlar
Bu dosya, kasıtlı olarak ertelenen teknik kararları ve ileride ele alınması gereken
tasarım noktalarını tutar. Her giriş hangi issue'ya bağlı olduğunu belirtir.
---
## ✅ TAMAMLANDI — GC-hazır nesne modeli + array runtime (2026-06-20)
ADR-020…024 (değer/referans semantiği, null güvenliği, mark-sweep GC, eşitlik)
doğrultusunda uçtan uca array çalışıyor:
- `src/vm/object.hpp` — Object, ArrayObject, Heap (v1: toplama yok, GC-hazır header)
- `src/vm/value.hpp` — ValueKind::Ref + Null eklendi (dil anahtar sözcüğü `null`, `nil` DEĞİL)
- `src/ir/instruction.hpp` — ARRAY_NEW/GET/SET/LEN eklendi
- Array literal parser (`[1,2,3]`), `int[]` tip sözdizimi (Java/C# stili)
- Referans semantiği, kimlik `==` (ADR-023), sınır kontrolü
- Golden test: `tests/golden/array/ref_semantics.sqt`
## ✅ TAMAMLANDI — Struct runtime + E010 revizyonu (2026-06-20)
ADR-020 doğrultusunda struct referans semantiğiyle uçtan uca çalışıyor:
- `src/vm/object.hpp` — StructObject : Object, alan erişimi (GC-hazır header)
- `src/vm/value.hpp` — ValueKind::Null eklendi (dil anahtar sözcüğü `null`)
- E010 revizyonu: referansla tutulan `struct Node { Node next; }` artık meşru
(döngü kurulabilir, GC v2 ile toplanacak)
## ✅ TAMAMLANDI — float/double aritmetik runtime (#44) (2026-06-20)
- `src/vm/value.hpp` — ValueKind::Float + floatValue alanı
- IR opcode'ları: FADD/FSUB/FMUL/FDIV + float karşılaştırma
- Literal bağlama-göre tipleme korundu (sabit folding dahil)
## ✅ TAMAMLANDI — String cilası (ADR-024) (2026-06-20)
- `src/core/type.hpp``isString()` yüklem yardımcısı eklendi
- `src/ir/instruction.hpp``STRING_CONCAT` opcode eklendi
- `src/semantic/type_checker.cpp``+` string için izin (her iki taraf `string` → sonuç `string`)
- `src/ir/ir_generator.cpp``generateBinaryArithmetic` string tespiti: `ADD``STRING_CONCAT`; `+=` için de `STRING_CONCAT`
- `src/vm/interpreter.cpp``STRING_CONCAT` case: `stringValue + stringValue`
- `tests/golden/string/concat.sqt` — concat, `+=`, içerik `==` golden testi
- İçerik `==` / `!=` VM'de zaten vardı (ADR-023/024); `print(string)` zaten çalışıyordu
## ✅ TAMAMLANDI — Hata yönetimi (ADR-025, #57) (2026-06-20)
- `src/parser/ast_node.hpp``TryStatement`, `ThrowStatement` ASTKind eklendi
- `src/parser/nodes/statements.hpp/.cpp``TryStatementNode`, `ThrowStatementNode`
- `src/parser/parser_base.hpp` + `parser.cpp``parseTryStatement()`, `parseThrowStatement()`
- `src/ir/instruction.hpp``ENTER_TRY`, `LEAVE_TRY`, `THROW` opcode'ları
- `src/ir/ir_generator.cpp` — try/catch/throw IR üretimi
- `src/vm/interpreter.hpp``TryFrame` struct, `tryStack_`, `pendingThrow_`, `makeErrorValue()`
- `src/vm/interpreter.cpp` — ENTER_TRY/LEAVE_TRY/THROW VM uygulaması; runtime hataları
(DIV/0, array OOB) `pendingThrow_` üzerinden Error nesnesi olarak yakalanabilir hale getirildi
- `src/symbol/symbol_collector.cpp``Error` builtin struct kaydı (alan sırası: line,col,message,trace,code)
- `src/semantic/type_checker.cpp` — TryStatement/ThrowStatement tip kontrolü (unchecked)
- `tests/golden/error/basic_catch.sqt` — sıfıra bölme yakalama
- `tests/golden/error/throw_and_nested.sqt` — iç içe fonksiyon unwind + array OOB + throw
- **Not:** IR satır tablosu (stacktrace doldurma) ertelendi — trace alanı boş kalıyor
## ✅ TAMAMLANDI — Null akış-analizi (ADR-021) (2026-06-20)
- `src/core/type.hpp``bool nullable` alanı; `asNullable()`, `asNonNull()`, `equalsBase()`, `isNullLiteral()` yardımcıları; `fromName("int?")` desteği; `toString()``int?`
- `src/parser/parser.cpp``?` suffix ayrıştırma (değişken, parametre, dönüş tipi); dispatch'te `int? f()``parseFunctionDecl()` yönlendirmesi düzeltildi
- `src/ir/instruction.hpp``LOAD_NULL` opcode eklendi
- `src/ir/ir_generator.cpp``LiteralType::BOŞ``LOAD_NULL`
- `src/vm/interpreter.cpp``LOAD_NULL` case → `Value::null()`
- `src/semantic/type_checker.hpp``narrowedNonNull_` set; `extractNullCheck()`, `alwaysExits()` yardımcıları
- `src/semantic/type_checker.cpp`:
- `checkAssign`: `T? ← null` OK; `T ← T?` hata (E003); `T? ← T` OK (widening)
- `checkExpr Literal BOŞ`: null sentinel tipi (`Void+nullable`)
- `checkExpr Identifier`: `narrowedNonNull_`'dan non-null olduğu bilinenlerde nullable flag'i kaldırılıyor
- `checkExpr BinaryExpression`: `&&` sağ taraf narrowing; nullable operand hatası (E003)
- `checkExpr MemberAccess`: nullable nesne üstünde doğrudan erişim hatası
- `checkStmt Block`: guard pattern (`if (a == null) return;` → sonrasında `a` non-null)
- `checkStmt IfStatement`: nested narrowing (`if (a != null)` → then'de non-null, `if (a == null)` → else'de non-null)
- `tests/golden/null/narrowing.sqt` — nested + guard narrowing, `int?` dönüş tipi ✓
- `tests/golden/null/nullable_assign_error.sqt``T? → T` atama E003 ✓
- `tests/golden/null/nullable_operand_error.sqt` — nullable aritmetik operand E003 ✓
- `tests/golden/null/and_narrowing.sqt``&&` sağ taraf narrowing ✓
## 🚀 SIRADAKİ İŞ
1. **mark-sweep GC v2 (#56)** — en son; özellik bloklamaz, en karmaşık. Trigger basit
"her N tahsiste" yeter; nesne modeli zaten GC-hazır.
ık mimari borçlar: **#56** (döngüsel referans → mark-sweep GC v2), **#57** (hata
modeli görünürlük alt-ekseni).
> ⚠️ **Terminoloji kilidi (Sonnet):** anlaşılan isimleri değiştirme/icat etme.
> Dil anahtar sözcüğü **`null`** (`nil` değil), array literal **`[...]`** (`{...}` değil),
> hata tipi **`Error`**. İsmi belirsizse **icat etme, Opus'a sor.** Ayrıntı:
> `docs/sonnet-handoff.md` Bölüm 6 (terminoloji kilidi).
---
## #modül-scope — IRFunction.moduleId: Modül-düzeyi değişken izolasyonu
**Etkilenen dosyalar:**
- `src/ir/instruction.hpp``LOAD_GLOBAL` / `STORE_GLOBAL` yorumları
- `src/ir/ir_program.hpp``globalCount`, `globalNames`
- `src/vm/interpreter.hpp``globalSlots_`
- `src/vm/interpreter.cpp``LOAD_GLOBAL` / `STORE_GLOBAL` case'leri
**Mevcut durum (tek dosya):**
`LOAD_GLOBAL dest, N``globalSlots_[N]` — düz vektör, tek modül varsayımı.
Tek dosyada bu doğru çalışır; `globalSlots_[0]` her zaman bu dosyanın 0. modül-değişkenidir.
**Çok modüllü derlemede yapılması gereken:**
Her `IRFunction`'a `std::string moduleId` (veya `int moduleIndex`) alanı ekle.
`Interpreter`'da `globalSlots_` yerine `std::unordered_map<std::string, std::vector<Value>> moduleSlots_` tut.
`LOAD_GLOBAL` çalışırken `frame.function->moduleId` ile doğru modülün slot alanına bak.
```
// Hedef tasarım (modül sistemi gelince):
case Opcode::LOAD_GLOBAL:
frame.slots[instr.dest] = moduleSlots_[frame.function->moduleId][instr.intValue];
break;
```
**Ne zaman:** Modül sistemi issue'ları (#3 import sözdizimi, #4 görünürlük, #5 çoklu dosya)
ele alınırken bu değişikliği de kapsama al.
---
## #sembol-modül — Symbol.sourceModule: Sembol tablosunda açık modül kimliği
**Etkilenen dosyalar:**
- `src/symbol/symbol.hpp``Symbol` struct
**Mevcut durum:**
`Symbol.definitionLoc.filePath` dosya yolunu tutuyor — modül bilgisi dolaylı olarak var.
Ama doğrudan `moduleId` / `moduleName` alanı yok; filtre/lookup için her seferinde
`definitionLoc.filePath`'i ayrıştırmak gerekir.
**Yapılması gereken:**
`Symbol` struct'ına `std::string sourceModule` alanı ekle (modül adı veya dosya yolu).
Özellikle cross-module sembol çözümleme, LSP "tanıma git" ve hata mesajlarında
"hangi modülden geldi" bilgisi için kritik.
**Ne zaman:** `#3` (import sözdizimi) veya `#4` (görünürlük) issue'larında.

Binary file not shown.

View File

@ -1,23 +1,34 @@
# ninja log v7
13 4576 1781796718440262330 CMakeFiles/saqut.dir/src/core/sourcefile.cpp.o 20f68631dd335029
13 4805 1781796718441539505 CMakeFiles/saqut.dir/src/lexer/lexer.cpp.o 5fd259c0401f3e22
1 2117 1781796771817437208 CMakeFiles/saqut.dir/src/tokenizer/tokenizer.cpp.o fbabe80dcb141239
4580 9322 1781796723007277591 CMakeFiles/saqut.dir/src/parser/parser.cpp.o 59cdb5935c541b26
21 6876 1781796718448262357 CMakeFiles/saqut.dir/src/parser/nodes/program.cpp.o 9313cba8d8daffed
16 6700 1781796718443848488 CMakeFiles/saqut.dir/src/parser/nodes/identifier.cpp.o e3b5b38d75fcd2ca
15 7814 1781796718443331391 CMakeFiles/saqut.dir/src/parser/nodes/expressions.cpp.o 5f5bb01381a3c3ad
16 7589 1781796718444498682 CMakeFiles/saqut.dir/src/parser/nodes/literal.cpp.o 55743f37408c5f
21 7502 1781796718449424977 CMakeFiles/saqut.dir/src/parser/nodes/statements.cpp.o 3c8869307381c930
14 6864 1781796718442362341 CMakeFiles/saqut.dir/src/parser/nodes/binary_expr.cpp.o 5cc8b697133bcf64
15 6733 1781796718442847556 CMakeFiles/saqut.dir/src/parser/nodes/declarations.cpp.o c3d262615ede4c95
1 4629 1781801148234045650 CMakeFiles/saqut.dir/src/main.cpp.o 3cfef7a665d5bf87
4629 4900 1781801152862380672 saqut f2e198803c4dbffb
0 22 1781801180493522122 build.ninja 1876a59d627a585
0 22 1781801180493522122 /home/saqut/Masaüstü/saqutcompiler/build/cmake_install.cmake 1876a59d627a585
6733 11112 1781796725160284765 CMakeFiles/saqut.dir/src/symbol/symbol_collector.cpp.o ec4e483b8ddb4007
4805 9685 1781796723232278341 CMakeFiles/saqut.dir/src/semantic/structural_validator.cpp.o 248faa3675024351
6700 10405 1781796725127284655 CMakeFiles/saqut.dir/src/semantic/type_checker.cpp.o b29c133293d988b0
1 850 1781801148235507662 CMakeFiles/saqut.dir/src/vm/interpreter.cpp.o b7dd80e002d68a1d
2 957 1781800866770475511 CMakeFiles/saqut.dir/src/ir/ir_function.cpp.o 10f5e8dfd1461d69
2 718 1781800866771246136 CMakeFiles/saqut.dir/src/ir/ir_program.cpp.o 9518231d970828da
2 3169 1781800866771136888 CMakeFiles/saqut.dir/src/ir/ir_generator.cpp.o 10a1ed4e1f52e530
1 9 1781900092189939762 /home/saqut/Masaüstü/saqutcompiler/build/CMakeFiles/cmake.verify_globs 1813c41e0f312d7e
10 1691 1781900092199402809 CMakeFiles/saqut.dir/src/ir/ir_program.cpp.o d681b36458a6e5f5
10 1957 1781900092199188672 CMakeFiles/saqut.dir/src/ir/ir_function.cpp.o 85cbc174284792d4
10 5411 1781900092199511505 CMakeFiles/saqut.dir/src/lexer/lexer.cpp.o 90eeec811f2137e6
10 5413 1781900092198939716 CMakeFiles/saqut.dir/src/core/sourcefile.cpp.o da6f5fc90e87e6b1
10 6729 1781900092199847028 CMakeFiles/saqut.dir/src/parser/nodes/declarations.cpp.o b6c56f04a257f685
15 7732 1781900092203939691 CMakeFiles/saqut.dir/src/parser/nodes/expressions.cpp.o 4057e3d63c63a1ab
10 8908 1781900092199302769 CMakeFiles/saqut.dir/src/ir/ir_generator.cpp.o 84c9f816f969cfa7
10 9701 1781900092199743167 CMakeFiles/saqut.dir/src/parser/nodes/binary_expr.cpp.o d2e2bb2f8a63c6d2
1709 9770 1781900093898639567 CMakeFiles/saqut.dir/src/parser/nodes/literal.cpp.o 78f2c4da7c9b2281
15 10364 1781900092204948414 CMakeFiles/saqut.dir/src/parser/nodes/identifier.cpp.o eb96bb4b1eb4ad80
1957 11871 1781900094145929879 CMakeFiles/saqut.dir/src/parser/nodes/program.cpp.o ac5bbcd74d87561a
9770 11899 1781900101958890478 CMakeFiles/saqut.dir/src/vm/interpreter.cpp.o 88078036625564ef
5413 11959 1781900097601912436 CMakeFiles/saqut.dir/src/parser/parser.cpp.o 2c65b7be26cead32
10 12284 1781900092199621706 CMakeFiles/saqut.dir/src/main.cpp.o 110c26cb1d0c3a23
6729 13187 1781900098917905800 CMakeFiles/saqut.dir/src/semantic/structural_validator.cpp.o 4bfec8abc0e9893e
5412 13356 1781900097601088348 CMakeFiles/saqut.dir/src/parser/nodes/statements.cpp.o b5c20724bbf3648c
7733 14099 1781900099922227854 CMakeFiles/saqut.dir/src/semantic/type_checker.cpp.o 15f44776b9c3e26d
9701 14179 1781900101889890826 CMakeFiles/saqut.dir/src/tokenizer/tokenizer.cpp.o a01677f8bb4f4dbc
8908 14635 1781900101096894819 CMakeFiles/saqut.dir/src/symbol/symbol_collector.cpp.o 3348f498f369213d
14635 14953 1781900106823866003 saqut 8f3d7184b374150b
2 17 1781900144964675644 /home/saqut/Masaüstü/saqutcompiler/build/CMakeFiles/cmake.verify_globs 1813c41e0f312d7e
18 4193 1781900144981580253 CMakeFiles/saqut.dir/src/semantic/structural_validator.cpp.o 4bfec8abc0e9893e
18 4260 1781900144981478187 CMakeFiles/saqut.dir/src/parser/parser.cpp.o 2c65b7be26cead32
18 4852 1781900144981695435 CMakeFiles/saqut.dir/src/semantic/type_checker.cpp.o 15f44776b9c3e26d
18 4914 1781900144981374397 CMakeFiles/saqut.dir/src/parser/nodes/declarations.cpp.o b6c56f04a257f685
18 5211 1781900144980675565 CMakeFiles/saqut.dir/src/ir/ir_generator.cpp.o 84c9f816f969cfa7
18 5324 1781900144981813038 CMakeFiles/saqut.dir/src/symbol/symbol_collector.cpp.o 3348f498f369213d
18 6912 1781900144981279910 CMakeFiles/saqut.dir/src/main.cpp.o 110c26cb1d0c3a23
6912 7184 1781900151874641436 saqut 8f3d7184b374150b
1 8 1781900314792856660 /home/saqut/Masaüstü/saqutcompiler/build/CMakeFiles/cmake.verify_globs 1813c41e0f312d7e
9 4869 1781900314800856623 CMakeFiles/saqut.dir/src/main.cpp.o 110c26cb1d0c3a23
4869 5168 1781900319660833784 saqut 8f3d7184b374150b

View File

@ -1,4 +1,269 @@
---
events:
-
kind: "message-v1"
backtrace:
- "/usr/share/cmake-3.28/Modules/CMakeDetermineSystem.cmake:233 (message)"
- "CMakeLists.txt:2 (project)"
message: |
The system is: Linux - 6.18.5 - x86_64
-
kind: "message-v1"
backtrace:
- "/usr/share/cmake-3.28/Modules/CMakeDetermineCompilerId.cmake:17 (message)"
- "/usr/share/cmake-3.28/Modules/CMakeDetermineCompilerId.cmake:64 (__determine_compiler_id_test)"
- "/usr/share/cmake-3.28/Modules/CMakeDetermineCXXCompiler.cmake:126 (CMAKE_DETERMINE_COMPILER_ID)"
- "CMakeLists.txt:2 (project)"
message: |
Compiling the CXX compiler identification source file "CMakeCXXCompilerId.cpp" succeeded.
Compiler: /usr/bin/c++
Build flags:
Id flags:
The output was:
0
Compilation of the CXX compiler identification source "CMakeCXXCompilerId.cpp" produced "a.out"
The CXX compiler identification is GNU, found in:
/home/user/saqut/build/CMakeFiles/3.28.3/CompilerIdCXX/a.out
-
kind: "try_compile-v1"
backtrace:
- "/usr/share/cmake-3.28/Modules/CMakeDetermineCompilerABI.cmake:57 (try_compile)"
- "/usr/share/cmake-3.28/Modules/CMakeTestCXXCompiler.cmake:26 (CMAKE_DETERMINE_COMPILER_ABI)"
- "CMakeLists.txt:2 (project)"
checks:
- "Detecting CXX compiler ABI info"
directories:
source: "/home/user/saqut/build/CMakeFiles/CMakeScratch/TryCompile-6ljCUz"
binary: "/home/user/saqut/build/CMakeFiles/CMakeScratch/TryCompile-6ljCUz"
cmakeVariables:
CMAKE_CXX_FLAGS: ""
CMAKE_CXX_FLAGS_DEBUG: "-g"
CMAKE_EXE_LINKER_FLAGS: ""
buildResult:
variable: "CMAKE_CXX_ABI_COMPILED"
cached: true
stdout: |
Change Dir: '/home/user/saqut/build/CMakeFiles/CMakeScratch/TryCompile-6ljCUz'
Run Build Command(s): /usr/bin/ninja -v cmTC_b1346
[1/2] /usr/bin/c++ -v -o CMakeFiles/cmTC_b1346.dir/CMakeCXXCompilerABI.cpp.o -c /usr/share/cmake-3.28/Modules/CMakeCXXCompilerABI.cpp
Using built-in specs.
COLLECT_GCC=/usr/bin/c++
OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 13.3.0-6ubuntu2~24.04.1' --with-bugurl=file:///usr/share/doc/gcc-13/README.Bugs --enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++,m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-13 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/libexec --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-libstdcxx-backtrace --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --enable-cet --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-13-EldibY/gcc-13-13.3.0/debian/tmp-nvptx/usr,amdgcn-amdhsa=/build/gcc-13-EldibY/gcc-13-13.3.0/debian/tmp-gcn/usr --enable-offload-defaulted --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu --with-build-config=bootstrap-lto-lean --enable-link-serialization=2
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 13.3.0 (Ubuntu 13.3.0-6ubuntu2~24.04.1)
COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_b1346.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_b1346.dir/'
/usr/libexec/gcc/x86_64-linux-gnu/13/cc1plus -quiet -v -imultiarch x86_64-linux-gnu -D_GNU_SOURCE /usr/share/cmake-3.28/Modules/CMakeCXXCompilerABI.cpp -quiet -dumpdir CMakeFiles/cmTC_b1346.dir/ -dumpbase CMakeCXXCompilerABI.cpp.cpp -dumpbase-ext .cpp -mtune=generic -march=x86-64 -version -fasynchronous-unwind-tables -fstack-protector-strong -Wformat -Wformat-security -fstack-clash-protection -fcf-protection -o /tmp/ccKBrizP.s
GNU C++17 (Ubuntu 13.3.0-6ubuntu2~24.04.1) version 13.3.0 (x86_64-linux-gnu)
compiled by GNU C version 13.3.0, GMP version 6.3.0, MPFR version 4.2.1, MPC version 1.3.1, isl version isl-0.26-GMP
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring duplicate directory "/usr/include/x86_64-linux-gnu/c++/13"
ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/13/include-fixed/x86_64-linux-gnu"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/13/include-fixed"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/13/../../../../x86_64-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
/usr/include/c++/13
/usr/include/x86_64-linux-gnu/c++/13
/usr/include/c++/13/backward
/usr/lib/gcc/x86_64-linux-gnu/13/include
/usr/local/include
/usr/include/x86_64-linux-gnu
/usr/include
End of search list.
Compiler executable checksum: 7896445e4990772fdae9dc0659a99266
COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_b1346.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_b1346.dir/'
as -v --64 -o CMakeFiles/cmTC_b1346.dir/CMakeCXXCompilerABI.cpp.o /tmp/ccKBrizP.s
GNU assembler version 2.42 (x86_64-linux-gnu) using BFD version (GNU Binutils for Ubuntu) 2.42
COMPILER_PATH=/usr/libexec/gcc/x86_64-linux-gnu/13/:/usr/libexec/gcc/x86_64-linux-gnu/13/:/usr/libexec/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/13/:/usr/lib/gcc/x86_64-linux-gnu/
LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/13/:/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/13/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/13/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_b1346.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_b1346.dir/CMakeCXXCompilerABI.cpp.'
[2/2] : && /usr/bin/c++ -v CMakeFiles/cmTC_b1346.dir/CMakeCXXCompilerABI.cpp.o -o cmTC_b1346 && :
Using built-in specs.
COLLECT_GCC=/usr/bin/c++
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-linux-gnu/13/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 13.3.0-6ubuntu2~24.04.1' --with-bugurl=file:///usr/share/doc/gcc-13/README.Bugs --enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++,m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-13 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/libexec --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-libstdcxx-backtrace --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --enable-cet --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-13-EldibY/gcc-13-13.3.0/debian/tmp-nvptx/usr,amdgcn-amdhsa=/build/gcc-13-EldibY/gcc-13-13.3.0/debian/tmp-gcn/usr --enable-offload-defaulted --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu --with-build-config=bootstrap-lto-lean --enable-link-serialization=2
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 13.3.0 (Ubuntu 13.3.0-6ubuntu2~24.04.1)
COMPILER_PATH=/usr/libexec/gcc/x86_64-linux-gnu/13/:/usr/libexec/gcc/x86_64-linux-gnu/13/:/usr/libexec/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/13/:/usr/lib/gcc/x86_64-linux-gnu/
LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/13/:/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/13/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/13/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-v' '-o' 'cmTC_b1346' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'cmTC_b1346.'
/usr/libexec/gcc/x86_64-linux-gnu/13/collect2 -plugin /usr/libexec/gcc/x86_64-linux-gnu/13/liblto_plugin.so -plugin-opt=/usr/libexec/gcc/x86_64-linux-gnu/13/lto-wrapper -plugin-opt=-fresolution=/tmp/cci1AaX8.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=gnu --as-needed -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -z now -z relro -o cmTC_b1346 /usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/Scrt1.o /usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/13/crtbeginS.o -L/usr/lib/gcc/x86_64-linux-gnu/13 -L/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/13/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/13/../../.. CMakeFiles/cmTC_b1346.dir/CMakeCXXCompilerABI.cpp.o -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/lib/gcc/x86_64-linux-gnu/13/crtendS.o /usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/crtn.o
COLLECT_GCC_OPTIONS='-v' '-o' 'cmTC_b1346' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'cmTC_b1346.'
exitCode: 0
-
kind: "message-v1"
backtrace:
- "/usr/share/cmake-3.28/Modules/CMakeDetermineCompilerABI.cmake:127 (message)"
- "/usr/share/cmake-3.28/Modules/CMakeTestCXXCompiler.cmake:26 (CMAKE_DETERMINE_COMPILER_ABI)"
- "CMakeLists.txt:2 (project)"
message: |
Parsed CXX implicit include dir info: rv=done
found start of include info
found start of implicit include info
add: [/usr/include/c++/13]
add: [/usr/include/x86_64-linux-gnu/c++/13]
add: [/usr/include/c++/13/backward]
add: [/usr/lib/gcc/x86_64-linux-gnu/13/include]
add: [/usr/local/include]
add: [/usr/include/x86_64-linux-gnu]
add: [/usr/include]
end of search list found
collapse include dir [/usr/include/c++/13] ==> [/usr/include/c++/13]
collapse include dir [/usr/include/x86_64-linux-gnu/c++/13] ==> [/usr/include/x86_64-linux-gnu/c++/13]
collapse include dir [/usr/include/c++/13/backward] ==> [/usr/include/c++/13/backward]
collapse include dir [/usr/lib/gcc/x86_64-linux-gnu/13/include] ==> [/usr/lib/gcc/x86_64-linux-gnu/13/include]
collapse include dir [/usr/local/include] ==> [/usr/local/include]
collapse include dir [/usr/include/x86_64-linux-gnu] ==> [/usr/include/x86_64-linux-gnu]
collapse include dir [/usr/include] ==> [/usr/include]
implicit include dirs: [/usr/include/c++/13;/usr/include/x86_64-linux-gnu/c++/13;/usr/include/c++/13/backward;/usr/lib/gcc/x86_64-linux-gnu/13/include;/usr/local/include;/usr/include/x86_64-linux-gnu;/usr/include]
-
kind: "message-v1"
backtrace:
- "/usr/share/cmake-3.28/Modules/CMakeDetermineCompilerABI.cmake:159 (message)"
- "/usr/share/cmake-3.28/Modules/CMakeTestCXXCompiler.cmake:26 (CMAKE_DETERMINE_COMPILER_ABI)"
- "CMakeLists.txt:2 (project)"
message: |
Parsed CXX implicit link information:
link line regex: [^( *|.*[/\\])(ld|CMAKE_LINK_STARTFILE-NOTFOUND|([^/\\]+-)?ld|collect2)[^/\\]*( |$)]
ignore line: [Change Dir: '/home/user/saqut/build/CMakeFiles/CMakeScratch/TryCompile-6ljCUz']
ignore line: []
ignore line: [Run Build Command(s): /usr/bin/ninja -v cmTC_b1346]
ignore line: [[1/2] /usr/bin/c++ -v -o CMakeFiles/cmTC_b1346.dir/CMakeCXXCompilerABI.cpp.o -c /usr/share/cmake-3.28/Modules/CMakeCXXCompilerABI.cpp]
ignore line: [Using built-in specs.]
ignore line: [COLLECT_GCC=/usr/bin/c++]
ignore line: [OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa]
ignore line: [OFFLOAD_TARGET_DEFAULT=1]
ignore line: [Target: x86_64-linux-gnu]
ignore line: [Configured with: ../src/configure -v --with-pkgversion='Ubuntu 13.3.0-6ubuntu2~24.04.1' --with-bugurl=file:///usr/share/doc/gcc-13/README.Bugs --enable-languages=c ada c++ go d fortran objc obj-c++ m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-13 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/libexec --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-libstdcxx-backtrace --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --enable-cet --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32 m64 mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-13-EldibY/gcc-13-13.3.0/debian/tmp-nvptx/usr amdgcn-amdhsa=/build/gcc-13-EldibY/gcc-13-13.3.0/debian/tmp-gcn/usr --enable-offload-defaulted --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu --with-build-config=bootstrap-lto-lean --enable-link-serialization=2]
ignore line: [Thread model: posix]
ignore line: [Supported LTO compression algorithms: zlib zstd]
ignore line: [gcc version 13.3.0 (Ubuntu 13.3.0-6ubuntu2~24.04.1) ]
ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_b1346.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_b1346.dir/']
ignore line: [ /usr/libexec/gcc/x86_64-linux-gnu/13/cc1plus -quiet -v -imultiarch x86_64-linux-gnu -D_GNU_SOURCE /usr/share/cmake-3.28/Modules/CMakeCXXCompilerABI.cpp -quiet -dumpdir CMakeFiles/cmTC_b1346.dir/ -dumpbase CMakeCXXCompilerABI.cpp.cpp -dumpbase-ext .cpp -mtune=generic -march=x86-64 -version -fasynchronous-unwind-tables -fstack-protector-strong -Wformat -Wformat-security -fstack-clash-protection -fcf-protection -o /tmp/ccKBrizP.s]
ignore line: [GNU C++17 (Ubuntu 13.3.0-6ubuntu2~24.04.1) version 13.3.0 (x86_64-linux-gnu)]
ignore line: [ compiled by GNU C version 13.3.0 GMP version 6.3.0 MPFR version 4.2.1 MPC version 1.3.1 isl version isl-0.26-GMP]
ignore line: []
ignore line: [GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072]
ignore line: [ignoring duplicate directory "/usr/include/x86_64-linux-gnu/c++/13"]
ignore line: [ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"]
ignore line: [ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/13/include-fixed/x86_64-linux-gnu"]
ignore line: [ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/13/include-fixed"]
ignore line: [ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/13/../../../../x86_64-linux-gnu/include"]
ignore line: [#include "..." search starts here:]
ignore line: [#include <...> search starts here:]
ignore line: [ /usr/include/c++/13]
ignore line: [ /usr/include/x86_64-linux-gnu/c++/13]
ignore line: [ /usr/include/c++/13/backward]
ignore line: [ /usr/lib/gcc/x86_64-linux-gnu/13/include]
ignore line: [ /usr/local/include]
ignore line: [ /usr/include/x86_64-linux-gnu]
ignore line: [ /usr/include]
ignore line: [End of search list.]
ignore line: [Compiler executable checksum: 7896445e4990772fdae9dc0659a99266]
ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_b1346.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_b1346.dir/']
ignore line: [ as -v --64 -o CMakeFiles/cmTC_b1346.dir/CMakeCXXCompilerABI.cpp.o /tmp/ccKBrizP.s]
ignore line: [GNU assembler version 2.42 (x86_64-linux-gnu) using BFD version (GNU Binutils for Ubuntu) 2.42]
ignore line: [COMPILER_PATH=/usr/libexec/gcc/x86_64-linux-gnu/13/:/usr/libexec/gcc/x86_64-linux-gnu/13/:/usr/libexec/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/13/:/usr/lib/gcc/x86_64-linux-gnu/]
ignore line: [LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/13/:/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/13/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/13/../../../:/lib/:/usr/lib/]
ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_b1346.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_b1346.dir/CMakeCXXCompilerABI.cpp.']
ignore line: [[2/2] : && /usr/bin/c++ -v CMakeFiles/cmTC_b1346.dir/CMakeCXXCompilerABI.cpp.o -o cmTC_b1346 && :]
ignore line: [Using built-in specs.]
ignore line: [COLLECT_GCC=/usr/bin/c++]
ignore line: [COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-linux-gnu/13/lto-wrapper]
ignore line: [OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa]
ignore line: [OFFLOAD_TARGET_DEFAULT=1]
ignore line: [Target: x86_64-linux-gnu]
ignore line: [Configured with: ../src/configure -v --with-pkgversion='Ubuntu 13.3.0-6ubuntu2~24.04.1' --with-bugurl=file:///usr/share/doc/gcc-13/README.Bugs --enable-languages=c ada c++ go d fortran objc obj-c++ m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-13 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/libexec --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-libstdcxx-backtrace --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --enable-cet --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32 m64 mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-13-EldibY/gcc-13-13.3.0/debian/tmp-nvptx/usr amdgcn-amdhsa=/build/gcc-13-EldibY/gcc-13-13.3.0/debian/tmp-gcn/usr --enable-offload-defaulted --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu --with-build-config=bootstrap-lto-lean --enable-link-serialization=2]
ignore line: [Thread model: posix]
ignore line: [Supported LTO compression algorithms: zlib zstd]
ignore line: [gcc version 13.3.0 (Ubuntu 13.3.0-6ubuntu2~24.04.1) ]
ignore line: [COMPILER_PATH=/usr/libexec/gcc/x86_64-linux-gnu/13/:/usr/libexec/gcc/x86_64-linux-gnu/13/:/usr/libexec/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/13/:/usr/lib/gcc/x86_64-linux-gnu/]
ignore line: [LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/13/:/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/13/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/13/../../../:/lib/:/usr/lib/]
ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'cmTC_b1346' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'cmTC_b1346.']
link line: [ /usr/libexec/gcc/x86_64-linux-gnu/13/collect2 -plugin /usr/libexec/gcc/x86_64-linux-gnu/13/liblto_plugin.so -plugin-opt=/usr/libexec/gcc/x86_64-linux-gnu/13/lto-wrapper -plugin-opt=-fresolution=/tmp/cci1AaX8.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=gnu --as-needed -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -z now -z relro -o cmTC_b1346 /usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/Scrt1.o /usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/13/crtbeginS.o -L/usr/lib/gcc/x86_64-linux-gnu/13 -L/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/13/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/13/../../.. CMakeFiles/cmTC_b1346.dir/CMakeCXXCompilerABI.cpp.o -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/lib/gcc/x86_64-linux-gnu/13/crtendS.o /usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/crtn.o]
arg [/usr/libexec/gcc/x86_64-linux-gnu/13/collect2] ==> ignore
arg [-plugin] ==> ignore
arg [/usr/libexec/gcc/x86_64-linux-gnu/13/liblto_plugin.so] ==> ignore
arg [-plugin-opt=/usr/libexec/gcc/x86_64-linux-gnu/13/lto-wrapper] ==> ignore
arg [-plugin-opt=-fresolution=/tmp/cci1AaX8.res] ==> ignore
arg [-plugin-opt=-pass-through=-lgcc_s] ==> ignore
arg [-plugin-opt=-pass-through=-lgcc] ==> ignore
arg [-plugin-opt=-pass-through=-lc] ==> ignore
arg [-plugin-opt=-pass-through=-lgcc_s] ==> ignore
arg [-plugin-opt=-pass-through=-lgcc] ==> ignore
arg [--build-id] ==> ignore
arg [--eh-frame-hdr] ==> ignore
arg [-m] ==> ignore
arg [elf_x86_64] ==> ignore
arg [--hash-style=gnu] ==> ignore
arg [--as-needed] ==> ignore
arg [-dynamic-linker] ==> ignore
arg [/lib64/ld-linux-x86-64.so.2] ==> ignore
arg [-pie] ==> ignore
arg [-znow] ==> ignore
arg [-zrelro] ==> ignore
arg [-o] ==> ignore
arg [cmTC_b1346] ==> ignore
arg [/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/Scrt1.o] ==> obj [/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/Scrt1.o]
arg [/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/crti.o] ==> obj [/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/crti.o]
arg [/usr/lib/gcc/x86_64-linux-gnu/13/crtbeginS.o] ==> obj [/usr/lib/gcc/x86_64-linux-gnu/13/crtbeginS.o]
arg [-L/usr/lib/gcc/x86_64-linux-gnu/13] ==> dir [/usr/lib/gcc/x86_64-linux-gnu/13]
arg [-L/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu] ==> dir [/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu]
arg [-L/usr/lib/gcc/x86_64-linux-gnu/13/../../../../lib] ==> dir [/usr/lib/gcc/x86_64-linux-gnu/13/../../../../lib]
arg [-L/lib/x86_64-linux-gnu] ==> dir [/lib/x86_64-linux-gnu]
arg [-L/lib/../lib] ==> dir [/lib/../lib]
arg [-L/usr/lib/x86_64-linux-gnu] ==> dir [/usr/lib/x86_64-linux-gnu]
arg [-L/usr/lib/../lib] ==> dir [/usr/lib/../lib]
arg [-L/usr/lib/gcc/x86_64-linux-gnu/13/../../..] ==> dir [/usr/lib/gcc/x86_64-linux-gnu/13/../../..]
arg [CMakeFiles/cmTC_b1346.dir/CMakeCXXCompilerABI.cpp.o] ==> ignore
arg [-lstdc++] ==> lib [stdc++]
arg [-lm] ==> lib [m]
arg [-lgcc_s] ==> lib [gcc_s]
arg [-lgcc] ==> lib [gcc]
arg [-lc] ==> lib [c]
arg [-lgcc_s] ==> lib [gcc_s]
arg [-lgcc] ==> lib [gcc]
arg [/usr/lib/gcc/x86_64-linux-gnu/13/crtendS.o] ==> obj [/usr/lib/gcc/x86_64-linux-gnu/13/crtendS.o]
arg [/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/crtn.o] ==> obj [/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/crtn.o]
collapse obj [/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/Scrt1.o] ==> [/usr/lib/x86_64-linux-gnu/Scrt1.o]
collapse obj [/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/crti.o] ==> [/usr/lib/x86_64-linux-gnu/crti.o]
collapse obj [/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/crtn.o] ==> [/usr/lib/x86_64-linux-gnu/crtn.o]
collapse library dir [/usr/lib/gcc/x86_64-linux-gnu/13] ==> [/usr/lib/gcc/x86_64-linux-gnu/13]
collapse library dir [/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu] ==> [/usr/lib/x86_64-linux-gnu]
collapse library dir [/usr/lib/gcc/x86_64-linux-gnu/13/../../../../lib] ==> [/usr/lib]
collapse library dir [/lib/x86_64-linux-gnu] ==> [/lib/x86_64-linux-gnu]
collapse library dir [/lib/../lib] ==> [/lib]
collapse library dir [/usr/lib/x86_64-linux-gnu] ==> [/usr/lib/x86_64-linux-gnu]
collapse library dir [/usr/lib/../lib] ==> [/usr/lib]
collapse library dir [/usr/lib/gcc/x86_64-linux-gnu/13/../../..] ==> [/usr/lib]
implicit libs: [stdc++;m;gcc_s;gcc;c;gcc_s;gcc]
implicit objs: [/usr/lib/x86_64-linux-gnu/Scrt1.o;/usr/lib/x86_64-linux-gnu/crti.o;/usr/lib/gcc/x86_64-linux-gnu/13/crtbeginS.o;/usr/lib/gcc/x86_64-linux-gnu/13/crtendS.o;/usr/lib/x86_64-linux-gnu/crtn.o]
implicit dirs: [/usr/lib/gcc/x86_64-linux-gnu/13;/usr/lib/x86_64-linux-gnu;/usr/lib;/lib/x86_64-linux-gnu;/lib]
implicit fwks: []
...
---
events:
-
@ -113,6 +378,65 @@ events:
- "/usr/bin/site_perl"
- "/usr/bin/vendor_perl"
- "/usr/bin/core_perl"
-
kind: "find-v1"
backtrace:
- "/usr/share/cmake/Modules/CMakeDetermineCompiler.cmake:73 (find_program)"
- "/usr/share/cmake/Modules/CMakeDetermineCXXCompiler.cmake:69 (_cmake_find_compiler)"
- "CMakeLists.txt:2 (project)"
mode: "program"
variable: "CMAKE_CXX_COMPILER"
description: "CXX compiler"
settings:
SearchFramework: "NEVER"
SearchAppBundle: "NEVER"
CMAKE_FIND_USE_CMAKE_PATH: true
CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH: true
CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH: true
CMAKE_FIND_USE_CMAKE_SYSTEM_PATH: true
CMAKE_FIND_USE_INSTALL_PREFIX: true
names:
- "c++"
- "CC"
- "g++"
- "aCC"
- "cl"
- "bcc"
- "xlC"
- "icpx"
- "icx"
- "clang++"
candidate_directories:
- "/home/saqut/.local/bin/"
- "/usr/local/bin/"
- "/usr/bin/"
- "/bin/"
- "/usr/local/sbin/"
- "/opt/cuda/bin/"
- "/var/lib/flatpak/exports/bin/"
- "/usr/lib/jvm/default/bin/"
- "/usr/bin/site_perl/"
- "/usr/bin/vendor_perl/"
- "/usr/bin/core_perl/"
searched_directories:
- "/home/saqut/.local/bin/c++"
- "/usr/local/bin/c++"
found: "/usr/bin/c++"
search_context:
ENV{PATH}:
- "/home/saqut/.local/bin"
- "/home/saqut/.local/bin"
- "/home/saqut/.local/bin"
- "/usr/local/bin"
- "/usr/bin"
- "/bin"
- "/usr/local/sbin"
- "/opt/cuda/bin"
- "/var/lib/flatpak/exports/bin"
- "/usr/lib/jvm/default/bin"
- "/usr/bin/site_perl"
- "/usr/bin/vendor_perl"
- "/usr/bin/core_perl"
-
kind: "find-v1"
backtrace:
@ -162,7 +486,7 @@ events:
- "CMakeLists.txt:2 (project)"
message: |
Compiling the CXX compiler identification source file "CMakeCXXCompilerId.cpp" succeeded.
Compiler: /usr/bin/g++
Compiler: /usr/bin/c++
Build flags:
Id flags:
@ -893,8 +1217,8 @@ events:
checks:
- "Detecting CXX compiler ABI info"
directories:
source: "/home/saqut/Masa\u00fcst\u00fc/saqutcompiler/build/CMakeFiles/CMakeScratch/TryCompile-KRXVj0"
binary: "/home/saqut/Masa\u00fcst\u00fc/saqutcompiler/build/CMakeFiles/CMakeScratch/TryCompile-KRXVj0"
source: "/home/saqut/Masa\u00fcst\u00fc/saqutcompiler/build/CMakeFiles/CMakeScratch/TryCompile-bNmRFu"
binary: "/home/saqut/Masa\u00fcst\u00fc/saqutcompiler/build/CMakeFiles/CMakeScratch/TryCompile-bNmRFu"
cmakeVariables:
CMAKE_CXX_FLAGS: ""
CMAKE_CXX_FLAGS_DEBUG: "-g"
@ -905,19 +1229,19 @@ events:
variable: "CMAKE_CXX_ABI_COMPILED"
cached: true
stdout: |
Change Dir: '/home/saqut/Masaüstü/saqutcompiler/build/CMakeFiles/CMakeScratch/TryCompile-KRXVj0'
Change Dir: '/home/saqut/Masaüstü/saqutcompiler/build/CMakeFiles/CMakeScratch/TryCompile-bNmRFu'
Run Build Command(s): /usr/bin/ninja -v cmTC_aae80
[1/2] /usr/bin/g++ -v -o CMakeFiles/cmTC_aae80.dir/CMakeCXXCompilerABI.cpp.o -c /usr/share/cmake/Modules/CMakeCXXCompilerABI.cpp
Run Build Command(s): /usr/bin/ninja -v cmTC_a8847
[1/2] /usr/bin/c++ -v -o CMakeFiles/cmTC_a8847.dir/CMakeCXXCompilerABI.cpp.o -c /usr/share/cmake/Modules/CMakeCXXCompilerABI.cpp
Using built-in specs.
COLLECT_GCC=/usr/bin/g++
COLLECT_GCC=/usr/bin/c++
Target: x86_64-pc-linux-gnu
Configured with: /build/gcc/src/gcc/configure --enable-languages=ada,c,c++,d,fortran,go,lto,m2,objc,obj-c++,rust,cobol --enable-bootstrap --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=https://gitlab.archlinux.org/archlinux/packaging/packages/gcc/-/issues --with-build-config=bootstrap-lto --with-linker-hash-style=gnu --with-system-zlib --enable-cet=auto --enable-checking=release --enable-clocale=gnu --enable-default-pie --enable-default-ssp --enable-gnu-indirect-function --enable-gnu-unique-object --enable-libstdcxx-backtrace --enable-link-serialization=1 --enable-linker-build-id --enable-lto --enable-multilib --enable-plugin --enable-shared --enable-threads=posix --disable-libssp --disable-libstdcxx-pch --disable-werror --disable-fixincludes
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 16.1.1 20260430 (GCC)
COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_aae80.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_aae80.dir/'
/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/cc1plus -quiet -v -D_GNU_SOURCE /usr/share/cmake/Modules/CMakeCXXCompilerABI.cpp -quiet -dumpdir CMakeFiles/cmTC_aae80.dir/ -dumpbase CMakeCXXCompilerABI.cpp.cpp -dumpbase-ext .cpp -mtune=generic -march=x86-64 -version -o /tmp/ccmm6pzq.s
COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_a8847.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_a8847.dir/'
/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/cc1plus -quiet -v -D_GNU_SOURCE /usr/share/cmake/Modules/CMakeCXXCompilerABI.cpp -quiet -dumpdir CMakeFiles/cmTC_a8847.dir/ -dumpbase CMakeCXXCompilerABI.cpp.cpp -dumpbase-ext .cpp -mtune=generic -march=x86-64 -version -o /tmp/cch7GwnZ.s
GNU C++20 (GCC) version 16.1.1 20260430 (x86_64-pc-linux-gnu)
compiled by GNU C version 16.1.1 20260430, GMP version 6.3.0, MPFR version 4.2.2, MPC version 1.4.1, isl version isl-0.27-GMP
@ -934,15 +1258,15 @@ events:
/usr/include
End of search list.
Compiler executable checksum: d47d0c990a24bc0dbaf3bd00656bd5f3
COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_aae80.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_aae80.dir/'
as -v --64 -o CMakeFiles/cmTC_aae80.dir/CMakeCXXCompilerABI.cpp.o /tmp/ccmm6pzq.s
COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_a8847.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_a8847.dir/'
as -v --64 -o CMakeFiles/cmTC_a8847.dir/CMakeCXXCompilerABI.cpp.o /tmp/cch7GwnZ.s
GNU assembler version 2.46.0 (x86_64-pc-linux-gnu) using BFD version (GNU Binutils) 2.46.0
COMPILER_PATH=/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/:/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/:/usr/lib/gcc/x86_64-pc-linux-gnu/:/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/:/usr/lib/gcc/x86_64-pc-linux-gnu/
LIBRARY_PATH=/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/:/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/:/lib/../lib/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_aae80.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_aae80.dir/CMakeCXXCompilerABI.cpp.'
[2/2] : && /usr/bin/g++ -v -Wl,-v CMakeFiles/cmTC_aae80.dir/CMakeCXXCompilerABI.cpp.o -o cmTC_aae80 && :
COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_a8847.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_a8847.dir/CMakeCXXCompilerABI.cpp.'
[2/2] : && /usr/bin/c++ -v -Wl,-v CMakeFiles/cmTC_a8847.dir/CMakeCXXCompilerABI.cpp.o -o cmTC_a8847 && :
Using built-in specs.
COLLECT_GCC=/usr/bin/g++
COLLECT_GCC=/usr/bin/c++
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: /build/gcc/src/gcc/configure --enable-languages=ada,c,c++,d,fortran,go,lto,m2,objc,obj-c++,rust,cobol --enable-bootstrap --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=https://gitlab.archlinux.org/archlinux/packaging/packages/gcc/-/issues --with-build-config=bootstrap-lto --with-linker-hash-style=gnu --with-system-zlib --enable-cet=auto --enable-checking=release --enable-clocale=gnu --enable-default-pie --enable-default-ssp --enable-gnu-indirect-function --enable-gnu-unique-object --enable-libstdcxx-backtrace --enable-link-serialization=1 --enable-linker-build-id --enable-lto --enable-multilib --enable-plugin --enable-shared --enable-threads=posix --disable-libssp --disable-libstdcxx-pch --disable-werror --disable-fixincludes
@ -951,12 +1275,12 @@ events:
gcc version 16.1.1 20260430 (GCC)
COMPILER_PATH=/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/:/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/:/usr/lib/gcc/x86_64-pc-linux-gnu/:/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/:/usr/lib/gcc/x86_64-pc-linux-gnu/
LIBRARY_PATH=/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/:/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/:/lib/../lib/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-v' '-o' 'cmTC_aae80' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'cmTC_aae80.'
/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/collect2 -plugin /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/lto-wrapper -plugin-opt=-fresolution=/tmp/cce8QsNN.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-latomic_asneeded -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc --build-id --eh-frame-hdr --hash-style=gnu -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -o cmTC_aae80 /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/Scrt1.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/crti.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/crtbeginS.o -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1 -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../.. -L/lib -L/usr/lib -v CMakeFiles/cmTC_aae80.dir/CMakeCXXCompilerABI.cpp.o -lstdc++ -lm -lgcc_s -lgcc -latomic_asneeded -lc -lgcc_s -lgcc /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/crtendS.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/crtn.o
COLLECT_GCC_OPTIONS='-v' '-o' 'cmTC_a8847' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'cmTC_a8847.'
/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/collect2 -plugin /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/lto-wrapper -plugin-opt=-fresolution=/tmp/cce2Bg9n.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-latomic_asneeded -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc --build-id --eh-frame-hdr --hash-style=gnu -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -o cmTC_a8847 /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/Scrt1.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/crti.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/crtbeginS.o -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1 -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../.. -L/lib -L/usr/lib -v CMakeFiles/cmTC_a8847.dir/CMakeCXXCompilerABI.cpp.o -lstdc++ -lm -lgcc_s -lgcc -latomic_asneeded -lc -lgcc_s -lgcc /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/crtendS.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/crtn.o
collect2 version 16.1.1 20260430
/usr/bin/ld -plugin /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/lto-wrapper -plugin-opt=-fresolution=/tmp/cce8QsNN.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-latomic_asneeded -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc --build-id --eh-frame-hdr --hash-style=gnu -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -o cmTC_aae80 /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/Scrt1.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/crti.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/crtbeginS.o -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1 -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../.. -L/lib -L/usr/lib -v CMakeFiles/cmTC_aae80.dir/CMakeCXXCompilerABI.cpp.o -lstdc++ -lm -lgcc_s -lgcc -latomic_asneeded -lc -lgcc_s -lgcc /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/crtendS.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/crtn.o
/usr/bin/ld -plugin /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/lto-wrapper -plugin-opt=-fresolution=/tmp/cce2Bg9n.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-latomic_asneeded -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc --build-id --eh-frame-hdr --hash-style=gnu -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -o cmTC_a8847 /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/Scrt1.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/crti.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/crtbeginS.o -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1 -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../.. -L/lib -L/usr/lib -v CMakeFiles/cmTC_a8847.dir/CMakeCXXCompilerABI.cpp.o -lstdc++ -lm -lgcc_s -lgcc -latomic_asneeded -lc -lgcc_s -lgcc /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/crtendS.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/crtn.o
GNU ld (GNU Binutils) 2.46.0
COLLECT_GCC_OPTIONS='-v' '-o' 'cmTC_aae80' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'cmTC_aae80.'
COLLECT_GCC_OPTIONS='-v' '-o' 'cmTC_a8847' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'cmTC_a8847.'
exitCode: 0
-
@ -995,19 +1319,19 @@ events:
Parsed CXX implicit link information:
link line regex: [^( *|.*[/\\])(ld[0-9]*(|\\.[a-rt-z][a-z]*|\\.s[a-np-z][a-z]*|\\.so[a-z]+)|CMAKE_LINK_STARTFILE-NOTFOUND|([^/\\]+-)?ld|collect2)[^/\\]*( |$)]
linker tool regex: [^[ ]*(->|"|[0-9]+>[ -]*Build:[ 0-9]+ ms[ ]*)?[ ]*(([^"]*[/\\])?(ld[0-9]*(|\\.[a-rt-z][a-z]*|\\.s[a-np-z][a-z]*|\\.so[a-z]+)))("|,| |$)]
ignore line: [Change Dir: '/home/saqut/Masaüstü/saqutcompiler/build/CMakeFiles/CMakeScratch/TryCompile-KRXVj0']
ignore line: [Change Dir: '/home/saqut/Masaüstü/saqutcompiler/build/CMakeFiles/CMakeScratch/TryCompile-bNmRFu']
ignore line: []
ignore line: [Run Build Command(s): /usr/bin/ninja -v cmTC_aae80]
ignore line: [[1/2] /usr/bin/g++ -v -o CMakeFiles/cmTC_aae80.dir/CMakeCXXCompilerABI.cpp.o -c /usr/share/cmake/Modules/CMakeCXXCompilerABI.cpp]
ignore line: [Run Build Command(s): /usr/bin/ninja -v cmTC_a8847]
ignore line: [[1/2] /usr/bin/c++ -v -o CMakeFiles/cmTC_a8847.dir/CMakeCXXCompilerABI.cpp.o -c /usr/share/cmake/Modules/CMakeCXXCompilerABI.cpp]
ignore line: [Using built-in specs.]
ignore line: [COLLECT_GCC=/usr/bin/g++]
ignore line: [COLLECT_GCC=/usr/bin/c++]
ignore line: [Target: x86_64-pc-linux-gnu]
ignore line: [Configured with: /build/gcc/src/gcc/configure --enable-languages=ada c c++ d fortran go lto m2 objc obj-c++ rust cobol --enable-bootstrap --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=https://gitlab.archlinux.org/archlinux/packaging/packages/gcc/-/issues --with-build-config=bootstrap-lto --with-linker-hash-style=gnu --with-system-zlib --enable-cet=auto --enable-checking=release --enable-clocale=gnu --enable-default-pie --enable-default-ssp --enable-gnu-indirect-function --enable-gnu-unique-object --enable-libstdcxx-backtrace --enable-link-serialization=1 --enable-linker-build-id --enable-lto --enable-multilib --enable-plugin --enable-shared --enable-threads=posix --disable-libssp --disable-libstdcxx-pch --disable-werror --disable-fixincludes]
ignore line: [Thread model: posix]
ignore line: [Supported LTO compression algorithms: zlib zstd]
ignore line: [gcc version 16.1.1 20260430 (GCC) ]
ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_aae80.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_aae80.dir/']
ignore line: [ /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/cc1plus -quiet -v -D_GNU_SOURCE /usr/share/cmake/Modules/CMakeCXXCompilerABI.cpp -quiet -dumpdir CMakeFiles/cmTC_aae80.dir/ -dumpbase CMakeCXXCompilerABI.cpp.cpp -dumpbase-ext .cpp -mtune=generic -march=x86-64 -version -o /tmp/ccmm6pzq.s]
ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_a8847.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_a8847.dir/']
ignore line: [ /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/cc1plus -quiet -v -D_GNU_SOURCE /usr/share/cmake/Modules/CMakeCXXCompilerABI.cpp -quiet -dumpdir CMakeFiles/cmTC_a8847.dir/ -dumpbase CMakeCXXCompilerABI.cpp.cpp -dumpbase-ext .cpp -mtune=generic -march=x86-64 -version -o /tmp/cch7GwnZ.s]
ignore line: [GNU C++20 (GCC) version 16.1.1 20260430 (x86_64-pc-linux-gnu)]
ignore line: [ compiled by GNU C version 16.1.1 20260430 GMP version 6.3.0 MPFR version 4.2.2 MPC version 1.4.1 isl version isl-0.27-GMP]
ignore line: []
@ -1024,15 +1348,15 @@ events:
ignore line: [ /usr/include]
ignore line: [End of search list.]
ignore line: [Compiler executable checksum: d47d0c990a24bc0dbaf3bd00656bd5f3]
ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_aae80.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_aae80.dir/']
ignore line: [ as -v --64 -o CMakeFiles/cmTC_aae80.dir/CMakeCXXCompilerABI.cpp.o /tmp/ccmm6pzq.s]
ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_a8847.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_a8847.dir/']
ignore line: [ as -v --64 -o CMakeFiles/cmTC_a8847.dir/CMakeCXXCompilerABI.cpp.o /tmp/cch7GwnZ.s]
ignore line: [GNU assembler version 2.46.0 (x86_64-pc-linux-gnu) using BFD version (GNU Binutils) 2.46.0]
ignore line: [COMPILER_PATH=/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/:/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/:/usr/lib/gcc/x86_64-pc-linux-gnu/:/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/:/usr/lib/gcc/x86_64-pc-linux-gnu/]
ignore line: [LIBRARY_PATH=/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/:/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/:/lib/../lib/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../:/lib/:/usr/lib/]
ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_aae80.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_aae80.dir/CMakeCXXCompilerABI.cpp.']
ignore line: [[2/2] : && /usr/bin/g++ -v -Wl -v CMakeFiles/cmTC_aae80.dir/CMakeCXXCompilerABI.cpp.o -o cmTC_aae80 && :]
ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_a8847.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_a8847.dir/CMakeCXXCompilerABI.cpp.']
ignore line: [[2/2] : && /usr/bin/c++ -v -Wl -v CMakeFiles/cmTC_a8847.dir/CMakeCXXCompilerABI.cpp.o -o cmTC_a8847 && :]
ignore line: [Using built-in specs.]
ignore line: [COLLECT_GCC=/usr/bin/g++]
ignore line: [COLLECT_GCC=/usr/bin/c++]
ignore line: [COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/lto-wrapper]
ignore line: [Target: x86_64-pc-linux-gnu]
ignore line: [Configured with: /build/gcc/src/gcc/configure --enable-languages=ada c c++ d fortran go lto m2 objc obj-c++ rust cobol --enable-bootstrap --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=https://gitlab.archlinux.org/archlinux/packaging/packages/gcc/-/issues --with-build-config=bootstrap-lto --with-linker-hash-style=gnu --with-system-zlib --enable-cet=auto --enable-checking=release --enable-clocale=gnu --enable-default-pie --enable-default-ssp --enable-gnu-indirect-function --enable-gnu-unique-object --enable-libstdcxx-backtrace --enable-link-serialization=1 --enable-linker-build-id --enable-lto --enable-multilib --enable-plugin --enable-shared --enable-threads=posix --disable-libssp --disable-libstdcxx-pch --disable-werror --disable-fixincludes]
@ -1041,13 +1365,13 @@ events:
ignore line: [gcc version 16.1.1 20260430 (GCC) ]
ignore line: [COMPILER_PATH=/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/:/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/:/usr/lib/gcc/x86_64-pc-linux-gnu/:/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/:/usr/lib/gcc/x86_64-pc-linux-gnu/]
ignore line: [LIBRARY_PATH=/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/:/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/:/lib/../lib/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../:/lib/:/usr/lib/]
ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'cmTC_aae80' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'cmTC_aae80.']
link line: [ /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/collect2 -plugin /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/lto-wrapper -plugin-opt=-fresolution=/tmp/cce8QsNN.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-latomic_asneeded -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc --build-id --eh-frame-hdr --hash-style=gnu -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -o cmTC_aae80 /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/Scrt1.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/crti.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/crtbeginS.o -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1 -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../.. -L/lib -L/usr/lib -v CMakeFiles/cmTC_aae80.dir/CMakeCXXCompilerABI.cpp.o -lstdc++ -lm -lgcc_s -lgcc -latomic_asneeded -lc -lgcc_s -lgcc /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/crtendS.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/crtn.o]
ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'cmTC_a8847' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'cmTC_a8847.']
link line: [ /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/collect2 -plugin /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/lto-wrapper -plugin-opt=-fresolution=/tmp/cce2Bg9n.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-latomic_asneeded -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc --build-id --eh-frame-hdr --hash-style=gnu -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -o cmTC_a8847 /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/Scrt1.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/crti.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/crtbeginS.o -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1 -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../.. -L/lib -L/usr/lib -v CMakeFiles/cmTC_a8847.dir/CMakeCXXCompilerABI.cpp.o -lstdc++ -lm -lgcc_s -lgcc -latomic_asneeded -lc -lgcc_s -lgcc /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/crtendS.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/crtn.o]
arg [/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/collect2] ==> ignore
arg [-plugin] ==> ignore
arg [/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/liblto_plugin.so] ==> ignore
arg [-plugin-opt=/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/lto-wrapper] ==> ignore
arg [-plugin-opt=-fresolution=/tmp/cce8QsNN.res] ==> ignore
arg [-plugin-opt=-fresolution=/tmp/cce2Bg9n.res] ==> ignore
arg [-plugin-opt=-pass-through=-lgcc_s] ==> ignore
arg [-plugin-opt=-pass-through=-lgcc] ==> ignore
arg [-plugin-opt=-pass-through=-latomic_asneeded] ==> ignore
@ -1063,7 +1387,7 @@ events:
arg [/lib64/ld-linux-x86-64.so.2] ==> ignore
arg [-pie] ==> ignore
arg [-o] ==> ignore
arg [cmTC_aae80] ==> ignore
arg [cmTC_a8847] ==> ignore
arg [/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/Scrt1.o] ==> obj [/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/Scrt1.o]
arg [/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/crti.o] ==> obj [/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/crti.o]
arg [/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/crtbeginS.o] ==> obj [/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/crtbeginS.o]
@ -1075,7 +1399,7 @@ events:
arg [-L/lib] ==> dir [/lib]
arg [-L/usr/lib] ==> dir [/usr/lib]
arg [-v] ==> ignore
arg [CMakeFiles/cmTC_aae80.dir/CMakeCXXCompilerABI.cpp.o] ==> ignore
arg [CMakeFiles/cmTC_a8847.dir/CMakeCXXCompilerABI.cpp.o] ==> ignore
arg [-lstdc++] ==> lib [stdc++]
arg [-lm] ==> lib [m]
arg [-lgcc_s] ==> lib [gcc_s]
@ -1087,7 +1411,7 @@ events:
arg [/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/crtendS.o] ==> obj [/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/crtendS.o]
arg [/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/crtn.o] ==> obj [/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/crtn.o]
ignore line: [collect2 version 16.1.1 20260430]
ignore line: [/usr/bin/ld -plugin /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/lto-wrapper -plugin-opt=-fresolution=/tmp/cce8QsNN.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-latomic_asneeded -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc --build-id --eh-frame-hdr --hash-style=gnu -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -o cmTC_aae80 /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/Scrt1.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/crti.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/crtbeginS.o -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1 -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../.. -L/lib -L/usr/lib -v CMakeFiles/cmTC_aae80.dir/CMakeCXXCompilerABI.cpp.o -lstdc++ -lm -lgcc_s -lgcc -latomic_asneeded -lc -lgcc_s -lgcc /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/crtendS.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/crtn.o]
ignore line: [/usr/bin/ld -plugin /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/lto-wrapper -plugin-opt=-fresolution=/tmp/cce2Bg9n.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-latomic_asneeded -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc --build-id --eh-frame-hdr --hash-style=gnu -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -o cmTC_a8847 /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/Scrt1.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/crti.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/crtbeginS.o -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1 -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../.. -L/lib -L/usr/lib -v CMakeFiles/cmTC_a8847.dir/CMakeCXXCompilerABI.cpp.o -lstdc++ -lm -lgcc_s -lgcc -latomic_asneeded -lc -lgcc_s -lgcc /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/crtendS.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/crtn.o]
linker tool for 'CXX': /usr/bin/ld
collapse obj [/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/Scrt1.o] ==> [/usr/lib/Scrt1.o]
collapse obj [/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/crti.o] ==> [/usr/lib/crti.o]

View File

@ -1,3 +1,4 @@
/home/saqut/Masaüstü/saqutcompiler/build/CMakeFiles/saqut.dir
/home/saqut/Masaüstü/saqutcompiler/build/CMakeFiles/test.dir
/home/saqut/Masaüstü/saqutcompiler/build/CMakeFiles/edit_cache.dir
/home/saqut/Masaüstü/saqutcompiler/build/CMakeFiles/rebuild_cache.dir

View File

@ -0,0 +1,46 @@
# CMAKE generated file: DO NOT EDIT!
# Generated by CMake Version 4.3
# ALL_GOLDEN_SQT at CMakeLists.txt:40 (file)
file(GLOB_RECURSE NEW_GLOB LIST_DIRECTORIES false "/home/saqut/Masaüstü/saqutcompiler/tests/golden/*.sqt")
set(OLD_GLOB
"/home/saqut/Masaüstü/saqutcompiler/tests/golden/arithmetic/basic.sqt"
"/home/saqut/Masaüstü/saqutcompiler/tests/golden/arithmetic/compound_mod.sqt"
"/home/saqut/Masaüstü/saqutcompiler/tests/golden/arithmetic/mod_by_zero.sqt"
"/home/saqut/Masaüstü/saqutcompiler/tests/golden/arithmetic/precedence.sqt"
"/home/saqut/Masaüstü/saqutcompiler/tests/golden/fibonacci/fib.sqt"
"/home/saqut/Masaüstü/saqutcompiler/tests/golden/logic/not_operator.sqt"
"/home/saqut/Masaüstü/saqutcompiler/tests/golden/logic/short_circuit.sqt"
"/home/saqut/Masaüstü/saqutcompiler/tests/golden/loops/basic.sqt"
"/home/saqut/Masaüstü/saqutcompiler/tests/golden/loops/do_while_once.sqt"
"/home/saqut/Masaüstü/saqutcompiler/tests/golden/loops/do_while_truthy.sqt"
"/home/saqut/Masaüstü/saqutcompiler/tests/golden/loops/for_break_continue.sqt"
"/home/saqut/Masaüstü/saqutcompiler/tests/golden/loops/nested_break.sqt"
"/home/saqut/Masaüstü/saqutcompiler/tests/golden/loops/while_break_continue.sqt"
"/home/saqut/Masaüstü/saqutcompiler/tests/golden/opt/dce.sqt"
"/home/saqut/Masaüstü/saqutcompiler/tests/golden/opt/folding.sqt"
"/home/saqut/Masaüstü/saqutcompiler/tests/golden/opt/run_opt.sqt"
"/home/saqut/Masaüstü/saqutcompiler/tests/golden/string/equality.sqt"
"/home/saqut/Masaüstü/saqutcompiler/tests/golden/string/hello.sqt"
"/home/saqut/Masaüstü/saqutcompiler/tests/golden/string/ordering_error.sqt"
)
if(NOT "${NEW_GLOB}" STREQUAL "${OLD_GLOB}")
message("-- GLOB mismatch!")
set(NEW_ONLY ${NEW_GLOB})
set(OLD_ONLY ${OLD_GLOB})
list(REMOVE_ITEM NEW_ONLY ${OLD_GLOB})
list(REMOVE_ITEM OLD_ONLY ${NEW_GLOB})
if(NEW_ONLY)
message("The following files were added:")
foreach(VAR_FILE IN LISTS NEW_ONLY)
message(" +${VAR_FILE}")
endforeach()
endif()
if(OLD_ONLY)
message("The following files were removed:")
foreach(VAR_FILE IN LISTS OLD_ONLY)
message(" -${VAR_FILE}")
endforeach()
endif()
file(TOUCH_NOCREATE "/home/saqut/Masaüstü/saqutcompiler/build/CMakeFiles/cmake.verify_globs")
endif()

View File

@ -0,0 +1 @@
# This file is generated by CMake for checking of the VerifyGlobs.cmake file

View File

@ -79,6 +79,15 @@ rule RERUN_CMAKE
generator = 1
#############################################
# Rule for re-checking globbed directories.
rule VERIFY_GLOBS
command = /usr/bin/cmake -P /home/saqut/Masaüstü/saqutcompiler/build/CMakeFiles/VerifyGlobs.cmake
description = Re-checking globbed directories...
generator = 1
#############################################
# Rule for cleaning all built files.

48
build/CTestTestfile.cmake Normal file
View File

@ -0,0 +1,48 @@
# CMake generated Testfile for
# Source directory: /home/saqut/Masaüstü/saqutcompiler
# Build directory: /home/saqut/Masaüstü/saqutcompiler/build
#
# This file includes the relevant testing commands required for
# testing this directory and lists subdirectories to be tested as well.
add_test(unit_tests "bash" "/home/saqut/Masaüstü/saqutcompiler/tests/run.sh")
set_tests_properties(unit_tests PROPERTIES _BACKTRACE_TRIPLES "/home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt;31;add_test;/home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt;0;")
add_test(golden_arithmetic_basic "/usr/bin/cmake" "-DBINARY=/home/saqut/Masaüstü/saqutcompiler/build/saqut" "-DSOURCE=/home/saqut/Masaüstü/saqutcompiler/tests/golden/arithmetic/basic.sqt" "-DEXPECTED=/home/saqut/Masaüstü/saqutcompiler/tests/golden/arithmetic/basic.expected" "-P" "/home/saqut/Masaüstü/saqutcompiler/cmake/run_golden.cmake")
set_tests_properties(golden_arithmetic_basic PROPERTIES _BACKTRACE_TRIPLES "/home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt;51;add_test;/home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt;0;")
add_test(golden_arithmetic_compound_mod "/usr/bin/cmake" "-DBINARY=/home/saqut/Masaüstü/saqutcompiler/build/saqut" "-DSOURCE=/home/saqut/Masaüstü/saqutcompiler/tests/golden/arithmetic/compound_mod.sqt" "-DEXPECTED=/home/saqut/Masaüstü/saqutcompiler/tests/golden/arithmetic/compound_mod.expected" "-P" "/home/saqut/Masaüstü/saqutcompiler/cmake/run_golden.cmake")
set_tests_properties(golden_arithmetic_compound_mod PROPERTIES _BACKTRACE_TRIPLES "/home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt;51;add_test;/home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt;0;")
add_test(golden_arithmetic_mod_by_zero_runtime_error "/usr/bin/cmake" "-DBINARY=/home/saqut/Masaüstü/saqutcompiler/build/saqut" "-DSOURCE=/home/saqut/Masaüstü/saqutcompiler/tests/golden/arithmetic/mod_by_zero.sqt" "-DEXPECTED=/home/saqut/Masaüstü/saqutcompiler/tests/golden/arithmetic/mod_by_zero.runtime_error" "-P" "/home/saqut/Masaüstü/saqutcompiler/cmake/run_golden_error.cmake")
set_tests_properties(golden_arithmetic_mod_by_zero_runtime_error PROPERTIES _BACKTRACE_TRIPLES "/home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt;109;add_test;/home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt;0;")
add_test(golden_arithmetic_precedence "/usr/bin/cmake" "-DBINARY=/home/saqut/Masaüstü/saqutcompiler/build/saqut" "-DSOURCE=/home/saqut/Masaüstü/saqutcompiler/tests/golden/arithmetic/precedence.sqt" "-DEXPECTED=/home/saqut/Masaüstü/saqutcompiler/tests/golden/arithmetic/precedence.expected" "-P" "/home/saqut/Masaüstü/saqutcompiler/cmake/run_golden.cmake")
set_tests_properties(golden_arithmetic_precedence PROPERTIES _BACKTRACE_TRIPLES "/home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt;51;add_test;/home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt;0;")
add_test(golden_fibonacci_fib "/usr/bin/cmake" "-DBINARY=/home/saqut/Masaüstü/saqutcompiler/build/saqut" "-DSOURCE=/home/saqut/Masaüstü/saqutcompiler/tests/golden/fibonacci/fib.sqt" "-DEXPECTED=/home/saqut/Masaüstü/saqutcompiler/tests/golden/fibonacci/fib.expected" "-P" "/home/saqut/Masaüstü/saqutcompiler/cmake/run_golden.cmake")
set_tests_properties(golden_fibonacci_fib PROPERTIES _BACKTRACE_TRIPLES "/home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt;51;add_test;/home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt;0;")
add_test(golden_logic_not_operator "/usr/bin/cmake" "-DBINARY=/home/saqut/Masaüstü/saqutcompiler/build/saqut" "-DSOURCE=/home/saqut/Masaüstü/saqutcompiler/tests/golden/logic/not_operator.sqt" "-DEXPECTED=/home/saqut/Masaüstü/saqutcompiler/tests/golden/logic/not_operator.expected" "-P" "/home/saqut/Masaüstü/saqutcompiler/cmake/run_golden.cmake")
set_tests_properties(golden_logic_not_operator PROPERTIES _BACKTRACE_TRIPLES "/home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt;51;add_test;/home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt;0;")
add_test(golden_logic_short_circuit "/usr/bin/cmake" "-DBINARY=/home/saqut/Masaüstü/saqutcompiler/build/saqut" "-DSOURCE=/home/saqut/Masaüstü/saqutcompiler/tests/golden/logic/short_circuit.sqt" "-DEXPECTED=/home/saqut/Masaüstü/saqutcompiler/tests/golden/logic/short_circuit.expected" "-P" "/home/saqut/Masaüstü/saqutcompiler/cmake/run_golden.cmake")
set_tests_properties(golden_logic_short_circuit PROPERTIES _BACKTRACE_TRIPLES "/home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt;51;add_test;/home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt;0;")
add_test(golden_loops_basic "/usr/bin/cmake" "-DBINARY=/home/saqut/Masaüstü/saqutcompiler/build/saqut" "-DSOURCE=/home/saqut/Masaüstü/saqutcompiler/tests/golden/loops/basic.sqt" "-DEXPECTED=/home/saqut/Masaüstü/saqutcompiler/tests/golden/loops/basic.expected" "-P" "/home/saqut/Masaüstü/saqutcompiler/cmake/run_golden.cmake")
set_tests_properties(golden_loops_basic PROPERTIES _BACKTRACE_TRIPLES "/home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt;51;add_test;/home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt;0;")
add_test(golden_loops_do_while_once "/usr/bin/cmake" "-DBINARY=/home/saqut/Masaüstü/saqutcompiler/build/saqut" "-DSOURCE=/home/saqut/Masaüstü/saqutcompiler/tests/golden/loops/do_while_once.sqt" "-DEXPECTED=/home/saqut/Masaüstü/saqutcompiler/tests/golden/loops/do_while_once.expected" "-P" "/home/saqut/Masaüstü/saqutcompiler/cmake/run_golden.cmake")
set_tests_properties(golden_loops_do_while_once PROPERTIES _BACKTRACE_TRIPLES "/home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt;51;add_test;/home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt;0;")
add_test(golden_loops_do_while_truthy "/usr/bin/cmake" "-DBINARY=/home/saqut/Masaüstü/saqutcompiler/build/saqut" "-DSOURCE=/home/saqut/Masaüstü/saqutcompiler/tests/golden/loops/do_while_truthy.sqt" "-DEXPECTED=/home/saqut/Masaüstü/saqutcompiler/tests/golden/loops/do_while_truthy.expected" "-P" "/home/saqut/Masaüstü/saqutcompiler/cmake/run_golden.cmake")
set_tests_properties(golden_loops_do_while_truthy PROPERTIES _BACKTRACE_TRIPLES "/home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt;51;add_test;/home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt;0;")
add_test(golden_loops_for_break_continue "/usr/bin/cmake" "-DBINARY=/home/saqut/Masaüstü/saqutcompiler/build/saqut" "-DSOURCE=/home/saqut/Masaüstü/saqutcompiler/tests/golden/loops/for_break_continue.sqt" "-DEXPECTED=/home/saqut/Masaüstü/saqutcompiler/tests/golden/loops/for_break_continue.expected" "-P" "/home/saqut/Masaüstü/saqutcompiler/cmake/run_golden.cmake")
set_tests_properties(golden_loops_for_break_continue PROPERTIES _BACKTRACE_TRIPLES "/home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt;51;add_test;/home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt;0;")
add_test(golden_loops_nested_break "/usr/bin/cmake" "-DBINARY=/home/saqut/Masaüstü/saqutcompiler/build/saqut" "-DSOURCE=/home/saqut/Masaüstü/saqutcompiler/tests/golden/loops/nested_break.sqt" "-DEXPECTED=/home/saqut/Masaüstü/saqutcompiler/tests/golden/loops/nested_break.expected" "-P" "/home/saqut/Masaüstü/saqutcompiler/cmake/run_golden.cmake")
set_tests_properties(golden_loops_nested_break PROPERTIES _BACKTRACE_TRIPLES "/home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt;51;add_test;/home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt;0;")
add_test(golden_loops_while_break_continue "/usr/bin/cmake" "-DBINARY=/home/saqut/Masaüstü/saqutcompiler/build/saqut" "-DSOURCE=/home/saqut/Masaüstü/saqutcompiler/tests/golden/loops/while_break_continue.sqt" "-DEXPECTED=/home/saqut/Masaüstü/saqutcompiler/tests/golden/loops/while_break_continue.expected" "-P" "/home/saqut/Masaüstü/saqutcompiler/cmake/run_golden.cmake")
set_tests_properties(golden_loops_while_break_continue PROPERTIES _BACKTRACE_TRIPLES "/home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt;51;add_test;/home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt;0;")
add_test(golden_opt_dce_ir_opt "/usr/bin/cmake" "-DBINARY=/home/saqut/Masaüstü/saqutcompiler/build/saqut" "-DSOURCE=/home/saqut/Masaüstü/saqutcompiler/tests/golden/opt/dce.sqt" "-DEXPECTED=/home/saqut/Masaüstü/saqutcompiler/tests/golden/opt/dce.ir_opt.expected" "-DCOMMAND=ir" "-DOPTIMIZED=1" "-P" "/home/saqut/Masaüstü/saqutcompiler/cmake/run_golden.cmake")
set_tests_properties(golden_opt_dce_ir_opt PROPERTIES _BACKTRACE_TRIPLES "/home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt;64;add_test;/home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt;0;")
add_test(golden_opt_folding_ir_opt "/usr/bin/cmake" "-DBINARY=/home/saqut/Masaüstü/saqutcompiler/build/saqut" "-DSOURCE=/home/saqut/Masaüstü/saqutcompiler/tests/golden/opt/folding.sqt" "-DEXPECTED=/home/saqut/Masaüstü/saqutcompiler/tests/golden/opt/folding.ir_opt.expected" "-DCOMMAND=ir" "-DOPTIMIZED=1" "-P" "/home/saqut/Masaüstü/saqutcompiler/cmake/run_golden.cmake")
set_tests_properties(golden_opt_folding_ir_opt PROPERTIES _BACKTRACE_TRIPLES "/home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt;64;add_test;/home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt;0;")
add_test(golden_opt_run_opt "/usr/bin/cmake" "-DBINARY=/home/saqut/Masaüstü/saqutcompiler/build/saqut" "-DSOURCE=/home/saqut/Masaüstü/saqutcompiler/tests/golden/opt/run_opt.sqt" "-DEXPECTED=/home/saqut/Masaüstü/saqutcompiler/tests/golden/opt/run_opt.expected" "-P" "/home/saqut/Masaüstü/saqutcompiler/cmake/run_golden.cmake")
set_tests_properties(golden_opt_run_opt PROPERTIES _BACKTRACE_TRIPLES "/home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt;51;add_test;/home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt;0;")
add_test(golden_opt_run_opt_run_opt "/usr/bin/cmake" "-DBINARY=/home/saqut/Masaüstü/saqutcompiler/build/saqut" "-DSOURCE=/home/saqut/Masaüstü/saqutcompiler/tests/golden/opt/run_opt.sqt" "-DEXPECTED=/home/saqut/Masaüstü/saqutcompiler/tests/golden/opt/run_opt.run_opt.expected" "-DOPTIMIZED=1" "-P" "/home/saqut/Masaüstü/saqutcompiler/cmake/run_golden.cmake")
set_tests_properties(golden_opt_run_opt_run_opt PROPERTIES _BACKTRACE_TRIPLES "/home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt;80;add_test;/home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt;0;")
add_test(golden_string_equality "/usr/bin/cmake" "-DBINARY=/home/saqut/Masaüstü/saqutcompiler/build/saqut" "-DSOURCE=/home/saqut/Masaüstü/saqutcompiler/tests/golden/string/equality.sqt" "-DEXPECTED=/home/saqut/Masaüstü/saqutcompiler/tests/golden/string/equality.expected" "-P" "/home/saqut/Masaüstü/saqutcompiler/cmake/run_golden.cmake")
set_tests_properties(golden_string_equality PROPERTIES _BACKTRACE_TRIPLES "/home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt;51;add_test;/home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt;0;")
add_test(golden_string_hello "/usr/bin/cmake" "-DBINARY=/home/saqut/Masaüstü/saqutcompiler/build/saqut" "-DSOURCE=/home/saqut/Masaüstü/saqutcompiler/tests/golden/string/hello.sqt" "-DEXPECTED=/home/saqut/Masaüstü/saqutcompiler/tests/golden/string/hello.expected" "-P" "/home/saqut/Masaüstü/saqutcompiler/cmake/run_golden.cmake")
set_tests_properties(golden_string_hello PROPERTIES _BACKTRACE_TRIPLES "/home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt;51;add_test;/home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt;0;")
add_test(golden_string_ordering_error_compile_error "/usr/bin/cmake" "-DBINARY=/home/saqut/Masaüstü/saqutcompiler/build/saqut" "-DSOURCE=/home/saqut/Masaüstü/saqutcompiler/tests/golden/string/ordering_error.sqt" "-DEXPECTED=/home/saqut/Masaüstü/saqutcompiler/tests/golden/string/ordering_error.compile_error" "-P" "/home/saqut/Masaüstü/saqutcompiler/cmake/run_golden_error.cmake")
set_tests_properties(golden_string_ordering_error_compile_error PROPERTIES _BACKTRACE_TRIPLES "/home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt;95;add_test;/home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt;0;")

File diff suppressed because one or more lines are too long

39
cmake/run_golden.cmake Normal file
View File

@ -0,0 +1,39 @@
# run_golden.cmake tek bir golden test çalıştırır ve çıktıyı karşılaştırır.
#
# Parametreler (cmake -D ile geçilir):
# BINARY saqut binary yolu
# SOURCE test .sqt dosyası (tam yol)
# EXPECTED beklenen çıktı dosyası (tam yol)
# COMMAND "run" (varsayılan) veya "ir"
# OPTIMIZED 1 ise --optimized bayrağı eklenir
if(NOT DEFINED COMMAND)
set(COMMAND "run")
endif()
set(EXTRA_FLAGS "")
if(OPTIMIZED)
list(APPEND EXTRA_FLAGS "--optimized")
endif()
execute_process(
COMMAND "${BINARY}" "${COMMAND}" ${EXTRA_FLAGS} "file:${SOURCE}"
OUTPUT_VARIABLE ACTUAL
ERROR_VARIABLE STDERR_OUT
RESULT_VARIABLE EXIT_CODE
)
if(NOT EXIT_CODE EQUAL 0)
message(FATAL_ERROR
"saqut ${COMMAND} başarısız (exit ${EXIT_CODE}):\n${STDERR_OUT}")
endif()
file(READ "${EXPECTED}" EXPECTED_CONTENT)
if(NOT ACTUAL STREQUAL EXPECTED_CONTENT)
message(FATAL_ERROR
"Çıktı uyuşmuyor: ${SOURCE}\n"
"--- BEKLENEN ---\n${EXPECTED_CONTENT}"
"--- GERÇEK ---\n${ACTUAL}"
)
endif()

View File

@ -0,0 +1,29 @@
# run_golden_error.cmake derleme hatası BEKLEYEN golden test.
#
# Parametreler (cmake -D ile geçilir):
# BINARY saqut binary yolu
# SOURCE test .sqt dosyası (tam yol)
# EXPECTED beklenen hata içeriği (.compile_error dosyası); stderr bu
# metni içermeli (regex veya düz dize olarak eşleşir)
execute_process(
COMMAND "${BINARY}" run "file:${SOURCE}"
OUTPUT_VARIABLE STDOUT_OUT
ERROR_VARIABLE STDERR_OUT
RESULT_VARIABLE EXIT_CODE
)
if(EXIT_CODE EQUAL 0)
message(FATAL_ERROR
"Derleme hatası bekleniyordu ama program başarıyla çalıştı: ${SOURCE}\n"
"Çıktı: ${STDOUT_OUT}")
endif()
file(READ "${EXPECTED}" EXPECTED_CONTENT)
string(STRIP "${EXPECTED_CONTENT}" EXPECTED_CONTENT)
if(NOT STDERR_OUT MATCHES "${EXPECTED_CONTENT}")
message(FATAL_ERROR
"Beklenen '${EXPECTED_CONTENT}' mesajı stderr'de bulunamadı: ${SOURCE}\n"
"Stderr: ${STDERR_OUT}")
endif()

View File

@ -10,12 +10,11 @@
> 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.
> ✅ **Uygulama durumu:** Bu belgedeki ADR-006…019 kararlarında tarif edilen
> makine **kodlandı ve çalışıyor.** Sembol tablosu, semantik analiz, tip sistemi,
> diagnostic motoru, optimizasyon (constant folding + DCE), IR üreteci ve bytecode
> VM'in tamamı uygulandı. `examples/fibonacci.sqt` uçtan uca çalışıyor.
> Güncel "çalışıyor / henüz yok" listesi için bkz. `CLAUDE.md`.
---
@ -105,46 +104,45 @@ sembol tablosunun optimizasyondan önceki ve sonraki halini ayrı ayrı görebil
symbol bağı, erişilebilirlik, constness ekler). Ağacı **bozmaz**, zenginleştirir.
Orijinal AST hâlâ kaynak kodun tam izdüşümüdür.
2. **Optimizasyon dönüşümü, ağacın bir KOPYASI (klon) üzerinde yapılır.**
Orijinal analizli AST = "öncesi"; klon + dönüştürülmüş AST = "sonrası".
Ağaç klonlamak ucuz ve basittir, yalnızca `--optimized` istendiğinde yapılır.
2. **Optimizasyon dönüşümü iki yolla yapılabilir:**
**Sonuç:** Hem "bellek canavarı" felsefesi korunur (orijinal AST her şeyi tutar),
hem optimizasyon yapılır, hem de öncesi/sonrası ayrı ayrı incelenebilir.
a. **`ast` komutu için klon:** orijinal AST dokunulmadan kalır, klon üstünde
pass'ler çalışır. Kullanıcı "öncesi" ve "sonrası" AST'yi ayrı ayrı
görebilir. `OptimizationManager::optimize()` bu yolu kullanır.
b. **Diğer tüm komutlar için yerinde (in-place):** `run --optimized`,
`ir --optimized` vb. tek versiyon üretiyor — orijinali saklamaya gerek yok.
`OptimizationManager::runPassesInPlace()` bu yolu kullanır, klon maliyeti yok.
**Sonuç:** "bellek canavarı" felsefesi `ast` komutunda korunur; diğer komutlar
gereksiz klon maliyeti taşımaz.
```
saqut ast file.sqt → ham + annotate edilmiş AST (1+2 burada durur)
saqut ast file.sqt --optimized → klon, folding uygulanmış (3 var)
saqut run file.sqt --optimized → yerinde optimize → IR → VM (klon yok)
saqut ir file.sqt --optimized → yerinde optimize → IR dump (klon yok)
```
### Güncelleme — Klon maliyeti yük taşır (load-bearing)
### Güncelleme — Klon ve sembol tablosu paylaşımı
İ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:
`deepClone` sembol tablosunu yeniden eşlemez (remap etmez) — klondaki
`IdentifierNode::resolvedSymbol` orijinal `Symbol` nesnelerini gösterir. Bu
**güvenlidir**, çünkü:
`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).
- `Symbol::references` bir **konum listesi** (`std::vector<SourceLocation>`),
referans sayacı değildir. Klonda bir `IdentifierNode` silindiğinde bu liste
değişmez.
- `IdentifierNode` destructor'ı yoktur; `resolvedSymbol`'e dokunan hiçbir yıkıcı
kodu çalışmaz.
- Klondaki pass'ler Symbol nesnelerini **okur** (slot numarası, tip vb.),
**yazmaz** — paylaşım salt-okunur (read-only) kullanımdır.
**Klonlanırken karar verilmesi gereken iki nokta (açıkça belgele):**
**Parent pointer'lar** ise yeniden bağlanır — klon node'larının `parent`'ı
orijinali değil, klonu gösterir (deepClone bunu zaten yapar).
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.
Önceki versiyon "sembol tablosu klonlanır ve remap edilir" diyordu; bu hem hiç
implement edilmedi hem de gerekli değildi. Düzeltildi.
---
@ -513,6 +511,11 @@ bir yükümlülüktür ama **frontend'i bloklamaz** ve kolay yolu vardır:
### Güncelleme — Scope-tabanlı bellek artık GEREKÇELİ (bağımlılığı belgele)
> ⚠️ **İPTAL — bu güncelleme ADR-020 ile geçersiz kılındı.** Bileşik tipler artık
> runtime'da referans (JS/Java/C# modeli); bileşikler scope'tan kaçar, bellek
> erişilebilirliğe bağlı, geri-kazanım stratejisi (#56) gerekecek. Aşağıdaki
> "GC gerekmez" sonucu **artık geçerli değildir** — tarihsel bağlam için bırakıldı.
Önceki kaygı ("scope çıkışında free, aliasing/escape altında bozulur") kilitli
dil kimliğiyle **lehte çözüldü:**
@ -662,12 +665,457 @@ modelini birlikte zorlar — ikisi de bu yüzden ertelendi.
---
## ADR-020: Değer vs Referans Semantiği — Bileşik Tipler Runtime'da Referanstır
### Bağlam
ADR-014/018/019 boyunca bellek modeli tek bir **taşıyıcı varsayıma** dayanıyordu:
> "kullanıcı pointer'ı yok + kaçan referans yok → array/struct scope'tan kaçamaz
> → scope-tabanlı bellek çalışır, **GC gerekmez**."
Bu varsayım, `interface`'in (ADR-018) ve closure'ın ertelenmesinin de ikinci
gerekçesiydi. Tasarım oturumunda **bilinçli olarak değiştirildi.** "Pointer yok"
ilkesinin gerçekte ne demek olduğu netleşti:
> **"Pointer/referans yok" = kullanıcıya `&`/`*` *sözdizimi* verilmez.**
> Bu bir *value-semantics* iddiası değildi; amacı sözdizimsel pointer kontrolünü
> kullanıcıdan almaktı. Derleyici ve runtime, bileşik değerleri her aşamada
> **referansla** taşır — aksi halde her atama/çağrı/dönüşte derin kopya yaşanır
> ve bağlı yapılar (node) imkânsızlaşırdı.
### Karar
✅ **İki katmanlı semantik (JavaScript / Java / C# nesne modeli):**
| Kategori | Tipler | Atama / parametre semantiği |
|---|---|---|
| **Primitive** | `int`, `float`, `bool`, (`char` vb.) | **Saf değer** — kopyalanır |
| **Bileşik (referans)** | `struct`, `array`, `string`\*, (ileride `class`, `function`) | **Referans** — paylaşılır |
- `a=0; b=a; b=5``a` hâlâ `0` (primitive kopya). Fonksiyon parametresinde de aynı.
- `func(arr)` → array'in **kendisi** geçer; `func` içinde değişen çağıranı **etkiler**.
- `func(arr[0])` → eleman primitive → **kopya**; çağıranı **etkilemez**.
- \* `string`'in primitive-gibi mi (immutable değer) yoksa referans mı sayılacağı
ayrı bir alt-karar; #40 ile beraber netleşecek.
**`class` ve `function` tipleri sözdizimsel olarak rezerve** — şu an semantik
yok, backend'i ilgilendirmez; ileride referans tip olarak gelecekler. Lexer/parser
keyword'leri tanıyıp "henüz desteklenmiyor" diyebilir. (ADR-014'teki "class yok
sayılır" maddesi bu yönde yumuşatıldı: yok sayılmaz, rezerve edilir.)
### Bilinçli geri açtığımız problem: kaçma / yaşam-süresi
Bu karar, ADR-014'ün "scope-tabanlı bellek GEREKÇELİ / GC gerekmez" sonucunu
**iptal eder.** Referansla:
1. **Aliasing gerçek.** `b = a; b.x = 5``a.x` de değişir. "Takma ad yok, akıl
yürütmesi kolay" sadeliği takas edildi. **Determinizm korunur** — tek
iş-parçacığı, deterministik kayıt-tekrar / time-travel debug hâlâ doğal; takas
edilen yalnızca aliasing-özgürlüğüdür.
2. **Bileşikler scope'tan kaçar.** Bir node `return` edilebilir veya başka bir
struct'ın alanında saklanabilir → "scope çıkışında free" **artık yanlış.**
Sahiplik scope'a değil **erişilebilirliğe** bağlı.
3. **Döngüsel yapılar artık meşru ve istenen.** `struct Node { Node next; }`
ADR-011/014'te `E010` ile yasaktı (by-value → sonsuz boyut). Referansla alan
pointer-boyutlu → **sonlu** → bağlı liste / ağaç / graf **yazılabilir.** Bunlar
dilin hedef kullanımının kalbi: XML node'ları, JSON kalıpları, class'sız ORM.
**Sonuç:** `E010` revize edilmeli — referansla tutulan struct alanı için döngü
artık hata değildir.
### Bunun açtığı zorunlu problem (ayrı issue)
Döngüsel referans → naif **referans sayımı (`shared_ptr`) sızdırır.** Bu artık
"olabilir" değil, dilin **hedeflediği** yapıların (graf/döngü) doğrudan sonucu.
Bir geri-kazanım stratejisi (izleyici GC / döngü toplayıcı) **kesinlikle**
gerekecek. Bu güçlü mimari borç **#56**'da izlenir ve `karar-gerekli`. v1 motoru
`shared_ptr` ile başlayıp döngüyü **bilinçli ve belgeleyerek** sızdırabilir, ama
ürünleşmeden önce çözülmek zorundadır.
### İptal/revize edilen önceki kararlar
- **ADR-014** — "scope-tabanlı bellek GEREKÇELİ / GC gerekmez" sonucu **iptal.**
Bellek artık scope'a değil erişilebilirliğe bağlı; geri-kazanım stratejisi #56.
- **ADR-018 / ADR-019**`interface` / closure'ı ertelemenin "kaçma problemini
yeniden açar" gerekçesi **artık geçersiz** (problem zaten açık). Bu ikisini
*daha kolay* alınabilir kılar — ama hâlâ kapsam dışı, sadece engeli değişti.
- **ADR-011**`E010` döngüsel struct kuralı revize edilecek (yukarı bkz.).
---
## ADR-021: Null Güvenliği — `Type?` Nullable + Akış-Duyarlı Null Analizi
### Bağlam
ADR-020 ile bileşik tipler referans oldu. Referans, "gösterecek bir şey yok"
durumunu (bağlı listenin sonu, başlatılmamış alan) **zorunlu** kılar. "null her
yerde" (Java/C#/JS) milyar dolarlık hatadır: null-deref çalışma zamanında patlar.
saQut'un kimliği "kafes — derleyici/VM seni korur" → bunu derleme zamanında
yakalamak istiyoruz.
### Karar
✅ **Kotlin/Swift modeli: varsayılan null-OLAMAZ, nullable açıkça `?` ile.**
- `Node a` → asla null olamaz; başlatılması zorunlu.
- `Node? a` → null olabilir; başlatılmazsa değeri **`null`**.
- `null` literali yalnızca `T?` tipine atanabilir; `Node a = null`**derleme hatası**.
- `T?` üstünde doğrudan alan/eleman erişimi (`a.next`) → **derleme hatası**
(önce null-kontrolü şart).
### Atama/operand kuralı`T <: T?` (tek yönlü), katı
**Alt-tip:** `T <: T?`. Yani:
- `int? a = 5;` → ✓ (int → int?, **genişletme serbest**).
- `int a = bir_int?;` → ✗ (int? → int, **daraltma yasak**).
**Katı operand kuralı:** non-null bir bağlamda — atamanın sol tarafı, **her
operatör operandı**, non-null bekleyen bir argüman — değer **statik olarak non-null**
olmalı. `int a = b + c + d`'de `b/c/d`'den **biri bile** nullable ise → **derleme
hatası.** Sembol tablosu/akış görünümü seviyesinde: `notnull = notnull + notnull + …`.
Sezgi yok, deterministik. (`notnull + notnull` → `notnull`.)
### Akış-duyarlı null analizi (flow-sensitive narrowing)
`T?` bir değişken **program noktasına göre** "kesin non-null" kanıtlandıysa
daraltılır:
```c
Node? a = ...;
// a.next; // E0xx: a null olabilir
if (a != null) {
a.next; // OK — bu dalda a, Node'a daraltıldı
}
// a.next; // yine hata (daldan çıkıldı)
if (a == null) return; // guard / erken çıkış
a.next; // OK — buradan sonrası kesin non-null
```
`if` bu sistemin **bel kemiğidir** — sadece büyük/küçük/eşitlik değil, nullable
aklamanın da aracı. **İki form da desteklenir:**
1. **Nested (blok-kapsamlı):** `if (a != null) { /* a: T burada */ }`. Ayrıca
`if/else`'in zıt dalı, `while (a != null) { … }`.
2. **Sıralı (guard / erken-çıkış):** `if (a == null) return; /* a: T bundan sonra */`.
Dal kesin çıkıyorsa (`return`/`throw`/`break`/`continue`) negasyonu **ardışık**
koda taşınır.
**Mekanik:** CFG üzerinde ileri-yönlü dataflow; her nullable değişken için kafes
`{MaybeNull, NonNull}`. Koşullarda daraltma (`!= null`, `== null` guard, `&&`
kısa-devre sağ tarafı); kesin-çıkış dalları negasyonu ardına taşır; birleşme (join)
muhafazakâr (bir daldan MaybeNull gelirse MaybeNull); atama RHS'e göre sıfırlar.
> **Karmaşıklaştırma sınırı:** narrowing yalnızca **doğrudan test edilen değişken**
> için tanınır (`x == null`/`x != null`). **Alias takibi YOK** (`y = x; if (y != null)`
> → x daralmaz) ve keyfi teorem-ispatı yok. Bu, derleyiciyi basit tutarken yaygın
> durumların hepsini kapsar → developer **uzun/karmaşık kod yazmak zorunda kalmaz.**
> **Runtime maliyeti SIFIR** — tamamen derleme-zamanı analizi; üretilen kodda
> fazladan kontrol yok.
### Kaçış kapısı YOK — `!` ve `??` YASAK
Null **yalnızca görünür kontrol akışıyla** (yukarıdaki `if` narrowing) aklanır.
Gizli runtime null-aklama operatörleri **yasaktır:**
- ❌ **`x!`** (non-null iddiası) — "compiler'a güvenme, runtime'da kontrol et"
= statik garantiyi delen gizli backdoor. *(ADR-021'in ilk taslağındaki `a!`
KALDIRILDI.)*
- ❌ **`x ?? default`** (elvis), **`x?.field`** (güvenli çağrı) — null durumunu
sessizce gizleyen şeker.
> Ayrım: `as int`'in başarısızlıkta fırlatması yasak **değil** — o bir null-backdoor
> değil, kendiliğinden başarısız olabilen bir *dönüşüm* (ADR-026).
### Frontend her şeyi kesin çözer (backend-bağımsızlık)
Nullability **tamamen frontend'de** çözülür; tüm null-güvenlik hataları IR'den
**önce** verilir. Backend'ler (IR+VM, ileride C-transpile) null-güvenliği **yeniden
analiz etmez** — garantiyi hazır devralır (ADR-006/019). Bu sayede: well-typed saf
saQut kodu **statik null-güvenlidir** → non-null referans deref'i runtime null-kontrolü
**gerektirmez** (perf + sadelik). Runtime null-deref hatası (ADR-025) bu yüzden
geriye esas olarak **FFI sınırı** (host non-null sözünü çiğnerse) ve savunma amaçlı
backstop olarak kalır — saf saQut kodu bunu üretmez.
### Mimari yeri
Bu, saQut'un ilk gerçek **akış-duyarlı** analizidir. **Yapısal kontrol akışı**
üstünde (AST + structured CFG) yapılabilir; tam SSA gerektirmez → **#2 (CFG/SSA
gerekli mi?)** için somut veri: şimdilik yapısal akış analizi yeter. **#20**
(akıllı diagnostic) bu analizden beslenir ("burada null olabilir, çünkü …").
---
## ADR-022: Bellek Geri-Kazanımı — Basit Deterministik Mark-Sweep + GC-Hazır Nesne Modeli
### Bağlam
ADR-020 referans semantiği → döngüsel yapılar (#56). Kısıtlar: GC **basit ve
deterministik** olmalı, "karmaşık ve rastgele" istenmiyor. Ayrıca bu, **geç
değiştirilmesi en pahalı** karardır (nesne modeline işler) → topuğa sıkmamak
kritik.
### Önce yanlış-eşleştirmeyi temizle
**`null`/`?` GC'yi zorlaştırmaz.** Nullable tamamen derleme-zamanı/tip meselesidir;
runtime'da null referans sadece "boş işaretçi" → GC için *daha kolay* (izlenecek
nesne yok). null ile GC **dik (orthogonal)**; aralarında gerilim yoktur.
### Seçenekler ve neden mark-sweep
| Strateji | Döngü | Basitlik | Topuğa-sıkma riski |
|---|---|---|---|
| Refcount (`shared_ptr` her yerde) | ❌ sızdırır | başta basit | **Yüksek** — node dilinde döngü kaçınılmaz; üstüne döngü toplayıcı = CPython karmaşıklığı (tam "karmaşık/rastgele") |
| **Mark-sweep, taşımasız, stop-the-world** | ✅ | **en basit *doğru* GC** | **Düşük** — gelişmiş GC'lerin tabanı; üstüne eklenir, yeniden yazılmaz |
| Generational / incremental / compacting | ✅ | karmaşık (write barrier, remembered set) | pause'lar belirsizleşir = istenmeyen "rastgele" |
✅ **Karar: taşımasız (non-moving), stop-the-world, basit mark-sweep.**
- Döngüleri **bedavaya** toplar (izleme döngü umursamaz) → #56'yı gerçekten çözer.
- **Deterministik:** GC belirli safepoint'lerde çalışır (ör. her N tahsiste) →
kayıt-tekrar / time-travel bit-aynı kalır ("cage" korunur). "Rastgele" değil.
- Taşımasız → işaretçi düzeltme / barrier yok → VM'in geri kalanı GC'ye katılmak
zorunda değil. *Crafting Interpreters*'ın `clox`'u tam bunu yapar (~birkaç yüz satır).
### Topuğa-sıkmama kuralı — nesne modelini ŞİMDİ GC-hazır kur
Asıl risk GC'yi *yazmak* değil, nesne modelini sonradan ona uyduramamaktır. O
yüzden **bugünden** (toplama yokken bile):
1. Her heap nesnesine küçük **header**: tip tag + mark biti + tüm-nesneler listesi için `next`.
2. VM **kök (root) sayımı** yapabilsin: operand stack, frame local'leri, global'ler.
3. Bir nesne **içerdiği referansları** sayabilsin: referans-tipli struct alanları,
referans-tipli array elemanları.
Bu üçü hazırsa "mark-sweep'i aç" **lokal bir ekleme** olur, nesne-modeli yeniden
yazımı değil.
### Aşamalandırma (#56'nın yönü)
- **v1 (şimdi):** GC-header'lı tahsis + intrusive tüm-nesneler listesi + kök sayımı.
**Toplama yok** (program sonunda hepsini bırak / arena). Fibonacci/test ölçeğinde
sorunsuz; kısa programlar sızıntıdan etkilenmez.
- **v2 (#56 ciddileşince):** aynı header+kök+çocuk-sayımı üstünde mark-sweep'i aç.
Model yeniden yazılmaz.
- **`shared_ptr`'dan kaçın:** v1'de bile her referansa refcount gömmek, sonra
mark-sweep için **sökmek** ayrı bir topuğa-sıkmadır. Baştan GC-header modeli kur,
sadece henüz toplama.
### Performans notu — asıl "katil" nerede?
- **Nullability / null:** runtime maliyeti **sıfır** — katil değil.
- **Referans modeli:** her bileşik heap'te + işaretçi dolaylılığı → düzenli ama
yönetilebilir maliyet; ileride **escape analizi** ile kaçmayan nesneleri stack'e
alıp *semantiği bozmadan* hızlandırılır (opt-in, sonra).
- **Tek yüksek-değişim-maliyetli karar = GC.** Onu da (a) basit mark-sweep seçip
(b) modeli baştan GC-hazır kurarak de-risk ettik. **Kaçınılacak gerçek katil:
refcount'u kalıcı model yapmak.**
---
## ADR-023: Eşitlik Semantiği — Referanslarda Kimlik Eşitliği (`==`)
### Bağlam
ADR-020 ile bileşik tipler referans. `==` / `!=` referans tipler için ne yapsın?
Yapısal (derin) eşitlik sezgisel ama üç sorunu var: (1) büyük yapıda **derin
gezinme maliyeti**, (2) yeni açtığımız **döngüsel grafta sonsuz döngü** riski
(ziyaret-takibi şart), (3) seçtiğimiz referans modeliyle **tutarsız**.
### Karar
✅ **Kimlik eşitliği (A):**
| Kategori | `==` davranışı |
|---|---|
| Primitive (`int`/`float`/`bool`) | **değer** karşılaştırması (`3 == 3`) |
| Referans (`struct`, `array`) | **kimlik** — aynı nesne mi? (işaretçi aynılığı) |
| `string` | ⏸️ **#40'a bağlı** — aşağıdaki nota bak |
| `null` | `null == null` → true; `null == nesne` → false; `a == null` null-daraltma deyimi (ADR-021) |
İçerik karşılaştırması istenirse **ayrı, niyeti görünür** bir mekanizmayla gelir
(ileride builtin `deepEquals()` / PHP'nin `==` vs `===` vs `clone` ailesi gibi) —
asla sessizce `==`'e bağlanmaz. Gerekçe: deepEqual'ı `==`'e bağlamak büyük/döngüsel
yapılarda performans ve sonsuz-döngü tuzağıdır; "cam kutu, sürpriz yok" kimliğiyle
de çelişir.
### ⚠️ String istisnası (Java gotcha'sı)
Saf kimlik eşitliğini string'e de uygularsak `"abc" == "abc"`**false** olur —
Java'nın en çok sövülen hatası. Çoğu dil string'i istisna yapar (JS'te string
primitive → içerik; C# overload; Python intern). Bu yüzden **string'in `==`'i
içerik eşitliği olmalı**, ki bu string'i **immutable değer-tipi** olarak modellemeyi
güçlü biçimde öneriyor (bkz. #40). ADR-023 struct/array'i kilitler; string'in `==`'i
#40'ta netleşir ama **varsayılan yön: içerik eşitliği.**
### Açık (ileride, çok uzak — şimdi karar değil)
- **`obj == obj`'i hata/uyarı yapmak:** kullanıcıyı niyetini açık yazmaya zorlamak
(kimlik mi içerik mi). Daha katı bir duruş; v0'da `==` = kimlik serbest.
- **Kullanıcı-tanımlı eşitlik (OOP'siz):** ileride bir tip için `equals(T,T)->bool`
konvansiyonu veya benzeri ile `==`'i kullanıcının tanımlamasına izin vermek —
operator-overload'un OOP'siz karşılığı. Çok uzak.
---
## ADR-024: String — Immutable Değer-Tipi, İç Temsil UTF-8
### Bağlam
ADR-020 string'i "bileşik (referans)" listesine `?` ile koymuştu; ADR-023 string
`==`'inin **içerik** olmasını istedi (Java gotcha'sından kaçınmak için). İkisi de
string'i değişmez-değer modeline itti.
### Karar
✅ **String = immutable (değişmez) değer-tipi; iç temsil UTF-8 bayt.**
- **Immutable:** oluşturulduktan sonra içeriği değişmez; `s = s + "x"` **yeni**
string üretir, eskisini değiştirmez.
- **`==` içerik eşitliği** (ADR-023 istisnası). Paylaşılınca değişmediği için
içerik-eşitliği güvenlidir; aliasing sürprizi yok (JS'in string'i primitive gibi
davranmasının sebebi budur).
- **GC dostu:** serbestçe paylaşılır / intern edilebilir.
- **İç temsil UTF-8** (Rust/Go/Swift hattı): kompakt, web-doğal, ASCII'de ucuz.
`s[i]` **karakter** indeksi O(1) **değildir** → bayt / scalar / grapheme erişimi
**açıkça** ayrılır; sahte O(1) vaat edilmez (Java/JS'in "uzunluk emoji'de yalan
söylüyor" sürprizinden kaçın). Host tarafında `std::string` ham bayt olarak oturur.
- **Verimli birleştirme** için ileride ayrı **builder** tipi (StringBuilder / `join`)
— çekirdeği kirletmeden, döngüde O(n²)'den kaçınmak için.
### Etkilenen
- **#40** (string işlem yüzeyi) bu kararla netleşti; **#9** (iç temsil) = UTF-8.
- ADR-020'deki string `?` işareti → "değer-tipi" olarak çözüldü.
---
## ADR-025: Hata Yönetim Modeli — Struct-Tabanlı Yakalanabilir Hatalar (Swift-tarzı)
### Bağlam
ADR-020 (struct = referans) → null bir struct alanına erişim/yazma ihtimali doğdu:
klasik NullPointerException. ADR-021 statik analizi *kanıtlayabildiğini* derleme
zamanında yakalar, ama `!` iddiası ve kanıtlanamayan durumlar (struct alanı,
cross-fonksiyon) için bir **runtime backstop** gerekir. Ayrıca array OOB, /0 gibi
faults. Java/C#/JS bunları **yakalanabilir** hata yapar — ama OOP exception
hiyerarşisi (`extends Exception`) bizde yok.
### Karar
✅ **Yakalanabilir, struct-tabanlı hata modeli — OOP'siz.**
Hata *değeri* Swift gibi (düz struct, hiyerarşi/extend yok); *görünürlük* Java/C#/JS
gibi (**unchecked** — fonksiyon işaretlenmez, klasik `try{}catch{}`). "Exception'ın
tanıdık catch-and-jump ergonomisi + OOP'suz değer."
1. **Hata değeri = standart built-in struct** — extend yok, OOP yok, deterministik:
```
struct Error {
int line; // hata satırı
int col; // sütun ("char" tip adıyla çakışmaması için col)
string message; // insan-okunur (derleyicinin W/E kataloğundan)
string trace; // stacktrace, en içten dışa
string code; // makine-okunur W/E kodu (E010 vb.) — JSON/toolbox filtresi
}
```
2. **try/catch (unwind + jump):** hata oluşunca en yakın çevreleyen `catch`'e
zıplanır; `catch (e)``e : Error`.
3. **Runtime null-deref = yakalanabilir hata** (NPE analoğu). ADR-021 statik
analizinin **backstop'u**: `a!` patlayınca + analizin kanıtlayamadığı durumlar.
Array OOB ve /0 da aynı kapıdan.
4. **`throw`** ile kullanıcı da hata kaldırabilir (`Error` doldurup).
5. **Determinizm:** unwind deterministik; stacktrace frame'lerden üretilir;
time-travel/replay handle eklenebilir.
### Görünürlük — KARAR: (ii) görünmez / unchecked (Java/C#/JS usulü)
**Fonksiyonlar işaretlenmez.** "Bu hata yapabilir / yapamaz" anotasyonu **YOK**
(C++'ın `noexcept`/`constexpr` benzeri kirlilik istenmiyor). Çağrıda `try f()`
işareti de yok. **Klasik `try { ... } catch (e) { ... }` bloğu** — "anam babam usulü".
**Gerekçe:** developer'a **güven** + insanların derin try-catch alışkanlığını bozmamak
(sözdizimini tanıdık tut, içgüdüye dokunma). Hatalar zaten çoğunlukla FFI, bellek
dolması ve derleyici-içi durumlardan doğar; her çağrıyı işaretlemenin bedeli faydadan
büyük.
> Not: Bu, `Type?` (explicit nullable) ile **bilinçli** felsefi ayrışmadır — null
> *tipte* görünür, ama hata akışı *blok* düzeyinde tanıdık tutulur. Reddedilen (i):
> Swift/Zig'in imza-işaretli + çağrıda `try f()` modeli.
### Stacktrace mekaniği (modelden bağımsız önkoşul)
- Her `CallFrame``IRFunction` + komut işaretçisi; **IR'a satır tablosu**
(komut index → kaynak konum) eklenir (önce taşıyıp taşımadığı doğrulanmalı).
- panic/throw'da frame stack gezilir → `fonksiyon + konum`, en içten dışa → `trace`.
- Sunum: derleme-zamanı diagnostic ile **aynı kabuk** (kod + mesaj + konum +
"nasıl düzelt" #20), hem insan hem **JSON** (toolbox: her hata yapılandırılmış nesne).
- Farklılaştırıcı: deterministik → trace'e adım indeksi → hataya **geri sar**.
### İlişkili güncellemeler
- **ADR-014 "tuple yok" → "tuple ERTELENDİ"** (reddedilmedi; çoklu-dönüş kodu
spagettileştirir, şimdilik uzak ama masada — `interface` gibi).
- **`finally` yerine ileride `defer`** (GC'li, RAII'siz dilde daha temiz). Ayrı küçük karar.
- ADR-021 ile uyum: statik analiz provable null'ı yakalar; bu hata onun backstop'u + `!`.
---
## ADR-026: Tip Dönüşümü — `as` (Skaler/String), Başarısızlık Hedef Tipinin Nullable'lığıyla
### Bağlam
ADR-010 "gizli int↔float yok" → değişken-değişken dönüşüm **açık** olmalı. float
runtime'ı var ama cast sözdizimi yoktu → int↔float dönüşümü imkânsızdı. Ayrıca
elimizde null (ADR-021) + hata (ADR-025) modelleri var; cast bunlarla örtüşmeli.
### Karar
**Sözdizimi: `as` (infix, sola-bağlı).** `deger as int`.
- Sola-bağlı olduğu için zincir **lineer** okunur: `a as int as string` =
`((a as int) as string)`, parantez gerekmez (fonksiyon-stili `int(float(a))`'nın
iç içe çirkinliği yok).
- `int(x)` fonksiyon-stili **reddedildi** ("int adlı fonksiyon mu, cast mı"
belirsizliği); C-tarzı `(int)x` ve `static_cast<>` reddedildi.
**Kapsam: yalnızca skaler + string** (`int`/`float`/`bool`/`string` arası).
- **Struct/array cast'e GİRMEZ.** Farklı struct'lar ayrı tiplerdir; "dönüşümleri"
geliştiricinin yazdığı **açık yapıcı fonksiyonlarla** olur (`Employee yap(Person p)`).
Gerekçe: yapısal/duck eşleme veya reinterpret = derleyiciyi karmaşıklaştırır +
sessiz alan kaybı = hataya açık. OOP'siz "cage" kimliğiyle uyumsuz.
**Başarısızlık davranışı = HEDEF TİPİN nullable'lığı** (ayrı `as?` operatörü YOK):
- `x as int` → hedef non-null → başarısızsa **`Error` fırlatır** (ADR-025), sonuç `int`.
- `x as int?` → hedef nullable → başarısızsa **`null` döner**, sonuç `int?`.
Nullable her zaman **tipte** (`?`) yaşar, ayrı operatör icat edilmez. Sonra `int?`'i
`int`'e çevirmek için **narrowing** (`if`) gerekir — `!`/`??` yasak (ADR-021).
### Dönüşüm matrisi
| Dönüşüm | Hatasız mı? | Not |
|---|---|---|
| `int → float` | ✅ hatasız | büyük int'te kesinlik kaybı olabilir, patlamaz |
| `int → string`, `float → string` | ✅ hatasız | biçimlendirme |
| `string → int`/`float` | ⚠️ fallible | parse; `"abc"``as int` fırlatır / `as int?` null |
| `float → int` | ⚠️ fallible | sonlu & aralık-içi: **sıfıra doğru kırpılır** (`1.71→1`, `-1.71→-1`); NaN/Inf/taşma → fırlatır / null |
| `bool ↔ int` | (karar) | başta yasak tutmak en güvenlisi; gerekirse açılır |
### Örnek (ADR-021 ile birlikte)
```
int a = 1.71 as int?; // ✗ DERLEME HATASI: int? → int (daraltma); cast başarılı olsa bile statik tip int?
int a = 1.71 as int; // ✓ a = 1 (kırpma); başarısızsa Error
int? a = 1.71 as int?; // ✓ tipler eşit
```
---
## Kararların Özet Tablosu
| 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; `clone()` merkezi, sembol tablosu remap edilir |
| 007 | Analiz vs optimizasyon | Analiz yerinde; `ast` komutu klon üstünde dönüştürür (öncesi/sonrası karşılaştırması); `run`/`ir` yerinde optimize eder (klon yok); sembol bağları salt-okunur paylaşım (remap gerekmez) |
| 008 | Optimizasyon konumu | Basitler AST'de, dataflow gerektirenler IR'de |
| 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 |
@ -680,3 +1128,10 @@ modelini birlikte zorlar — ikisi de bu yüzden ertelendi.
| 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 |
| 020 | Değer/referans semantiği | Primitive=değer, bileşik (struct/array/string)=referans; "pointer yok"=`&`/`*` sözdizimi yok; kaçma/lifetime problemi bilinçli açıldı → GC borcu (#56); ADR-014'ün "GC gerekmez" sonucu iptal |
| 021 | Null güvenliği | `Type?` nullable, varsayılan non-null; akış-duyarlı null analizi (compile-time, runtime maliyeti sıfır); `!` runtime-kontrollü non-null iddiası |
| 022 | Bellek geri-kazanımı | Basit taşımasız stop-the-world mark-sweep (deterministik); nesne modeli baştan GC-hazır (header+root+child); v1 toplamasız, v2 mark-sweep; refcount kalıcı model DEĞİL; #56'nın yönü |
| 023 | Eşitlik semantiği | `==` = primitive değer / referans (struct,array) **kimlik**; deepEqual asla `==`'e bağlanmaz (ayrı `deepEquals()`); string `==` içerik (→ #40, Java gotcha'sından kaçın); `obj==obj` hata + kullanıcı-tanımlı eşitlik = uzak gelecek |
| 024 | String | Immutable değer-tipi, iç temsil **UTF-8**; `==` içerik; mutasyon yeni string üretir; bayt/scalar/grapheme açıkça ayrı; verimli birleştirme için ileride builder; #40/#9'u çözer |
| 025 | Hata yönetimi | Struct-tabanlı yakalanabilir hata (değer Swift gibi, OOP yok); standart `Error{line,col,message,trace,code}`; klasik `try{}catch{}` **unchecked** (fonksiyon işaretsiz, Java usulü); runtime null-deref/OOB yakalanabilir (esasen FFI backstop); deterministik stacktrace (IR satır tablosu); tuple→ertelendi; finally→`defer`; #57 |
| 026 | Tip dönüşümü | `as` (infix, sola-bağlı), yalnızca skaler+string; struct/array cast YOK (elle yapıcı fonksiyon); başarısızlık hedef nullable'lığıyla (`as int` fırlatır / `as int?` null); float→int kırpma; #42 |

View File

@ -0,0 +1,60 @@
# ADR-008: && ve || kısa devre değerlendirmesi
## Durum
Kabul edildi.
## Bağlam
Mevcut kodda `&&` ve `||` çalışma anında bozuk: IR üretici bu operatörler için
`case` içermiyor, `default` koluna düşüp `LOAD_CONST 0` üretiyor — yani değişken
operandlarda her zaman `false` dönüyor. Yalnızca her iki operand sabit olduğunda
sabit katlama doğru sonucu veriyor. (Kanıt: `ir_generator.cpp:395-413`,
`constant_folding.hpp:107-112`; davranış referansı bölüm B.)
## Karar
`&&` ve `||` **KISA DEVRE** değerlendirilir:
- `a && b`: `a` false ise `b` **HİÇ değerlendirilmez**, sonuç `false`.
- `a || b`: `a` true ise `b` **HİÇ değerlendirilmez**, sonuç `true`.
Bu, bu operatörlerin sıradan ikili işlem (iki tarafı hesapla sonra birleştir)
**DEĞİL**, bir dallanma olarak üretilmesi gerektiği anlamına gelir.
IR şeması:
```
a && b:
slot_a = [a değerlendir]
result = freshSlot()
LOAD_CONST result, 0 ; varsayılan: false
JIF_FALSE slot_a → DONE ; a false? b'yi atla, result=0 kalsın
slot_b = [b değerlendir]
LOAD_SLOT result, slot_b ; result = b'nin değeri
DONE:
a || b:
slot_a = [a değerlendir]
result = freshSlot()
LOAD_CONST result, 1 ; varsayılan: true
JIF_TRUE slot_a → DONE ; a true? b'yi atla, result=1 kalsın
slot_b = [b değerlendir]
LOAD_SLOT result, slot_b ; result = b'nin değeri
DONE:
```
`||` için `JIF_TRUE` opcode'u gerekir. `JIF_FALSE`'un simetriği olarak
`instruction.hpp`'e ve `interpreter.cpp`'e eklendi. `do-while` döngüsünün
mevcut `EQUAL_EQUAL(cond, 1)` geçici çözümü bu opcode'dan faydalanabilir
(ayrı düzeltme — bu ADR kapsamı dışı).
## Gerekçe
- C-ailesi dillerin (C, Go, Java, JS, C#) tamamı kısa devre yapar; hedef kitle
bunu bekler.
- Performans artısı: gereksiz sağ-taraf değerlendirmesi atlanır; kısa devre
OLMAYAN versiyon her iki tarafı da her zaman hesaplayacağı için daha yavaştır.
- Niş ile uyumlu: derleyici "şu çağrı şu durumda atlandı" diye gösterebilir.
## Sonuçlar
- Tek dezavantaj: mantıksal operatörün sağındaki yan etki koşullu çalışır.
Bu kabul edilir; yan etkiyi koşula gömmek zaten kötü kalıptır.
- Sabit katlama yolu (`constant_folding.hpp`) zaten doğru çalışıyordu ve
değiştirilmedi; bu düzeltme yalnızca değişken-operand (IR üretim) yolunu etkiler.

225
docs/architecture.md Normal file
View File

@ -0,0 +1,225 @@
# saQut — Mimari Referans
**Programlanabilir, incelenebilir bir derleyici — bir "alet çantası" (toolbox).**
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.
---
## Tasarım felsefesi — neden saQut farklı?
saQut "daha iyi bir dil" iddiasında değil. Farkı, **derleyiciyi bir platform**
olarak ele almasında. İki taahhüt üstüne kuruludur:
**1. Cam (gör + sorgula + içine müdahale et).** Her aşama — token, AST, sembol
tablosu, tip, IR — kararlı, makine-okur ve **çift yönlü** bir arayüzden
erişilebilir olmalıdır. Sadece "dök ve göster" değil: kendi AST'ini verip tip
kontrolü isteyebilmeli, IR verip çalıştırabilmelisin. **Turnusol testi:** bir
yabancı, yalnızca `saqut ast` + `saqut symbols` çıktısından, bizden habersiz bir
LSP yazabiliyor mu? Cevap "evet" ise platform gerçektir.
**2. Kafes (deterministik + yetenek-güvenli çalıştırma).** Pointer yok, value
semantics, scope-tabanlı bellek ve **tek dış-dünya kapısı olan FFI seam**
(ADR-016) sayesinde saQut kodu, host'un açıkça izin verdiği fonksiyonlar dışında
dünyaya dokunamaz. Bytecode VM deterministiktir (ADR-015): aynı girdi → aynı
çıktı → aynı çalışma. "Sadelik" diye tasarlanan bu kararlar aslında bir
**yetenek-güvenliği (capability sandbox)** kurar — güvenilmeyen veya
AI-üretimi kodu güvenle çalıştırmak için biçilmiş kaftan.
**Bu ikisinin ödülü — kayıt & tekrar (record-replay).** 🚧 *(vizyon, v0 değil;
bkz. issue #94.)* Belirsizliğin tek kaynağı (kullanıcı girdisi, zaman, IO,
GC/thread kararları) FFI kapısından geçtiği için, mükemmel tekrar oynatma için
**her değişkeni her adımda kaydetmek gerekmez** — yalnızca kapıdan geçen değerler
kaydedilir, gerisi VM deterministik olarak yeniden çalıştırılarak üretilir. Boyut
gigabayttan kilobayta düşer. Replay modunda FFI çağrıları gerçekten çalışmaz,
kaydedilmiş değeri döndürür (dosyayı tekrar silmez, sunucuya tekrar istek atmaz).
Böylece "benim makinemde çalışıyor, müşteride patlıyor" sorunu: müşteri bir dump
yollar, sen çöküşü adım adım, aynı verilerle geri sararsın.
> Log, önceden sormayı akıl ettiğin sorulara cevap verir; **tekrar-oynatma,
> çöküşten *sonra* aklına gelen sorulara.** Zaman-yolculuğu hata ayıklama ayrı
> bir altyapı değildir — cam sorgularına bir **zaman koordinatı** eklemektir.
⚠️ Bu ödülün bedeli v0'da ödenir: **determinizm kutsaldır ve her belirsizlik
kaynağı kayıt-altına-alınabilir tek kapıdan geçmelidir.** Sonradan eklenemez;
baştan korunur.
---
## Mimari hatlar
```
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.
---
## CLI (mevcut + planlanan)
```
# --- çalışıyor ---
saqut tokens file:kaynak.sqt # token listesi
saqut ast file:kaynak.sqt # AST (JSON)
saqut symbols file:kaynak.sqt # sembol tablosu (iskelet)
# --- 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)
```
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.
---
## Batteries / stdlib — kuzey yıldızı, ertelendi
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.**
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.
- **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).
---
## Belge haritası
| 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 |
---
## İlke
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.

View File

@ -18,9 +18,10 @@
> **ç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.**
> - **Yapılan vs planlanan:** Tüm pipeline uygulandı. `examples/fibonacci.sqt`
> uçtan uca çalışıyor (lexer → tokenizer → parser → sembol tablosu → tip
> denetleyici → optimizasyon → IR üreteci → bytecode VM). ADR-001'deki
> "mevcut durum" listesi artık tarihseldir; güncel durum için bkz. `CLAUDE.md`.
---

View File

@ -10,21 +10,12 @@
> 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).
> ✅ **Birinci kilometre taşı AŞILDI.** Faz 04 uygulandı; `examples/fibonacci.sqt`
> uçtan uca çalışıyor. Bu yol haritası artık tarihsel bir referanstır.
>
> 🎯 **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.
> **Sonraki hedefler:** float/double codegen, struct IR, array IR, açık bug'lar
> (#35 bellek sızıntısı, #36 W003 uyarısı, #37 `%=` IR, #38 global değişken IR).
> Güncel "çalışıyor / henüz yok" listesi için bkz. `CLAUDE.md`.
---
@ -46,7 +37,7 @@ Katman eşlemesi (ADR-006):
---
## Faz 0 — Temeller (Type + Diagnostic + Hata Kataloğu)
## Faz 0 — Temeller (Type + Diagnostic + Hata Kataloğu) — TAMAMLANDI
**Bağımlılık:** yok. **Hedef:** her şeyin üstüne kurulacağı temel veri yapıları.
İlgili ADR: 010 (Type), 013 (Diagnostic).
@ -91,7 +82,7 @@ Katman eşlemesi (ADR-006):
---
## Faz 1 — AST Refactor (ExpressionNode / StatementNode + analiz alanları)
## Faz 1 — AST Refactor (ExpressionNode / StatementNode + analiz alanları) — TAMAMLANDI
**Bağımlılık:** Faz 0 (Type). **Hedef:** node hiyerarşisini ifade/deyim olarak
ayır, analiz alanlarını ekle. İlgili ADR: 012, 013.
@ -116,7 +107,7 @@ ayır, analiz alanlarını ekle. İlgili ADR: 012, 013.
---
## Faz 2 — Symbol Table (scope'lu, iki-geçişli toplama)
## Faz 2 — Symbol Table (scope'lu, iki-geçişli toplama) — TAMAMLANDI
**Bağımlılık:** Faz 0, 1. **Hedef:** isim çözümleme + scope + referans toplama.
İlgili ADR: 011, 013.
@ -150,7 +141,7 @@ ayır, analiz alanlarını ekle. İlgili ADR: 012, 013.
---
## Faz 3 — Semantic Analiz (Tip Kontrolü + Yapısal Doğrulama)
## Faz 3 — Semantic Analiz (Tip Kontrolü + Yapısal Doğrulama) — TAMAMLANDI
**Bağımlılık:** Faz 2. **Hedef:** tipleri ata/kontrol et, yapısal kuralları
doğrula. İlgili ADR: 010, 013.
@ -173,7 +164,7 @@ doğrula. İlgili ADR: 010, 013.
---
## Faz 4 — Optimizasyon Framework
## Faz 4 — Optimizasyon Framework — TAMAMLANDI
**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.

186
docs/sonnet-handoff.md Normal file
View File

@ -0,0 +1,186 @@
# 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>`; 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. |
ı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<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, `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<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).
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ıı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 — REVİZE).** Ayrı **frontend** görevi: `Type?` tip
sistemi + `T <: T?` atama kuralı + katı operand kuralı + akış-duyarlı narrowing
(nested `if` + sıralı guard + `&&`). ⚠️ **`a!`/`??`/`?.` YASAK** — null yalnızca
görünür `if` ile 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.
4. **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`. `throw` ile 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`/`constexpr` tarzı YOK), çağrıda **`try 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).
5. **float/double (#44).** Bağımsız; `Value::Float` + FADD… opcode + tip denetleyici.
6. **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`) + `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`** | ~~`nil`~~, ~~`none`~~, ~~`void`~~ |
| Nullable tip işareti | **`Type?`** (ör. `int?`, `Node?`) | ~~`Optional<T>`~~, ~~`Type \| null`~~ |
| Non-null iddiası / elvis / safe-call | **YASAK**`if` narrowing kullan | ~~`a!`~~, ~~`a ?? x`~~, ~~`a?.f`~~ (ADR-021 revize) |
| Array literal | **`[1, 2, 3]`** | ~~`{1,2,3}`~~ |
| Array tip | **`int[]`** | ~~`array<int>`~~, ~~`[]int`~~ |
| Hata tipi | **`Error`** (`{line,char,message,trace,code}`) | ~~`Exception`~~, ~~`Err`~~ |
| Hata kaldırma / yakalama | **`throw` / `try` / `catch`** | ~~`raise`~~, ~~`rescue`~~ |
| Fonksiyon | **`func`** | ~~`fn`~~, ~~`function`~~, ~~`def`~~ |
| 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.

25
examples/test_bitwise.sqt Normal file
View File

@ -0,0 +1,25 @@
int global_x = 10;
int global_y = 3;
int main() {
// global değişken testi (#38)
print(global_x);
print(global_y);
// bitsel AND, OR, SHL, SHR (#45)
int a = 12;
int b = 10;
print(a & b);
print(a | b);
print(1 << 3);
print(16 >> 2);
// unary ~ ve !
int c = 0;
print(!c);
int d = 5;
print(!d);
print(~0);
return 0;
}

347
readme.md
View File

@ -1,225 +1,186 @@
# saQut
**Programlanabilir, incelenebilir bir derleyici — bir "alet çantası" (toolbox).**
> **A compiler built as a toolbox, not a black box —**
> every internal phase is a first-class, inspectable output.
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.
```
saqut tokens file:fib.sqt → token stream, JSON
saqut ast file:fib.sqt → full AST, JSON
saqut ast file:fib.sqt --optimized → constant-folded + DCE'd AST
saqut run file:fib.sqt → execute via IR + bytecode VM
```
Uygulama dili **C++**'tır (header-only eğilimli, bkz. `docs/fikirler.md` ADR-003).
Most compilers are black boxes. saQut is a **glass box.**
---
## Şu an ne çalışıyor, ne çalışmıyor
## What is it?
Belgeler **planlanan** ile **yapılan**ı net ayırır. Bugünkü gerçek durum:
saQut is a **procedural language compiler** written in C++.
The language is small and C-flavoured on purpose — it is a vehicle, not the product.
The product is **a compilation pipeline where every stage is named, queryable, and machine-readable.**
### ✅ Ç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`.
You can pipe `saqut ast` into your own tool.
You can hand the optimized AST diff to a review script.
A stranger with no access to source could write an LSP from `saqut symbols` output alone.
That is the test saQut is designed to pass.
---
## Dil kimliği (kilitli)
## The language looks like this
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).
```c
int fibonacci(int n) {
if (n <= 1) {
return n;
}
return fibonacci(n - 1) + fibonacci(n - 2);
}
| Özellik | Karar |
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));
print(fibonacciIterative(n));
return 0;
}
```
- No mandatory `class` / `main` boilerplate
- Typed functions, `struct`, `int[]` arrays
- `int`, `float`, `bool`, `string` literal types
- Value semantics — no user-visible pointers
- Single FFI seam (`callhost`) — the only door to the outside world
**Deliberately absent:** OOP, closures, generics, implicit int↔float coercion, `auto`.
---
## Build
**Requirements:** C++17, CMake ≥ 3.16, Ninja
```bash
git clone https://github.com/abdussamedulutas/saqut
cd saqut
cmake -B build -G Ninja
cmake --build build
```
Binary lands at `build/saqut`.
**Tested on:** Linux (x86-64, Manjaro). macOS and Windows untested but no platform-specific code.
---
## CLI
| Command | What you get |
|---|---|
| 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) |
| `saqut tokens file:src.sqt` | Token stream with positions |
| `saqut ast file:src.sqt` | Full AST as JSON |
| `saqut ast file:src.sqt --optimized` | AST after constant folding + dead-code elimination |
| `saqut symbols file:src.sqt` | Symbol table dump |
| `saqut check file:src.sqt` | Semantic analysis only — errors and warnings, JSON |
| `saqut ir file:src.sqt` | IR instruction dump |
| `saqut run file:src.sqt` | Compile and run via bytecode VM |
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.
Every output is designed to be piped, diffed, or consumed by other tools.
---
## Ç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.
---
## Tasarım felsefesi — neden saQut farklı?
saQut "daha iyi bir dil" iddiasında değil. Farkı, **derleyiciyi bir platform**
olarak ele almasında. İki taahhüt üstüne kuruludur:
**1. Cam (gör + sorgula + içine müdahale et).** Her aşama — token, AST, sembol
tablosu, tip, IR — kararlı, makine-okur ve **çift yönlü** bir arayüzden
erişilebilir olmalıdır. Sadece "dök ve göster" değil: kendi AST'ini verip tip
kontrolü isteyebilmeli, IR verip çalıştırabilmelisin. **Turnusol testi:** bir
yabancı, yalnızca `saqut ast` + `saqut symbols` çıktısından, bizden habersiz bir
LSP yazabiliyor mu? Cevap "evet" ise platform gerçektir.
**2. Kafes (deterministik + yetenek-güvenli çalıştırma).** Pointer yok, value
semantics, scope-tabanlı bellek ve **tek dış-dünya kapısı olan FFI seam**
(ADR-016) sayesinde saQut kodu, host'un açıkça izin verdiği fonksiyonlar dışında
dünyaya dokunamaz. Bytecode VM deterministiktir (ADR-015): aynı girdi → aynı
çıktı → aynı çalışma. "Sadelik" diye tasarlanan bu kararlar aslında bir
**yetenek-güvenliği (capability sandbox)** kurar — güvenilmeyen veya
AI-üretimi kodu güvenle çalıştırmak için biçilmiş kaftan.
**Bu ikisinin ödülü — kayıt & tekrar (record-replay).** 🚧 *(vizyon, v0 değil;
bkz. issue #94.)* Belirsizliğin tek kaynağı (kullanıcı girdisi, zaman, IO,
GC/thread kararları) FFI kapısından geçtiği için, mükemmel tekrar oynatma için
**her değişkeni her adımda kaydetmek gerekmez** — yalnızca kapıdan geçen değerler
kaydedilir, gerisi VM deterministik olarak yeniden çalıştırılarak üretilir. Boyut
gigabayttan kilobayta düşer. Replay modunda FFI çağrıları gerçekten çalışmaz,
kaydedilmiş değeri döndürür (dosyayı tekrar silmez, sunucuya tekrar istek atmaz).
Böylece "benim makinemde çalışıyor, müşteride patlıyor" sorunu: müşteri bir dump
yollar, sen çöküşü adım adım, aynı verilerle geri sararsın.
> Log, önceden sormayı akıl ettiğin sorulara cevap verir; **tekrar-oynatma,
> çöküşten *sonra* aklına gelen sorulara.** Zaman-yolculuğu hata ayıklama ayrı
> bir altyapı değildir — cam sorgularına bir **zaman koordinatı** eklemektir.
⚠️ Bu ödülün bedeli v0'da ödenir: **determinizm kutsaldır ve her belirsizlik
kaynağı kayıt-altına-alınabilir tek kapıdan geçmelidir.** Sonradan eklenemez;
baştan korunur.
---
## Mimari hatlar
## Pipeline
```
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 ┘
Source
│ Lexer + Tokenizer
Tokens ──────────────────── saqut tokens
│ Pratt parser + recursive descent
AST ─────────────────────── saqut ast
│ Symbol collector (two-pass)
Symbol Table ────────────── saqut symbols
│ Type checker + structural validator
Annotated AST
│ Optimization Manager (clone — original untouched)
│ ├─ Constant Folding pass
│ └─ Dead Code Elimination pass
Optimized AST ───────────── saqut ast --optimized
│ IR Generator
IR ──────────────────────── saqut ir
│ Bytecode VM (interpreter loop)
Output ──────────────────── 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.
The optimizer works on a **clone** of the AST — the original is preserved.
Constant folding and DCE run in a fixpoint loop until nothing changes.
---
## CLI (mevcut + planlanan)
## What works right now
```
# --- çalışıyor ---
saqut tokens file:kaynak.sqt # token listesi
saqut ast file:kaynak.sqt # AST (JSON)
saqut symbols file:kaynak.sqt # sembol tablosu (iskelet)
# --- 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)
```
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.
---
## Batteries / stdlib — kuzey yıldızı, ertelendi
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.**
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.
- **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).
---
## Belge haritası
| Belge | İçerik |
| Stage | Status |
|---|---|
| `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 |
| Lexer / Tokenizer | ✅ |
| Pratt parser | ✅ |
| AST + JSON serialization | ✅ |
| Symbol table (two-pass collector) | ✅ |
| Type checker | ✅ |
| Structural validator | ✅ |
| Constant folding (int, bool, logical, unary) | ✅ |
| Dead code elimination | ✅ |
| IR generator + bytecode VM | ✅ |
| `saqut run` executes fibonacci | ✅ |
| `string` type | ✅ |
| `struct` | 🚧 |
| `int[]` arrays | 🚧 |
| Standard library / FFI beyond `print` | 🚧 |
---
## İlke
## Philosophy in two sentences
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.
**Glass:** every compilation stage is a stable, queryable output — tokens, AST, symbols, IR — all separately inspectable and pipeable.
**Cage:** no user pointers, value semantics, single FFI door — the VM is deterministic, which makes record-replay and time-travel debugging a natural extension, not an afterthought.
The long version is in [`docs/architecture.md`](docs/architecture.md).
---
## Design records
Architectural decisions live in `docs/`:
| File | Coverage |
|---|---|
| [`docs/fikirler.md`](docs/fikirler.md) | ADR-001005: backend strategy, parser, header-only, token, IR |
| [`docs/adr-frontend-analiz.md`](docs/adr-frontend-analiz.md) | ADR-006019: analysis, optimization, execution model, FFI, memory |
| [`docs/roadmap-frontend.md`](docs/roadmap-frontend.md) | Phase-by-phase implementation plan |
| [`docs/architecture.md`](docs/architecture.md) | Full architecture reference (Turkish) |
---
## License
Source-available, commercial use restricted.
Free for: personal use, learning, writing and running saQut programs, internal tooling.
Requires permission for: hosting as a service, embedding sub-components commercially, redistributing as a product.
See [`LICENSE.md`](LICENSE.md) for the full terms.
Commercial licensing: saqutsoftware+gitea@gmail.com

View File

@ -7,8 +7,12 @@
#include "parser/parser.hpp"
#include "symbol/symbol_table.hpp"
#include "symbol/symbol_collector.hpp"
#include "semantic/type_checker.hpp"
#include "semantic/structural_validator.hpp"
#include "diagnostic/diagnostic_engine.hpp"
#include "ir/ir_generator.hpp"
#include "core/config.hpp"
#include "opt/optimization_manager.hpp"
inline int cmdIr(const CliArgs& args) {
std::string filePath = inputFilePath(args);
@ -29,6 +33,8 @@ inline int cmdIr(const CliArgs& args) {
SymbolTable symbolTable;
DiagnosticEngine diag;
SymbolCollector(symbolTable, diag).collect(ast);
TypeChecker(symbolTable, diag).check(ast);
StructuralValidator(diag).validate(ast);
if (diag.hasErrors()) {
diag.printAll(std::cerr);
@ -37,9 +43,18 @@ inline int cmdIr(const CliArgs& args) {
return 1;
}
// --optimized: constant folding + DCE yerinde uygulanır, klon yok.
// IR dump için tek versiyon yeterli — ast komutu gibi karşılaştırma yok.
if (args.optimized) {
CompilerConfig cfg;
DiagnosticEngine optDiag;
OptimizationManager(cfg, optDiag).runPassesInPlace(ast, &symbolTable);
if (optDiag.errorCount() + optDiag.warningCount() > 0)
optDiag.printAll(std::cerr); // W002 vb. uyarılar stderr'e
}
IRGenerator irGenerator;
IRProgram program = irGenerator.generate(ast, symbolTable);
program.dump();
delete ast;

View File

@ -2,12 +2,11 @@
// saQut CLI — run komutu
//
// Tam derleme + çalıştırma pipeline'ı:
// tokenize → parse → sembol topla → IR üret → VM çalıştır
// tokenize → parse → sembol topla → [opsiyonel: optimize] → IR üret → VM çalıştır
//
// Başarı kriteri:
// build/saqut run file:examples/fibonacci.sqt
// → 55
// → 55
// --optimized bayrağı: AST yerinde optimize edilir (klon yok — sadece tek versiyon
// gerekiyor). ast komutu orijinali saklaması gerektiği için klon kullanır; run/ir
// kullanmaz. Aynı pattern ir.hpp'de de var — paralel değişikliklerde ikisine bak.
// ============================================================================
#ifndef SAQUT_CLI_RUN
@ -22,6 +21,8 @@
#include "semantic/type_checker.hpp"
#include "semantic/structural_validator.hpp"
#include "diagnostic/diagnostic_engine.hpp"
#include "core/config.hpp"
#include "opt/optimization_manager.hpp"
#include "ir/ir_generator.hpp"
#include "vm/interpreter.hpp"
@ -43,7 +44,7 @@ inline int cmdRun(const CliArgs& args) {
return 1;
}
// ── Aşama 3: Sembol toplama ───────────────────────────────────────────
// ── Aşama 3: Sembol toplama + semantik analiz ─────────────────────────
// Identifier'ların resolvedSymbol'ü doldurulur — IR generator buna ihtiyaç duyar.
SymbolTable symbolTable;
DiagnosticEngine diag;
@ -59,11 +60,22 @@ inline int cmdRun(const CliArgs& args) {
return 1;
}
// ── Aşama 4: IR üretimi ───────────────────────────────────────────────
// ── Aşama 4 (opsiyonel): Optimizasyon ────────────────────────────────
// --optimized: constant folding + DCE yerinde uygulanır, klon yok.
// Tek versiyon (optimize edilmiş) yeterli — ast komutu gibi karşılaştırma yok.
if (args.optimized) {
CompilerConfig cfg;
DiagnosticEngine optDiag;
OptimizationManager(cfg, optDiag).runPassesInPlace(ast, &symbolTable);
if (optDiag.errorCount() + optDiag.warningCount() > 0)
optDiag.printAll(std::cerr); // W002 (derleme zamanı sıfıra bölme) vb.
}
// ── Aşama 5: IR üretimi ───────────────────────────────────────────────
IRGenerator irGenerator;
IRProgram program = irGenerator.generate(ast, symbolTable);
// ── Aşama 5: VM çalıştırma ────────────────────────────────────────────
// ── Aşama 6: VM çalıştırma ────────────────────────────────────────────
int exitCode = 0;
try {
Interpreter vm(program);

View File

@ -73,6 +73,7 @@ struct Type {
std::shared_ptr<Type> returnType; // kind == Function
std::vector<Type> paramTypes; // kind == Function
std::string structName; // kind == Struct
bool nullable = false; // ADR-021: Type? sözdizimi
// ------------------------------------------------------------------ //
// Factory'ler
@ -132,11 +133,26 @@ struct Type {
prim == PrimitiveKind::Double);
}
bool isString() const {
return kind == TypeKind::Primitive && prim == PrimitiveKind::String;
}
// ADR-021: "null" literal tipi — yalnızca nullable değişkene atanabilir
bool isNullLiteral() const {
return kind == TypeKind::Primitive && prim == PrimitiveKind::Void && nullable;
}
// Nullable kopyası döndür
Type asNullable() const { Type t = *this; t.nullable = true; return t; }
Type asNonNull() const { Type t = *this; t.nullable = false; return t; }
// ------------------------------------------------------------------ //
// equals — Yapısal eşitlik (katı; gizli dönüşüm yok, ADR-010)
// ------------------------------------------------------------------ //
// Yapısal eşitlik — nullable dahil (ADR-021: int ≠ int?)
bool equals(const Type& o) const {
if (kind != o.kind) return false;
if (nullable != o.nullable) return false;
switch (kind) {
case TypeKind::Primitive:
return prim == o.prim;
@ -154,13 +170,14 @@ struct Type {
return true;
}
case TypeKind::Error:
// Error == Error: ardışık sahte hataların bastırılması tip
// denetleyicinin sorumluluğundadır (operandı Error ise hata üretme).
return true;
}
return false; // erişilemez (tüm enum değerleri kapsandı)
return false;
}
// Temel yapısal eşitlik — nullable farkını yok say (T == T? üstün çakışma için)
bool equalsBase(const Type& o) const { return asNonNull().equals(o.asNonNull()); }
// ------------------------------------------------------------------ //
// İsim yardımcıları
// ------------------------------------------------------------------ //
@ -177,10 +194,15 @@ struct Type {
return "?";
}
// Bir tip adından (parser tipleri string olarak tutar) primitif Type üretir.
// Bilinen primitif değilse Error döner — bilinmeyen tip adının teşhisi
// (E007) çağıranın (Faz 2/3) işidir; bu fonksiyon sessizce Error verir.
// Bir tip adından (parser tipleri string olarak tutar) Type üretir.
// "int?" → nullable int; "int[]" → int array; bilinen değilse Error.
static Type fromName(const std::string& n) {
// Nullable soneki: "int?", "string?" vb. (ADR-021)
if (!n.empty() && n.back() == '?') {
Type base = fromName(n.substr(0, n.size() - 1));
if (!base.isError()) return base.asNullable();
return error();
}
if (n == "int") return Int();
if (n == "float") return Float();
if (n == "double") return Double();
@ -188,6 +210,11 @@ struct Type {
if (n == "string") return String();
if (n == "bool") return Bool();
if (n == "void") return Void();
// "int[]", "float[]" vb. — suffix [] ile dizi tipi
if (n.size() > 2 && n.substr(n.size() - 2) == "[]") {
Type elem = fromName(n.substr(0, n.size() - 2));
if (!elem.isError()) return array(elem);
}
return error();
}
@ -195,27 +222,28 @@ struct Type {
// toString — İnsan-okur ("int", "int[]", "fn(int,int)->int")
// ------------------------------------------------------------------ //
std::string toString() const {
std::string base;
switch (kind) {
case TypeKind::Primitive:
return primName(prim);
base = primName(prim); break;
case TypeKind::Array:
return (elementType ? elementType->toString() : "<?>") + "[]";
base = (elementType ? elementType->toString() : "<?>") + "[]"; break;
case TypeKind::Struct:
return "struct " + structName;
base = "struct " + structName; break;
case TypeKind::Function: {
std::string s = "fn(";
base = "fn(";
for (size_t i = 0; i < paramTypes.size(); ++i) {
if (i) s += ",";
s += paramTypes[i].toString();
if (i) base += ",";
base += paramTypes[i].toString();
}
s += ")->";
s += returnType ? returnType->toString() : "<?>";
return s;
base += ")->";
base += returnType ? returnType->toString() : "<?>";
break;
}
case TypeKind::Error:
return "<error>";
}
return "<?>";
return nullable ? base + "?" : base;
}
// ------------------------------------------------------------------ //

View File

@ -20,6 +20,7 @@
// LESS/LEQ/... : dest, left, right (sonuç: 1=doğru, 0=yanlış)
// JMP : jumpTarget
// JIF_FALSE : cond, jumpTarget
// JIF_TRUE : cond, jumpTarget
// CALL : dest, functionName, argSlots
// RETURN : src
// CALLHOST : functionName, argSlots
@ -41,6 +42,7 @@ enum class Opcode {
// Örnek: LOAD_CONST dest=3 val=10 → slot[3] = 10
LOAD_STRING, // slots[dest] = stringValue (metin sabitini slota yükle)
LOAD_NULL, // slots[dest] = null (ADR-021: ValueKind::Null)
// Örnek: LOAD_STRING dest=2 val="Merhaba" → slot[2] = "Merhaba"
LOAD_SLOT, // slots[dest] = slots[src]
@ -54,6 +56,13 @@ enum class Opcode {
DIV, // UYARI: sıfıra bölme → runtime_error fırlatılır
MOD,
// --- Bitsel (tümü: slots[dest] = slots[left] OP slots[right]) ---
BAND, // slots[left] & slots[right]
BOR, // slots[left] | slots[right]
SHL, // slots[left] << slots[right]
SHR, // slots[left] >> slots[right]
BNOT, // ~slots[src] → slots[dest] (tekli operatör; src kullanır, left/right değil)
// --- Karşılaştırma (sonuç: 1 = doğru, 0 = yanlış) ---
LESS, // slots[left] < slots[right]
LESS_EQUAL, // slots[left] <= slots[right]
@ -64,7 +73,8 @@ enum class Opcode {
// --- Kontrol akışı ---
JMP, // Koşulsuz atlama: ip = jumpTarget
JIF_FALSE, // Koşullu atlama: slots[cond] == 0 ise ip = jumpTarget
JIF_FALSE, // Koşullu atlama: slots[cond] falsy ise ip = jumpTarget
JIF_TRUE, // Koşullu atlama: slots[cond] truthy ise ip = jumpTarget
// --- Fonksiyon çağrısı ---
CALL, // Başka bir saQut fonksiyonunu çağır.
@ -73,6 +83,47 @@ enum class Opcode {
RETURN, // Bu frame'i kapat, slots[src]'yi caller'a ilet.
// --- Float aritmetik (#44) ---
LOAD_FLOAT, // slots[dest] = floatValue (double sabit yükle)
FADD, // slots[dest] = slots[left] + slots[right] (float)
FSUB, // slots[dest] = slots[left] - slots[right] (float)
FMUL, // slots[dest] = slots[left] * slots[right] (float)
FDIV, // slots[dest] = slots[left] / slots[right] (float; sıfır → runtime_error)
FNEG, // slots[dest] = -slots[src] (float tekli eksi)
INT_TO_FLOAT, // slots[dest] = (double)slots[src] — gizli int→float çevrimi (literal atamasında)
FLOAT_TO_INT, // slots[dest] = (int)slots[src] — açık cast (ileride: int(x))
// --- Struct (ADR-020: referans semantiği) ---
STRUCT_NEW, // slots[dest] = yeni StructObject(intValue alan sayısı); functionName = struct tipi adı
FIELD_GET, // slots[dest] = slots[src].fields[intValue] (src=nesne, intValue=alan indeksi)
FIELD_SET, // slots[dest].fields[intValue] = slots[right] (dest=nesne, intValue=alan indeksi, right=değer)
// --- Array (ADR-020: referans semantiği) ---
ARRAY_NEW, // slots[dest] = yeni ArrayObject(intValue eleman kapasitesi)
ARRAY_GET, // slots[dest] = slots[left][slots[right]] — sınır kontrolü
ARRAY_SET, // slots[dest][slots[left]] = slots[right] — sınır kontrolü (dest=dizi, left=idx, right=değer)
ARRAY_LEN, // slots[dest] = slots[src].uzunluk()
// --- Modül-düzeyi değişken erişimi ---
// "Global" değil: her değişken kendi dosyasına (modülüne) aittir.
// Başka modüller bu alana doğrudan erişemez; yalnızca export/import ile ulaşabilir.
// TODO(#modül-scope): IRFunction.moduleId eklenerek çok-modüllü derlemede
// her fonksiyonun kendi modülünün slot alanına bakması sağlanacak (bkz. TODO.md).
LOAD_GLOBAL, // slots[dest] = moduleSlots[intValue] (bu modülün modül-düzeyi değişkeni)
STORE_GLOBAL, // moduleSlots[intValue] = slots[src]
// --- String işlemleri (ADR-024: immutable değer-tipi, içerik ==) ---
STRING_CONCAT, // slots[dest] = slots[left] + slots[right] (yeni string üretir)
// --- Hata yönetimi (ADR-025: UNCHECKED try/catch/throw) ---
ENTER_TRY, // try bloğuna giriş: TryFrame'i yığına it
// dest = catch bloğundaki Error değerinin yazılacağı slot
// jumpTarget = catch bloğunun IR konumu (-1 → backpatch)
// callDepth = VM, callStack.size()'ı kayıt altına alır (unwind için)
LEAVE_TRY, // try bloğundan normal çıkış: TryFrame'i çıkar (istisna olmadı)
THROW, // slots[src] değerini fırlat → en yakın ENTER_TRY'a unwind
// Yakalanmamışsa C++ exception olarak yükseltilir
// --- Dış dünya (FFI — Foreign Function Interface) ---
CALLHOST, // Host (C++) fonksiyonunu çağır. Şu an sadece "print" destekli.
// Dönüş değeri yok; sadece yan etki (stdout'a yazmak gibi).
@ -83,12 +134,35 @@ inline const char* opcodeName(Opcode op) {
switch (op) {
case Opcode::LOAD_CONST: return "LOAD_CONST";
case Opcode::LOAD_STRING: return "LOAD_STRING";
case Opcode::LOAD_NULL: return "LOAD_NULL";
case Opcode::LOAD_SLOT: return "LOAD_SLOT";
case Opcode::ADD: return "ADD";
case Opcode::SUB: return "SUB";
case Opcode::MUL: return "MUL";
case Opcode::DIV: return "DIV";
case Opcode::MOD: return "MOD";
case Opcode::BAND: return "BAND";
case Opcode::BOR: return "BOR";
case Opcode::SHL: return "SHL";
case Opcode::SHR: return "SHR";
case Opcode::BNOT: return "BNOT";
case Opcode::LOAD_FLOAT: return "LOAD_FLOAT";
case Opcode::FADD: return "FADD";
case Opcode::FSUB: return "FSUB";
case Opcode::FMUL: return "FMUL";
case Opcode::FDIV: return "FDIV";
case Opcode::FNEG: return "FNEG";
case Opcode::INT_TO_FLOAT: return "INT_TO_FLOAT";
case Opcode::FLOAT_TO_INT: return "FLOAT_TO_INT";
case Opcode::STRUCT_NEW: return "STRUCT_NEW";
case Opcode::FIELD_GET: return "FIELD_GET";
case Opcode::FIELD_SET: return "FIELD_SET";
case Opcode::ARRAY_NEW: return "ARRAY_NEW";
case Opcode::ARRAY_GET: return "ARRAY_GET";
case Opcode::ARRAY_SET: return "ARRAY_SET";
case Opcode::ARRAY_LEN: return "ARRAY_LEN";
case Opcode::LOAD_GLOBAL: return "LOAD_GLOBAL";
case Opcode::STORE_GLOBAL: return "STORE_GLOBAL";
case Opcode::LESS: return "LESS";
case Opcode::LESS_EQUAL: return "LESS_EQUAL";
case Opcode::GREATER: return "GREATER";
@ -97,8 +171,13 @@ inline const char* opcodeName(Opcode op) {
case Opcode::NOT_EQUAL: return "NOT_EQUAL";
case Opcode::JMP: return "JMP";
case Opcode::JIF_FALSE: return "JIF_FALSE";
case Opcode::JIF_TRUE: return "JIF_TRUE";
case Opcode::CALL: return "CALL";
case Opcode::RETURN: return "RETURN";
case Opcode::STRING_CONCAT: return "STRING_CONCAT";
case Opcode::ENTER_TRY: return "ENTER_TRY";
case Opcode::LEAVE_TRY: return "LEAVE_TRY";
case Opcode::THROW: return "THROW";
case Opcode::CALLHOST: return "CALLHOST";
}
return "UNKNOWN";
@ -128,6 +207,9 @@ struct Instruction {
// LOAD_CONST için yüklenecek tam sayı sabiti
int intValue = 0;
// LOAD_FLOAT için yüklenecek double sabiti (#44)
double floatValue = 0.0;
// LOAD_STRING için yüklenecek metin sabiti (tırnak işaretleri olmadan)
std::string stringValue;

View File

@ -20,7 +20,15 @@ static const char* opSymbol(Opcode op) {
case Opcode::SUB: return "-";
case Opcode::MUL: return "*";
case Opcode::DIV: return "/";
case Opcode::FADD: return "+.";
case Opcode::FSUB: return "-.";
case Opcode::FMUL: return "*.";
case Opcode::FDIV: return "/.";
case Opcode::MOD: return "%";
case Opcode::BAND: return "&";
case Opcode::BOR: return "|";
case Opcode::SHL: return "<<";
case Opcode::SHR: return ">>";
case Opcode::LESS: return "<";
case Opcode::LESS_EQUAL: return "<=";
case Opcode::GREATER: return ">";
@ -35,6 +43,8 @@ static bool isBinaryOp(Opcode op) {
switch (op) {
case Opcode::ADD: case Opcode::SUB: case Opcode::MUL:
case Opcode::DIV: case Opcode::MOD:
case Opcode::FADD: case Opcode::FSUB: case Opcode::FMUL: case Opcode::FDIV:
case Opcode::BAND: case Opcode::BOR: case Opcode::SHL: case Opcode::SHR:
case Opcode::LESS: case Opcode::LESS_EQUAL:
case Opcode::GREATER: case Opcode::GREATER_EQUAL:
case Opcode::EQUAL_EQUAL: case Opcode::NOT_EQUAL:
@ -113,6 +123,48 @@ void IRFunction::dump() const {
}
std::cout << ")";
} else if (ins.opcode == Opcode::BNOT) {
std::cout << slot(ins.dest) << " = ~" << slot(ins.src);
} else if (ins.opcode == Opcode::LOAD_FLOAT) {
std::cout << slot(ins.dest) << " = " << ins.floatValue;
} else if (ins.opcode == Opcode::INT_TO_FLOAT) {
std::cout << slot(ins.dest) << " = (float)" << slot(ins.src);
} else if (ins.opcode == Opcode::FLOAT_TO_INT) {
std::cout << slot(ins.dest) << " = (int)" << slot(ins.src);
} else if (ins.opcode == Opcode::FNEG) {
std::cout << slot(ins.dest) << " = -" << slot(ins.src);
} else if (ins.opcode == Opcode::STRUCT_NEW) {
std::cout << slot(ins.dest) << " = struct<" << ins.functionName << ">[" << ins.intValue << " alan]";
} else if (ins.opcode == Opcode::FIELD_GET) {
std::cout << slot(ins.dest) << " = " << slot(ins.src) << "." << ins.intValue;
} else if (ins.opcode == Opcode::FIELD_SET) {
std::cout << slot(ins.dest) << "." << ins.intValue << " = " << slot(ins.right);
} else if (ins.opcode == Opcode::ARRAY_NEW) {
std::cout << slot(ins.dest) << " = array[" << ins.intValue << "]";
} else if (ins.opcode == Opcode::ARRAY_GET) {
std::cout << slot(ins.dest) << " = " << slot(ins.left) << "[" << slot(ins.right) << "]";
} else if (ins.opcode == Opcode::ARRAY_SET) {
std::cout << slot(ins.dest) << "[" << slot(ins.left) << "] = " << slot(ins.right);
} else if (ins.opcode == Opcode::ARRAY_LEN) {
std::cout << slot(ins.dest) << " = len(" << slot(ins.src) << ")";
} else if (ins.opcode == Opcode::LOAD_GLOBAL) {
std::cout << slot(ins.dest) << " = global[" << ins.intValue << "]";
} else if (ins.opcode == Opcode::STORE_GLOBAL) {
std::cout << "global[" << ins.intValue << "] = " << slot(ins.src);
} else if (ins.opcode == Opcode::RETURN) {
std::cout << slot(ins.src);
}

View File

@ -10,32 +10,55 @@
#include <stdexcept>
#include <string>
// Error struct alan sırası (ADR-025): makeError için IR tarafından bilinir
// 0=line, 1=col, 2=message, 3=trace, 4=code
static constexpr int ERROR_FIELD_COUNT = 5;
// ─────────────────────────────────────────────────────────────────────────────
// generate — Ana giriş noktası
// ─────────────────────────────────────────────────────────────────────────────
IRProgram IRGenerator::generate(ASTNode* programNode, SymbolTable& /*symbolTable*/) {
IRProgram IRGenerator::generate(ASTNode* programNode, SymbolTable& symbolTable) {
IRProgram program;
// ProgramNode'un her çocuğunu gez.
// Bizi ilgilendiren: FunctionDecl. StructDecl/GlobalVar → TODO.
// 0. Geçiş: struct layout haritasını sembol tablosundan al
structLayouts_ = symbolTable.structLayouts;
// 1. Geçiş: modül-düzeyi VariableDecl'leri topla ve kayıt et
// "Global" değil — bu dosyanın (modülün) kendi değişkenleri.
std::vector<VariableDeclNode*> globalVars;
for (ASTNode* child : programNode->getChildren()) {
if (child->kind == ASTKind::VariableDecl) {
auto* vd = (VariableDeclNode*)child;
nameToGlobal_[vd->name] = globalCount_++;
program.globalCount++;
program.globalNames.push_back(vd->name);
globalVars.push_back(vd);
}
}
// 2. Geçiş: fonksiyonları üret
for (ASTNode* child : programNode->getChildren()) {
if (child->kind == ASTKind::FunctionDecl) {
// Her fonksiyon üretimi için sıfırla
nameToSlot_.clear();
nextSlot_ = 0;
// IRFunction oluştur, currentFunction_ olarak işaretle
auto* fnDecl = (FunctionDeclNode*)child;
IRFunction irFn(fnDecl->name, (int)fnDecl->params.size());
program.addFunction(std::move(irFn));
// addFunction std::move yaptığı için pointer'ı haritadan alalım
currentFunction_ = program.findFunction(fnDecl->name);
generateFunction(child);
// main'in başında global değişkenlerin init ifadelerini üret
if (fnDecl->name == "main") {
for (VariableDeclNode* gv : globalVars) {
if (gv->initExpr) {
int initSlot = generateExpression(gv->initExpr);
emitStoreGlobal(initSlot, nameToGlobal_[gv->name]);
}
}
}
// Fonksiyon bitti — toplam slot sayısını kaydet
generateFunction(child);
currentFunction_->slotCount = nextSlot_;
}
}
@ -81,7 +104,7 @@ void IRGenerator::generateStatement(ASTNode* node) {
break;
}
// ── Değişken bildirimi: int x = <ifade> ──────────────────────────────
// ── Değişken bildirimi: int x = <ifade> / Point p; ────────────────
case ASTKind::VariableDecl: {
auto* vd = (VariableDeclNode*)node;
@ -90,14 +113,22 @@ void IRGenerator::generateStatement(ASTNode* node) {
registerVariable(vd->name, varSlot);
if (vd->initExpr) {
// Başlatma ifadesini üret, sonucu bir slotta al
int initSlot = generateExpression(vd->initExpr);
if (initSlot != varSlot) {
// Sonuç başka bir slotta, değişkenin slotuna kopyala
emitLoadSlot(varSlot, initSlot);
// float/double değişkenine int sabit atama → INT_TO_FLOAT
bool targetIsFloat = (vd->varType == "float" || vd->varType == "double");
bool srcIsInt = false;
if (auto* e = dynamic_cast<ExpressionNode*>(vd->initExpr))
srcIsInt = e->resolvedType.isPrimitive() && e->resolvedType.prim == PrimitiveKind::Int;
if (targetIsFloat && srcIsInt) {
int conv = freshSlot();
emitIntToFloat(conv, initSlot);
initSlot = conv;
}
// initSlot == varSlot: LOAD_CONST doğrudan varSlot'a yazıldı, kopya gerekmez
if (initSlot != varSlot) emitLoadSlot(varSlot, initSlot);
} else if (structLayouts_.count(vd->varType)) {
// Struct değişkeni: init ifadesi yoksa boş StructObject oluştur
int fc = getStructFieldCount(vd->varType);
emitStructNew(varSlot, vd->varType, fc);
}
// Sibling VariableDecl'ler: int a, b; → children'da diğer VariableDecl'ler
@ -153,84 +184,101 @@ void IRGenerator::generateStatement(ASTNode* node) {
case ASTKind::WhileStatement: {
auto* ws = (WhileStatementNode*)node;
// Döngü başının konumu — geri-jump buraya gelecek
int loopStart = currentInstrIndex();
loopContextStack_.push_back({});
int condSlot = generateExpression(ws->condition);
int exitJump = emitJumpIfFalse(condSlot); // ileri, backpatch bekliyor
int condSlot = generateExpression(ws->condition);
int exitJump = emitJumpIfFalse(condSlot);
if (ws->body) generateStatement(ws->body);
// Geri-jump: hedef zaten biliniyor (loopStart)
emitJumpUnconditional(loopStart);
// continue → LOOP_START (hedef baştan beri biliniyor)
for (int idx : loopContextStack_.back().continueJumps)
currentFunction_->instructions[idx].jumpTarget = loopStart;
// Döngü çıkış noktası → exitJump'ı doldur
patchJump(exitJump);
emitJumpUnconditional(loopStart);
patchJump(exitJump); // OUT burası
// break → OUT
int outTarget = currentInstrIndex();
for (int idx : loopContextStack_.back().breakJumps)
currentFunction_->instructions[idx].jumpTarget = outTarget;
loopContextStack_.pop_back();
break;
}
// ── for (init; koşul; güncelleme) { gövde } ─────────────────────────
//
// Üretilen IR yapısı:
// IR yapısı (continue C_LABEL'a, break OUT'a atlar):
// [init]
// LOOP_START:
// [koşul] → condSlot
// JIF_FALSE condSlot → LOOP_END (ileri-jump, backpatch)
// [koşul] → JIF_FALSE OUT
// [gövde]
// C_LABEL:
// [güncelleme]
// JMP LOOP_START (geri-jump, hedef biliniyor)
// LOOP_END:
// JMP LOOP_START
// OUT:
// ─────────────────────────────────────────────────────────────────────
case ASTKind::ForStatement: {
auto* fs = (ForStatementNode*)node;
// Init: genellikle "int i = 0" gibi bir VariableDecl
if (fs->init) generateStatement(fs->init);
// Döngü başı konumu — geri-jump'ın hedefi
int loopStart = currentInstrIndex();
loopContextStack_.push_back({});
// Koşul
int condSlot = fs->condition ? generateExpression(fs->condition) : -1;
int exitJump = (condSlot != -1) ? emitJumpIfFalse(condSlot) : -1;
// Gövde
if (fs->body) generateStatement(fs->body);
// Güncelleme (ör: i = i + 1) — ifade deyimi, sonuç önemsiz
// C_LABEL: güncelleme başlangıcı — continue buraya atlar
int cLabel = currentInstrIndex();
for (int idx : loopContextStack_.back().continueJumps)
currentFunction_->instructions[idx].jumpTarget = cLabel;
if (fs->update) generateExpression(fs->update);
// Geri-jump: hedef loopStart, zaten biliniyor
emitJumpUnconditional(loopStart);
// Döngü çıkışı → exitJump'ı doldur
if (exitJump != -1) patchJump(exitJump);
if (exitJump != -1) patchJump(exitJump); // OUT burası
// break → OUT
int outTarget = currentInstrIndex();
for (int idx : loopContextStack_.back().breakJumps)
currentFunction_->instructions[idx].jumpTarget = outTarget;
loopContextStack_.pop_back();
break;
}
// ── do { gövde } while (koşul) ───────────────────────────────────────
case ASTKind::DoWhileStatement: {
auto* dw = (DoWhileStatementNode*)node;
int loopStart = currentInstrIndex();
loopContextStack_.push_back({});
if (dw->body) generateStatement(dw->body);
// COND_LABEL: koşul değerlendirmesi — continue buraya atlar
int condLabel = currentInstrIndex();
for (int idx : loopContextStack_.back().continueJumps)
currentFunction_->instructions[idx].jumpTarget = condLabel;
int condSlot = generateExpression(dw->condition);
// Koşul doğruysa geri atla (1 = doğru → atla; 0 = yanlış → devam)
// JIF_FALSE koşul yanlışsa atlar; biz doğruysa atlamak istiyoruz.
// Bu yüzden JIF_FALSE yerine "doğruysa atla" mantığı lazım.
// Basit çözüm: koşulun tersini al (0→1, diğer→0) ve JIF_FALSE kullan.
// NOT: saQut'ta "!" operatörü yok henüz; NOT talimatı eklenebilir.
// Şimdilik: koşul slotuna bak, sıfır değilse geri atla.
// TODO(vm-genişletme): JIF_TRUE talimatı ekle
// Geçici çözüm: sabit 1 ile karşılaştır (condSlot != 0 → geri)
int oneSlot = freshSlot();
emitLoadConst(oneSlot, 1);
int eqSlot = freshSlot();
emitBinaryOp(Opcode::EQUAL_EQUAL, eqSlot, condSlot, oneSlot);
int skipJump = emitJumpIfFalse(eqSlot); // koşul yanlışsa döngüden çık
emitJumpUnconditional(loopStart); // geri atla
patchJump(skipJump);
Instruction jit(Opcode::JIF_TRUE);
jit.cond = condSlot;
jit.jumpTarget = loopStart;
currentFunction_->instructions.push_back(std::move(jit));
// break → OUT (JIF_TRUE'dan sonraki konum)
int outTarget = currentInstrIndex();
for (int idx : loopContextStack_.back().breakJumps)
currentFunction_->instructions[idx].jumpTarget = outTarget;
loopContextStack_.pop_back();
break;
}
@ -244,10 +292,66 @@ void IRGenerator::generateStatement(ASTNode* node) {
break;
}
case ASTKind::BreakStatement:
case ASTKind::ContinueStatement:
// TODO(vm-genişletme): break/continue için JMP + label mekanizması gerekir
case ASTKind::BreakStatement: {
int jumpIdx = emitJumpUnconditional(-1);
if (!loopContextStack_.empty())
loopContextStack_.back().breakJumps.push_back(jumpIdx);
break;
}
case ASTKind::ContinueStatement: {
int jumpIdx = emitJumpUnconditional(-1);
if (!loopContextStack_.empty())
loopContextStack_.back().continueJumps.push_back(jumpIdx);
break;
}
// ── try { body } catch (Error e) { handler } (ADR-025) ────────────
case ASTKind::TryStatement: {
auto* ts = (TryStatementNode*)node;
// Catch değişkeni için slot; VM bu slota Error nesnesini yazar
int errorSlot = freshSlot();
if (!ts->catchVar.empty())
registerVariable(ts->catchVar, errorSlot);
// ENTER_TRY: catch hedefi henüz bilinmiyor (-1), sonradan patchlanır
Instruction enterTry(Opcode::ENTER_TRY);
enterTry.dest = errorSlot;
enterTry.jumpTarget = -1;
currentFunction_->instructions.push_back(std::move(enterTry));
int enterTryIdx = (int)currentFunction_->instructions.size() - 1;
// Try gövdesi
if (ts->body) generateStatement(ts->body);
// Normal çıkış: try frame'ini çıkar
Instruction leaveTry(Opcode::LEAVE_TRY);
currentFunction_->instructions.push_back(std::move(leaveTry));
// Catch bloğunu atla (normal akışta)
int jumpOverCatch = emitJumpUnconditional(-1);
// Catch etiketi: ENTER_TRY buraya atlayacak
int catchLabel = currentInstrIndex();
currentFunction_->instructions[enterTryIdx].jumpTarget = catchLabel;
// Catch gövdesi
if (ts->handler) generateStatement(ts->handler);
// Catch bitti
patchJump(jumpOverCatch);
break;
}
// ── throw <ifade>; (ADR-025) ────────────────────────────────────────
case ASTKind::ThrowStatement: {
auto* th = (ThrowStatementNode*)node;
int valSlot = th->value ? generateExpression(th->value) : freshSlot();
Instruction ins(Opcode::THROW);
ins.src = valSlot;
currentFunction_->instructions.push_back(std::move(ins));
break;
}
default:
break;
@ -270,14 +374,29 @@ int IRGenerator::generateExpression(ASTNode* node) {
switch (lit->literalType) {
case LiteralType::INTEGER: {
int value = 0;
if (lit->parserToken.token)
value = std::stoi(lit->parserToken.token->token);
emitLoadConst(slot, value);
// Float/double bağlamında tam sayı literali → LOAD_FLOAT (bağlama-göre tip, ADR-010)
bool asFloat = lit->resolvedType.isPrimitive() &&
(lit->resolvedType.prim == PrimitiveKind::Float ||
lit->resolvedType.prim == PrimitiveKind::Double);
if (asFloat) {
double val = 0.0;
if (lit->hasDirectValue) val = (double)lit->directIntValue;
else if (lit->parserToken.token) val = std::stod(lit->parserToken.token->token);
emitLoadFloat(slot, val);
} else {
int value = 0;
if (lit->hasDirectValue) value = lit->directIntValue;
else if (lit->parserToken.token) value = std::stoi(lit->parserToken.token->token);
emitLoadConst(slot, value);
}
break;
}
case LiteralType::BOOLEAN: {
int value = (lit->parserToken.token &&
int value = 0;
if (lit->hasDirectValue)
value = lit->directIntValue ? 1 : 0;
else
value = (lit->parserToken.token &&
lit->parserToken.token->token == "true") ? 1 : 0;
emitLoadConst(slot, value);
break;
@ -301,25 +420,32 @@ int IRGenerator::generateExpression(ASTNode* node) {
currentFunction_->instructions.push_back(std::move(ins));
break;
}
case LiteralType::FLOAT:
throw std::runtime_error(
"IR üretim hatası: float literal şu an VM tarafından desteklenmiyor. "
"Tam sayı kullanın veya float desteği eklenene kadar bekleyin.");
case LiteralType::FLOAT: {
double val = 0.0;
if (lit->parserToken.token)
val = std::stod(lit->parserToken.token->token);
emitLoadFloat(slot, val);
break;
}
case LiteralType::BOŞ:
throw std::runtime_error(
"IR üretim hatası: null literal şu an VM tarafından desteklenmiyor.");
// null literal → ValueKind::Null (ADR-021)
{ Instruction ins(Opcode::LOAD_NULL); ins.dest = slot;
currentFunction_->instructions.push_back(std::move(ins)); }
break;
}
return slot;
}
// ── Değişken ismi: n, first, second ... ──────────────────────────────
// Bu değişkenin değeri zaten bir slotta. O slotu döndür.
case ASTKind::Identifier: {
auto* id = (IdentifierNode*)node;
std::string name = id->parserToken.token ? id->parserToken.token->token : "";
// Önce builtin mi? (print gibi) — identifier olarak gelen builtin fonksiyon
// çağrıları CallExpression içinde yakalanıyor, burada sadece değişken kalır
if (isGlobal(name)) {
int tempSlot = freshSlot();
emitLoadGlobal(tempSlot, getGlobalIndex(name));
return tempSlot;
}
return lookupVariable(name);
}
@ -327,42 +453,87 @@ int IRGenerator::generateExpression(ASTNode* node) {
case ASTKind::BinaryExpression: {
auto* bin = (BinaryExpressionNode*)node;
// Atama operatörleri: x = expr, x += expr ...
// Sol taraf bir değişken, sağ taraf hesaplanır ve o değişkene yazılır.
// Atama operatörleri: x = expr ve a[i] = expr
if (bin->Operator == TokenType::EQUAL) {
// Sağ tarafı hesapla
int rhsSlot = generateExpression(bin->Right);
// Sol taraf değişkenin slotunu bul
// a[i] = val → ARRAY_SET
if (bin->Left && bin->Left->kind == ASTKind::IndexExpression) {
auto* idx = (IndexExpressionNode*)bin->Left;
int arrSlot = generateExpression(idx->object);
int idxSlot = generateExpression(idx->index);
emitArraySet(arrSlot, idxSlot, rhsSlot);
return rhsSlot;
}
// p.field = val → FIELD_SET
if (bin->Left && bin->Left->kind == ASTKind::MemberAccess) {
auto* ma = (MemberAccessNode*)bin->Left;
int objSlot = generateExpression(ma->object);
std::string structName;
if (auto* exprObj = dynamic_cast<ExpressionNode*>(ma->object))
structName = exprObj->resolvedType.structName;
int idx2 = getStructFieldIndex(structName, ma->member);
if (idx2 >= 0) emitFieldSet(objSlot, idx2, rhsSlot);
return rhsSlot;
}
auto* lhsId = (IdentifierNode*)bin->Left;
std::string varName = lhsId->parserToken.token->token;
int varSlot = lookupVariable(varName);
// Sonucu değişkenin slotuna kopyala
if (rhsSlot != varSlot) {
emitLoadSlot(varSlot, rhsSlot);
if (isGlobal(varName)) {
emitStoreGlobal(rhsSlot, getGlobalIndex(varName));
return rhsSlot;
}
int varSlot = lookupVariable(varName);
if (rhsSlot != varSlot) emitLoadSlot(varSlot, rhsSlot);
return varSlot;
}
// Birleşik atama: += -= *= /=
// x += y ≡ x = x + y
if (bin->Operator == TokenType::PLUS_EQUAL ||
bin->Operator == TokenType::MINUS_EQUAL ||
bin->Operator == TokenType::STAR_EQUAL ||
bin->Operator == TokenType::SLASH_EQUAL) {
// Birleşik atama: += -= *= /= %= &= |= <<= >>=
// x OP= y ≡ x = x OP y
if (bin->Operator == TokenType::PLUS_EQUAL ||
bin->Operator == TokenType::MINUS_EQUAL ||
bin->Operator == TokenType::STAR_EQUAL ||
bin->Operator == TokenType::SLASH_EQUAL ||
bin->Operator == TokenType::PERCENT_EQUAL ||
bin->Operator == TokenType::AMPERSAND_EQUAL ||
bin->Operator == TokenType::PIPE_EQUAL ||
bin->Operator == TokenType::LSHIFT_EQUAL ||
bin->Operator == TokenType::RSHIFT_EQUAL) {
auto* lhsId = (IdentifierNode*)bin->Left;
std::string varName = lhsId->parserToken.token->token;
int varSlot = lookupVariable(varName);
int rhsSlot = generateExpression(bin->Right);
Opcode arithOp = Opcode::ADD;
if (bin->Operator == TokenType::MINUS_EQUAL) arithOp = Opcode::SUB;
else if (bin->Operator == TokenType::STAR_EQUAL) arithOp = Opcode::MUL;
else if (bin->Operator == TokenType::SLASH_EQUAL) arithOp = Opcode::DIV;
if (bin->Operator == TokenType::MINUS_EQUAL) arithOp = Opcode::SUB;
else if (bin->Operator == TokenType::STAR_EQUAL) arithOp = Opcode::MUL;
else if (bin->Operator == TokenType::SLASH_EQUAL) arithOp = Opcode::DIV;
else if (bin->Operator == TokenType::PERCENT_EQUAL) arithOp = Opcode::MOD;
else if (bin->Operator == TokenType::AMPERSAND_EQUAL) arithOp = Opcode::BAND;
else if (bin->Operator == TokenType::PIPE_EQUAL) arithOp = Opcode::BOR;
else if (bin->Operator == TokenType::LSHIFT_EQUAL) arithOp = Opcode::SHL;
else if (bin->Operator == TokenType::RSHIFT_EQUAL) arithOp = Opcode::SHR;
// string += string → STRING_CONCAT (ADR-024)
if (bin->Operator == TokenType::PLUS_EQUAL) {
if (auto* e = dynamic_cast<ExpressionNode*>(bin->Right))
if (e->resolvedType.isString()) arithOp = Opcode::STRING_CONCAT;
}
int resultSlot = freshSlot();
if (isGlobal(varName)) {
int currentSlot = freshSlot();
emitLoadGlobal(currentSlot, getGlobalIndex(varName));
emitBinaryOp(arithOp, resultSlot, currentSlot, rhsSlot);
emitStoreGlobal(resultSlot, getGlobalIndex(varName));
return resultSlot;
}
int varSlot = lookupVariable(varName);
emitBinaryOp(arithOp, resultSlot, varSlot, rhsSlot);
emitLoadSlot(varSlot, resultSlot);
return varSlot;
@ -378,8 +549,18 @@ int IRGenerator::generateExpression(ASTNode* node) {
int zeroSlot = freshSlot();
emitLoadConst(zeroSlot, 0);
emitBinaryOp(Opcode::SUB, resultSlot, zeroSlot, operandSlot);
} else if (bin->Operator == TokenType::BANG) {
// !x → (x == 0): sıfırsa 1, değilse 0
int zeroSlot = freshSlot();
emitLoadConst(zeroSlot, 0);
emitBinaryOp(Opcode::EQUAL_EQUAL, resultSlot, operandSlot, zeroSlot);
} else if (bin->Operator == TokenType::TILDE) {
// ~x — bitsel değil
Instruction ins(Opcode::BNOT);
ins.dest = resultSlot;
ins.src = operandSlot;
currentFunction_->instructions.push_back(std::move(ins));
} else {
// Diğer unary operatörler → TODO
emitLoadSlot(resultSlot, operandSlot);
}
return resultSlot;
@ -399,6 +580,36 @@ int IRGenerator::generateExpression(ASTNode* node) {
case TokenType::GREATER_EQUAL: return generateBinaryArithmetic(Opcode::GREATER_EQUAL, bin->Left, bin->Right);
case TokenType::EQUAL_EQUAL: return generateBinaryArithmetic(Opcode::EQUAL_EQUAL, bin->Left, bin->Right);
case TokenType::BANG_EQUAL: return generateBinaryArithmetic(Opcode::NOT_EQUAL, bin->Left, bin->Right);
// Bitsel operatörler
case TokenType::AMPERSAND: return generateBinaryArithmetic(Opcode::BAND, bin->Left, bin->Right);
case TokenType::PIPE: return generateBinaryArithmetic(Opcode::BOR, bin->Left, bin->Right);
case TokenType::LSHIFT: return generateBinaryArithmetic(Opcode::SHL, bin->Left, bin->Right);
case TokenType::RSHIFT: return generateBinaryArithmetic(Opcode::SHR, bin->Left, bin->Right);
// Mantıksal operatörler: kısa devre dallanmasıyla üretilir (ADR-008).
// NOT: sıradan ikili işlem değil — b, a'nın değerine göre atlanabilir.
case TokenType::AMPERSAND_AMPERSAND: {
int slotA = generateExpression(bin->Left);
int result = freshSlot();
emitLoadConst(result, 0); // varsayılan: false
int skipB = emitJumpIfFalse(slotA); // a false → b'yi atla
int slotB = generateExpression(bin->Right);
emitLoadSlot(result, slotB); // result = b
patchJump(skipB);
return result;
}
case TokenType::PIPE_PIPE: {
int slotA = generateExpression(bin->Left);
int result = freshSlot();
emitLoadConst(result, 1); // varsayılan: true
int skipB = emitJumpIfTrue(slotA); // a true → b'yi atla
int slotB = generateExpression(bin->Right);
emitLoadSlot(result, slotB); // result = b
patchJump(skipB);
return result;
}
default: {
// Bilinmeyen operatör — boş slot döndür
int slot = freshSlot();
@ -473,6 +684,42 @@ int IRGenerator::generateExpression(ASTNode* node) {
return resultSlot; // artırmadan önceki değer
}
// ── Üye erişimi okuma: p.x ───────────────────────────────────────────
case ASTKind::MemberAccess: {
auto* ma = (MemberAccessNode*)node;
int objSlot = generateExpression(ma->object);
int destSlot = freshSlot();
// Nesnenin struct adını resolvedType üstünden al (tip denetleyici yazdı)
std::string structName;
if (auto* exprObj = dynamic_cast<ExpressionNode*>(ma->object))
structName = exprObj->resolvedType.structName;
int idx = getStructFieldIndex(structName, ma->member);
if (idx >= 0) emitFieldGet(destSlot, objSlot, idx);
return destSlot;
}
case ASTKind::ArrayLiteral: {
auto* al = (ArrayLiteralNode*)node;
int arrSlot = freshSlot();
emitArrayNew(arrSlot, (int)al->elements.size());
for (int i = 0; i < (int)al->elements.size(); i++) {
int idxSlot = freshSlot();
emitLoadConst(idxSlot, i);
int valSlot = generateExpression(al->elements[i]);
emitArraySet(arrSlot, idxSlot, valSlot);
}
return arrSlot;
}
// ── Index erişimi okuma: a[i] ─────────────────────────────────────────
case ASTKind::IndexExpression: {
auto* idx = (IndexExpressionNode*)node;
int arrSlot = generateExpression(idx->object);
int idxSlot = generateExpression(idx->index);
int destSlot = freshSlot();
emitArrayGet(destSlot, arrSlot, idxSlot);
return destSlot;
}
default:
// Bilinmeyen ifade türü
return freshSlot(); // boş slot (0 değeriyle)
@ -487,7 +734,52 @@ int IRGenerator::generateBinaryArithmetic(Opcode opcode, ASTNode* leftNode, ASTN
int leftSlot = generateExpression(leftNode);
int rightSlot = generateExpression(rightNode);
int destSlot = freshSlot();
emitBinaryOp(opcode, destSlot, leftSlot, rightSlot);
// Float tip kontrolü — resolvedType üstünden (tip denetleyici tarafından yazıldı)
bool leftIsFloat = false, rightIsFloat = false;
bool leftIsString = false, rightIsString = false;
if (auto* e = dynamic_cast<ExpressionNode*>(leftNode)) {
leftIsFloat = e->resolvedType.isPrimitive() &&
(e->resolvedType.prim == PrimitiveKind::Float ||
e->resolvedType.prim == PrimitiveKind::Double);
leftIsString = e->resolvedType.isString();
}
if (auto* e = dynamic_cast<ExpressionNode*>(rightNode)) {
rightIsFloat = e->resolvedType.isPrimitive() &&
(e->resolvedType.prim == PrimitiveKind::Float ||
e->resolvedType.prim == PrimitiveKind::Double);
rightIsString = e->resolvedType.isString();
}
// String birleştirme (ADR-024): + → STRING_CONCAT
if ((leftIsString || rightIsString) && opcode == Opcode::ADD) {
emitBinaryOp(Opcode::STRING_CONCAT, destSlot, leftSlot, rightSlot);
return destSlot;
}
if (leftIsFloat || rightIsFloat) {
// Int operandı float'a çevir
if (!leftIsFloat) {
int conv = freshSlot();
emitIntToFloat(conv, leftSlot);
leftSlot = conv;
}
if (!rightIsFloat) {
int conv = freshSlot();
emitIntToFloat(conv, rightSlot);
rightSlot = conv;
}
// Float opcode eşleştirmesi
Opcode floatOp = opcode;
if (opcode == Opcode::ADD) floatOp = Opcode::FADD;
else if (opcode == Opcode::SUB) floatOp = Opcode::FSUB;
else if (opcode == Opcode::MUL) floatOp = Opcode::FMUL;
else if (opcode == Opcode::DIV) floatOp = Opcode::FDIV;
// karşılaştırma opcodeları aynı kalır (LESS, GREATER, vb.)
emitBinaryOp(floatOp, destSlot, leftSlot, rightSlot);
} else {
emitBinaryOp(opcode, destSlot, leftSlot, rightSlot);
}
return destSlot;
}
@ -531,6 +823,111 @@ void IRGenerator::emitLoadSlot(int destSlot, int srcSlot) {
currentFunction_->instructions.push_back(std::move(ins));
}
void IRGenerator::emitLoadGlobal(int destSlot, int globalIndex) {
Instruction ins(Opcode::LOAD_GLOBAL);
ins.dest = destSlot;
ins.intValue = globalIndex;
currentFunction_->instructions.push_back(std::move(ins));
}
void IRGenerator::emitStoreGlobal(int srcSlot, int globalIndex) {
Instruction ins(Opcode::STORE_GLOBAL);
ins.src = srcSlot;
ins.intValue = globalIndex;
currentFunction_->instructions.push_back(std::move(ins));
}
void IRGenerator::emitLoadFloat(int destSlot, double value) {
Instruction ins(Opcode::LOAD_FLOAT);
ins.dest = destSlot;
ins.floatValue = value;
currentFunction_->instructions.push_back(std::move(ins));
}
void IRGenerator::emitIntToFloat(int destSlot, int srcSlot) {
Instruction ins(Opcode::INT_TO_FLOAT);
ins.dest = destSlot;
ins.src = srcSlot;
currentFunction_->instructions.push_back(std::move(ins));
}
void IRGenerator::emitStructNew(int destSlot, const std::string& structType, int fieldCount) {
Instruction ins(Opcode::STRUCT_NEW);
ins.dest = destSlot;
ins.intValue = fieldCount;
ins.functionName = structType; // struct tip adı
currentFunction_->instructions.push_back(std::move(ins));
}
void IRGenerator::emitFieldGet(int destSlot, int objSlot, int fieldIdx) {
Instruction ins(Opcode::FIELD_GET);
ins.dest = destSlot;
ins.src = objSlot;
ins.intValue = fieldIdx;
currentFunction_->instructions.push_back(std::move(ins));
}
void IRGenerator::emitFieldSet(int objSlot, int fieldIdx, int valSlot) {
Instruction ins(Opcode::FIELD_SET);
ins.dest = objSlot;
ins.intValue = fieldIdx;
ins.right = valSlot;
currentFunction_->instructions.push_back(std::move(ins));
}
void IRGenerator::emitArrayNew(int destSlot, int capacity) {
Instruction ins(Opcode::ARRAY_NEW);
ins.dest = destSlot;
ins.intValue = capacity;
currentFunction_->instructions.push_back(std::move(ins));
}
void IRGenerator::emitArrayGet(int destSlot, int arrSlot, int idxSlot) {
Instruction ins(Opcode::ARRAY_GET);
ins.dest = destSlot;
ins.left = arrSlot;
ins.right = idxSlot;
currentFunction_->instructions.push_back(std::move(ins));
}
void IRGenerator::emitArraySet(int arrSlot, int idxSlot, int valSlot) {
Instruction ins(Opcode::ARRAY_SET);
ins.dest = arrSlot;
ins.left = idxSlot;
ins.right = valSlot;
currentFunction_->instructions.push_back(std::move(ins));
}
void IRGenerator::emitArrayLen(int destSlot, int arrSlot) {
Instruction ins(Opcode::ARRAY_LEN);
ins.dest = destSlot;
ins.src = arrSlot;
currentFunction_->instructions.push_back(std::move(ins));
}
int IRGenerator::getStructFieldIndex(const std::string& structType, const std::string& fieldName) const {
auto it = structLayouts_.find(structType);
if (it == structLayouts_.end()) return -1;
for (int i = 0; i < (int)it->second.size(); i++)
if (it->second[i].first == fieldName) return i;
return -1;
}
int IRGenerator::getStructFieldCount(const std::string& structType) const {
auto it = structLayouts_.find(structType);
if (it == structLayouts_.end()) return 0;
return (int)it->second.size();
}
bool IRGenerator::isGlobal(const std::string& name) const {
return nameToGlobal_.count(name) > 0;
}
int IRGenerator::getGlobalIndex(const std::string& name) const {
auto it = nameToGlobal_.find(name);
return (it != nameToGlobal_.end()) ? it->second : -1;
}
void IRGenerator::emitBinaryOp(Opcode op, int destSlot, int leftSlot, int rightSlot) {
Instruction ins(op);
ins.dest = destSlot;
@ -557,7 +954,14 @@ int IRGenerator::emitJumpIfFalse(int condSlot) {
ins.cond = condSlot;
ins.jumpTarget = -1; // henüz bilinmiyor — patchJump() bekliyor
currentFunction_->instructions.push_back(std::move(ins));
// Bu instruction'ın indeksini döndür (backpatch için)
return (int)currentFunction_->instructions.size() - 1;
}
int IRGenerator::emitJumpIfTrue(int condSlot) {
Instruction ins(Opcode::JIF_TRUE);
ins.cond = condSlot;
ins.jumpTarget = -1;
currentFunction_->instructions.push_back(std::move(ins));
return (int)currentFunction_->instructions.size() - 1;
}

View File

@ -22,8 +22,11 @@
#include <string>
#include <unordered_map>
#include <vector>
#include <utility>
#include "ir/ir_program.hpp"
#include "symbol/symbol_table.hpp"
#include "core/type.hpp"
#include "parser/ast_node.hpp"
class IRGenerator {
@ -55,7 +58,18 @@ private:
// Talimatları currentFunction_->instructions'a ekler.
void emitLoadConst(int destSlot, int value);
void emitLoadFloat(int destSlot, double value);
void emitIntToFloat(int destSlot, int srcSlot);
void emitLoadSlot(int destSlot, int srcSlot);
void emitLoadGlobal(int destSlot, int globalIndex);
void emitStoreGlobal(int srcSlot, int globalIndex);
void emitStructNew(int destSlot, const std::string& structType, int fieldCount);
void emitFieldGet(int destSlot, int objSlot, int fieldIdx);
void emitFieldSet(int objSlot, int fieldIdx, int valSlot);
void emitArrayNew(int destSlot, int capacity);
void emitArrayGet(int destSlot, int arrSlot, int idxSlot);
void emitArraySet(int arrSlot, int idxSlot, int valSlot);
void emitArrayLen(int destSlot, int arrSlot);
void emitBinaryOp(Opcode op, int destSlot, int leftSlot, int rightSlot);
void emitReturn(int srcSlot);
// Koşulsuz atlama yazar; instruction indeksini döndürür (backpatch için).
@ -66,19 +80,44 @@ private:
// Döndürülen indeks ileride patchJump() ile doldurulur (backpatch).
int emitJumpIfFalse(int condSlot);
// JIF_TRUE talimatını -1 hedefle yazar, instruction indeksini döndürür.
int emitJumpIfTrue(int condSlot);
// Daha önce -1 hedefle yazılan jump'ın hedefini şu anki pozisyona doldur.
void patchJump(int instrIndex);
// Şu an kaç talimat üretildi? (jump hedefi belirlemek için)
int currentInstrIndex() const;
// ── Döngü bağlamı yığını — break/continue hedefleri ─────────────────
// Her döngüye girerken bir giriş push'lanır, çıkınca pop'lanır.
// İç içe döngülerde en üstteki giriş en içteki döngüye aittir.
struct LoopContext {
std::vector<int> breakJumps; // patch bekleyen break JMP indeksleri
std::vector<int> continueJumps; // patch bekleyen continue JMP indeksleri
};
std::vector<LoopContext> loopContextStack_;
// ── Per-function üretim durumu ────────────────────────────────────────
IRFunction* currentFunction_ = nullptr; // şu an üretilen fonksiyon
int nextSlot_ = 0; // sıradaki boş slot numarası
// Değişken ismi → slot numarası.
// Sınırlama: aynı isimdeki farklı scope değişkenleri çakışır (TODO).
// Değişken ismi → slot numarası (lokal).
std::unordered_map<std::string, int> nameToSlot_;
// Global değişken ismi → global index
std::unordered_map<std::string, int> nameToGlobal_;
int globalCount_ = 0;
// Struct alan düzeni: struct adı → sıralı [(alan adı, Type)] listesi
// Sembol tablosundan generate() başında kopyalanır.
std::unordered_map<std::string, std::vector<std::pair<std::string, Type>>> structLayouts_;
int getStructFieldIndex(const std::string& structType, const std::string& fieldName) const;
int getStructFieldCount(const std::string& structType) const;
bool isGlobal(const std::string& name) const;
int getGlobalIndex(const std::string& name) const;
};
#endif // SAQUT_IR_GENERATOR

View File

@ -3,6 +3,14 @@
void IRProgram::dump() const {
std::cout << "IR DUMP\n\n";
if (globalCount > 0) {
std::cout << "GLOBALS (" << globalCount << ")\n";
for (int i = 0; i < (int)globalNames.size(); i++)
std::cout << " global[" << i << "] = " << globalNames[i] << "\n";
std::cout << "\n";
}
for (const auto& name : functionOrder) {
auto it = functions.find(name);
if (it != functions.end()) it->second.dump();

View File

@ -29,6 +29,14 @@ struct IRProgram {
// Ekleme sırası (dump'ta orijinal sırayla göstermek için)
std::vector<std::string> functionOrder;
// Modül-düzeyi değişkenler (LOAD_GLOBAL / STORE_GLOBAL için)
// Bunlar "global" değil — bu IRProgram'ın temsil ettiği tek modüle aittir.
// Çok-modüllü derlemede her modülün kendi IRProgram'ı (veya ayrı slot alanı) olur.
// TODO(#modül-scope): moduleId alanı eklenince Interpreter bu alana
// frame.function->moduleId üzerinden erişecek (bkz. TODO.md).
int globalCount = 0;
std::vector<std::string> globalNames; // index → isim (dump için)
// Yeni fonksiyon ekle
void addFunction(IRFunction fn) {
functionOrder.push_back(fn.name);

View File

@ -104,6 +104,10 @@ private:
case TokenType::GREATER:
case TokenType::LESS_EQUAL:
case TokenType::GREATER_EQUAL:
case TokenType::AMPERSAND:
case TokenType::PIPE:
case TokenType::LSHIFT:
case TokenType::RSHIFT:
case TokenType::AMPERSAND_AMPERSAND:
case TokenType::PIPE_PIPE:
return true;
@ -125,6 +129,10 @@ private:
case TokenType::GREATER: return l > r ? 1 : 0;
case TokenType::LESS_EQUAL: return l <= r ? 1 : 0;
case TokenType::GREATER_EQUAL: return l >= r ? 1 : 0;
case TokenType::AMPERSAND: return l & r;
case TokenType::PIPE: return l | r;
case TokenType::LSHIFT: return l << r;
case TokenType::RSHIFT: return l >> r;
case TokenType::AMPERSAND_AMPERSAND: return (l && r) ? 1 : 0;
case TokenType::PIPE_PIPE: return (l || r) ? 1 : 0;
default: return 0;

View File

@ -15,9 +15,12 @@
#include "parser/nodes/declarations.hpp"
#include "parser/nodes/expressions.hpp"
#include "parser/nodes/program.hpp"
#include "diagnostic/diagnostic_engine.hpp"
class DeadCodeElimPass : public OptimizationPass {
public:
explicit DeadCodeElimPass(DiagnosticEngine& diag) : diag_(diag) {}
bool run(ASTNode* root, SymbolTable*) override {
changed_ = false;
visit(root);
@ -30,6 +33,7 @@ public:
}
private:
DiagnosticEngine& diag_;
bool changed_ = false;
void visit(ASTNode* node) {
@ -45,11 +49,12 @@ private:
for (auto* child : ch) {
if (term) {
// Bu deyim erişilemez
if (auto* sn = dynamic_cast<StatementNode*>(child)) {
if (sn->isReachable) {
sn->isReachable = false;
changed_ = true;
diag_.report("W003", sn->loc,
"Bu kod hiçbir zaman çalışmaz (return/break/continue sonrası)");
}
}
}
@ -59,12 +64,14 @@ private:
term = true;
}
// Erişilemez çocukları sil ve vektörden çıkar
ch.erase(std::remove_if(ch.begin(), ch.end(),
// remove_if erişilemez düğümleri sona taşır (silmez), sonra delete
auto toErase = std::remove_if(ch.begin(), ch.end(),
[](ASTNode* n) {
auto* sn = dynamic_cast<StatementNode*>(n);
return sn && !sn->isReachable;
}), ch.end());
});
for (auto it = toErase; it != ch.end(); ++it) delete *it;
ch.erase(toErase, ch.end());
// Alt bloklara da in
for (auto* child : ch) visit(child);

View File

@ -1,9 +1,18 @@
// ============================================================================
// saQut — Optimizasyon Yöneticisi (ADR-007, ADR-009)
//
// 1. AST'yi klonlar (orijinal dokunulmaz).
// 2. Etkin pass'leri fixpoint döngüsüyle çalıştırır.
// 3. Optimize edilmiş klon sahipliğini döndürür (caller delete eder).
// İKİ KULLANIM YOLU:
//
// 1. runPassesInPlace(root, table)
// Pass'leri verilen AST üstünde doğrudan çalıştırır — klon yok.
// run / ir / transpile gibi "tek seferlik" komutlar bu yolu kullanır:
// AST'nin tek versiyonu gerekiyor, orijinali saklamaya gerek yok.
//
// 2. optimize(root, table) [sadece ast komutu için]
// Önce deepClone, sonra runPassesInPlace. Orijinali dokunulmaz bırakır.
// Çıktı: optimize edilmiş klon (caller delete eder).
// ast komutunun "öncesi / sonrası" karşılaştırması için zorunlu.
// Diğer komutlar bu yolu ÇAĞIRMAMALI — gereksiz klon maliyeti.
//
// Fixpoint garantisi: her pass yalnızca küçülten dönüşümler yapar
// (katlama: n düğüm → 1 düğüm; DCE: düğüm siler). Büyüten pass
@ -29,22 +38,27 @@ public:
if (cfg.optConstantFolding)
passes_.push_back(std::make_unique<ConstantFoldingPass>(diag));
if (cfg.optDeadCodeElim)
passes_.push_back(std::make_unique<DeadCodeElimPass>());
passes_.push_back(std::make_unique<DeadCodeElimPass>(diag));
maxRounds_ = cfg.maxFixpointRounds;
}
// optimize: AST'yi klonlar ve optimize edilmiş kopyayı döndürür.
// Dönen pointer caller'a aittir (delete edilmeli).
ASTNode* optimize(ASTNode* root, SymbolTable* table) {
ASTNode* clone = deepClone(root);
// Pass'leri verilen AST üstünde yerinde çalıştırır — klon yok.
// run / ir ve diğer tek-versiyon komutları bu yolu kullanır.
void runPassesInPlace(ASTNode* root, SymbolTable* table) {
for (int round = 0; round < maxRounds_; ++round) {
bool anyChange = false;
for (auto& pass : passes_)
if (pass->run(clone, table)) anyChange = true;
if (pass->run(root, table)) anyChange = true;
if (!anyChange) break;
}
}
// Önce deepClone, sonra runPassesInPlace. Orijinal dokunulmaz.
// SADECE ast komutu kullanır — öncesi/sonrası karşılaştırması için.
// Dönen pointer caller'a aittir (delete edilmeli).
ASTNode* optimize(ASTNode* root, SymbolTable* table) {
ASTNode* clone = deepClone(root);
runPassesInPlace(clone, table);
return clone;
}

View File

@ -87,6 +87,8 @@ enum class ASTKind {
ExpressionStatement, // ifade + noktalı virgül (;)
// children: [expression]
// Örn: x = 5; veya foo();
TryStatement, // try { body } catch (Error e) { handler } (ADR-025)
ThrowStatement, // throw <ifade>; (ADR-025)
/* ====== İfadeler (Expressions) ====== */
BinaryExpression, // İkili işlem: sol OP sağ.
@ -107,6 +109,8 @@ enum class ASTKind {
// children: [object], [member]
IndexExpression, // Dizi/indeks erişimi: a[i].
// children: [object], [index]
ArrayLiteral, // Dizi literali: [1, 2, 3].
// children: [element0, element1, ...]
};
// ============================================================================
@ -236,10 +240,12 @@ public:
// KARMAŞIKLIK: O(1) — referans döndürür
std::vector<ASTNode*>& getChildren() { return children; }
// ~ASTNode() — Sanal yıkıcı (polimorfik silme için)
// delete ASTNode* yapıldığında doğru alt sınıf yıkıcısı çağrılır.
// Bu olmazsa türetilmiş sınıfların kaynakları sızdırılır.
virtual ~ASTNode() = default;
// ~ASTNode() — children vektörünü özyinelemeli siler.
// Typed pointer'lar (condition, thenBranch vb.) alt sınıf yıkıcılarına bırakılır;
// children vektörü ile typed pointer'lar örtüşmediği için double-delete olmaz.
virtual ~ASTNode() {
for (auto* ch : children) delete ch;
}
protected:
// children — Alt düğümlerin vektörü.

View File

@ -10,6 +10,7 @@ public:
ASTNode* Right = nullptr;
BinaryExpressionNode();
~BinaryExpressionNode() override { delete Left; delete Right; }
void log(int indent = 0) override;
std::string toJson(int depth = 0) override;
};

View File

@ -3,6 +3,7 @@
// FunctionDeclNode
FunctionDeclNode::FunctionDeclNode() { kind = ASTKind::FunctionDecl; }
FunctionDeclNode::~FunctionDeclNode() { for (auto* p : params) delete p; }
void FunctionDeclNode::log(int indent) {
std::cout << jsonIndent(indent) << "FunctionDecl (" << name << " : " << returnType << ")\n";
for (auto* child : children) child->log(indent + 1);

View File

@ -11,6 +11,7 @@ public:
std::string returnType;
std::vector<VariableDeclNode*> params; // TODO(faz2): parametreler
FunctionDeclNode();
~FunctionDeclNode() override;
void log(int indent = 0) override;
std::string toJson(int depth = 0) override;
};
@ -21,6 +22,7 @@ public:
std::string name;
ASTNode* initExpr = nullptr;
VariableDeclNode();
~VariableDeclNode() override { delete initExpr; }
void log(int indent = 0) override;
std::string toJson(int depth = 0) override;
};

View File

@ -53,6 +53,23 @@ std::string MemberAccessNode::toJson(int depth) {
return obj.str();
}
// ArrayLiteralNode
ArrayLiteralNode::ArrayLiteralNode() { kind = ASTKind::ArrayLiteral; }
void ArrayLiteralNode::log(int indent) {
std::cout << jsonIndent(indent) << "ArrayLiteral [" << elements.size() << " eleman]\n";
for (auto* e : elements) e->log(indent + 1);
}
std::string ArrayLiteralNode::toJson(int depth) {
JsonObject obj(depth);
obj.add("kind", "ArrayLiteral");
obj.addArray("elements", [&]() {
for (auto* e : elements) obj.addItem(e->toJson(depth + 2));
});
obj.addRaw("resolvedType", resolvedTypeJson());
obj.addRaw("location", loc.toJson());
return obj.str();
}
// IndexExpressionNode
IndexExpressionNode::IndexExpressionNode() { kind = ASTKind::IndexExpression; }
void IndexExpressionNode::log(int indent) {

View File

@ -8,6 +8,7 @@ public:
ASTNode* operand = nullptr;
TokenType Operator;
PostfixNode();
~PostfixNode() override { delete operand; }
void log(int indent = 0) override;
std::string toJson(int depth = 0) override;
};
@ -17,6 +18,7 @@ public:
ASTNode* callee = nullptr;
std::vector<ASTNode*> arguments;
CallExpressionNode();
~CallExpressionNode() override { delete callee; for (auto* a : arguments) delete a; }
void log(int indent = 0) override;
std::string toJson(int depth = 0) override;
};
@ -27,6 +29,7 @@ public:
std::string member;
bool arrow = false;
MemberAccessNode();
~MemberAccessNode() override { delete object; }
void log(int indent = 0) override;
std::string toJson(int depth = 0) override;
};
@ -36,6 +39,16 @@ public:
ASTNode* object = nullptr;
ASTNode* index = nullptr;
IndexExpressionNode();
~IndexExpressionNode() override { delete object; delete index; }
void log(int indent = 0) override;
std::string toJson(int depth = 0) override;
};
class ArrayLiteralNode : public ExpressionNode {
public:
std::vector<ASTNode*> elements;
ArrayLiteralNode();
~ArrayLiteralNode() override { for (auto* e : elements) delete e; }
void log(int indent = 0) override;
std::string toJson(int depth = 0) override;
};

View File

@ -1,6 +1,5 @@
#include "parser/nodes/identifier.hpp"
#include <iostream>
#include <sstream>
#include "parser/ast_json.hpp"
IdentifierNode::IdentifierNode() { kind = ASTKind::Identifier; }
@ -11,14 +10,10 @@ void IdentifierNode::log(int indent) {
}
std::string IdentifierNode::toJson(int depth) {
std::string in = jsonIndent(depth);
std::string name = parserToken.token ? parserToken.token->token : "?";
std::ostringstream ss;
ss << "{\n"
<< in << " \"kind\": \"Identifier\",\n"
<< in << " \"name\": \"" << jsonEscape(name) << "\",\n"
<< in << " \"resolvedType\": " << resolvedTypeJson() << ",\n"
<< in << " \"location\": " << loc.toJson() << "\n"
<< in << "}";
return ss.str();
JsonObject obj(depth);
obj.add("kind", "Identifier");
obj.add("name", parserToken.token ? parserToken.token->token : "?");
obj.addRaw("resolvedType", resolvedTypeJson());
obj.addRaw("location", loc.toJson());
return obj.str();
}

View File

@ -1,6 +1,5 @@
#include "parser/nodes/literal.hpp"
#include <iostream>
#include <sstream>
#include "parser/ast_json.hpp"
LiteralNode::LiteralNode() { kind = ASTKind::Literal; }
@ -18,22 +17,17 @@ void LiteralNode::log(int indent) {
}
std::string LiteralNode::toJson(int depth) {
std::string in = jsonIndent(depth);
std::string val = hasDirectValue ? std::to_string(directIntValue)
: (parserToken.token ? parserToken.token->token : "?");
std::ostringstream ss;
ss << "{\n"
<< in << " \"kind\": \"Literal\",\n"
<< in << " \"literalType\": \"" << literalTypeToString(literalType) << "\",\n"
<< in << " \"value\": \"" << jsonEscape(val) << "\"";
if (literalType == LiteralType::INTEGER && literalBase != 10) {
ss << ",\n" << in << " \"base\": " << literalBase;
}
if (literalType == LiteralType::FLOAT) {
ss << ",\n" << in << " \"isFloat\": true";
}
ss << ",\n" << in << " \"resolvedType\": " << resolvedTypeJson();
ss << ",\n" << in << " \"location\": " << loc.toJson() << "\n"
<< in << "}";
return ss.str();
JsonObject obj(depth);
obj.add("kind", "Literal");
obj.add("literalType", literalTypeToString(literalType));
obj.add("value", val);
if (literalType == LiteralType::INTEGER && literalBase != 10)
obj.add("base", literalBase);
if (literalType == LiteralType::FLOAT)
obj.add("isFloat", true);
obj.addRaw("resolvedType", resolvedTypeJson());
obj.addRaw("location", loc.toJson());
return obj.str();
}

View File

@ -147,3 +147,36 @@ std::string ExpressionStatementNode::toJson(int depth) {
obj.addRaw("location", loc.toJson());
return obj.str();
}
// TryStatementNode (ADR-025)
TryStatementNode::TryStatementNode() { kind = ASTKind::TryStatement; }
void TryStatementNode::log(int indent) {
std::cout << jsonIndent(indent) << "TryStatement (catch " << catchVar << ")\n";
if (body) body->log(indent + 1);
if (handler) handler->log(indent + 1);
}
std::string TryStatementNode::toJson(int depth) {
JsonObject obj(depth);
obj.add("kind", "TryStatement");
obj.add("catchVar", catchVar);
if (body) obj.addRaw("body", body->toJson(depth + 1));
if (handler) obj.addRaw("handler", handler->toJson(depth + 1));
obj.add("isReachable", isReachable);
obj.addRaw("location", loc.toJson());
return obj.str();
}
// ThrowStatementNode (ADR-025)
ThrowStatementNode::ThrowStatementNode() { kind = ASTKind::ThrowStatement; }
void ThrowStatementNode::log(int indent) {
std::cout << jsonIndent(indent) << "ThrowStatement\n";
if (value) value->log(indent + 1);
}
std::string ThrowStatementNode::toJson(int depth) {
JsonObject obj(depth);
obj.add("kind", "ThrowStatement");
if (value) obj.addRaw("value", value->toJson(depth + 1));
obj.add("isReachable", isReachable);
obj.addRaw("location", loc.toJson());
return obj.str();
}

View File

@ -16,6 +16,7 @@ public:
ASTNode* thenBranch = nullptr;
ASTNode* elseBranch = nullptr;
IfStatementNode();
~IfStatementNode() override { delete condition; delete thenBranch; delete elseBranch; }
void log(int indent = 0) override;
std::string toJson(int depth = 0) override;
};
@ -25,6 +26,7 @@ public:
ASTNode* condition = nullptr;
ASTNode* body = nullptr;
WhileStatementNode();
~WhileStatementNode() override { delete condition; delete body; }
void log(int indent = 0) override;
std::string toJson(int depth = 0) override;
};
@ -36,6 +38,7 @@ public:
ASTNode* update = nullptr;
ASTNode* body = nullptr;
ForStatementNode();
~ForStatementNode() override { delete init; delete condition; delete update; delete body; }
void log(int indent = 0) override;
std::string toJson(int depth = 0) override;
};
@ -45,6 +48,7 @@ public:
ASTNode* condition = nullptr;
ASTNode* body = nullptr;
DoWhileStatementNode();
~DoWhileStatementNode() override { delete body; delete condition; }
void log(int indent = 0) override;
std::string toJson(int depth = 0) override;
};
@ -53,6 +57,7 @@ class ReturnStatementNode : public StatementNode {
public:
ASTNode* value = nullptr;
ReturnStatementNode();
~ReturnStatementNode() override { delete value; }
void log(int indent = 0) override;
std::string toJson(int depth = 0) override;
};
@ -75,6 +80,29 @@ class ExpressionStatementNode : public StatementNode {
public:
ASTNode* expression = nullptr;
ExpressionStatementNode();
~ExpressionStatementNode() override { delete expression; }
void log(int indent = 0) override;
std::string toJson(int depth = 0) override;
};
// ADR-025: try { body } catch (Error catchVar) { handler }
class TryStatementNode : public StatementNode {
public:
ASTNode* body = nullptr;
std::string catchVar; // catch değişken adı (ör. "e")
ASTNode* handler = nullptr;
TryStatementNode();
~TryStatementNode() override { delete body; delete handler; }
void log(int indent = 0) override;
std::string toJson(int depth = 0) override;
};
// ADR-025: throw <ifade>;
class ThrowStatementNode : public StatementNode {
public:
ASTNode* value = nullptr;
ThrowStatementNode();
~ThrowStatementNode() override { delete value; }
void log(int indent = 0) override;
std::string toJson(int depth = 0) override;
};

View File

@ -85,8 +85,15 @@ ASTNode* Parser::parseDeclaration() {
})) {
auto la1 = lookahead(1);
auto la2 = lookahead(2);
// int name( → fonksiyon
if (la1.type == TokenType::IDENTIFIER && la2.type == TokenType::LPAREN)
return parseFunctionDecl();
// int? name( → nullable dönüş tipli fonksiyon (ADR-021)
if (la1.type == TokenType::TERNARY) {
auto la3 = lookahead(3);
if (la2.type == TokenType::IDENTIFIER && la3.type == TokenType::LPAREN)
return parseFunctionDecl();
}
return parseVariableDecl();
}
@ -99,6 +106,11 @@ ASTNode* Parser::parseDeclaration() {
auto la2 = lookahead(2);
if (la1.type == TokenType::IDENTIFIER && la2.type == TokenType::LPAREN)
return parseFunctionDecl();
if (la1.type == TokenType::TERNARY) {
auto la3 = lookahead(3);
if (la2.type == TokenType::IDENTIFIER && la3.type == TokenType::LPAREN)
return parseFunctionDecl();
}
if (la1.type == TokenType::IDENTIFIER)
return parseVariableDecl();
}
@ -150,6 +162,23 @@ ASTNode* Parser::parseNullDenotation() {
return expr;
}
// Array literal: [expr, expr, ...]
if (ct.type == TokenType::LBRACKET) {
nextToken();
ArrayLiteralNode* arr = new ArrayLiteralNode();
arr->loc = ct.token ? ct.token->loc : SourceLocation{};
if (currentToken().type != TokenType::RBRACKET) {
arr->elements.push_back(parseExpression(0));
while (currentToken().type == TokenType::COMMA) {
nextToken();
arr->elements.push_back(parseExpression(0));
}
}
if (currentToken().type == TokenType::RBRACKET)
nextToken();
return arr;
}
if (ct.is({
TokenType::PLUS_PLUS, TokenType::MINUS_MINUS,
TokenType::PLUS, TokenType::MINUS,
@ -299,6 +328,10 @@ ASTNode* Parser::parseFunctionDecl() {
fn->returnType = currentToken().token->token;
nextToken();
// ADR-021: nullable dönüş tipi — int? f()
if (currentToken().type == TokenType::TERNARY)
{ nextToken(); fn->returnType += "?"; }
fn->name = currentToken().token->token;
nextToken();
@ -315,6 +348,16 @@ ASTNode* Parser::parseFunctionDecl() {
if (!isTypeKw || !typeTok.token) break;
std::string paramType = typeTok.token->token;
nextToken();
// int[] a — tip sonrasında [] varsa array tipi
if (currentToken().type == TokenType::LBRACKET) {
nextToken();
if (currentToken().type == TokenType::RBRACKET)
nextToken();
paramType += "[]";
}
// ADR-021: nullable parametre — int? a
if (currentToken().type == TokenType::TERNARY)
{ nextToken(); paramType += "?"; }
if (currentToken().type != TokenType::IDENTIFIER || !currentToken().token) break;
VariableDeclNode* param = new VariableDeclNode();
param->loc = currentToken().token->loc;
@ -364,6 +407,18 @@ ASTNode* Parser::parseVariableDecl() {
vd->varType = currentToken().token->token;
nextToken();
// Java/C# stili: int[] x — tip adından hemen sonra [] gelir
if (currentToken().type == TokenType::LBRACKET) {
nextToken();
if (currentToken().type == TokenType::RBRACKET)
nextToken();
vd->varType += "[]";
}
// ADR-021: nullable soneki — int? x
if (currentToken().type == TokenType::TERNARY)
{ nextToken(); vd->varType += "?"; }
if (currentToken().type != TokenType::IDENTIFIER) {
std::cerr << "Parser hatası: değişken ismi bekleniyor\n";
return vd;
@ -372,6 +427,7 @@ ASTNode* Parser::parseVariableDecl() {
vd->name = currentToken().token->token;
nextToken();
// C stili: int x[] — geriye dönük uyumluluk (postfix [])
if (currentToken().type == TokenType::LBRACKET) {
nextToken();
while (currentToken().type != TokenType::RBRACKET &&
@ -380,6 +436,7 @@ ASTNode* Parser::parseVariableDecl() {
nextToken();
if (currentToken().type == TokenType::RBRACKET)
nextToken();
if (vd->varType.back() != ']') vd->varType += "[]";
}
if (currentToken().type == TokenType::EQUAL) {
@ -452,6 +509,12 @@ ASTNode* Parser::parseStatement() {
if (ct.type == TokenType::KW_CONTINUE)
return parseContinueStatement();
if (ct.type == TokenType::KW_TRY)
return parseTryStatement();
if (ct.type == TokenType::KW_THROW)
return parseThrowStatement();
if (ct.is({
TokenType::KW_VOID, TokenType::KW_INT, TokenType::KW_FLOAT_TYPE,
TokenType::KW_DOUBLE, TokenType::KW_BOOL, TokenType::KW_CHAR,
@ -463,6 +526,15 @@ ASTNode* Parser::parseStatement() {
if (ct.type == TokenType::KW_STRUCT)
return parseStructDecl();
// Kullanıcı tanımlı struct tipiyle değişken bildirimi: Point p; veya Point p = ...;
if (ct.type == TokenType::IDENTIFIER) {
auto la1 = lookahead(1);
// "TypeName varName" veya "TypeName varName = ..." → değişken bildirimi
// (TypeName LPAREN → ifade; o durumda parseExpressionStatement devam eder)
if (la1.type == TokenType::IDENTIFIER)
return parseVariableDecl();
}
return parseExpressionStatement();
}
@ -627,3 +699,43 @@ ASTNode* Parser::parseExpressionStatement() {
return es;
}
// ADR-025: try { body } catch (Error catchVar) { handler }
ASTNode* Parser::parseTryStatement() {
TryStatementNode* ts = new TryStatementNode();
ts->loc = currentToken().token->loc;
nextToken(); // tüket: try
ts->body = parseBlock();
// catch (Error e)
if (currentToken().type == TokenType::KW_CATCH) {
nextToken(); // tüket: catch
if (currentToken().type == TokenType::LPAREN)
nextToken(); // tüket: (
// "Error" tip adını atla
if (currentToken().type == TokenType::IDENTIFIER ||
currentToken().type == TokenType::KW_STRING_TYPE)
nextToken(); // tüket: Error (ya da herhangi bir tip adı)
// catch değişken adını al
if (currentToken().type == TokenType::IDENTIFIER && currentToken().token)
ts->catchVar = currentToken().token->token;
nextToken(); // tüket: değişken adı
if (currentToken().type == TokenType::RPAREN)
nextToken(); // tüket: )
ts->handler = parseBlock();
}
return ts;
}
// ADR-025: throw <ifade>;
ASTNode* Parser::parseThrowStatement() {
ThrowStatementNode* th = new ThrowStatementNode();
th->loc = currentToken().token->loc;
nextToken(); // tüket: throw
th->value = parseExpression();
if (currentToken().type == TokenType::SEMICOLON)
nextToken();
return th;
}

View File

@ -51,6 +51,8 @@ private:
ASTNode* parseBreakStatement();
ASTNode* parseContinueStatement();
ASTNode* parseExpressionStatement();
ASTNode* parseTryStatement();
ASTNode* parseThrowStatement();
// --- İfadeler (Pratt parser) ---
ASTNode* parseExpression();

View File

@ -21,6 +21,50 @@ int TypeChecker::numericRank(const Type& t) {
}
}
// ADR-021: "a != null" / "a == null" kalıbını ayrıştır
// Dönüş: {varName, isNotNull} — varName boşsa kalıp tanınmadı.
std::pair<std::string, bool> TypeChecker::extractNullCheck(ASTNode* cond) {
if (!cond || cond->kind != ASTKind::BinaryExpression) return {"", false};
auto* bin = (BinaryExpressionNode*)cond;
bool isNE = (bin->Operator == TokenType::BANG_EQUAL);
bool isEE = (bin->Operator == TokenType::EQUAL_EQUAL);
if (!isNE && !isEE) return {"", false};
// Hangi taraf null literal?
auto isNullLit = [](ASTNode* n) -> bool {
if (!n || n->kind != ASTKind::Literal) return false;
return ((LiteralNode*)n)->literalType == LiteralType::BOŞ;
};
auto identName = [](ASTNode* n) -> std::string {
if (!n || n->kind != ASTKind::Identifier) return "";
auto* id = (IdentifierNode*)n;
return id->parserToken.token ? id->parserToken.token->token : "";
};
std::string var;
if (isNullLit(bin->Right)) var = identName(bin->Left);
else if (isNullLit(bin->Left)) var = identName(bin->Right);
if (var.empty()) return {"", false};
return {var, isNE}; // isNE=true → "a != null"; false → "a == null"
}
// ADR-021: guard pattern — bu statement her zaman çıkış yapıyor mu?
bool TypeChecker::alwaysExits(ASTNode* stmt) {
if (!stmt) return false;
switch (stmt->kind) {
case ASTKind::ReturnStatement:
case ASTKind::ThrowStatement:
case ASTKind::BreakStatement:
case ASTKind::ContinueStatement:
return true;
case ASTKind::Block: {
auto& ch = stmt->getChildren();
return !ch.empty() && alwaysExits(ch.back());
}
default: return false;
}
}
// ─────────────────────────────────────────────────────────────────────────────
// check — giriş noktası
// ─────────────────────────────────────────────────────────────────────────────
@ -62,21 +106,41 @@ bool TypeChecker::checkAssign(const Type& target, const Type& src,
const SourceLocation& loc,
const std::string& ctx) {
if (target.isError() || src.isError()) return true; // önceki hata, sessiz geç
if (target.equals(src)) return true;
// ADR-021: null literal ataması
if (src.isNullLiteral()) {
if (target.nullable) return true; // T? ← null → OK
diag_.report("E003", loc,
"'" + ctx + "': null non-null tipine (" + target.toString() + ") atanamaz");
return false;
}
// ADR-021: nullable uyumu
// T? ← T → OK (widening: non-null, nullable'a gider)
// T ← T? → E (narrowing: nullable, non-null'a gidemez; narrowing gerekli)
if (src.nullable && !target.nullable && src.equalsBase(target)) {
diag_.report("E003", loc,
"'" + ctx + "': " + src.toString() +
" nullable tipi non-null " + target.toString() + " tipine atanamaz"
" (if ile null kontrolü yapın)");
return false;
}
// T? ← T → OK (equalsBase eşleşiyorsa, nullable farkı widening)
if (!src.nullable && target.nullable && src.equalsBase(target)) return true;
if (target.equals(src)) return true;
int tRank = numericRank(target);
int sRank = numericRank(src);
if (tRank >= 0 && sRank >= 0) {
if (tRank > sRank) {
// Genişletme (widening): int→float, int→double, float→double
if (srcIsLiteral) return true; // literal bağlama-göre tiplenir, uyarısız
if (srcIsLiteral) return true;
diag_.report("W004", loc,
"'" + ctx + "': " + src.toString() +
"" + target.toString() + " örtük genişletme");
return true;
} else {
// Daraltma (narrowing): float→int, double→float, vb.
diag_.report("E003", loc,
"'" + ctx + "': " + src.toString() +
"" + target.toString() + " daraltma (veri kaybı)");
@ -84,7 +148,6 @@ bool TypeChecker::checkAssign(const Type& target, const Type& src,
}
}
// Tamamen farklı tipler
diag_.report("E003", loc,
"'" + ctx + "': " + src.toString() +
" tipi " + target.toString() + " tipine atanamaz");
@ -100,13 +163,32 @@ void TypeChecker::checkStmt(ASTNode* node) {
switch (node->kind) {
case ASTKind::Block:
for (ASTNode* child : node->getChildren()) checkStmt(child);
case ASTKind::Block: {
// ADR-021: guard/sıralı narrowing — if (a == null) return; → sonrasında a non-null
std::vector<std::string> guardNarrowed; // bu blokta guard'la daraltılanlar
for (ASTNode* child : node->getChildren()) {
checkStmt(child);
// guard kontrolü: if (a == null) { return/throw/break/continue; }
if (child->kind == ASTKind::IfStatement) {
auto* ifn = (IfStatementNode*)child;
if (!ifn->elseBranch && ifn->thenBranch && alwaysExits(ifn->thenBranch)) {
auto [var, isNotNull] = extractNullCheck(ifn->condition);
if (!var.empty() && !isNotNull) { // "a == null" → guard
narrowedNonNull_.insert(var);
guardNarrowed.push_back(var);
}
}
}
}
for (auto& v : guardNarrowed) narrowedNonNull_.erase(v);
break;
}
case ASTKind::VariableDecl: {
auto* vd = (VariableDeclNode*)node;
Type targetType = Type::fromName(vd->varType);
if (targetType.isError() && table_.structLayouts.count(vd->varType))
targetType = Type::structType(vd->varType);
if (vd->initExpr) {
Type srcType = checkExpr(vd->initExpr, targetType);
bool isLit = vd->initExpr->kind == ASTKind::Literal;
@ -142,9 +224,23 @@ void TypeChecker::checkStmt(ASTNode* node) {
case ASTKind::IfStatement: {
auto* ifn = (IfStatementNode*)node;
if (ifn->condition) checkExpr(ifn->condition);
if (ifn->condition) checkExpr(ifn->condition);
// ADR-021: nested narrowing — if (a != null) { a non-null } else { a null }
auto [narrowVar, isNotNull] = extractNullCheck(ifn->condition);
if (!narrowVar.empty() && isNotNull) // "a != null" → then'de non-null
narrowedNonNull_.insert(narrowVar);
if (ifn->thenBranch) checkStmt(ifn->thenBranch);
if (!narrowVar.empty() && isNotNull)
narrowedNonNull_.erase(narrowVar);
if (!narrowVar.empty() && !isNotNull) // "a == null" → else'de non-null
narrowedNonNull_.insert(narrowVar);
if (ifn->elseBranch) checkStmt(ifn->elseBranch);
if (!narrowVar.empty() && !isNotNull)
narrowedNonNull_.erase(narrowVar);
break;
}
@ -178,6 +274,21 @@ void TypeChecker::checkStmt(ASTNode* node) {
case ASTKind::ContinueStatement:
break; // yapısal doğrulama StructuralValidator'ın işi
// ADR-025: try { body } catch (Error e) { handler }
case ASTKind::TryStatement: {
auto* ts = (TryStatementNode*)node;
if (ts->body) checkStmt(ts->body);
if (ts->handler) checkStmt(ts->handler);
break;
}
// ADR-025: throw <ifade>; — unchecked, herhangi bir değer atılabilir
case ASTKind::ThrowStatement: {
auto* th = (ThrowStatementNode*)node;
if (th->value) checkExpr(th->value);
break;
}
default:
break;
}
@ -220,7 +331,14 @@ Type TypeChecker::checkExpr(ASTNode* node, const Type& expected) {
break;
case LiteralType::BOOLEAN: result = Type::Bool(); break;
case LiteralType::STRING: result = Type::String(); break;
default: result = Type::error(); break;
case LiteralType::BOŞ:
// null literal: bağlam nullable ise o tip, değilse Void+nullable (null sentinel)
if (!expected.isError() && expected.nullable)
result = expected;
else
result = Type::Void().asNullable(); // null sentinel
break;
default: result = Type::error(); break;
}
break;
}
@ -229,6 +347,12 @@ Type TypeChecker::checkExpr(ASTNode* node, const Type& expected) {
case ASTKind::Identifier: {
auto* id = (IdentifierNode*)node;
result = id->resolvedSymbol ? id->resolvedSymbol->type : Type::error();
// ADR-021: narrowing — bu değişken null kontrolünden geçtiyse non-null say
if (result.nullable && id->parserToken.token) {
std::string name = id->parserToken.token->token;
if (narrowedNonNull_.count(name))
result = result.asNonNull();
}
break;
}
@ -265,23 +389,68 @@ Type TypeChecker::checkExpr(ASTNode* node, const Type& expected) {
}
Type leftType = checkExpr(bin->Left);
Type rightType = checkExpr(bin->Right);
// Mantıksal
if (bin->Operator == TokenType::AMPERSAND_AMPERSAND ||
bin->Operator == TokenType::PIPE_PIPE) {
// ADR-021: && kısa-devre sağ taraf narrowing — "a != null && a.field"
if (bin->Operator == TokenType::AMPERSAND_AMPERSAND) {
auto [narrowVar, isNotNull] = extractNullCheck(bin->Left);
if (!narrowVar.empty() && isNotNull)
narrowedNonNull_.insert(narrowVar);
checkExpr(bin->Right);
if (!narrowVar.empty() && isNotNull)
narrowedNonNull_.erase(narrowVar);
result = Type::Bool();
break;
}
// Karşılaştırma
if (bin->Operator == TokenType::EQUAL_EQUAL ||
bin->Operator == TokenType::BANG_EQUAL ||
bin->Operator == TokenType::LESS ||
Type rightType = checkExpr(bin->Right);
// Mantıksal (||)
if (bin->Operator == TokenType::PIPE_PIPE) {
result = Type::Bool();
break;
}
// Eşitlik karşılaştırması: string dahil herhangi tiple çalışır
if (bin->Operator == TokenType::EQUAL_EQUAL ||
bin->Operator == TokenType::BANG_EQUAL) {
result = Type::Bool();
break;
}
// Sıralama karşılaştırması: YALNIZCA sayısal tipler
if (bin->Operator == TokenType::LESS ||
bin->Operator == TokenType::LESS_EQUAL ||
bin->Operator == TokenType::GREATER ||
bin->Operator == TokenType::GREATER_EQUAL) {
result = Type::Bool();
if (leftType.isError() || rightType.isError()) {
result = Type::error(); // önceki hata, sessiz geç
} else if (leftType.isNumeric() && rightType.isNumeric()) {
result = Type::Bool();
} else {
diag_.report("E003", bin->loc,
"Sıralama operatörü yalnızca sayısal tiplerle kullanılabilir: " +
leftType.toString() +
" — string için yalnızca == ve != kullanın");
result = Type::error();
}
break;
}
// ADR-021: katı operand kuralı — non-null bağlamda nullable operand yasak
// (eşitlik / null karşılaştırmaları için geçerli değil)
if (!leftType.isError() && !rightType.isError() &&
(leftType.nullable || rightType.nullable)) {
diag_.report("E003", bin->loc,
"Nullable operand: '" + leftType.toString() + "' ve '" +
rightType.toString() + "' — null kontrolü yapın veya daraltın");
result = Type::error();
break;
}
// String birleştirme: yalnızca + operatörü (ADR-024)
if (bin->Operator == TokenType::PLUS &&
leftType.isString() && rightType.isString()) {
result = Type::String();
break;
}
@ -359,15 +528,34 @@ Type TypeChecker::checkExpr(ASTNode* node, const Type& expected) {
// ── MemberAccess / IndexExpression ─────────────────────────────────────
case ASTKind::MemberAccess: {
auto* ma = (MemberAccessNode*)node;
checkExpr(ma->object);
result = Type::error(); // TODO(faz3+): struct alan çözümü
Type objType = checkExpr(ma->object);
// ADR-021: nullable nesne üstünde doğrudan alan erişimi yasak
if (objType.nullable) {
diag_.report("E003", node->loc,
"Nullable tip '" + objType.toString() + "' üstünde doğrudan erişim"
" — if ile null kontrolü yapın");
result = Type::error();
break;
}
if (objType.isStruct()) {
result = table_.getFieldType(objType.structName, ma->member);
if (result.isError())
diag_.report("E001", node->loc,
"'" + objType.structName + "' struct'ında '" + ma->member + "' alanı yok");
} else {
result = Type::error();
}
break;
}
case ASTKind::IndexExpression: {
auto* ie = (IndexExpressionNode*)node;
checkExpr(ie->object);
Type objType = checkExpr(ie->object);
if (ie->index) checkExpr(ie->index);
result = Type::error(); // TODO(faz3+): array eleman tipi
// array eleman tipi
if (objType.isArray() && objType.elementType)
result = *objType.elementType;
else
result = Type::Int(); // varsayılan (tip çıkarımı tam değil)
break;
}

View File

@ -1,6 +1,8 @@
#ifndef SAQUT_SEMANTIC_TYPE_CHECKER
#define SAQUT_SEMANTIC_TYPE_CHECKER
#include <unordered_set>
#include <string>
#include "symbol/symbol_table.hpp"
#include "diagnostic/diagnostic_engine.hpp"
#include "parser/ast_node.hpp"
@ -31,11 +33,20 @@ private:
// İki sayısal tipin genişlik sırası: int=0, float=1, double=2; -1 = sayısal değil.
static int numericRank(const Type& t);
// ADR-021: if-narrowing — null kontrolü kalıbını ayrıştır
// Dönüş: {varName, isNotNull} — "a != null" → {a, true}; "a == null" → {a, false}; {"", _} = kalıp yok
static std::pair<std::string, bool> extractNullCheck(ASTNode* cond);
// Bir statement her zaman çıkış yapıyor mu? (return/throw/break/continue)
static bool alwaysExits(ASTNode* stmt);
SymbolTable& table_;
DiagnosticEngine& diag_;
Type currentReturnType_; // aktif fonksiyonun beklenen dönüş tipi
bool inFunction_ = false;
// ADR-021: akış-duyarlı null daraltma — bu kapsamda non-null olduğu bilinen değişkenler
std::unordered_set<std::string> narrowedNonNull_;
};
#endif // SAQUT_SEMANTIC_TYPE_CHECKER

View File

@ -29,6 +29,18 @@ void SymbolCollector::seedBuiltins() {
Type::function(Type::Void(), {}),
SourceLocation{});
if (s) s->isBuiltin = true;
// ADR-025: Error builtin struct — try/catch için
// Alan sırası VM makeErrorValue() ile eşleşmeli: [line, col, message, trace, code]
table_.structLayouts["Error"] = {
{"line", Type::Int()},
{"col", Type::Int()},
{"message", Type::String()},
{"trace", Type::String()},
{"code", Type::String()}
};
table_.define("Error", SymbolKind::Struct, Type::structType("Error"), {});
structFields_["Error"]; // cycle checker'a tanıt
}
// ─────────────────────────────────────────────────────────────────────────────
@ -77,14 +89,15 @@ void SymbolCollector::pass1Globals(ASTNode* program) {
"'" + st->name + "' zaten bu kapsamda tanımlı");
break;
}
// struct alan isimlerini cycle check için kaydet
// structFields_'e her zaman bir giriş aç (typeFromName için gerekli)
structFields_[st->name]; // boş vektör oluşturur; by-value döngü artık referans semantiğiyle meşru (ADR-020)
// structLayouts: tüm alanlar (isim + tip) sırayla — IR üreteci ve tip denetleyici için
for (ASTNode* fieldNode : st->getChildren()) {
if (fieldNode->kind == ASTKind::VariableDecl) {
auto* vd = (VariableDeclNode*)fieldNode;
// yalnızca struct tipindeki alanları izle
Type ft = Type::fromName(vd->varType);
if (ft.isError()) // primitif değilse struct tipi olabilir
structFields_[st->name].push_back(vd->varType);
Type ft = typeFromName(vd->varType, vd->loc);
table_.structLayouts[st->name].push_back({vd->name, ft});
}
}
break;
@ -124,44 +137,10 @@ void SymbolCollector::pass1Globals(ASTNode* program) {
// ─────────────────────────────────────────────────────────────────────────────
void SymbolCollector::checkStructCycles() {
// white=0 / gray=1 / black=2
std::unordered_map<std::string, int> color;
for (auto& kv : structFields_) color[kv.first] = 0;
std::function<bool(const std::string&)> dfs = [&](const std::string& name) -> bool {
auto it = color.find(name);
if (it == color.end()) return false; // primitif / bilinmeyen → çevrim değil
if (it->second == 1) return true; // gray → back-edge → çevrim!
if (it->second == 2) return false; // black → zaten işlendi
it->second = 1; // gri yap
auto fit = structFields_.find(name);
if (fit != structFields_.end()) {
for (const std::string& dep : fit->second) {
if (dfs(dep)) return true;
}
}
it->second = 2; // siyah yap
return false;
};
for (auto& kv : structFields_) {
if (color[kv.first] == 0) {
// DFS başlat
color[kv.first] = 1;
for (const std::string& dep : kv.second) {
if (dfs(dep)) {
// tanımlama konumunu bulmak için global scope'ta ara
Symbol* s = table_.global()->lookupLocal(kv.first);
SourceLocation loc = s ? s->definitionLoc : SourceLocation{};
diag_.report("E010", loc,
"Döngüsel struct: '" + kv.first + "' by-value sonsuz boyut oluşturur");
break;
}
}
color[kv.first] = 2;
}
}
// ADR-020: Struct alanları referans semantiği taşır (Object* pointer).
// By-value gömme yok → sonsuz-boyut döngüsü imkânsız.
// E010 artık üretilmez; bu metot koşullu olarak devre dışı.
// TODO(gelecek): Primitive tipler için by-value gömme eklenirse E010 geri açılır.
}
// ─────────────────────────────────────────────────────────────────────────────
@ -306,6 +285,29 @@ void SymbolCollector::walkStmt(ASTNode* node) {
case ASTKind::ContinueStatement:
break; // yaprak
// ADR-025: try { body } catch (Error e) { handler }
case ASTKind::TryStatement: {
auto* ts = (TryStatementNode*)node;
if (ts->body) walkStmt(ts->body);
// catch değişkeni catch bloğu kapsamında görünür
if (ts->handler) {
table_.enterScope();
if (!ts->catchVar.empty())
table_.define(ts->catchVar, SymbolKind::Variable,
Type::structType("Error"), {});
walkStmt(ts->handler);
table_.exitScope();
}
break;
}
// ADR-025: throw <ifade>;
case ASTKind::ThrowStatement: {
auto* th = (ThrowStatementNode*)node;
if (th->value) walkExpr(th->value);
break;
}
default:
break;
}

View File

@ -3,6 +3,7 @@
#include <memory>
#include <vector>
#include <unordered_map>
#include "symbol/scope.hpp"
class SymbolTable {
@ -50,6 +51,26 @@ public:
return result;
}
// Struct alan düzeni: struct adı → sıralı [(alan adı, tip)] listesi
// Sembol toplayıcı doldurur; tip denetleyici ve IR üreteci okur.
std::unordered_map<std::string, std::vector<std::pair<std::string, Type>>> structLayouts;
int getFieldIndex(const std::string& structName, const std::string& fieldName) const {
auto it = structLayouts.find(structName);
if (it == structLayouts.end()) return -1;
for (int i = 0; i < (int)it->second.size(); i++)
if (it->second[i].first == fieldName) return i;
return -1;
}
Type getFieldType(const std::string& structName, const std::string& fieldName) const {
auto it = structLayouts.find(structName);
if (it == structLayouts.end()) return Type::error();
for (auto& p : it->second)
if (p.first == fieldName) return p.second;
return Type::error();
}
private:
Scope* newScope(Scope* p) {
scopes_.push_back(std::make_unique<Scope>(p));

View File

@ -1,8 +1,26 @@
#include "vm/interpreter.hpp"
#include "vm/object.hpp"
#include <iostream>
#include <stdexcept>
// ── makeErrorValue ─────────────────────────────────────────────────────────────
// ADR-025: Error struct oluşturur — alan sırası: [line, col, message, trace, code]
Value Interpreter::makeErrorValue(const std::string& message,
const std::string& code,
int line, int col) {
StructObject* obj = heap_.allocStruct(5);
obj->fields[0] = Value::fromInt(line);
obj->fields[1] = Value::fromInt(col);
obj->fields[2] = Value::fromString(message);
obj->fields[3] = Value::fromString(""); // trace — ileride IR satır tablosuyla doldurulacak
obj->fields[4] = Value::fromString(code);
return Value::fromRef(obj);
}
int Interpreter::run() {
// Global slot'ları sıfırla
globalSlots_.assign(program_.globalCount, Value::fromInt(0));
IRFunction* mainFunction = program_.findFunction("main");
if (!mainFunction)
throw std::runtime_error("Çalışma hatası: 'main' fonksiyonu bulunamadı");
@ -38,6 +56,10 @@ int Interpreter::run() {
frame.slots[instr.dest] = Value::fromString(instr.stringValue);
break;
case Opcode::LOAD_NULL:
frame.slots[instr.dest] = Value::null();
break;
case Opcode::LOAD_SLOT:
frame.slots[instr.dest] = frame.slots[instr.src];
break;
@ -59,17 +81,46 @@ int Interpreter::run() {
break;
case Opcode::DIV: {
int d = frame.slots[instr.right].intValue;
if (d == 0) throw std::runtime_error("Çalışma hatası: sıfıra bölme");
if (d == 0) { pendingThrow_ = makeErrorValue("Sıfıra bölme", "E_DIVZERO"); break; }
frame.slots[instr.dest] = Value::fromInt(frame.slots[instr.left].intValue / d);
break;
}
case Opcode::MOD: {
int d = frame.slots[instr.right].intValue;
if (d == 0) throw std::runtime_error("Çalışma hatası: sıfıra bölme (mod)");
if (d == 0) { pendingThrow_ = makeErrorValue("Sıfıra bölme (mod)", "E_DIVZERO"); break; }
frame.slots[instr.dest] = Value::fromInt(frame.slots[instr.left].intValue % d);
break;
}
// ── Bitsel ────────────────────────────────────────────────────────
case Opcode::BAND:
frame.slots[instr.dest] = Value::fromInt(
frame.slots[instr.left].intValue & frame.slots[instr.right].intValue);
break;
case Opcode::BOR:
frame.slots[instr.dest] = Value::fromInt(
frame.slots[instr.left].intValue | frame.slots[instr.right].intValue);
break;
case Opcode::SHL:
frame.slots[instr.dest] = Value::fromInt(
frame.slots[instr.left].intValue << frame.slots[instr.right].intValue);
break;
case Opcode::SHR:
frame.slots[instr.dest] = Value::fromInt(
frame.slots[instr.left].intValue >> frame.slots[instr.right].intValue);
break;
case Opcode::BNOT:
frame.slots[instr.dest] = Value::fromInt(~frame.slots[instr.src].intValue);
break;
// ── Global değişken erişimi ────────────────────────────────────────
case Opcode::LOAD_GLOBAL:
frame.slots[instr.dest] = globalSlots_[instr.intValue];
break;
case Opcode::STORE_GLOBAL:
globalSlots_[instr.intValue] = frame.slots[instr.src];
break;
// ── Karşılaştırma ─────────────────────────────────────────────────
case Opcode::LESS:
frame.slots[instr.dest] = Value::fromInt(
@ -89,17 +140,25 @@ int Interpreter::run() {
break;
case Opcode::EQUAL_EQUAL: {
auto& lv = frame.slots[instr.left]; auto& rv = frame.slots[instr.right];
int r = (lv.kind == ValueKind::String)
? (lv.stringValue == rv.stringValue ? 1 : 0)
: (lv.intValue == rv.intValue ? 1 : 0);
int r;
if (lv.kind == ValueKind::Ref || rv.kind == ValueKind::Ref)
r = (lv.ref == rv.ref ? 1 : 0); // ADR-023: array/struct kimlik karşılaştırması
else if (lv.kind == ValueKind::String)
r = (lv.stringValue == rv.stringValue ? 1 : 0);
else
r = (lv.intValue == rv.intValue ? 1 : 0);
frame.slots[instr.dest] = Value::fromInt(r);
break;
}
case Opcode::NOT_EQUAL: {
auto& lv = frame.slots[instr.left]; auto& rv = frame.slots[instr.right];
int r = (lv.kind == ValueKind::String)
? (lv.stringValue != rv.stringValue ? 1 : 0)
: (lv.intValue != rv.intValue ? 1 : 0);
int r;
if (lv.kind == ValueKind::Ref || rv.kind == ValueKind::Ref)
r = (lv.ref != rv.ref ? 1 : 0);
else if (lv.kind == ValueKind::String)
r = (lv.stringValue != rv.stringValue ? 1 : 0);
else
r = (lv.intValue != rv.intValue ? 1 : 0);
frame.slots[instr.dest] = Value::fromInt(r);
break;
}
@ -112,6 +171,10 @@ int Interpreter::run() {
if (!frame.slots[instr.cond].isTruthy())
frame.instructionPointer = instr.jumpTarget;
break;
case Opcode::JIF_TRUE:
if (frame.slots[instr.cond].isTruthy())
frame.instructionPointer = instr.jumpTarget;
break;
// ── Fonksiyon çağrısı ─────────────────────────────────────────────
case Opcode::CALL: {
@ -148,11 +211,170 @@ int Interpreter::run() {
continue;
}
// ── Float aritmetik (#44) ─────────────────────────────────────────
case Opcode::LOAD_FLOAT:
frame.slots[instr.dest] = Value::fromFloat(instr.floatValue);
break;
case Opcode::FADD:
frame.slots[instr.dest] = Value::fromFloat(
frame.slots[instr.left].floatValue + frame.slots[instr.right].floatValue);
break;
case Opcode::FSUB:
frame.slots[instr.dest] = Value::fromFloat(
frame.slots[instr.left].floatValue - frame.slots[instr.right].floatValue);
break;
case Opcode::FMUL:
frame.slots[instr.dest] = Value::fromFloat(
frame.slots[instr.left].floatValue * frame.slots[instr.right].floatValue);
break;
case Opcode::FDIV: {
double r = frame.slots[instr.right].floatValue;
if (r == 0.0) { pendingThrow_ = makeErrorValue("Float sıfıra bölme", "E_DIVZERO"); break; }
frame.slots[instr.dest] = Value::fromFloat(frame.slots[instr.left].floatValue / r);
break;
}
case Opcode::FNEG:
frame.slots[instr.dest] = Value::fromFloat(-frame.slots[instr.src].floatValue);
break;
case Opcode::INT_TO_FLOAT:
frame.slots[instr.dest] = Value::fromFloat((double)frame.slots[instr.src].intValue);
break;
case Opcode::FLOAT_TO_INT:
frame.slots[instr.dest] = Value::fromInt((int)frame.slots[instr.src].floatValue);
break;
// ── Struct (ADR-020: referans semantiği) ──────────────────────────
case Opcode::STRUCT_NEW: {
StructObject* obj = heap_.allocStruct(instr.intValue);
frame.slots[instr.dest] = Value::fromRef(obj);
break;
}
case Opcode::FIELD_GET: {
Value& objVal = frame.slots[instr.src];
if (objVal.kind != ValueKind::Ref || !objVal.ref)
throw std::runtime_error("Çalışma hatası: struct değil");
auto* obj = (StructObject*)objVal.ref;
int idx = instr.intValue;
if (idx < 0 || idx >= (int)obj->fields.size())
throw std::runtime_error("Çalışma hatası: geçersiz struct alan indeksi " + std::to_string(idx));
frame.slots[instr.dest] = obj->fields[idx];
break;
}
case Opcode::FIELD_SET: {
Value& objVal = frame.slots[instr.dest];
if (objVal.kind != ValueKind::Ref || !objVal.ref)
throw std::runtime_error("Çalışma hatası: struct değil");
auto* obj = (StructObject*)objVal.ref;
int idx = instr.intValue;
if (idx < 0 || idx >= (int)obj->fields.size())
throw std::runtime_error("Çalışma hatası: geçersiz struct alan indeksi " + std::to_string(idx));
obj->fields[idx] = frame.slots[instr.right];
break;
}
// ── Array (ADR-020: referans semantiği) ───────────────────────────
case Opcode::ARRAY_NEW: {
ArrayObject* arr = heap_.allocArray(instr.intValue);
arr->elements.resize(instr.intValue, Value::fromInt(0));
frame.slots[instr.dest] = Value::fromRef(arr);
break;
}
case Opcode::ARRAY_GET: {
Value& arrVal = frame.slots[instr.left];
if (arrVal.kind != ValueKind::Ref || !arrVal.ref) {
pendingThrow_ = makeErrorValue("Dizi beklendi, farklı tip alındı", "E_TYPE"); break;
}
auto* arr = (ArrayObject*)arrVal.ref;
int idx = frame.slots[instr.right].intValue;
if (idx < 0 || idx >= (int)arr->elements.size()) {
pendingThrow_ = makeErrorValue(
"Dizi sınır dışı (indeks=" + std::to_string(idx) +
", uzunluk=" + std::to_string(arr->elements.size()) + ")", "E_OOB");
break;
}
frame.slots[instr.dest] = arr->elements[idx];
break;
}
case Opcode::ARRAY_SET: {
Value& arrVal = frame.slots[instr.dest];
if (arrVal.kind != ValueKind::Ref || !arrVal.ref) {
pendingThrow_ = makeErrorValue("Dizi beklendi, farklı tip alındı", "E_TYPE"); break;
}
auto* arr = (ArrayObject*)arrVal.ref;
int idx = frame.slots[instr.left].intValue;
if (idx < 0 || idx >= (int)arr->elements.size()) {
pendingThrow_ = makeErrorValue(
"Dizi sınır dışı (indeks=" + std::to_string(idx) +
", uzunluk=" + std::to_string(arr->elements.size()) + ")", "E_OOB");
break;
}
arr->elements[idx] = frame.slots[instr.right];
break;
}
case Opcode::ARRAY_LEN: {
Value& arrVal = frame.slots[instr.src];
if (arrVal.kind != ValueKind::Ref || !arrVal.ref)
throw std::runtime_error("Çalışma hatası: dizi değil");
auto* arr = (ArrayObject*)arrVal.ref;
frame.slots[instr.dest] = Value::fromInt((int)arr->elements.size());
break;
}
// ── String (ADR-024: immutable değer-tipi, içerik ==) ────────────
case Opcode::STRING_CONCAT:
frame.slots[instr.dest] = Value::fromString(
frame.slots[instr.left].stringValue +
frame.slots[instr.right].stringValue);
break;
// ── Hata yönetimi (ADR-025) ──────────────────────────────────────
case Opcode::ENTER_TRY:
tryStack_.push_back({callStack_.size(), instr.jumpTarget, instr.dest});
break;
case Opcode::LEAVE_TRY:
if (!tryStack_.empty()) tryStack_.pop_back();
break;
case Opcode::THROW:
pendingThrow_ = frame.slots[instr.src];
break;
// ── FFI ───────────────────────────────────────────────────────────
case Opcode::CALLHOST:
executeHostFunction(instr.functionName, frame.slots, instr.argSlots);
break;
}
// ── pendingThrow_ işle: try varsa catch'e unwind, yoksa fırlat ───
if (pendingThrow_.has_value()) {
Value errVal = std::move(*pendingThrow_);
pendingThrow_.reset();
if (!tryStack_.empty()) {
TryFrame tf = tryStack_.back();
tryStack_.pop_back();
// catch bloğunun bulunduğu frame'e unwind
while (callStack_.size() > tf.callStackDepth)
callStack_.pop_back();
// Error'ı catch değişkenine bağla ve catch etiketine atla
callStack_.back().slots[tf.errorSlot] = errVal;
callStack_.back().instructionPointer = tf.catchTarget;
} else {
// Yakalanmamış hata — mesajı çıkar ve C++ exception olarak yükselt
std::string msg = "Yakalanmamış hata";
if (errVal.kind == ValueKind::Ref && errVal.ref) {
auto* s = static_cast<StructObject*>(errVal.ref);
if ((int)s->fields.size() > 2 &&
s->fields[2].kind == ValueKind::String)
msg = s->fields[2].stringValue;
} else if (errVal.kind == ValueKind::String) {
msg = errVal.stringValue;
}
throw std::runtime_error(msg);
}
continue;
}
}
return 0;
@ -164,8 +386,7 @@ void Interpreter::executeHostFunction(const std::string& name,
if (name == "print") {
if (!argSlots.empty()) {
const Value& val = slots[argSlots[0]];
if (val.kind == ValueKind::String) std::cout << val.stringValue << "\n";
else std::cout << val.intValue << "\n";
std::cout << val.toString() << "\n";
}
return;
}

View File

@ -14,8 +14,17 @@
#define SAQUT_VM_INTERPRETER
#include <vector>
#include <optional>
#include "ir/ir_program.hpp"
#include "vm/call_frame.hpp"
#include "vm/object.hpp"
// ADR-025: try bloğu girişinde yığına eklenen kayıt
struct TryFrame {
size_t callStackDepth; // ENTER_TRY anındaki callStack_.size() — unwind için
int catchTarget; // catch bloğunun IR instruction indeksi
int errorSlot; // catch değişkeninin slot numarası (catch frame'inde)
};
class Interpreter {
public:
@ -26,8 +35,17 @@ public:
int run();
private:
IRProgram& program_;
IRProgram& program_;
std::vector<CallFrame> callStack_;
std::vector<Value> globalSlots_;
Heap heap_;
std::vector<TryFrame> tryStack_; // ADR-025: aktif try çerçeveleri
std::optional<Value> pendingThrow_; // bekleyen istisna değeri
// Error StructObject oluştur (ADR-025): [line, col, message, trace, code]
Value makeErrorValue(const std::string& message,
const std::string& code = "",
int line = 0, int col = 0);
// Host (C++) fonksiyon çağrısı — şu an sadece "print" destekli
void executeHostFunction(const std::string& name,

78
src/vm/object.hpp Normal file
View File

@ -0,0 +1,78 @@
#ifndef SAQUT_VM_OBJECT
#define SAQUT_VM_OBJECT
#include <vector>
// ADR-022: GC-hazır nesne modeli (v1: toplama yok, sadece header + liste kancası).
// Her heap nesnesi bu yapıdan türer.
// marked + next: mark-sweep için hazır; v1'de kullanılmaz.
// TODO(#56): mark-sweep v2 — Heap::collect() bu header'ı kullanacak.
enum class ObjectType { Array, Struct };
struct Object {
ObjectType type;
bool marked = false; // mark-sweep için (v2); şimdilik kullanılmaz
Object* next = nullptr; // "tüm nesneler" intrusive listesi
};
// Forward declare — Value, Object*'ı taşır; Object, Value içerir.
struct Value;
struct ArrayObject : Object {
std::vector<Value> elements;
explicit ArrayObject(int capacity = 0) {
type = ObjectType::Array;
if (capacity > 0) elements.reserve(capacity);
}
};
// ADR-020: Struct = referans semantiği. Alanlar sıra indeksiyle erişilir.
struct StructObject : Object {
std::vector<Value> fields;
explicit StructObject(int fieldCount = 0) {
type = ObjectType::Struct;
fields.resize(fieldCount); // Value::fromInt(0) ile başlatılır (varsayılan)
}
};
// ── Heap ─────────────────────────────────────────────────────────────────────
// Tüm nesneleri intrusive listede tutar. v1'de serbest bırakma yok.
// TODO(#56): mark-sweep v2 — collect() kök taraması yapacak, ölü nesneleri silecek.
struct Heap {
Object* head = nullptr;
int allocCount = 0;
ArrayObject* allocArray(int capacity = 0) {
auto* obj = new ArrayObject(capacity);
obj->next = head;
head = obj;
allocCount++;
return obj;
}
StructObject* allocStruct(int fieldCount) {
auto* obj = new StructObject(fieldCount);
obj->next = head;
head = obj;
allocCount++;
return obj;
// TODO(#56): mark-sweep kök taraması buradan
}
// v1: process exit'te OS toplar; yıkıcı tüm nesneleri siler.
~Heap() {
Object* cur = head;
while (cur) {
Object* nxt = cur->next;
delete cur;
cur = nxt;
}
}
Heap() = default;
Heap(const Heap&) = delete;
Heap& operator=(const Heap&) = delete;
};
#endif // SAQUT_VM_OBJECT

View File

@ -1,62 +1,90 @@
// ============================================================================
// saQut VM — Value (Çalışma Zamanı Değer)
//
// Bir saQut değerinin bellekteki temsilidir.
//
// ŞU AN SADECE INT:
// fibonacci.sqt tamamen int kullanır, bu dikey dilim için int yeterli.
// İleride float, bool, string eklenmesi için "kind" alanı iskelet olarak bırakıldı.
//
// BOOLEAN OLARAK KULLANIM:
// JIF_FALSE talimatı değerin 0 olup olmadığına bakar.
// 0 = yanlış, sıfır-dışı = doğru. C geleneği.
// ============================================================================
#ifndef SAQUT_VM_VALUE
#define SAQUT_VM_VALUE
#include <string>
#include <sstream>
#include <iomanip>
#include <stdexcept>
// Gelecekte float/bool/string eklendiğinde burası genişleyecek.
// Şimdilik sadece int.
// Forward — Object tam tanımı object.hpp'de; Value onu pointer olarak taşır.
struct Object;
// ADR-020: Primitive (int/bool) = değer; bileşik (array/struct/string) = referans.
// ADR-021: Null = nullable referansların null değeri (saQut'ta `null` anahtar sözcüğü).
// Bool ayrı kind değil — boolean sonuçlar int olarak saklanır (0=yanlış, sıfır-dışı=doğru).
enum class ValueKind {
Int,
Float, // #44: float/double tek kind; floatValue alanı taşır
String,
// Float, // TODO(vm-genişletme)
// Bool, // TODO(vm-genişletme)
Ref, // ADR-020: array/struct nesnesine Object* referansı
Null, // ADR-021: nullable referansın null değeri (saQut kaynağında `null`)
};
struct Value {
ValueKind kind = ValueKind::Int;
int intValue = 0;
std::string stringValue; // yalnızca kind == String için geçerli
double floatValue = 0.0; // kind == Float için
std::string stringValue; // kind == String için
Object* ref = nullptr; // kind == Ref için
static Value fromInt(int n) {
Value v;
v.kind = ValueKind::Int;
v.intValue = n;
return v;
Value v; v.kind = ValueKind::Int; v.intValue = n; return v;
}
static Value fromFloat(double d) {
Value v; v.kind = ValueKind::Float; v.floatValue = d; return v;
}
static Value fromString(std::string s) {
Value v;
v.kind = ValueKind::String;
v.stringValue = std::move(s);
return v;
Value v; v.kind = ValueKind::String; v.stringValue = std::move(s); return v;
}
static Value fromRef(Object* obj) {
Value v; v.kind = ValueKind::Ref; v.ref = obj; return v;
}
static Value null() {
Value v; v.kind = ValueKind::Null; return v;
}
// JIF_FALSE için: int 0 = yanlış, boş string = yanlış, diğer = doğru
bool isTruthy() const {
if (kind == ValueKind::Int) return intValue != 0;
if (kind == ValueKind::String) return !stringValue.empty();
switch (kind) {
case ValueKind::Int: return intValue != 0;
case ValueKind::Float: return floatValue != 0.0;
case ValueKind::String: return !stringValue.empty();
case ValueKind::Ref: return ref != nullptr;
case ValueKind::Null: return false;
}
return false;
}
// Okunabilir metin — dump ve hata mesajları için
std::string toString() const {
switch (kind) {
case ValueKind::Int: return std::to_string(intValue);
case ValueKind::Float: {
// Tam sayıysa "3.0", değilse "3.14" gibi — gereksiz sıfırları kırp
std::ostringstream oss;
oss << std::setprecision(10) << floatValue;
std::string s = oss.str();
// Nokta yoksa ".0" ekle (saQut float değerleri her zaman nokta içerir)
if (s.find('.') == std::string::npos && s.find('e') == std::string::npos)
s += ".0";
return s;
}
case ValueKind::String: return stringValue;
case ValueKind::Ref: return "<ref>";
case ValueKind::Null: return "null";
}
return "?";
}
std::string typeName() const {
switch (kind) {
case ValueKind::Int: return "int";
case ValueKind::Float: return "float";
case ValueKind::String: return "string";
case ValueKind::Ref: return "ref";
case ValueKind::Null: return "null";
}
return "?";
}

View File

@ -0,0 +1,5 @@
5
6
12
3
1

View File

@ -0,0 +1,8 @@
int main() {
print(2 + 3);
print(10 - 4);
print(3 * 4);
print(10 / 3);
print(10 % 3);
return 0;
}

View File

@ -0,0 +1,4 @@
2
1
0
2

View File

@ -0,0 +1,27 @@
// B8: %= bileşik atama doğru IR üretmeli.
// Elle hesap: 17%5=2, 10%3=1, 0%4=0, zincir: 20+5=25-3=22*2=44/4=11%3=2
int main() {
int a = 17;
a %= 5;
print(a); // 2
int b = 10;
b %= 3;
print(b); // 1
int c = 0;
c %= 4;
print(c); // 0
// Tüm bileşik atamalar zinciri (regresyon)
int x = 20;
x += 5; // 25
x -= 3; // 22
x *= 2; // 44
x /= 4; // 11
x %= 3; // 2
print(x); // 2
return 0;
}

View File

@ -0,0 +1 @@
sıfıra bölme \(mod\)

View File

@ -0,0 +1,8 @@
// Runtime test: a %= 0 → çalışma zamanı sıfıra bölme hatası vermeli.
int main() {
int a = 7;
a %= 0;
print(a);
return 0;
}

View File

@ -0,0 +1,6 @@
7
9
3
3
1
11

View File

@ -0,0 +1,9 @@
int main() {
print(1 + 2 * 3);
print((1 + 2) * 3);
print(10 - 4 - 3);
print(10 / 3);
print(10 % 3);
print(2 + 3 * 4 - 6 / 2);
return 0;
}

View File

@ -0,0 +1,4 @@
99
1
0
2

View File

@ -0,0 +1,15 @@
void degistir(int[] a) {
a[0] = 99;
}
int main() {
int[] x = [1, 2, 3];
degistir(x);
print(x[0]);
int[] y = x;
print(y == x);
int[] z = [1, 2, 3];
print(z == x);
print(x[1]);
return 0;
}

View File

@ -0,0 +1,5 @@
8
14
24
6
-1

View File

@ -0,0 +1,10 @@
int main() {
int a = 12;
int b = 10;
print(a & b);
print(a | b);
print(a << 1);
print(a >> 1);
print(~0);
return 0;
}

View File

@ -0,0 +1,4 @@
6
14
56
28

View File

@ -0,0 +1,12 @@
int main() {
int x = 15;
x &= 6;
print(x);
x |= 8;
print(x);
x <<= 2;
print(x);
x >>= 1;
print(x);
return 0;
}

View File

@ -0,0 +1,3 @@
yakalandi
Sıfıra bölme
E_DIVZERO

View File

@ -0,0 +1,14 @@
// ADR-025: temel try/catch — runtime hatasını yakala
int main() {
try {
int x = 10 / 0;
print("erişilmez");
} catch (Error e) {
print("yakalandi");
print(e.message);
print(e.code);
}
return 0;
}

View File

@ -0,0 +1,4 @@
OOB yakalandi
E_OOB
throw yakalandi
devam

View File

@ -0,0 +1,29 @@
// ADR-025: throw + iç içe fonksiyon çağrısında unwind + array OOB
int riskli() {
int arr[3] = [1, 2, 3];
return arr[10];
}
int main() {
// Dış fonksiyonda throw
try {
riskli();
print("erişilmez");
} catch (Error e) {
print("OOB yakalandi");
print(e.code);
}
// Açık throw — string değer atıp catch et
try {
throw "kullanici hatasi";
} catch (Error e) {
print("throw yakalandi");
}
// Catch sonrası akış devam etmeli
print("devam");
return 0;
}

View File

@ -0,0 +1,2 @@
55
55

View File

@ -0,0 +1,24 @@
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));
print(fibonacciIterative(n));
return 0;
}

View File

@ -0,0 +1,5 @@
5.14
6.28
1.14
1.57
1.0

View File

@ -0,0 +1,11 @@
int main() {
float x = 3.14;
float y = 2.0;
print(x + y);
print(x * y);
print(x - y);
print(x / y);
float z = 1;
print(z);
return 0;
}

View File

@ -0,0 +1,3 @@
5
105
8

View File

@ -0,0 +1,12 @@
int counter = 0;
int total = 100;
int main() {
counter = 5;
total = total + counter;
print(counter);
print(total);
counter += 3;
print(counter);
return 0;
}

View File

@ -0,0 +1,2 @@
10
20

View File

@ -0,0 +1,9 @@
int base = 10;
int doubled = 0;
int main() {
doubled = base * 2;
print(base);
print(doubled);
return 0;
}

View File

@ -0,0 +1,5 @@
1
0
1
0
1

View File

@ -0,0 +1,28 @@
// ! operatörü golden testi — değişken operandlar (bozuk olan yol).
// Sabit operandlar sabit katlama tarafından derleme zamanında hesaplanır;
// bu test IR üretim yolunu zorlayan değişken operandlar kullanır.
//
// Tanım: !x → sıfırsa 1, değilse 0. Sonuç her zaman 0 ya da 1.
int main() {
int z = 0;
int n = 5;
// Temel: !0 → 1, !5 → 0
print(!z);
print(!n);
// Çift değil normalleştirme: !!5 → 1, !!0 → 0
print(!!n);
print(!!z);
// if (!x) dallanma: z=0 iken gövde çalışmalı, n=5 iken çalışmamalı
if (!z) {
print(1);
}
if (!n) {
print(0);
}
return 0;
}

View File

@ -0,0 +1,5 @@
S
evet_and
evet_or1
S
evet_or2

View File

@ -0,0 +1,43 @@
// Kısa devre (short-circuit) değerlendirmesini kanıtlayan golden test.
//
// Amaç: sadece "doğru sonuç veriyor" değil, sağ taraftaki yan etkinin
// ATLANDIĞINI çıktıdan kanıtlamak. Tüm operandlar değişken (sabit değil)
// — sabit katlama yolunu değil, IR üretim yolunu test eder.
//
// Beklenen çıktı analizi:
// f=0 && side() → kısa devre → "S" ÇIKMIYOR
// t=1 && side() → b çalışır → "S" ÇIKIYOR, "evet_and"
// t=1 || side() → kısa devre → "S" ÇIKMIYOR, "evet_or1"
// f=0 || side() → b çalışır → "S" ÇIKIYOR, "evet_or2"
int side() {
print("S");
return 1;
}
int main() {
int f = 0;
int t = 1;
// && false-left: side() atlanmalı, "S" çıkmamalı
if (f && side()) {
print("hatali_and");
}
// && true-left: side() çalışmalı → "S" çıkar, sonra "evet_and"
if (t && side()) {
print("evet_and");
}
// || true-left: side() atlanmalı, "S" çıkmamalı, yine de "evet_or1" çıkar
if (t || side()) {
print("evet_or1");
}
// || false-left: side() çalışmalı → "S" çıkar, sonra "evet_or2"
if (f || side()) {
print("evet_or2");
}
return 0;
}

View File

@ -0,0 +1,9 @@
0
1
2
0
1
2
0
1
2

View File

@ -0,0 +1,18 @@
int main() {
int i = 0;
while (i < 3) {
print(i);
i = i + 1;
}
int j = 0;
do {
print(j);
j = j + 1;
} while (j < 3);
for (int k = 0; k < 3; k = k + 1) {
print(k);
}
return 0;
}

View File

@ -0,0 +1 @@
5

View File

@ -0,0 +1,8 @@
int main() {
int x = 5;
do {
print(x);
x = x + 1;
} while (x < 0);
return 0;
}

View File

@ -0,0 +1,4 @@
1
2
3
5

View File

@ -0,0 +1,25 @@
// B4 regresyon testi: do-while koşulu 1-olmayan sıfır-dışı değer üretince
// döngü yanlışlıkla çıkmamalı ("== 1" geçici çözümü bu hatayı veriyordu).
//
// Test 1: koşul 2 üretiyor — döngü 3 kez dönmeli (i: 0→1→2, çıkış i==3)
// Test 2: koşul 0 olunca düzgün çıkıyor — döngü 1 kez dönmeli
int main() {
// Koşul 2 (1-olmayan truthy): döngü erken çıkmamalı
int i = 0;
do {
i = i + 1;
print(i);
} while (i < 3);
// i<3 sonucu: i=1→1, i=2→1, i=3→0; çıktı: 1 2 3
// Koşul 0: tek iterasyon, gövde bir kez çalışır
int j = 5;
do {
print(j);
j = 0;
} while (j);
// j=5 → print(5), j=0 → while(0) → çıkış; çıktı: 5
return 0;
}

View File

@ -0,0 +1,5 @@
1
3
5
1
2

View File

@ -0,0 +1,24 @@
// for döngüsünde break ve continue golden testi.
//
// continue kanıtı: 2 ve 4 atlanır ama güncelleme (i++) hala çalışır.
// Eğer continue güncellemeyi atlasaydı i==2'de sonsuz döngüye girerdi.
// 5'in çıktıda görünmesi güncellemenin çalıştığını kanıtlar.
//
// break kanıtı: i==3'te erken çık — 3, 4, 5 görünmemeli.
int main() {
int i = 0;
for (i = 1; i <= 5; i = i + 1) {
if (i == 2) { continue; }
if (i == 4) { continue; }
print(i);
}
for (i = 1; i <= 5; i = i + 1) {
if (i == 3) { break; }
print(i);
}
return 0;
}

View File

@ -0,0 +1,6 @@
1
1
2
1
3
1

View File

@ -0,0 +1,21 @@
// İç içe döngü: içteki break sadece içteki döngüyü etkiler.
// Döngü bağlamı yığınının doğru çalıştığını kanıtlar.
//
// Beklenen: her dış iterasyonda j=1 yazdırılır, j=2'de inner break.
// Dış döngü i=1,2,3 boyunca devam eder — inner break dışarıya sızmaz.
int main() {
int i = 1;
while (i <= 3) {
int j = 1;
while (j <= 3) {
if (j == 2) { break; }
print(i);
print(j);
j = j + 1;
}
i = i + 1;
}
return 0;
}

View File

@ -0,0 +1,7 @@
1
2
4
5
1
2
3

View File

@ -0,0 +1,22 @@
// while döngüsünde break ve continue golden testi.
int main() {
int i = 0;
// continue: 3'ü atla
while (i < 5) {
i = i + 1;
if (i == 3) { continue; }
print(i);
}
// break: 4'te çık
i = 0;
while (i < 10) {
i = i + 1;
if (i == 4) { break; }
print(i);
}
return 0;
}

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,21 @@
// ADR-021: && sağ taraf narrowing
int? getValue() {
return 7;
}
bool check(int? v) {
if (v != null && v > 5) {
return true;
}
return false;
}
int main() {
bool r = check(getValue());
if (r) {
print(1);
} else {
print(0);
}
return 0;
}

View File

@ -0,0 +1,2 @@
42
0

Some files were not shown because too many files have changed in this diff Show More