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:
commit
fe8d73a13c
|
|
@ -17,6 +17,4 @@ scripts/gitea.py
|
||||||
__pycache__/
|
__pycache__/
|
||||||
|
|
||||||
# CMake versiyona özgü dosyalar (otomatik üretilir, her güncellemede değişir)
|
# CMake versiyona özgü dosyalar (otomatik üretilir, her güncellemede değişir)
|
||||||
build/CMakeFiles/[0-9]*/
|
build/*
|
||||||
build/.cmake/
|
|
||||||
build/compile_commands.json
|
|
||||||
|
|
|
||||||
90
CLAUDE.md
90
CLAUDE.md
|
|
@ -20,37 +20,95 @@ git'te izlenir.
|
||||||
ham hız değil). C'ye transpile ileride geçerli 2. backend. İleride makine kodu
|
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
|
gerekirse libgccjit/LLVM'e bağlanılır (çok uzak). Bellek = host C++ heap; özel
|
||||||
allocator yok. (ADR-015)
|
allocator yok. (ADR-015)
|
||||||
- **Dil kimliği:** prosedürel, C-ailesi sözdizimi, value semantics, zorunlu
|
- **Dil kimliği:** prosedürel, C-ailesi sözdizimi, zorunlu class/main boilerplate
|
||||||
class/main boilerplate yok. **Yok:** class/OOP, closure, generic, kullanıcı
|
yok. **Semantik (ADR-020):** primitive (`int`/`float`/`bool`) = **değer**;
|
||||||
pointer'ı (`*`/`&`), auto/tip çıkarımı, gizli int↔float (tek istisna sabit
|
bileşik (`struct`/`array`/`string`) = **referans** (JS/Java/C# modeli). "Pointer
|
||||||
folding). **Var:** struct, tipli fonksiyonlar, array (`int[]`). `interface`
|
yok" = kullanıcıya `&`/`*` **sözdizimi** verilmez; derleyici/runtime içeride ve
|
||||||
**ertelendi** (reddedilmedi, ADR-018).
|
ç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):** açı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
|
- **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
|
**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ü +
|
(parent pointer'lar + sembol tablosu remap edilir, ADR-007). Fixpoint döngüsü +
|
||||||
iterasyon tavanı (`maxFixpointRounds`, ADR-009).
|
iterasyon tavanı (`maxFixpointRounds`, ADR-009).
|
||||||
- **Literal/tip kuralı:** tamsayı literali bağlama-göre tiplenir (`float x = 1;`
|
- **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
|
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`
|
- **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"
|
ilk müşteri (ADR-016). Batteries = sınır/FFI problemi, "zlib'i yeniden yaz"
|
||||||
değil; kripto asla elle yazılmaz (ADR-017).
|
değil; kripto asla elle yazılmaz (ADR-017).
|
||||||
|
|
||||||
## Mevcut durum (yapılan vs planlanan)
|
## Mevcut durum (yapılan vs planlanan)
|
||||||
- **Çalışıyor:** lexer, tokenizer, Pratt parser, AST, AST'nin JSON serileştirmesi,
|
- **✅ Birinci kilometre taşı AŞILDI:** `examples/fibonacci.sqt`
|
||||||
CLI iskeleti (`tokens`/`ast`/`symbols`/`run`), konum takibi, basit aritmetiği
|
(recursive + iterative) `saqut run` ile çalışıyor → `55\n55`.
|
||||||
düşüren minimal IR deneyi.
|
- **Çalışıyor (tam pipeline):**
|
||||||
- **Planlı (henüz YOK):** sembol tablosu, semantik analiz, tip sistemi, diagnostic
|
- Lexer, tokenizer, Pratt parser, AST + JSON serileştirmesi
|
||||||
motoru, optimizasyon, IR+bytecode VM ile çalıştırma.
|
- Sembol tablosu (iki-geçişli toplayıcı, döngüsel struct tespiti)
|
||||||
- **Birinci kilometre taşı ("bitti" tanımı):** `examples/fibonacci.sqt`
|
- Tip sistemi (`src/core/type.hpp`) + diagnostic motoru (`src/diagnostic/`)
|
||||||
(recursive + iterative) derlenip çalıştırılabilmeli.
|
- 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.
|
- **İlke:** Önce uçtan uca tek **dikey dilim**, sonra çerçeve. Erken soyutlamadan kaçın.
|
||||||
|
|
||||||
## Belge haritası
|
## Belge haritası
|
||||||
- `readme.md` — toolbox çerçevesi, built-vs-planned, dil kimliği, çalıştırma modeli.
|
- `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/fikirler.md` — ADR-001…005 (backend stratejisi, parser, header-only, token, IR).
|
||||||
- `docs/adr-frontend-analiz.md` — ADR-006…019 (frontend, analiz/optimizasyon,
|
- `docs/adr-frontend-analiz.md` — ADR-006…026 (frontend, analiz/optimizasyon,
|
||||||
çalıştırma modeli, FFI, interface, bellek).
|
ç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 0–4 → fibonacci).
|
- `docs/roadmap-frontend.md` — faz-faz uygulama planı (Faz 0–4 → fibonacci).
|
||||||
- `docs/transkript-frontend-tasarim.md` — tasarım oturumu transkripti.
|
- `docs/transkript-frontend-tasarim.md` — tasarım oturumu transkripti.
|
||||||
- `examples/fibonacci.sqt` — geçerli referans program.
|
- `examples/fibonacci.sqt` — geçerli referans program.
|
||||||
|
|
@ -97,6 +155,6 @@ git'te izlenir.
|
||||||
|
|
||||||
## Çalışma konvansiyonları
|
## Çalışma konvansiyonları
|
||||||
- Commit mesajları sonunda: `Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>`.
|
- 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
|
- 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.
|
kullanıcı tarafından elle yapıştırılıyor.
|
||||||
|
|
|
||||||
|
|
@ -20,3 +20,99 @@ file(GLOB_RECURSE SOURCES "src/*.cpp")
|
||||||
add_executable(saqut ${SOURCES})
|
add_executable(saqut ${SOURCES})
|
||||||
|
|
||||||
target_include_directories(saqut PRIVATE src)
|
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()
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
||||||
|
Açı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.
|
|
@ -1,23 +1,34 @@
|
||||||
# ninja log v7
|
# ninja log v7
|
||||||
13 4576 1781796718440262330 CMakeFiles/saqut.dir/src/core/sourcefile.cpp.o 20f68631dd335029
|
1 9 1781900092189939762 /home/saqut/Masaüstü/saqutcompiler/build/CMakeFiles/cmake.verify_globs 1813c41e0f312d7e
|
||||||
13 4805 1781796718441539505 CMakeFiles/saqut.dir/src/lexer/lexer.cpp.o 5fd259c0401f3e22
|
10 1691 1781900092199402809 CMakeFiles/saqut.dir/src/ir/ir_program.cpp.o d681b36458a6e5f5
|
||||||
1 2117 1781796771817437208 CMakeFiles/saqut.dir/src/tokenizer/tokenizer.cpp.o fbabe80dcb141239
|
10 1957 1781900092199188672 CMakeFiles/saqut.dir/src/ir/ir_function.cpp.o 85cbc174284792d4
|
||||||
4580 9322 1781796723007277591 CMakeFiles/saqut.dir/src/parser/parser.cpp.o 59cdb5935c541b26
|
10 5411 1781900092199511505 CMakeFiles/saqut.dir/src/lexer/lexer.cpp.o 90eeec811f2137e6
|
||||||
21 6876 1781796718448262357 CMakeFiles/saqut.dir/src/parser/nodes/program.cpp.o 9313cba8d8daffed
|
10 5413 1781900092198939716 CMakeFiles/saqut.dir/src/core/sourcefile.cpp.o da6f5fc90e87e6b1
|
||||||
16 6700 1781796718443848488 CMakeFiles/saqut.dir/src/parser/nodes/identifier.cpp.o e3b5b38d75fcd2ca
|
10 6729 1781900092199847028 CMakeFiles/saqut.dir/src/parser/nodes/declarations.cpp.o b6c56f04a257f685
|
||||||
15 7814 1781796718443331391 CMakeFiles/saqut.dir/src/parser/nodes/expressions.cpp.o 5f5bb01381a3c3ad
|
15 7732 1781900092203939691 CMakeFiles/saqut.dir/src/parser/nodes/expressions.cpp.o 4057e3d63c63a1ab
|
||||||
16 7589 1781796718444498682 CMakeFiles/saqut.dir/src/parser/nodes/literal.cpp.o 55743f37408c5f
|
10 8908 1781900092199302769 CMakeFiles/saqut.dir/src/ir/ir_generator.cpp.o 84c9f816f969cfa7
|
||||||
21 7502 1781796718449424977 CMakeFiles/saqut.dir/src/parser/nodes/statements.cpp.o 3c8869307381c930
|
10 9701 1781900092199743167 CMakeFiles/saqut.dir/src/parser/nodes/binary_expr.cpp.o d2e2bb2f8a63c6d2
|
||||||
14 6864 1781796718442362341 CMakeFiles/saqut.dir/src/parser/nodes/binary_expr.cpp.o 5cc8b697133bcf64
|
1709 9770 1781900093898639567 CMakeFiles/saqut.dir/src/parser/nodes/literal.cpp.o 78f2c4da7c9b2281
|
||||||
15 6733 1781796718442847556 CMakeFiles/saqut.dir/src/parser/nodes/declarations.cpp.o c3d262615ede4c95
|
15 10364 1781900092204948414 CMakeFiles/saqut.dir/src/parser/nodes/identifier.cpp.o eb96bb4b1eb4ad80
|
||||||
1 4629 1781801148234045650 CMakeFiles/saqut.dir/src/main.cpp.o 3cfef7a665d5bf87
|
1957 11871 1781900094145929879 CMakeFiles/saqut.dir/src/parser/nodes/program.cpp.o ac5bbcd74d87561a
|
||||||
4629 4900 1781801152862380672 saqut f2e198803c4dbffb
|
9770 11899 1781900101958890478 CMakeFiles/saqut.dir/src/vm/interpreter.cpp.o 88078036625564ef
|
||||||
0 22 1781801180493522122 build.ninja 1876a59d627a585
|
5413 11959 1781900097601912436 CMakeFiles/saqut.dir/src/parser/parser.cpp.o 2c65b7be26cead32
|
||||||
0 22 1781801180493522122 /home/saqut/Masaüstü/saqutcompiler/build/cmake_install.cmake 1876a59d627a585
|
10 12284 1781900092199621706 CMakeFiles/saqut.dir/src/main.cpp.o 110c26cb1d0c3a23
|
||||||
6733 11112 1781796725160284765 CMakeFiles/saqut.dir/src/symbol/symbol_collector.cpp.o ec4e483b8ddb4007
|
6729 13187 1781900098917905800 CMakeFiles/saqut.dir/src/semantic/structural_validator.cpp.o 4bfec8abc0e9893e
|
||||||
4805 9685 1781796723232278341 CMakeFiles/saqut.dir/src/semantic/structural_validator.cpp.o 248faa3675024351
|
5412 13356 1781900097601088348 CMakeFiles/saqut.dir/src/parser/nodes/statements.cpp.o b5c20724bbf3648c
|
||||||
6700 10405 1781796725127284655 CMakeFiles/saqut.dir/src/semantic/type_checker.cpp.o b29c133293d988b0
|
7733 14099 1781900099922227854 CMakeFiles/saqut.dir/src/semantic/type_checker.cpp.o 15f44776b9c3e26d
|
||||||
1 850 1781801148235507662 CMakeFiles/saqut.dir/src/vm/interpreter.cpp.o b7dd80e002d68a1d
|
9701 14179 1781900101889890826 CMakeFiles/saqut.dir/src/tokenizer/tokenizer.cpp.o a01677f8bb4f4dbc
|
||||||
2 957 1781800866770475511 CMakeFiles/saqut.dir/src/ir/ir_function.cpp.o 10f5e8dfd1461d69
|
8908 14635 1781900101096894819 CMakeFiles/saqut.dir/src/symbol/symbol_collector.cpp.o 3348f498f369213d
|
||||||
2 718 1781800866771246136 CMakeFiles/saqut.dir/src/ir/ir_program.cpp.o 9518231d970828da
|
14635 14953 1781900106823866003 saqut 8f3d7184b374150b
|
||||||
2 3169 1781800866771136888 CMakeFiles/saqut.dir/src/ir/ir_generator.cpp.o 10a1ed4e1f52e530
|
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
|
||||||
|
|
|
||||||
|
|
@ -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:
|
events:
|
||||||
-
|
-
|
||||||
|
|
@ -113,6 +378,65 @@ events:
|
||||||
- "/usr/bin/site_perl"
|
- "/usr/bin/site_perl"
|
||||||
- "/usr/bin/vendor_perl"
|
- "/usr/bin/vendor_perl"
|
||||||
- "/usr/bin/core_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"
|
kind: "find-v1"
|
||||||
backtrace:
|
backtrace:
|
||||||
|
|
@ -162,7 +486,7 @@ events:
|
||||||
- "CMakeLists.txt:2 (project)"
|
- "CMakeLists.txt:2 (project)"
|
||||||
message: |
|
message: |
|
||||||
Compiling the CXX compiler identification source file "CMakeCXXCompilerId.cpp" succeeded.
|
Compiling the CXX compiler identification source file "CMakeCXXCompilerId.cpp" succeeded.
|
||||||
Compiler: /usr/bin/g++
|
Compiler: /usr/bin/c++
|
||||||
Build flags:
|
Build flags:
|
||||||
Id flags:
|
Id flags:
|
||||||
|
|
||||||
|
|
@ -893,8 +1217,8 @@ events:
|
||||||
checks:
|
checks:
|
||||||
- "Detecting CXX compiler ABI info"
|
- "Detecting CXX compiler ABI info"
|
||||||
directories:
|
directories:
|
||||||
source: "/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-KRXVj0"
|
binary: "/home/saqut/Masa\u00fcst\u00fc/saqutcompiler/build/CMakeFiles/CMakeScratch/TryCompile-bNmRFu"
|
||||||
cmakeVariables:
|
cmakeVariables:
|
||||||
CMAKE_CXX_FLAGS: ""
|
CMAKE_CXX_FLAGS: ""
|
||||||
CMAKE_CXX_FLAGS_DEBUG: "-g"
|
CMAKE_CXX_FLAGS_DEBUG: "-g"
|
||||||
|
|
@ -905,19 +1229,19 @@ events:
|
||||||
variable: "CMAKE_CXX_ABI_COMPILED"
|
variable: "CMAKE_CXX_ABI_COMPILED"
|
||||||
cached: true
|
cached: true
|
||||||
stdout: |
|
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
|
Run Build Command(s): /usr/bin/ninja -v cmTC_a8847
|
||||||
[1/2] /usr/bin/g++ -v -o CMakeFiles/cmTC_aae80.dir/CMakeCXXCompilerABI.cpp.o -c /usr/share/cmake/Modules/CMakeCXXCompilerABI.cpp
|
[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.
|
Using built-in specs.
|
||||||
COLLECT_GCC=/usr/bin/g++
|
COLLECT_GCC=/usr/bin/c++
|
||||||
Target: x86_64-pc-linux-gnu
|
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
|
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
|
Thread model: posix
|
||||||
Supported LTO compression algorithms: zlib zstd
|
Supported LTO compression algorithms: zlib zstd
|
||||||
gcc version 16.1.1 20260430 (GCC)
|
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/'
|
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_aae80.dir/ -dumpbase CMakeCXXCompilerABI.cpp.cpp -dumpbase-ext .cpp -mtune=generic -march=x86-64 -version -o /tmp/ccmm6pzq.s
|
/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)
|
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
|
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
|
/usr/include
|
||||||
End of search list.
|
End of search list.
|
||||||
Compiler executable checksum: d47d0c990a24bc0dbaf3bd00656bd5f3
|
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/'
|
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_aae80.dir/CMakeCXXCompilerABI.cpp.o /tmp/ccmm6pzq.s
|
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
|
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/
|
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/
|
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.'
|
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/g++ -v -Wl,-v CMakeFiles/cmTC_aae80.dir/CMakeCXXCompilerABI.cpp.o -o cmTC_aae80 && :
|
[2/2] : && /usr/bin/c++ -v -Wl,-v CMakeFiles/cmTC_a8847.dir/CMakeCXXCompilerABI.cpp.o -o cmTC_a8847 && :
|
||||||
Using built-in specs.
|
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
|
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/lto-wrapper
|
||||||
Target: x86_64-pc-linux-gnu
|
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
|
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)
|
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/
|
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/
|
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.'
|
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/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/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
|
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
|
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
|
exitCode: 0
|
||||||
-
|
-
|
||||||
|
|
@ -995,19 +1319,19 @@ events:
|
||||||
Parsed CXX implicit link information:
|
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)[^/\\]*( |$)]
|
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]+)))("|,| |$)]
|
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: []
|
||||||
ignore line: [Run Build Command(s): /usr/bin/ninja -v cmTC_aae80]
|
ignore line: [Run Build Command(s): /usr/bin/ninja -v cmTC_a8847]
|
||||||
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: [[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: [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: [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: [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: [Thread model: posix]
|
||||||
ignore line: [Supported LTO compression algorithms: zlib zstd]
|
ignore line: [Supported LTO compression algorithms: zlib zstd]
|
||||||
ignore line: [gcc version 16.1.1 20260430 (GCC) ]
|
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: [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_aae80.dir/ -dumpbase CMakeCXXCompilerABI.cpp.cpp -dumpbase-ext .cpp -mtune=generic -march=x86-64 -version -o /tmp/ccmm6pzq.s]
|
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: [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: [ 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: []
|
ignore line: []
|
||||||
|
|
@ -1024,15 +1348,15 @@ events:
|
||||||
ignore line: [ /usr/include]
|
ignore line: [ /usr/include]
|
||||||
ignore line: [End of search list.]
|
ignore line: [End of search list.]
|
||||||
ignore line: [Compiler executable checksum: d47d0c990a24bc0dbaf3bd00656bd5f3]
|
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: [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_aae80.dir/CMakeCXXCompilerABI.cpp.o /tmp/ccmm6pzq.s]
|
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: [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: [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: [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: [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/g++ -v -Wl -v CMakeFiles/cmTC_aae80.dir/CMakeCXXCompilerABI.cpp.o -o cmTC_aae80 && :]
|
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: [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: [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: [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: [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: [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: [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: [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.']
|
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/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]
|
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 [/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/collect2] ==> ignore
|
||||||
arg [-plugin] ==> ignore
|
arg [-plugin] ==> ignore
|
||||||
arg [/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/liblto_plugin.so] ==> 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=/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_s] ==> ignore
|
||||||
arg [-plugin-opt=-pass-through=-lgcc] ==> ignore
|
arg [-plugin-opt=-pass-through=-lgcc] ==> ignore
|
||||||
arg [-plugin-opt=-pass-through=-latomic_asneeded] ==> ignore
|
arg [-plugin-opt=-pass-through=-latomic_asneeded] ==> ignore
|
||||||
|
|
@ -1063,7 +1387,7 @@ events:
|
||||||
arg [/lib64/ld-linux-x86-64.so.2] ==> ignore
|
arg [/lib64/ld-linux-x86-64.so.2] ==> ignore
|
||||||
arg [-pie] ==> ignore
|
arg [-pie] ==> ignore
|
||||||
arg [-o] ==> 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/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/../../../../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]
|
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/lib] ==> dir [/lib]
|
||||||
arg [-L/usr/lib] ==> dir [/usr/lib]
|
arg [-L/usr/lib] ==> dir [/usr/lib]
|
||||||
arg [-v] ==> ignore
|
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 [-lstdc++] ==> lib [stdc++]
|
||||||
arg [-lm] ==> lib [m]
|
arg [-lm] ==> lib [m]
|
||||||
arg [-lgcc_s] ==> lib [gcc_s]
|
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/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]
|
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: [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
|
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/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]
|
collapse obj [/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/crti.o] ==> [/usr/lib/crti.o]
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
/home/saqut/Masaüstü/saqutcompiler/build/CMakeFiles/saqut.dir
|
/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/edit_cache.dir
|
||||||
/home/saqut/Masaüstü/saqutcompiler/build/CMakeFiles/rebuild_cache.dir
|
/home/saqut/Masaüstü/saqutcompiler/build/CMakeFiles/rebuild_cache.dir
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
# This file is generated by CMake for checking of the VerifyGlobs.cmake file
|
||||||
|
|
@ -79,6 +79,15 @@ rule RERUN_CMAKE
|
||||||
generator = 1
|
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.
|
# Rule for cleaning all built files.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
@ -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()
|
||||||
|
|
@ -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()
|
||||||
|
|
@ -10,12 +10,11 @@
|
||||||
> Tartışmanın tam akışı için bkz. `docs/transkript-frontend-tasarim.md`.
|
> Tartışmanın tam akışı için bkz. `docs/transkript-frontend-tasarim.md`.
|
||||||
> Uygulama planı için bkz. `docs/roadmap-frontend.md`.
|
> Uygulama planı için bkz. `docs/roadmap-frontend.md`.
|
||||||
>
|
>
|
||||||
> ⚠️ **Yapılan vs planlanan:** Bu belgedeki ADR-006…019 **tasarım kararlarıdır**;
|
> ✅ **Uygulama durumu:** Bu belgedeki ADR-006…019 kararlarında tarif edilen
|
||||||
> tarif edilen makine (sembol tablosu, semantik analiz, tip sistemi, diagnostic,
|
> makine **kodlandı ve çalışıyor.** Sembol tablosu, semantik analiz, tip sistemi,
|
||||||
> optimizasyon, IR+VM) **henüz kodlanmamıştır.** Bugün çalışan: lexer, tokenizer,
|
> diagnostic motoru, optimizasyon (constant folding + DCE), IR üreteci ve bytecode
|
||||||
> Pratt parser, AST, AST'nin JSON serileştirmesi, CLI iskeleti, konum takibi ve
|
> VM'in tamamı uygulandı. `examples/fibonacci.sqt` uçtan uca çalışıyor.
|
||||||
> basit aritmetiği düşüren minimal bir IR deneyi. Hiçbir ADR, var olmayan bir
|
> Güncel "çalışıyor / henüz yok" listesi için bkz. `CLAUDE.md`.
|
||||||
> mekanizmayı varmış gibi anlatmaz.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -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.
|
symbol bağı, erişilebilirlik, constness ekler). Ağacı **bozmaz**, zenginleştirir.
|
||||||
Orijinal AST hâlâ kaynak kodun tam izdüşümüdür.
|
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.**
|
2. **Optimizasyon dönüşümü iki yolla yapılabilir:**
|
||||||
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.
|
|
||||||
|
|
||||||
**Sonuç:** Hem "bellek canavarı" felsefesi korunur (orijinal AST her şeyi tutar),
|
a. **`ast` komutu için klon:** orijinal AST dokunulmadan kalır, klon üstünde
|
||||||
hem optimizasyon yapılır, hem de öncesi/sonrası ayrı ayrı incelenebilir.
|
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 → ham + annotate edilmiş AST (1+2 burada durur)
|
||||||
saqut ast file.sqt --optimized → klon, folding uygulanmış (3 var)
|
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
|
`deepClone` sembol tablosunu yeniden eşlemez (remap etmez) — klondaki
|
||||||
alıyor** ve bir **tutarlılık (coherence) problemini** atlıyordu. Düzeltme:
|
`IdentifierNode::resolvedSymbol` orijinal `Symbol` nesnelerini gösterir. Bu
|
||||||
|
**güvenlidir**, çünkü:
|
||||||
|
|
||||||
`ASTNode::clone()` "belki gerekir" değil, **merkezi ve spesifiye edilmesi
|
- `Symbol::references` bir **konum listesi** (`std::vector<SourceLocation>`),
|
||||||
zorunlu** bir bileşendir; tüm öncesi/sonrası hikâyesi ona dayanır (bkz. roadmap
|
referans sayacı değildir. Klonda bir `IdentifierNode` silindiğinde bu liste
|
||||||
Faz 4'te clone() yükseltildi).
|
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`'ı
|
Önceki versiyon "sembol tablosu klonlanır ve remap edilir" diyordu; bu hem hiç
|
||||||
orijinali değil, klonu göstermeli; yoksa yapısal doğrulama ve dönüşümler
|
implement edilmedi hem de gerekli değildi. Düzeltildi.
|
||||||
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.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -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)
|
### 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
|
Önceki kaygı ("scope çıkışında free, aliasing/escape altında bozulur") kilitli
|
||||||
dil kimliğiyle **lehte çözüldü:**
|
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
|
## Kararların Özet Tablosu
|
||||||
|
|
||||||
| ADR | Konu | Karar |
|
| ADR | Konu | Karar |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| 006 | Frontend mimarisi | Çok-aşamalı; frontend/middle-end/backend katmanları |
|
| 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 |
|
| 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 |
|
| 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 |
|
| 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 |
|
| 017 | Batteries/stdlib | Sınır problemi; küçük builtin + FFI/kütüphane; ertelendi |
|
||||||
| 018 | `interface` | Ertelendi (reddedilmedi); struct+fonksiyon yeter |
|
| 018 | `interface` | Ertelendi (reddedilmedi); struct+fonksiyon yeter |
|
||||||
| 019 | Frontend↔runtime | Frontend yapı+anlam; çekirdek/cihaz/çıktı runtime'a ait |
|
| 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 |
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
@ -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.
|
||||||
|
|
@ -18,9 +18,10 @@
|
||||||
> **çok uzak gelecektir**. ADR-001'deki karşılaştırmalar o gün için geçerli.
|
> **ç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
|
> - "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).
|
> 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
|
> - **Yapılan vs planlanan:** Tüm pipeline uygulandı. `examples/fibonacci.sqt`
|
||||||
> (lexer/tokenizer/parser/AST + minimal IR deneyi çalışır); kod üretimi ve VM
|
> uçtan uca çalışıyor (lexer → tokenizer → parser → sembol tablosu → tip
|
||||||
> **henüz yoktur.**
|
> denetleyici → optimizasyon → IR üreteci → bytecode VM). ADR-001'deki
|
||||||
|
> "mevcut durum" listesi artık tarihseldir; güncel durum için bkz. `CLAUDE.md`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,21 +10,12 @@
|
||||||
> yorum satırlarıyla takip edilebilir olmalıdır (header-only tarzı korunur,
|
> yorum satırlarıyla takip edilebilir olmalıdır (header-only tarzı korunur,
|
||||||
> bkz. ADR-003).
|
> bkz. ADR-003).
|
||||||
>
|
>
|
||||||
> ⚠️ **Yapılan vs planlanan:** Bugün çalışan = lexer, tokenizer, Pratt parser,
|
> ✅ **Birinci kilometre taşı AŞILDI.** Faz 0–4 uygulandı; `examples/fibonacci.sqt`
|
||||||
> AST, AST'nin JSON serileştirmesi, CLI iskeleti, konum takibi, basit aritmetiği
|
> uçtan uca çalışıyor. Bu yol haritası artık tarihsel bir referanstır.
|
||||||
> düşüren minimal IR deneyi. Bu yol haritasındaki **her şey planlıdır** (sembol
|
|
||||||
> tablosu, semantik analiz, tip sistemi, diagnostic, optimizasyon).
|
|
||||||
>
|
>
|
||||||
> 🎯 **Bu haftanın işi:** **sembol tablosu + iki-geçişli toplayıcı** (Faz 2),
|
> **Sonraki hedefler:** float/double codegen, struct IR, array IR, açık bug'lar
|
||||||
> hedef **"fibonacci'yi derle ve çalıştır"** (`examples/fibonacci.sqt`). Faz 0–1
|
> (#35 bellek sızıntısı, #36 W003 uyarısı, #37 `%=` IR, #38 global değişken IR).
|
||||||
> bunun önkoşuludur.
|
> Güncel "çalışıyor / henüz yok" listesi için bkz. `CLAUDE.md`.
|
||||||
>
|
|
||||||
> 🧭 **Önce dikey dilim, sonra çerçeve.** Bir şey çalışmadan önce genel pass
|
|
||||||
> manager / evrensel config / ağır soyutlama inşa etme. Uçtan uca tek bir dilim
|
|
||||||
> (kaynak → IR → çalıştır; tamsayı + değişken + kontrol akışı + tek `print`)
|
|
||||||
> önce çalışsın. Faz 4'ün framework'ü (OptimizationManager, fixpoint, config)
|
|
||||||
> ancak Faz 0–3 fibonacci'yi geçirdikten **sonra** anlam kazanır — erken
|
|
||||||
> soyutlama daha az değil, daha çok karmaşıklıktır.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -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ı.
|
**Bağımlılık:** yok. **Hedef:** her şeyin üstüne kurulacağı temel veri yapıları.
|
||||||
İlgili ADR: 010 (Type), 013 (Diagnostic).
|
İ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
|
**Bağımlılık:** Faz 0 (Type). **Hedef:** node hiyerarşisini ifade/deyim olarak
|
||||||
ayır, analiz alanlarını ekle. İlgili ADR: 012, 013.
|
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.
|
**Bağımlılık:** Faz 0, 1. **Hedef:** isim çözümleme + scope + referans toplama.
|
||||||
İlgili ADR: 011, 013.
|
İ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ı
|
**Bağımlılık:** Faz 2. **Hedef:** tipleri ata/kontrol et, yapısal kuralları
|
||||||
doğrula. İlgili ADR: 010, 013.
|
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
|
**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.
|
optimizasyon. **Orijinali bozmaz — klon üstünde** (ADR-007). İlgili ADR: 007, 008, 009.
|
||||||
|
|
|
||||||
|
|
@ -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. |
|
||||||
|
|
||||||
|
Açık mimari borç: **#56** (döngüsel referans → mark-sweep GC v2). Şimdilik toplama yok, bilinçli.
|
||||||
|
|
||||||
|
**Mevcut kod durumu:**
|
||||||
|
- int-only pipeline uçtan uca çalışıyor (`examples/fibonacci.sqt`).
|
||||||
|
- `src/vm/value.hpp` → `Value` = `{ ValueKind kind; int intValue; std::string stringValue; }`. String **inline** (immutable olduğu için yeterli — taşıma zorunlu değil).
|
||||||
|
- `src/ir/` → 3-adresli IR, slot tabanlı. `instruction.hpp`, `ir_generator.cpp`, `ir_program.hpp`.
|
||||||
|
- `src/vm/interpreter.cpp` → bytecode yorumlayıcı döngü. `call_frame.hpp` çağrı çerçevesi.
|
||||||
|
- struct/array: parser + semantik **var**, IR/VM codegen **YOK**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. İlk görev — GC-hazır nesne modeli + ARRAY runtime (dikey dilim)
|
||||||
|
|
||||||
|
**Neden array, string değil:** string zaten immutable-değer olarak inline çalışıyor;
|
||||||
|
asıl kararları (referans semantiği + GC-hazır nesne modeli + kimlik eşitliği)
|
||||||
|
**doğrulayan** ilk gerçek referans-tipi array'dir. Bu görev, struct'ın da oturacağı
|
||||||
|
temeli atar.
|
||||||
|
|
||||||
|
### KAPSAM DIŞI (bu görevde YAPMA — sonraki görevler)
|
||||||
|
- ❌ Gerçek çöp toplama (mark-sweep). ADR-022 v1 = toplama yok. Sadece header +
|
||||||
|
all-objects listesi + kök-sayımı *kancasını* kur.
|
||||||
|
- ❌ Tam null akış-analizi (ADR-021). `int[]?` parse edilebilir ama flow-narrowing
|
||||||
|
bu görevde değil.
|
||||||
|
- ❌ struct codegen, string UTF-8 cilası, builder. Ayrı görevler (Bölüm 2).
|
||||||
|
- ❌ `shared_ptr` ile nesne sahipliği. Düz `Object*` + intrusive liste.
|
||||||
|
|
||||||
|
### Adım 1.1 — Nesne modeli temeli (`src/vm/object.hpp` veya benzeri)
|
||||||
|
```cpp
|
||||||
|
enum class ObjectType { Array /*, Struct, String (ileride) */ };
|
||||||
|
|
||||||
|
struct Object {
|
||||||
|
ObjectType type;
|
||||||
|
bool marked = false; // mark-sweep için (v2); şimdilik kullanılmaz
|
||||||
|
Object* next = nullptr; // intrusive "tüm nesneler" listesi (mark-sweep tarayışı için)
|
||||||
|
};
|
||||||
|
```
|
||||||
|
- Bir **Heap/allocator**: `Object* allocate(...)` her yeni nesneyi `next` zincirine
|
||||||
|
ekler. **Free yok** (v1). Yıkıcıda/process exit'te toptan bırak.
|
||||||
|
- **Kök sayımı kancası:** VM'in operand stack + frame local'leri + global slot'lar
|
||||||
|
üstünden referansları gezebileceği bir yol bırak (şimdilik imza/TODO yeterli; içini
|
||||||
|
doldurmak v2). `// TODO(#56): mark-sweep kök taraması buradan` ile işaretle.
|
||||||
|
|
||||||
|
### Adım 1.2 — `Value`'yu referans taşıyacak şekilde genişlet (`src/vm/value.hpp`)
|
||||||
|
- `ValueKind`'a `Ref` ekle (array/struct nesnelerine `Object*`).
|
||||||
|
- `Value`'ya `Object* ref = nullptr;` alanı + `static Value fromRef(Object*)`.
|
||||||
|
- `Nil` kind ekle (ADR-021 null: `Type?` null değeri ve referans varsayılanı).
|
||||||
|
- `isTruthy`/`toString`/`typeName`'i yeni kind'lar için genişlet.
|
||||||
|
- String inline kalsın (`ValueKind::String`), dokunma.
|
||||||
|
|
||||||
|
### Adım 1.3 — ArrayObject
|
||||||
|
```cpp
|
||||||
|
struct ArrayObject : Object { // type = ObjectType::Array
|
||||||
|
std::vector<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ı açık API
|
||||||
|
olarak işaretle. (İstege bağlı: string'i de Object modeline taşıyıp intern et —
|
||||||
|
zorunlu değil.)
|
||||||
|
3. **Null akış-analizi (ADR-021 — 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.
|
||||||
|
|
@ -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
347
readme.md
|
|
@ -1,225 +1,186 @@
|
||||||
# saQut
|
# 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,
|
saqut tokens file:fib.sqt → token stream, JSON
|
||||||
AST, sembol tablosu, optimizasyonun öncesi/sonrası ve IR — hepsi ayrı ayrı
|
saqut ast file:fib.sqt → full AST, JSON
|
||||||
incelenebilir. Dil, bu aletin üzerinde çalıştığı küçük, prosedürel bir
|
saqut ast file:fib.sqt --optimized → constant-folded + DCE'd AST
|
||||||
örnektir; vitrin değil, alet.
|
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)
|
You can pipe `saqut ast` into your own tool.
|
||||||
- **Lexer** — karakter seviyesi tarama, konum takibi.
|
You can hand the optimized AST diff to a review script.
|
||||||
- **Tokenizer** — token üretimi (6 token tipi), yorum satırı desteği.
|
A stranger with no access to source could write an LSP from `saqut symbols` output alone.
|
||||||
- **Pratt parser** — ifade (Pratt) + statement (recursive descent) ayrıştırma.
|
That is the test saQut is designed to pass.
|
||||||
- **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)
|
## The language looks like this
|
||||||
|
|
||||||
Prosedürel, **C ailesi sözdizimi**, **value semantics**. İlk ifade doğrudan bir
|
```c
|
||||||
işlem/tanım olabilir; zorunlu class/`main` boilerplate'i yoktur (Java'nın aksine).
|
int fibonacci(int n) {
|
||||||
|
if (n <= 1) {
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
return fibonacci(n - 1) + fibonacci(n - 2);
|
||||||
|
}
|
||||||
|
|
||||||
| Ö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** |
|
| `saqut tokens file:src.sqt` | Token stream with positions |
|
||||||
| Closure | **Yok** |
|
| `saqut ast file:src.sqt` | Full AST as JSON |
|
||||||
| Generic | **Yok** |
|
| `saqut ast file:src.sqt --optimized` | AST after constant folding + dead-code elimination |
|
||||||
| Kullanıcıya açık pointer (`*` / `&`) | **Yok** — derleyici/runtime içeride pointer'ı serbestçe kullanır |
|
| `saqut symbols file:src.sqt` | Symbol table dump |
|
||||||
| `struct` | **Var** |
|
| `saqut check file:src.sqt` | Semantic analysis only — errors and warnings, JSON |
|
||||||
| Tipli fonksiyonlar (dönüş + parametre) | **Var** |
|
| `saqut ir file:src.sqt` | IR instruction dump |
|
||||||
| Array (`int[]`) | **Var** |
|
| `saqut run file:src.sqt` | Compile and run via bytecode VM |
|
||||||
| `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
|
Every output is designed to be piped, diffed, or consumed by other tools.
|
||||||
(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
|
## Pipeline
|
||||||
|
|
||||||
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
|
Source
|
||||||
│ lexer
|
│ Lexer + Tokenizer
|
||||||
▼
|
▼
|
||||||
TOKEN'LAR ────────────── saqut tokens
|
Tokens ──────────────────── saqut tokens
|
||||||
│ parser (Pratt + recursive descent)
|
│ Pratt parser + recursive descent
|
||||||
▼
|
▼
|
||||||
AST ──────────────────── saqut ast
|
AST ─────────────────────── saqut ast
|
||||||
│ sembol toplama (iki geçişli) ┐
|
│ Symbol collector (two-pass)
|
||||||
▼ │
|
▼
|
||||||
SEMBOL TABLOSU ───────── saqut symbols │ FRONTEND
|
Symbol Table ────────────── saqut symbols
|
||||||
│ semantik analiz (annotation) │ (yapı + anlam)
|
│ Type checker + structural validator
|
||||||
▼ │
|
▼
|
||||||
ANNOTATE EDİLMİŞ AST ─── saqut ast ┘
|
Annotated AST
|
||||||
│ optimizasyon (opsiyonel, klon üstünde) ── MIDDLE-END
|
│ Optimization Manager (clone — original untouched)
|
||||||
▼
|
│ ├─ Constant Folding pass
|
||||||
IR ───────────────────── (planlanan) ┐
|
│ └─ Dead Code Elimination pass
|
||||||
│ bytecode VM / yorumlayıcı döngü │ BACKEND
|
▼
|
||||||
▼ │ (çalıştırma + FFI seam)
|
Optimized AST ───────────── saqut ast --optimized
|
||||||
ÇALIŞTIRMA / ÇIKTI ───── saqut run ┘
|
│ IR Generator
|
||||||
|
▼
|
||||||
|
IR ──────────────────────── saqut ir
|
||||||
|
│ Bytecode VM (interpreter loop)
|
||||||
|
▼
|
||||||
|
Output ──────────────────── saqut run
|
||||||
```
|
```
|
||||||
|
|
||||||
- **Frontend** yapıyı ve anlamı modeller (tip, scope, dataflow).
|
The optimizer works on a **clone** of the AST — the original is preserved.
|
||||||
- **"Hangi çekirdek, hangi cihaz, ne zaman, hangi çıktı formatı"** runtime/backend
|
Constant folding and DCE run in a fixpoint loop until nothing changes.
|
||||||
meselesidir — frontend'e yüklenmez.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## CLI (mevcut + planlanan)
|
## What works right now
|
||||||
|
|
||||||
```
|
| Stage | Status |
|
||||||
# --- ç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 |
|
| Lexer / Tokenizer | ✅ |
|
||||||
| `docs/adr-frontend-analiz.md` | ADR-006…019: frontend, analiz/optimizasyon, çalıştırma modeli, FFI, interface, bellek |
|
| Pratt parser | ✅ |
|
||||||
| `docs/roadmap-frontend.md` | Faz-faz uygulama planı (sembol tablosu → fibonacci) |
|
| AST + JSON serialization | ✅ |
|
||||||
| `docs/transkript-frontend-tasarim.md` | Tasarım oturumunun transkripti |
|
| Symbol table (two-pass collector) | ✅ |
|
||||||
| `examples/fibonacci.sqt` | Geçerli referans program (semantik + kod üretimi fixture'ı) |
|
| Type checker | ✅ |
|
||||||
| `examples/parser-stress/` | Yalnızca parser'ı zorlayan, **geçerli olmayan** fixture'lar |
|
| 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
|
**Glass:** every compilation stage is a stable, queryable output — tokens, AST, symbols, IR — all separately inspectable and pipeable.
|
||||||
dikey dilim** çalıştır (kaynak → IR → çalıştır; tamsayı aritmetiği + değişken +
|
**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.
|
||||||
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
|
The long version is in [`docs/architecture.md`](docs/architecture.md).
|
||||||
çok** karmaşıklıktır.
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Design records
|
||||||
|
|
||||||
|
Architectural decisions live in `docs/`:
|
||||||
|
|
||||||
|
| File | Coverage |
|
||||||
|
|---|---|
|
||||||
|
| [`docs/fikirler.md`](docs/fikirler.md) | ADR-001–005: backend strategy, parser, header-only, token, IR |
|
||||||
|
| [`docs/adr-frontend-analiz.md`](docs/adr-frontend-analiz.md) | ADR-006–019: 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
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,12 @@
|
||||||
#include "parser/parser.hpp"
|
#include "parser/parser.hpp"
|
||||||
#include "symbol/symbol_table.hpp"
|
#include "symbol/symbol_table.hpp"
|
||||||
#include "symbol/symbol_collector.hpp"
|
#include "symbol/symbol_collector.hpp"
|
||||||
|
#include "semantic/type_checker.hpp"
|
||||||
|
#include "semantic/structural_validator.hpp"
|
||||||
#include "diagnostic/diagnostic_engine.hpp"
|
#include "diagnostic/diagnostic_engine.hpp"
|
||||||
#include "ir/ir_generator.hpp"
|
#include "ir/ir_generator.hpp"
|
||||||
|
#include "core/config.hpp"
|
||||||
|
#include "opt/optimization_manager.hpp"
|
||||||
|
|
||||||
inline int cmdIr(const CliArgs& args) {
|
inline int cmdIr(const CliArgs& args) {
|
||||||
std::string filePath = inputFilePath(args);
|
std::string filePath = inputFilePath(args);
|
||||||
|
|
@ -29,6 +33,8 @@ inline int cmdIr(const CliArgs& args) {
|
||||||
SymbolTable symbolTable;
|
SymbolTable symbolTable;
|
||||||
DiagnosticEngine diag;
|
DiagnosticEngine diag;
|
||||||
SymbolCollector(symbolTable, diag).collect(ast);
|
SymbolCollector(symbolTable, diag).collect(ast);
|
||||||
|
TypeChecker(symbolTable, diag).check(ast);
|
||||||
|
StructuralValidator(diag).validate(ast);
|
||||||
|
|
||||||
if (diag.hasErrors()) {
|
if (diag.hasErrors()) {
|
||||||
diag.printAll(std::cerr);
|
diag.printAll(std::cerr);
|
||||||
|
|
@ -37,9 +43,18 @@ inline int cmdIr(const CliArgs& args) {
|
||||||
return 1;
|
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;
|
IRGenerator irGenerator;
|
||||||
IRProgram program = irGenerator.generate(ast, symbolTable);
|
IRProgram program = irGenerator.generate(ast, symbolTable);
|
||||||
|
|
||||||
program.dump();
|
program.dump();
|
||||||
|
|
||||||
delete ast;
|
delete ast;
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,11 @@
|
||||||
// saQut CLI — run komutu
|
// saQut CLI — run komutu
|
||||||
//
|
//
|
||||||
// Tam derleme + çalıştırma pipeline'ı:
|
// 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:
|
// --optimized bayrağı: AST yerinde optimize edilir (klon yok — sadece tek versiyon
|
||||||
// build/saqut run file:examples/fibonacci.sqt
|
// gerekiyor). ast komutu orijinali saklaması gerektiği için klon kullanır; run/ir
|
||||||
// → 55
|
// kullanmaz. Aynı pattern ir.hpp'de de var — paralel değişikliklerde ikisine bak.
|
||||||
// → 55
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
#ifndef SAQUT_CLI_RUN
|
#ifndef SAQUT_CLI_RUN
|
||||||
|
|
@ -22,6 +21,8 @@
|
||||||
#include "semantic/type_checker.hpp"
|
#include "semantic/type_checker.hpp"
|
||||||
#include "semantic/structural_validator.hpp"
|
#include "semantic/structural_validator.hpp"
|
||||||
#include "diagnostic/diagnostic_engine.hpp"
|
#include "diagnostic/diagnostic_engine.hpp"
|
||||||
|
#include "core/config.hpp"
|
||||||
|
#include "opt/optimization_manager.hpp"
|
||||||
#include "ir/ir_generator.hpp"
|
#include "ir/ir_generator.hpp"
|
||||||
#include "vm/interpreter.hpp"
|
#include "vm/interpreter.hpp"
|
||||||
|
|
||||||
|
|
@ -43,7 +44,7 @@ inline int cmdRun(const CliArgs& args) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Aşama 3: Sembol toplama ───────────────────────────────────────────
|
// ── Aşama 3: Sembol toplama + semantik analiz ─────────────────────────
|
||||||
// Identifier'ların resolvedSymbol'ü doldurulur — IR generator buna ihtiyaç duyar.
|
// Identifier'ların resolvedSymbol'ü doldurulur — IR generator buna ihtiyaç duyar.
|
||||||
SymbolTable symbolTable;
|
SymbolTable symbolTable;
|
||||||
DiagnosticEngine diag;
|
DiagnosticEngine diag;
|
||||||
|
|
@ -59,11 +60,22 @@ inline int cmdRun(const CliArgs& args) {
|
||||||
return 1;
|
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;
|
IRGenerator irGenerator;
|
||||||
IRProgram program = irGenerator.generate(ast, symbolTable);
|
IRProgram program = irGenerator.generate(ast, symbolTable);
|
||||||
|
|
||||||
// ── Aşama 5: VM çalıştırma ────────────────────────────────────────────
|
// ── Aşama 6: VM çalıştırma ────────────────────────────────────────────
|
||||||
int exitCode = 0;
|
int exitCode = 0;
|
||||||
try {
|
try {
|
||||||
Interpreter vm(program);
|
Interpreter vm(program);
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,7 @@ struct Type {
|
||||||
std::shared_ptr<Type> returnType; // kind == Function
|
std::shared_ptr<Type> returnType; // kind == Function
|
||||||
std::vector<Type> paramTypes; // kind == Function
|
std::vector<Type> paramTypes; // kind == Function
|
||||||
std::string structName; // kind == Struct
|
std::string structName; // kind == Struct
|
||||||
|
bool nullable = false; // ADR-021: Type? sözdizimi
|
||||||
|
|
||||||
// ------------------------------------------------------------------ //
|
// ------------------------------------------------------------------ //
|
||||||
// Factory'ler
|
// Factory'ler
|
||||||
|
|
@ -132,11 +133,26 @@ struct Type {
|
||||||
prim == PrimitiveKind::Double);
|
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)
|
// 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 {
|
bool equals(const Type& o) const {
|
||||||
if (kind != o.kind) return false;
|
if (kind != o.kind) return false;
|
||||||
|
if (nullable != o.nullable) return false;
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case TypeKind::Primitive:
|
case TypeKind::Primitive:
|
||||||
return prim == o.prim;
|
return prim == o.prim;
|
||||||
|
|
@ -154,13 +170,14 @@ struct Type {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case TypeKind::Error:
|
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 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ı
|
// İsim yardımcıları
|
||||||
// ------------------------------------------------------------------ //
|
// ------------------------------------------------------------------ //
|
||||||
|
|
@ -177,10 +194,15 @@ struct Type {
|
||||||
return "?";
|
return "?";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bir tip adından (parser tipleri string olarak tutar) primitif Type üretir.
|
// Bir tip adından (parser tipleri string olarak tutar) Type üretir.
|
||||||
// Bilinen primitif değilse Error döner — bilinmeyen tip adının teşhisi
|
// "int?" → nullable int; "int[]" → int array; bilinen değilse Error.
|
||||||
// (E007) çağıranın (Faz 2/3) işidir; bu fonksiyon sessizce Error verir.
|
|
||||||
static Type fromName(const std::string& n) {
|
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 == "int") return Int();
|
||||||
if (n == "float") return Float();
|
if (n == "float") return Float();
|
||||||
if (n == "double") return Double();
|
if (n == "double") return Double();
|
||||||
|
|
@ -188,6 +210,11 @@ struct Type {
|
||||||
if (n == "string") return String();
|
if (n == "string") return String();
|
||||||
if (n == "bool") return Bool();
|
if (n == "bool") return Bool();
|
||||||
if (n == "void") return Void();
|
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();
|
return error();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -195,27 +222,28 @@ struct Type {
|
||||||
// toString — İnsan-okur ("int", "int[]", "fn(int,int)->int")
|
// toString — İnsan-okur ("int", "int[]", "fn(int,int)->int")
|
||||||
// ------------------------------------------------------------------ //
|
// ------------------------------------------------------------------ //
|
||||||
std::string toString() const {
|
std::string toString() const {
|
||||||
|
std::string base;
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case TypeKind::Primitive:
|
case TypeKind::Primitive:
|
||||||
return primName(prim);
|
base = primName(prim); break;
|
||||||
case TypeKind::Array:
|
case TypeKind::Array:
|
||||||
return (elementType ? elementType->toString() : "<?>") + "[]";
|
base = (elementType ? elementType->toString() : "<?>") + "[]"; break;
|
||||||
case TypeKind::Struct:
|
case TypeKind::Struct:
|
||||||
return "struct " + structName;
|
base = "struct " + structName; break;
|
||||||
case TypeKind::Function: {
|
case TypeKind::Function: {
|
||||||
std::string s = "fn(";
|
base = "fn(";
|
||||||
for (size_t i = 0; i < paramTypes.size(); ++i) {
|
for (size_t i = 0; i < paramTypes.size(); ++i) {
|
||||||
if (i) s += ",";
|
if (i) base += ",";
|
||||||
s += paramTypes[i].toString();
|
base += paramTypes[i].toString();
|
||||||
}
|
}
|
||||||
s += ")->";
|
base += ")->";
|
||||||
s += returnType ? returnType->toString() : "<?>";
|
base += returnType ? returnType->toString() : "<?>";
|
||||||
return s;
|
break;
|
||||||
}
|
}
|
||||||
case TypeKind::Error:
|
case TypeKind::Error:
|
||||||
return "<error>";
|
return "<error>";
|
||||||
}
|
}
|
||||||
return "<?>";
|
return nullable ? base + "?" : base;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------ //
|
// ------------------------------------------------------------------ //
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@
|
||||||
// LESS/LEQ/... : dest, left, right (sonuç: 1=doğru, 0=yanlış)
|
// LESS/LEQ/... : dest, left, right (sonuç: 1=doğru, 0=yanlış)
|
||||||
// JMP : jumpTarget
|
// JMP : jumpTarget
|
||||||
// JIF_FALSE : cond, jumpTarget
|
// JIF_FALSE : cond, jumpTarget
|
||||||
|
// JIF_TRUE : cond, jumpTarget
|
||||||
// CALL : dest, functionName, argSlots
|
// CALL : dest, functionName, argSlots
|
||||||
// RETURN : src
|
// RETURN : src
|
||||||
// CALLHOST : functionName, argSlots
|
// CALLHOST : functionName, argSlots
|
||||||
|
|
@ -41,6 +42,7 @@ enum class Opcode {
|
||||||
// Örnek: LOAD_CONST dest=3 val=10 → slot[3] = 10
|
// Örnek: LOAD_CONST dest=3 val=10 → slot[3] = 10
|
||||||
|
|
||||||
LOAD_STRING, // slots[dest] = stringValue (metin sabitini slota yükle)
|
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"
|
// Örnek: LOAD_STRING dest=2 val="Merhaba" → slot[2] = "Merhaba"
|
||||||
|
|
||||||
LOAD_SLOT, // slots[dest] = slots[src]
|
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
|
DIV, // UYARI: sıfıra bölme → runtime_error fırlatılır
|
||||||
MOD,
|
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ış) ---
|
// --- Karşılaştırma (sonuç: 1 = doğru, 0 = yanlış) ---
|
||||||
LESS, // slots[left] < slots[right]
|
LESS, // slots[left] < slots[right]
|
||||||
LESS_EQUAL, // slots[left] <= slots[right]
|
LESS_EQUAL, // slots[left] <= slots[right]
|
||||||
|
|
@ -64,7 +73,8 @@ enum class Opcode {
|
||||||
|
|
||||||
// --- Kontrol akışı ---
|
// --- Kontrol akışı ---
|
||||||
JMP, // Koşulsuz atlama: ip = jumpTarget
|
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ı ---
|
// --- Fonksiyon çağrısı ---
|
||||||
CALL, // Başka bir saQut fonksiyonunu çağır.
|
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.
|
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) ---
|
// --- Dış dünya (FFI — Foreign Function Interface) ---
|
||||||
CALLHOST, // Host (C++) fonksiyonunu çağır. Şu an sadece "print" destekli.
|
CALLHOST, // Host (C++) fonksiyonunu çağır. Şu an sadece "print" destekli.
|
||||||
// Dönüş değeri yok; sadece yan etki (stdout'a yazmak gibi).
|
// Dönüş değeri yok; sadece yan etki (stdout'a yazmak gibi).
|
||||||
|
|
@ -83,12 +134,35 @@ inline const char* opcodeName(Opcode op) {
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case Opcode::LOAD_CONST: return "LOAD_CONST";
|
case Opcode::LOAD_CONST: return "LOAD_CONST";
|
||||||
case Opcode::LOAD_STRING: return "LOAD_STRING";
|
case Opcode::LOAD_STRING: return "LOAD_STRING";
|
||||||
|
case Opcode::LOAD_NULL: return "LOAD_NULL";
|
||||||
case Opcode::LOAD_SLOT: return "LOAD_SLOT";
|
case Opcode::LOAD_SLOT: return "LOAD_SLOT";
|
||||||
case Opcode::ADD: return "ADD";
|
case Opcode::ADD: return "ADD";
|
||||||
case Opcode::SUB: return "SUB";
|
case Opcode::SUB: return "SUB";
|
||||||
case Opcode::MUL: return "MUL";
|
case Opcode::MUL: return "MUL";
|
||||||
case Opcode::DIV: return "DIV";
|
case Opcode::DIV: return "DIV";
|
||||||
case Opcode::MOD: return "MOD";
|
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: return "LESS";
|
||||||
case Opcode::LESS_EQUAL: return "LESS_EQUAL";
|
case Opcode::LESS_EQUAL: return "LESS_EQUAL";
|
||||||
case Opcode::GREATER: return "GREATER";
|
case Opcode::GREATER: return "GREATER";
|
||||||
|
|
@ -97,8 +171,13 @@ inline const char* opcodeName(Opcode op) {
|
||||||
case Opcode::NOT_EQUAL: return "NOT_EQUAL";
|
case Opcode::NOT_EQUAL: return "NOT_EQUAL";
|
||||||
case Opcode::JMP: return "JMP";
|
case Opcode::JMP: return "JMP";
|
||||||
case Opcode::JIF_FALSE: return "JIF_FALSE";
|
case Opcode::JIF_FALSE: return "JIF_FALSE";
|
||||||
|
case Opcode::JIF_TRUE: return "JIF_TRUE";
|
||||||
case Opcode::CALL: return "CALL";
|
case Opcode::CALL: return "CALL";
|
||||||
case Opcode::RETURN: return "RETURN";
|
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";
|
case Opcode::CALLHOST: return "CALLHOST";
|
||||||
}
|
}
|
||||||
return "UNKNOWN";
|
return "UNKNOWN";
|
||||||
|
|
@ -128,6 +207,9 @@ struct Instruction {
|
||||||
// LOAD_CONST için yüklenecek tam sayı sabiti
|
// LOAD_CONST için yüklenecek tam sayı sabiti
|
||||||
int intValue = 0;
|
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)
|
// LOAD_STRING için yüklenecek metin sabiti (tırnak işaretleri olmadan)
|
||||||
std::string stringValue;
|
std::string stringValue;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,15 @@ static const char* opSymbol(Opcode op) {
|
||||||
case Opcode::SUB: return "-";
|
case Opcode::SUB: return "-";
|
||||||
case Opcode::MUL: return "*";
|
case Opcode::MUL: return "*";
|
||||||
case Opcode::DIV: 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::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: return "<";
|
||||||
case Opcode::LESS_EQUAL: return "<=";
|
case Opcode::LESS_EQUAL: return "<=";
|
||||||
case Opcode::GREATER: return ">";
|
case Opcode::GREATER: return ">";
|
||||||
|
|
@ -35,6 +43,8 @@ static bool isBinaryOp(Opcode op) {
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case Opcode::ADD: case Opcode::SUB: case Opcode::MUL:
|
case Opcode::ADD: case Opcode::SUB: case Opcode::MUL:
|
||||||
case Opcode::DIV: case Opcode::MOD:
|
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::LESS: case Opcode::LESS_EQUAL:
|
||||||
case Opcode::GREATER: case Opcode::GREATER_EQUAL:
|
case Opcode::GREATER: case Opcode::GREATER_EQUAL:
|
||||||
case Opcode::EQUAL_EQUAL: case Opcode::NOT_EQUAL:
|
case Opcode::EQUAL_EQUAL: case Opcode::NOT_EQUAL:
|
||||||
|
|
@ -113,6 +123,48 @@ void IRFunction::dump() const {
|
||||||
}
|
}
|
||||||
std::cout << ")";
|
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) {
|
} else if (ins.opcode == Opcode::RETURN) {
|
||||||
std::cout << slot(ins.src);
|
std::cout << slot(ins.src);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,32 +10,55 @@
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#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ı
|
// generate — Ana giriş noktası
|
||||||
// ─────────────────────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
IRProgram IRGenerator::generate(ASTNode* programNode, SymbolTable& /*symbolTable*/) {
|
IRProgram IRGenerator::generate(ASTNode* programNode, SymbolTable& symbolTable) {
|
||||||
IRProgram program;
|
IRProgram program;
|
||||||
|
|
||||||
// ProgramNode'un her çocuğunu gez.
|
// 0. Geçiş: struct layout haritasını sembol tablosundan al
|
||||||
// Bizi ilgilendiren: FunctionDecl. StructDecl/GlobalVar → TODO.
|
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()) {
|
for (ASTNode* child : programNode->getChildren()) {
|
||||||
if (child->kind == ASTKind::FunctionDecl) {
|
if (child->kind == ASTKind::FunctionDecl) {
|
||||||
// Her fonksiyon üretimi için sıfırla
|
|
||||||
nameToSlot_.clear();
|
nameToSlot_.clear();
|
||||||
nextSlot_ = 0;
|
nextSlot_ = 0;
|
||||||
|
|
||||||
// IRFunction oluştur, currentFunction_ olarak işaretle
|
|
||||||
auto* fnDecl = (FunctionDeclNode*)child;
|
auto* fnDecl = (FunctionDeclNode*)child;
|
||||||
IRFunction irFn(fnDecl->name, (int)fnDecl->params.size());
|
IRFunction irFn(fnDecl->name, (int)fnDecl->params.size());
|
||||||
program.addFunction(std::move(irFn));
|
program.addFunction(std::move(irFn));
|
||||||
|
|
||||||
// addFunction std::move yaptığı için pointer'ı haritadan alalım
|
|
||||||
currentFunction_ = program.findFunction(fnDecl->name);
|
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_;
|
currentFunction_->slotCount = nextSlot_;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -81,7 +104,7 @@ void IRGenerator::generateStatement(ASTNode* node) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Değişken bildirimi: int x = <ifade> ──────────────────────────────
|
// ── Değişken bildirimi: int x = <ifade> / Point p; ────────────────
|
||||||
case ASTKind::VariableDecl: {
|
case ASTKind::VariableDecl: {
|
||||||
auto* vd = (VariableDeclNode*)node;
|
auto* vd = (VariableDeclNode*)node;
|
||||||
|
|
||||||
|
|
@ -90,14 +113,22 @@ void IRGenerator::generateStatement(ASTNode* node) {
|
||||||
registerVariable(vd->name, varSlot);
|
registerVariable(vd->name, varSlot);
|
||||||
|
|
||||||
if (vd->initExpr) {
|
if (vd->initExpr) {
|
||||||
// Başlatma ifadesini üret, sonucu bir slotta al
|
|
||||||
int initSlot = generateExpression(vd->initExpr);
|
int initSlot = generateExpression(vd->initExpr);
|
||||||
|
// float/double değişkenine int sabit atama → INT_TO_FLOAT
|
||||||
if (initSlot != varSlot) {
|
bool targetIsFloat = (vd->varType == "float" || vd->varType == "double");
|
||||||
// Sonuç başka bir slotta, değişkenin slotuna kopyala
|
bool srcIsInt = false;
|
||||||
emitLoadSlot(varSlot, initSlot);
|
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
|
// Sibling VariableDecl'ler: int a, b; → children'da diğer VariableDecl'ler
|
||||||
|
|
@ -153,84 +184,101 @@ void IRGenerator::generateStatement(ASTNode* node) {
|
||||||
case ASTKind::WhileStatement: {
|
case ASTKind::WhileStatement: {
|
||||||
auto* ws = (WhileStatementNode*)node;
|
auto* ws = (WhileStatementNode*)node;
|
||||||
|
|
||||||
// Döngü başının konumu — geri-jump buraya gelecek
|
|
||||||
int loopStart = currentInstrIndex();
|
int loopStart = currentInstrIndex();
|
||||||
|
loopContextStack_.push_back({});
|
||||||
|
|
||||||
int condSlot = generateExpression(ws->condition);
|
int condSlot = generateExpression(ws->condition);
|
||||||
int exitJump = emitJumpIfFalse(condSlot); // ileri, backpatch bekliyor
|
int exitJump = emitJumpIfFalse(condSlot);
|
||||||
|
|
||||||
if (ws->body) generateStatement(ws->body);
|
if (ws->body) generateStatement(ws->body);
|
||||||
|
|
||||||
// Geri-jump: hedef zaten biliniyor (loopStart)
|
// continue → LOOP_START (hedef baştan beri biliniyor)
|
||||||
emitJumpUnconditional(loopStart);
|
for (int idx : loopContextStack_.back().continueJumps)
|
||||||
|
currentFunction_->instructions[idx].jumpTarget = loopStart;
|
||||||
|
|
||||||
// Döngü çıkış noktası → exitJump'ı doldur
|
emitJumpUnconditional(loopStart);
|
||||||
patchJump(exitJump);
|
patchJump(exitJump); // OUT burası
|
||||||
|
|
||||||
|
// break → OUT
|
||||||
|
int outTarget = currentInstrIndex();
|
||||||
|
for (int idx : loopContextStack_.back().breakJumps)
|
||||||
|
currentFunction_->instructions[idx].jumpTarget = outTarget;
|
||||||
|
|
||||||
|
loopContextStack_.pop_back();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── for (init; koşul; güncelleme) { gövde } ─────────────────────────
|
// ── for (init; koşul; güncelleme) { gövde } ─────────────────────────
|
||||||
//
|
//
|
||||||
// Üretilen IR yapısı:
|
// IR yapısı (continue C_LABEL'a, break OUT'a atlar):
|
||||||
// [init]
|
// [init]
|
||||||
// LOOP_START:
|
// LOOP_START:
|
||||||
// [koşul] → condSlot
|
// [koşul] → JIF_FALSE OUT
|
||||||
// JIF_FALSE condSlot → LOOP_END (ileri-jump, backpatch)
|
|
||||||
// [gövde]
|
// [gövde]
|
||||||
|
// C_LABEL:
|
||||||
// [güncelleme]
|
// [güncelleme]
|
||||||
// JMP → LOOP_START (geri-jump, hedef biliniyor)
|
// JMP LOOP_START
|
||||||
// LOOP_END:
|
// OUT:
|
||||||
// ─────────────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────────────
|
||||||
case ASTKind::ForStatement: {
|
case ASTKind::ForStatement: {
|
||||||
auto* fs = (ForStatementNode*)node;
|
auto* fs = (ForStatementNode*)node;
|
||||||
|
|
||||||
// Init: genellikle "int i = 0" gibi bir VariableDecl
|
|
||||||
if (fs->init) generateStatement(fs->init);
|
if (fs->init) generateStatement(fs->init);
|
||||||
|
|
||||||
// Döngü başı konumu — geri-jump'ın hedefi
|
|
||||||
int loopStart = currentInstrIndex();
|
int loopStart = currentInstrIndex();
|
||||||
|
loopContextStack_.push_back({});
|
||||||
|
|
||||||
// Koşul
|
|
||||||
int condSlot = fs->condition ? generateExpression(fs->condition) : -1;
|
int condSlot = fs->condition ? generateExpression(fs->condition) : -1;
|
||||||
int exitJump = (condSlot != -1) ? emitJumpIfFalse(condSlot) : -1;
|
int exitJump = (condSlot != -1) ? emitJumpIfFalse(condSlot) : -1;
|
||||||
|
|
||||||
// Gövde
|
|
||||||
if (fs->body) generateStatement(fs->body);
|
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);
|
if (fs->update) generateExpression(fs->update);
|
||||||
|
|
||||||
// Geri-jump: hedef loopStart, zaten biliniyor
|
|
||||||
emitJumpUnconditional(loopStart);
|
emitJumpUnconditional(loopStart);
|
||||||
|
|
||||||
// Döngü çıkışı → exitJump'ı doldur
|
if (exitJump != -1) patchJump(exitJump); // OUT burası
|
||||||
if (exitJump != -1) patchJump(exitJump);
|
|
||||||
|
// break → OUT
|
||||||
|
int outTarget = currentInstrIndex();
|
||||||
|
for (int idx : loopContextStack_.back().breakJumps)
|
||||||
|
currentFunction_->instructions[idx].jumpTarget = outTarget;
|
||||||
|
|
||||||
|
loopContextStack_.pop_back();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── do { gövde } while (koşul) ───────────────────────────────────────
|
// ── do { gövde } while (koşul) ───────────────────────────────────────
|
||||||
case ASTKind::DoWhileStatement: {
|
case ASTKind::DoWhileStatement: {
|
||||||
auto* dw = (DoWhileStatementNode*)node;
|
auto* dw = (DoWhileStatementNode*)node;
|
||||||
|
|
||||||
int loopStart = currentInstrIndex();
|
int loopStart = currentInstrIndex();
|
||||||
|
loopContextStack_.push_back({});
|
||||||
|
|
||||||
if (dw->body) generateStatement(dw->body);
|
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);
|
int condSlot = generateExpression(dw->condition);
|
||||||
// Koşul doğruysa geri atla (1 = doğru → atla; 0 = yanlış → devam)
|
Instruction jit(Opcode::JIF_TRUE);
|
||||||
// JIF_FALSE koşul yanlışsa atlar; biz doğruysa atlamak istiyoruz.
|
jit.cond = condSlot;
|
||||||
// Bu yüzden JIF_FALSE yerine "doğruysa atla" mantığı lazım.
|
jit.jumpTarget = loopStart;
|
||||||
// Basit çözüm: koşulun tersini al (0→1, diğer→0) ve JIF_FALSE kullan.
|
currentFunction_->instructions.push_back(std::move(jit));
|
||||||
// NOT: saQut'ta "!" operatörü yok henüz; NOT talimatı eklenebilir.
|
|
||||||
// Şimdilik: koşul slotuna bak, sıfır değilse geri atla.
|
// break → OUT (JIF_TRUE'dan sonraki konum)
|
||||||
// TODO(vm-genişletme): JIF_TRUE talimatı ekle
|
int outTarget = currentInstrIndex();
|
||||||
// Geçici çözüm: sabit 1 ile karşılaştır (condSlot != 0 → geri)
|
for (int idx : loopContextStack_.back().breakJumps)
|
||||||
int oneSlot = freshSlot();
|
currentFunction_->instructions[idx].jumpTarget = outTarget;
|
||||||
emitLoadConst(oneSlot, 1);
|
|
||||||
int eqSlot = freshSlot();
|
loopContextStack_.pop_back();
|
||||||
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);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -244,10 +292,66 @@ void IRGenerator::generateStatement(ASTNode* node) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case ASTKind::BreakStatement:
|
case ASTKind::BreakStatement: {
|
||||||
case ASTKind::ContinueStatement:
|
int jumpIdx = emitJumpUnconditional(-1);
|
||||||
// TODO(vm-genişletme): break/continue için JMP + label mekanizması gerekir
|
if (!loopContextStack_.empty())
|
||||||
|
loopContextStack_.back().breakJumps.push_back(jumpIdx);
|
||||||
break;
|
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:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
@ -270,14 +374,29 @@ int IRGenerator::generateExpression(ASTNode* node) {
|
||||||
|
|
||||||
switch (lit->literalType) {
|
switch (lit->literalType) {
|
||||||
case LiteralType::INTEGER: {
|
case LiteralType::INTEGER: {
|
||||||
int value = 0;
|
// Float/double bağlamında tam sayı literali → LOAD_FLOAT (bağlama-göre tip, ADR-010)
|
||||||
if (lit->parserToken.token)
|
bool asFloat = lit->resolvedType.isPrimitive() &&
|
||||||
value = std::stoi(lit->parserToken.token->token);
|
(lit->resolvedType.prim == PrimitiveKind::Float ||
|
||||||
emitLoadConst(slot, value);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case LiteralType::BOOLEAN: {
|
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;
|
lit->parserToken.token->token == "true") ? 1 : 0;
|
||||||
emitLoadConst(slot, value);
|
emitLoadConst(slot, value);
|
||||||
break;
|
break;
|
||||||
|
|
@ -301,25 +420,32 @@ int IRGenerator::generateExpression(ASTNode* node) {
|
||||||
currentFunction_->instructions.push_back(std::move(ins));
|
currentFunction_->instructions.push_back(std::move(ins));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LiteralType::FLOAT:
|
case LiteralType::FLOAT: {
|
||||||
throw std::runtime_error(
|
double val = 0.0;
|
||||||
"IR üretim hatası: float literal şu an VM tarafından desteklenmiyor. "
|
if (lit->parserToken.token)
|
||||||
"Tam sayı kullanın veya float desteği eklenene kadar bekleyin.");
|
val = std::stod(lit->parserToken.token->token);
|
||||||
|
emitLoadFloat(slot, val);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case LiteralType::BOŞ:
|
case LiteralType::BOŞ:
|
||||||
throw std::runtime_error(
|
// null literal → ValueKind::Null (ADR-021)
|
||||||
"IR üretim hatası: null literal şu an VM tarafından desteklenmiyor.");
|
{ Instruction ins(Opcode::LOAD_NULL); ins.dest = slot;
|
||||||
|
currentFunction_->instructions.push_back(std::move(ins)); }
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return slot;
|
return slot;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Değişken ismi: n, first, second ... ──────────────────────────────
|
// ── Değişken ismi: n, first, second ... ──────────────────────────────
|
||||||
// Bu değişkenin değeri zaten bir slotta. O slotu döndür.
|
|
||||||
case ASTKind::Identifier: {
|
case ASTKind::Identifier: {
|
||||||
auto* id = (IdentifierNode*)node;
|
auto* id = (IdentifierNode*)node;
|
||||||
std::string name = id->parserToken.token ? id->parserToken.token->token : "";
|
std::string name = id->parserToken.token ? id->parserToken.token->token : "";
|
||||||
|
|
||||||
// Önce builtin mi? (print gibi) — identifier olarak gelen builtin fonksiyon
|
if (isGlobal(name)) {
|
||||||
// çağrıları CallExpression içinde yakalanıyor, burada sadece değişken kalır
|
int tempSlot = freshSlot();
|
||||||
|
emitLoadGlobal(tempSlot, getGlobalIndex(name));
|
||||||
|
return tempSlot;
|
||||||
|
}
|
||||||
return lookupVariable(name);
|
return lookupVariable(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -327,42 +453,87 @@ int IRGenerator::generateExpression(ASTNode* node) {
|
||||||
case ASTKind::BinaryExpression: {
|
case ASTKind::BinaryExpression: {
|
||||||
auto* bin = (BinaryExpressionNode*)node;
|
auto* bin = (BinaryExpressionNode*)node;
|
||||||
|
|
||||||
// Atama operatörleri: x = expr, x += expr ...
|
// Atama operatörleri: x = expr ve a[i] = expr
|
||||||
// Sol taraf bir değişken, sağ taraf hesaplanır ve o değişkene yazılır.
|
|
||||||
if (bin->Operator == TokenType::EQUAL) {
|
if (bin->Operator == TokenType::EQUAL) {
|
||||||
// Sağ tarafı hesapla
|
|
||||||
int rhsSlot = generateExpression(bin->Right);
|
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;
|
auto* lhsId = (IdentifierNode*)bin->Left;
|
||||||
std::string varName = lhsId->parserToken.token->token;
|
std::string varName = lhsId->parserToken.token->token;
|
||||||
int varSlot = lookupVariable(varName);
|
|
||||||
|
|
||||||
// Sonucu değişkenin slotuna kopyala
|
if (isGlobal(varName)) {
|
||||||
if (rhsSlot != varSlot) {
|
emitStoreGlobal(rhsSlot, getGlobalIndex(varName));
|
||||||
emitLoadSlot(varSlot, rhsSlot);
|
return rhsSlot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int varSlot = lookupVariable(varName);
|
||||||
|
if (rhsSlot != varSlot) emitLoadSlot(varSlot, rhsSlot);
|
||||||
return varSlot;
|
return varSlot;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Birleşik atama: += -= *= /=
|
// Birleşik atama: += -= *= /= %= &= |= <<= >>=
|
||||||
// x += y ≡ x = x + y
|
// x OP= y ≡ x = x OP y
|
||||||
if (bin->Operator == TokenType::PLUS_EQUAL ||
|
if (bin->Operator == TokenType::PLUS_EQUAL ||
|
||||||
bin->Operator == TokenType::MINUS_EQUAL ||
|
bin->Operator == TokenType::MINUS_EQUAL ||
|
||||||
bin->Operator == TokenType::STAR_EQUAL ||
|
bin->Operator == TokenType::STAR_EQUAL ||
|
||||||
bin->Operator == TokenType::SLASH_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;
|
auto* lhsId = (IdentifierNode*)bin->Left;
|
||||||
std::string varName = lhsId->parserToken.token->token;
|
std::string varName = lhsId->parserToken.token->token;
|
||||||
int varSlot = lookupVariable(varName);
|
|
||||||
int rhsSlot = generateExpression(bin->Right);
|
int rhsSlot = generateExpression(bin->Right);
|
||||||
|
|
||||||
Opcode arithOp = Opcode::ADD;
|
Opcode arithOp = Opcode::ADD;
|
||||||
if (bin->Operator == TokenType::MINUS_EQUAL) arithOp = Opcode::SUB;
|
if (bin->Operator == TokenType::MINUS_EQUAL) arithOp = Opcode::SUB;
|
||||||
else if (bin->Operator == TokenType::STAR_EQUAL) arithOp = Opcode::MUL;
|
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::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();
|
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);
|
emitBinaryOp(arithOp, resultSlot, varSlot, rhsSlot);
|
||||||
emitLoadSlot(varSlot, resultSlot);
|
emitLoadSlot(varSlot, resultSlot);
|
||||||
return varSlot;
|
return varSlot;
|
||||||
|
|
@ -378,8 +549,18 @@ int IRGenerator::generateExpression(ASTNode* node) {
|
||||||
int zeroSlot = freshSlot();
|
int zeroSlot = freshSlot();
|
||||||
emitLoadConst(zeroSlot, 0);
|
emitLoadConst(zeroSlot, 0);
|
||||||
emitBinaryOp(Opcode::SUB, resultSlot, zeroSlot, operandSlot);
|
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 {
|
} else {
|
||||||
// Diğer unary operatörler → TODO
|
|
||||||
emitLoadSlot(resultSlot, operandSlot);
|
emitLoadSlot(resultSlot, operandSlot);
|
||||||
}
|
}
|
||||||
return resultSlot;
|
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::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::EQUAL_EQUAL: return generateBinaryArithmetic(Opcode::EQUAL_EQUAL, bin->Left, bin->Right);
|
||||||
case TokenType::BANG_EQUAL: return generateBinaryArithmetic(Opcode::NOT_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: {
|
default: {
|
||||||
// Bilinmeyen operatör — boş slot döndür
|
// Bilinmeyen operatör — boş slot döndür
|
||||||
int slot = freshSlot();
|
int slot = freshSlot();
|
||||||
|
|
@ -473,6 +684,42 @@ int IRGenerator::generateExpression(ASTNode* node) {
|
||||||
return resultSlot; // artırmadan önceki değer
|
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:
|
default:
|
||||||
// Bilinmeyen ifade türü
|
// Bilinmeyen ifade türü
|
||||||
return freshSlot(); // boş slot (0 değeriyle)
|
return freshSlot(); // boş slot (0 değeriyle)
|
||||||
|
|
@ -487,7 +734,52 @@ int IRGenerator::generateBinaryArithmetic(Opcode opcode, ASTNode* leftNode, ASTN
|
||||||
int leftSlot = generateExpression(leftNode);
|
int leftSlot = generateExpression(leftNode);
|
||||||
int rightSlot = generateExpression(rightNode);
|
int rightSlot = generateExpression(rightNode);
|
||||||
int destSlot = freshSlot();
|
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;
|
return destSlot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -531,6 +823,111 @@ void IRGenerator::emitLoadSlot(int destSlot, int srcSlot) {
|
||||||
currentFunction_->instructions.push_back(std::move(ins));
|
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) {
|
void IRGenerator::emitBinaryOp(Opcode op, int destSlot, int leftSlot, int rightSlot) {
|
||||||
Instruction ins(op);
|
Instruction ins(op);
|
||||||
ins.dest = destSlot;
|
ins.dest = destSlot;
|
||||||
|
|
@ -557,7 +954,14 @@ int IRGenerator::emitJumpIfFalse(int condSlot) {
|
||||||
ins.cond = condSlot;
|
ins.cond = condSlot;
|
||||||
ins.jumpTarget = -1; // henüz bilinmiyor — patchJump() bekliyor
|
ins.jumpTarget = -1; // henüz bilinmiyor — patchJump() bekliyor
|
||||||
currentFunction_->instructions.push_back(std::move(ins));
|
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;
|
return (int)currentFunction_->instructions.size() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,11 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
#include <utility>
|
||||||
#include "ir/ir_program.hpp"
|
#include "ir/ir_program.hpp"
|
||||||
#include "symbol/symbol_table.hpp"
|
#include "symbol/symbol_table.hpp"
|
||||||
|
#include "core/type.hpp"
|
||||||
#include "parser/ast_node.hpp"
|
#include "parser/ast_node.hpp"
|
||||||
|
|
||||||
class IRGenerator {
|
class IRGenerator {
|
||||||
|
|
@ -55,7 +58,18 @@ private:
|
||||||
// Talimatları currentFunction_->instructions'a ekler.
|
// Talimatları currentFunction_->instructions'a ekler.
|
||||||
|
|
||||||
void emitLoadConst(int destSlot, int value);
|
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 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 emitBinaryOp(Opcode op, int destSlot, int leftSlot, int rightSlot);
|
||||||
void emitReturn(int srcSlot);
|
void emitReturn(int srcSlot);
|
||||||
// Koşulsuz atlama yazar; instruction indeksini döndürür (backpatch için).
|
// 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).
|
// Döndürülen indeks ileride patchJump() ile doldurulur (backpatch).
|
||||||
int emitJumpIfFalse(int condSlot);
|
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.
|
// Daha önce -1 hedefle yazılan jump'ın hedefini şu anki pozisyona doldur.
|
||||||
void patchJump(int instrIndex);
|
void patchJump(int instrIndex);
|
||||||
|
|
||||||
// Şu an kaç talimat üretildi? (jump hedefi belirlemek için)
|
// Şu an kaç talimat üretildi? (jump hedefi belirlemek için)
|
||||||
int currentInstrIndex() const;
|
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 ────────────────────────────────────────
|
// ── Per-function üretim durumu ────────────────────────────────────────
|
||||||
IRFunction* currentFunction_ = nullptr; // şu an üretilen fonksiyon
|
IRFunction* currentFunction_ = nullptr; // şu an üretilen fonksiyon
|
||||||
int nextSlot_ = 0; // sıradaki boş slot numarası
|
int nextSlot_ = 0; // sıradaki boş slot numarası
|
||||||
|
|
||||||
// Değişken ismi → slot numarası.
|
// Değişken ismi → slot numarası (lokal).
|
||||||
// Sınırlama: aynı isimdeki farklı scope değişkenleri çakışır (TODO).
|
|
||||||
std::unordered_map<std::string, int> nameToSlot_;
|
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
|
#endif // SAQUT_IR_GENERATOR
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,14 @@
|
||||||
|
|
||||||
void IRProgram::dump() const {
|
void IRProgram::dump() const {
|
||||||
std::cout << "IR DUMP\n\n";
|
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) {
|
for (const auto& name : functionOrder) {
|
||||||
auto it = functions.find(name);
|
auto it = functions.find(name);
|
||||||
if (it != functions.end()) it->second.dump();
|
if (it != functions.end()) it->second.dump();
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,14 @@ struct IRProgram {
|
||||||
// Ekleme sırası (dump'ta orijinal sırayla göstermek için)
|
// Ekleme sırası (dump'ta orijinal sırayla göstermek için)
|
||||||
std::vector<std::string> functionOrder;
|
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
|
// Yeni fonksiyon ekle
|
||||||
void addFunction(IRFunction fn) {
|
void addFunction(IRFunction fn) {
|
||||||
functionOrder.push_back(fn.name);
|
functionOrder.push_back(fn.name);
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,10 @@ private:
|
||||||
case TokenType::GREATER:
|
case TokenType::GREATER:
|
||||||
case TokenType::LESS_EQUAL:
|
case TokenType::LESS_EQUAL:
|
||||||
case TokenType::GREATER_EQUAL:
|
case TokenType::GREATER_EQUAL:
|
||||||
|
case TokenType::AMPERSAND:
|
||||||
|
case TokenType::PIPE:
|
||||||
|
case TokenType::LSHIFT:
|
||||||
|
case TokenType::RSHIFT:
|
||||||
case TokenType::AMPERSAND_AMPERSAND:
|
case TokenType::AMPERSAND_AMPERSAND:
|
||||||
case TokenType::PIPE_PIPE:
|
case TokenType::PIPE_PIPE:
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -125,6 +129,10 @@ private:
|
||||||
case TokenType::GREATER: return l > r ? 1 : 0;
|
case TokenType::GREATER: return l > r ? 1 : 0;
|
||||||
case TokenType::LESS_EQUAL: 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::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::AMPERSAND_AMPERSAND: return (l && r) ? 1 : 0;
|
||||||
case TokenType::PIPE_PIPE: return (l || r) ? 1 : 0;
|
case TokenType::PIPE_PIPE: return (l || r) ? 1 : 0;
|
||||||
default: return 0;
|
default: return 0;
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,12 @@
|
||||||
#include "parser/nodes/declarations.hpp"
|
#include "parser/nodes/declarations.hpp"
|
||||||
#include "parser/nodes/expressions.hpp"
|
#include "parser/nodes/expressions.hpp"
|
||||||
#include "parser/nodes/program.hpp"
|
#include "parser/nodes/program.hpp"
|
||||||
|
#include "diagnostic/diagnostic_engine.hpp"
|
||||||
|
|
||||||
class DeadCodeElimPass : public OptimizationPass {
|
class DeadCodeElimPass : public OptimizationPass {
|
||||||
public:
|
public:
|
||||||
|
explicit DeadCodeElimPass(DiagnosticEngine& diag) : diag_(diag) {}
|
||||||
|
|
||||||
bool run(ASTNode* root, SymbolTable*) override {
|
bool run(ASTNode* root, SymbolTable*) override {
|
||||||
changed_ = false;
|
changed_ = false;
|
||||||
visit(root);
|
visit(root);
|
||||||
|
|
@ -30,6 +33,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
DiagnosticEngine& diag_;
|
||||||
bool changed_ = false;
|
bool changed_ = false;
|
||||||
|
|
||||||
void visit(ASTNode* node) {
|
void visit(ASTNode* node) {
|
||||||
|
|
@ -45,11 +49,12 @@ private:
|
||||||
|
|
||||||
for (auto* child : ch) {
|
for (auto* child : ch) {
|
||||||
if (term) {
|
if (term) {
|
||||||
// Bu deyim erişilemez
|
|
||||||
if (auto* sn = dynamic_cast<StatementNode*>(child)) {
|
if (auto* sn = dynamic_cast<StatementNode*>(child)) {
|
||||||
if (sn->isReachable) {
|
if (sn->isReachable) {
|
||||||
sn->isReachable = false;
|
sn->isReachable = false;
|
||||||
changed_ = true;
|
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;
|
term = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Erişilemez çocukları sil ve vektörden çıkar
|
// remove_if erişilemez düğümleri sona taşır (silmez), sonra delete
|
||||||
ch.erase(std::remove_if(ch.begin(), ch.end(),
|
auto toErase = std::remove_if(ch.begin(), ch.end(),
|
||||||
[](ASTNode* n) {
|
[](ASTNode* n) {
|
||||||
auto* sn = dynamic_cast<StatementNode*>(n);
|
auto* sn = dynamic_cast<StatementNode*>(n);
|
||||||
return sn && !sn->isReachable;
|
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
|
// Alt bloklara da in
|
||||||
for (auto* child : ch) visit(child);
|
for (auto* child : ch) visit(child);
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,18 @@
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// saQut — Optimizasyon Yöneticisi (ADR-007, ADR-009)
|
// saQut — Optimizasyon Yöneticisi (ADR-007, ADR-009)
|
||||||
//
|
//
|
||||||
// 1. AST'yi klonlar (orijinal dokunulmaz).
|
// İKİ KULLANIM YOLU:
|
||||||
// 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).
|
// 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
|
// 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
|
// (katlama: n düğüm → 1 düğüm; DCE: düğüm siler). Büyüten pass
|
||||||
|
|
@ -29,22 +38,27 @@ public:
|
||||||
if (cfg.optConstantFolding)
|
if (cfg.optConstantFolding)
|
||||||
passes_.push_back(std::make_unique<ConstantFoldingPass>(diag));
|
passes_.push_back(std::make_unique<ConstantFoldingPass>(diag));
|
||||||
if (cfg.optDeadCodeElim)
|
if (cfg.optDeadCodeElim)
|
||||||
passes_.push_back(std::make_unique<DeadCodeElimPass>());
|
passes_.push_back(std::make_unique<DeadCodeElimPass>(diag));
|
||||||
maxRounds_ = cfg.maxFixpointRounds;
|
maxRounds_ = cfg.maxFixpointRounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
// optimize: AST'yi klonlar ve optimize edilmiş kopyayı döndürür.
|
// Pass'leri verilen AST üstünde yerinde çalıştırır — klon yok.
|
||||||
// Dönen pointer caller'a aittir (delete edilmeli).
|
// run / ir ve diğer tek-versiyon komutları bu yolu kullanır.
|
||||||
ASTNode* optimize(ASTNode* root, SymbolTable* table) {
|
void runPassesInPlace(ASTNode* root, SymbolTable* table) {
|
||||||
ASTNode* clone = deepClone(root);
|
|
||||||
|
|
||||||
for (int round = 0; round < maxRounds_; ++round) {
|
for (int round = 0; round < maxRounds_; ++round) {
|
||||||
bool anyChange = false;
|
bool anyChange = false;
|
||||||
for (auto& pass : passes_)
|
for (auto& pass : passes_)
|
||||||
if (pass->run(clone, table)) anyChange = true;
|
if (pass->run(root, table)) anyChange = true;
|
||||||
if (!anyChange) break;
|
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;
|
return clone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,8 @@ enum class ASTKind {
|
||||||
ExpressionStatement, // ifade + noktalı virgül (;)
|
ExpressionStatement, // ifade + noktalı virgül (;)
|
||||||
// children: [expression]
|
// children: [expression]
|
||||||
// Örn: x = 5; veya foo();
|
// Örn: x = 5; veya foo();
|
||||||
|
TryStatement, // try { body } catch (Error e) { handler } (ADR-025)
|
||||||
|
ThrowStatement, // throw <ifade>; (ADR-025)
|
||||||
|
|
||||||
/* ====== İfadeler (Expressions) ====== */
|
/* ====== İfadeler (Expressions) ====== */
|
||||||
BinaryExpression, // İkili işlem: sol OP sağ.
|
BinaryExpression, // İkili işlem: sol OP sağ.
|
||||||
|
|
@ -107,6 +109,8 @@ enum class ASTKind {
|
||||||
// children: [object], [member]
|
// children: [object], [member]
|
||||||
IndexExpression, // Dizi/indeks erişimi: a[i].
|
IndexExpression, // Dizi/indeks erişimi: a[i].
|
||||||
// children: [object], [index]
|
// 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
|
// KARMAŞIKLIK: O(1) — referans döndürür
|
||||||
std::vector<ASTNode*>& getChildren() { return children; }
|
std::vector<ASTNode*>& getChildren() { return children; }
|
||||||
|
|
||||||
// ~ASTNode() — Sanal yıkıcı (polimorfik silme için)
|
// ~ASTNode() — children vektörünü özyinelemeli siler.
|
||||||
// delete ASTNode* yapıldığında doğru alt sınıf yıkıcısı çağrılır.
|
// Typed pointer'lar (condition, thenBranch vb.) alt sınıf yıkıcılarına bırakılır;
|
||||||
// Bu olmazsa türetilmiş sınıfların kaynakları sızdırılır.
|
// children vektörü ile typed pointer'lar örtüşmediği için double-delete olmaz.
|
||||||
virtual ~ASTNode() = default;
|
virtual ~ASTNode() {
|
||||||
|
for (auto* ch : children) delete ch;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// children — Alt düğümlerin vektörü.
|
// children — Alt düğümlerin vektörü.
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ public:
|
||||||
ASTNode* Right = nullptr;
|
ASTNode* Right = nullptr;
|
||||||
|
|
||||||
BinaryExpressionNode();
|
BinaryExpressionNode();
|
||||||
|
~BinaryExpressionNode() override { delete Left; delete Right; }
|
||||||
void log(int indent = 0) override;
|
void log(int indent = 0) override;
|
||||||
std::string toJson(int depth = 0) override;
|
std::string toJson(int depth = 0) override;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
// FunctionDeclNode
|
// FunctionDeclNode
|
||||||
FunctionDeclNode::FunctionDeclNode() { kind = ASTKind::FunctionDecl; }
|
FunctionDeclNode::FunctionDeclNode() { kind = ASTKind::FunctionDecl; }
|
||||||
|
FunctionDeclNode::~FunctionDeclNode() { for (auto* p : params) delete p; }
|
||||||
void FunctionDeclNode::log(int indent) {
|
void FunctionDeclNode::log(int indent) {
|
||||||
std::cout << jsonIndent(indent) << "FunctionDecl (" << name << " : " << returnType << ")\n";
|
std::cout << jsonIndent(indent) << "FunctionDecl (" << name << " : " << returnType << ")\n";
|
||||||
for (auto* child : children) child->log(indent + 1);
|
for (auto* child : children) child->log(indent + 1);
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ public:
|
||||||
std::string returnType;
|
std::string returnType;
|
||||||
std::vector<VariableDeclNode*> params; // TODO(faz2): parametreler
|
std::vector<VariableDeclNode*> params; // TODO(faz2): parametreler
|
||||||
FunctionDeclNode();
|
FunctionDeclNode();
|
||||||
|
~FunctionDeclNode() override;
|
||||||
void log(int indent = 0) override;
|
void log(int indent = 0) override;
|
||||||
std::string toJson(int depth = 0) override;
|
std::string toJson(int depth = 0) override;
|
||||||
};
|
};
|
||||||
|
|
@ -21,6 +22,7 @@ public:
|
||||||
std::string name;
|
std::string name;
|
||||||
ASTNode* initExpr = nullptr;
|
ASTNode* initExpr = nullptr;
|
||||||
VariableDeclNode();
|
VariableDeclNode();
|
||||||
|
~VariableDeclNode() override { delete initExpr; }
|
||||||
void log(int indent = 0) override;
|
void log(int indent = 0) override;
|
||||||
std::string toJson(int depth = 0) override;
|
std::string toJson(int depth = 0) override;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,23 @@ std::string MemberAccessNode::toJson(int depth) {
|
||||||
return obj.str();
|
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::IndexExpressionNode() { kind = ASTKind::IndexExpression; }
|
IndexExpressionNode::IndexExpressionNode() { kind = ASTKind::IndexExpression; }
|
||||||
void IndexExpressionNode::log(int indent) {
|
void IndexExpressionNode::log(int indent) {
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ public:
|
||||||
ASTNode* operand = nullptr;
|
ASTNode* operand = nullptr;
|
||||||
TokenType Operator;
|
TokenType Operator;
|
||||||
PostfixNode();
|
PostfixNode();
|
||||||
|
~PostfixNode() override { delete operand; }
|
||||||
void log(int indent = 0) override;
|
void log(int indent = 0) override;
|
||||||
std::string toJson(int depth = 0) override;
|
std::string toJson(int depth = 0) override;
|
||||||
};
|
};
|
||||||
|
|
@ -17,6 +18,7 @@ public:
|
||||||
ASTNode* callee = nullptr;
|
ASTNode* callee = nullptr;
|
||||||
std::vector<ASTNode*> arguments;
|
std::vector<ASTNode*> arguments;
|
||||||
CallExpressionNode();
|
CallExpressionNode();
|
||||||
|
~CallExpressionNode() override { delete callee; for (auto* a : arguments) delete a; }
|
||||||
void log(int indent = 0) override;
|
void log(int indent = 0) override;
|
||||||
std::string toJson(int depth = 0) override;
|
std::string toJson(int depth = 0) override;
|
||||||
};
|
};
|
||||||
|
|
@ -27,6 +29,7 @@ public:
|
||||||
std::string member;
|
std::string member;
|
||||||
bool arrow = false;
|
bool arrow = false;
|
||||||
MemberAccessNode();
|
MemberAccessNode();
|
||||||
|
~MemberAccessNode() override { delete object; }
|
||||||
void log(int indent = 0) override;
|
void log(int indent = 0) override;
|
||||||
std::string toJson(int depth = 0) override;
|
std::string toJson(int depth = 0) override;
|
||||||
};
|
};
|
||||||
|
|
@ -36,6 +39,16 @@ public:
|
||||||
ASTNode* object = nullptr;
|
ASTNode* object = nullptr;
|
||||||
ASTNode* index = nullptr;
|
ASTNode* index = nullptr;
|
||||||
IndexExpressionNode();
|
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;
|
void log(int indent = 0) override;
|
||||||
std::string toJson(int depth = 0) override;
|
std::string toJson(int depth = 0) override;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
#include "parser/nodes/identifier.hpp"
|
#include "parser/nodes/identifier.hpp"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
|
||||||
#include "parser/ast_json.hpp"
|
#include "parser/ast_json.hpp"
|
||||||
|
|
||||||
IdentifierNode::IdentifierNode() { kind = ASTKind::Identifier; }
|
IdentifierNode::IdentifierNode() { kind = ASTKind::Identifier; }
|
||||||
|
|
@ -11,14 +10,10 @@ void IdentifierNode::log(int indent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string IdentifierNode::toJson(int depth) {
|
std::string IdentifierNode::toJson(int depth) {
|
||||||
std::string in = jsonIndent(depth);
|
JsonObject obj(depth);
|
||||||
std::string name = parserToken.token ? parserToken.token->token : "?";
|
obj.add("kind", "Identifier");
|
||||||
std::ostringstream ss;
|
obj.add("name", parserToken.token ? parserToken.token->token : "?");
|
||||||
ss << "{\n"
|
obj.addRaw("resolvedType", resolvedTypeJson());
|
||||||
<< in << " \"kind\": \"Identifier\",\n"
|
obj.addRaw("location", loc.toJson());
|
||||||
<< in << " \"name\": \"" << jsonEscape(name) << "\",\n"
|
return obj.str();
|
||||||
<< in << " \"resolvedType\": " << resolvedTypeJson() << ",\n"
|
|
||||||
<< in << " \"location\": " << loc.toJson() << "\n"
|
|
||||||
<< in << "}";
|
|
||||||
return ss.str();
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
#include "parser/nodes/literal.hpp"
|
#include "parser/nodes/literal.hpp"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
|
||||||
#include "parser/ast_json.hpp"
|
#include "parser/ast_json.hpp"
|
||||||
|
|
||||||
LiteralNode::LiteralNode() { kind = ASTKind::Literal; }
|
LiteralNode::LiteralNode() { kind = ASTKind::Literal; }
|
||||||
|
|
@ -18,22 +17,17 @@ void LiteralNode::log(int indent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string LiteralNode::toJson(int depth) {
|
std::string LiteralNode::toJson(int depth) {
|
||||||
std::string in = jsonIndent(depth);
|
|
||||||
std::string val = hasDirectValue ? std::to_string(directIntValue)
|
std::string val = hasDirectValue ? std::to_string(directIntValue)
|
||||||
: (parserToken.token ? parserToken.token->token : "?");
|
: (parserToken.token ? parserToken.token->token : "?");
|
||||||
std::ostringstream ss;
|
JsonObject obj(depth);
|
||||||
ss << "{\n"
|
obj.add("kind", "Literal");
|
||||||
<< in << " \"kind\": \"Literal\",\n"
|
obj.add("literalType", literalTypeToString(literalType));
|
||||||
<< in << " \"literalType\": \"" << literalTypeToString(literalType) << "\",\n"
|
obj.add("value", val);
|
||||||
<< in << " \"value\": \"" << jsonEscape(val) << "\"";
|
if (literalType == LiteralType::INTEGER && literalBase != 10)
|
||||||
if (literalType == LiteralType::INTEGER && literalBase != 10) {
|
obj.add("base", literalBase);
|
||||||
ss << ",\n" << in << " \"base\": " << literalBase;
|
if (literalType == LiteralType::FLOAT)
|
||||||
}
|
obj.add("isFloat", true);
|
||||||
if (literalType == LiteralType::FLOAT) {
|
obj.addRaw("resolvedType", resolvedTypeJson());
|
||||||
ss << ",\n" << in << " \"isFloat\": true";
|
obj.addRaw("location", loc.toJson());
|
||||||
}
|
return obj.str();
|
||||||
ss << ",\n" << in << " \"resolvedType\": " << resolvedTypeJson();
|
|
||||||
ss << ",\n" << in << " \"location\": " << loc.toJson() << "\n"
|
|
||||||
<< in << "}";
|
|
||||||
return ss.str();
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -147,3 +147,36 @@ std::string ExpressionStatementNode::toJson(int depth) {
|
||||||
obj.addRaw("location", loc.toJson());
|
obj.addRaw("location", loc.toJson());
|
||||||
return obj.str();
|
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();
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ public:
|
||||||
ASTNode* thenBranch = nullptr;
|
ASTNode* thenBranch = nullptr;
|
||||||
ASTNode* elseBranch = nullptr;
|
ASTNode* elseBranch = nullptr;
|
||||||
IfStatementNode();
|
IfStatementNode();
|
||||||
|
~IfStatementNode() override { delete condition; delete thenBranch; delete elseBranch; }
|
||||||
void log(int indent = 0) override;
|
void log(int indent = 0) override;
|
||||||
std::string toJson(int depth = 0) override;
|
std::string toJson(int depth = 0) override;
|
||||||
};
|
};
|
||||||
|
|
@ -25,6 +26,7 @@ public:
|
||||||
ASTNode* condition = nullptr;
|
ASTNode* condition = nullptr;
|
||||||
ASTNode* body = nullptr;
|
ASTNode* body = nullptr;
|
||||||
WhileStatementNode();
|
WhileStatementNode();
|
||||||
|
~WhileStatementNode() override { delete condition; delete body; }
|
||||||
void log(int indent = 0) override;
|
void log(int indent = 0) override;
|
||||||
std::string toJson(int depth = 0) override;
|
std::string toJson(int depth = 0) override;
|
||||||
};
|
};
|
||||||
|
|
@ -36,6 +38,7 @@ public:
|
||||||
ASTNode* update = nullptr;
|
ASTNode* update = nullptr;
|
||||||
ASTNode* body = nullptr;
|
ASTNode* body = nullptr;
|
||||||
ForStatementNode();
|
ForStatementNode();
|
||||||
|
~ForStatementNode() override { delete init; delete condition; delete update; delete body; }
|
||||||
void log(int indent = 0) override;
|
void log(int indent = 0) override;
|
||||||
std::string toJson(int depth = 0) override;
|
std::string toJson(int depth = 0) override;
|
||||||
};
|
};
|
||||||
|
|
@ -45,6 +48,7 @@ public:
|
||||||
ASTNode* condition = nullptr;
|
ASTNode* condition = nullptr;
|
||||||
ASTNode* body = nullptr;
|
ASTNode* body = nullptr;
|
||||||
DoWhileStatementNode();
|
DoWhileStatementNode();
|
||||||
|
~DoWhileStatementNode() override { delete body; delete condition; }
|
||||||
void log(int indent = 0) override;
|
void log(int indent = 0) override;
|
||||||
std::string toJson(int depth = 0) override;
|
std::string toJson(int depth = 0) override;
|
||||||
};
|
};
|
||||||
|
|
@ -53,6 +57,7 @@ class ReturnStatementNode : public StatementNode {
|
||||||
public:
|
public:
|
||||||
ASTNode* value = nullptr;
|
ASTNode* value = nullptr;
|
||||||
ReturnStatementNode();
|
ReturnStatementNode();
|
||||||
|
~ReturnStatementNode() override { delete value; }
|
||||||
void log(int indent = 0) override;
|
void log(int indent = 0) override;
|
||||||
std::string toJson(int depth = 0) override;
|
std::string toJson(int depth = 0) override;
|
||||||
};
|
};
|
||||||
|
|
@ -75,6 +80,29 @@ class ExpressionStatementNode : public StatementNode {
|
||||||
public:
|
public:
|
||||||
ASTNode* expression = nullptr;
|
ASTNode* expression = nullptr;
|
||||||
ExpressionStatementNode();
|
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;
|
void log(int indent = 0) override;
|
||||||
std::string toJson(int depth = 0) override;
|
std::string toJson(int depth = 0) override;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -85,8 +85,15 @@ ASTNode* Parser::parseDeclaration() {
|
||||||
})) {
|
})) {
|
||||||
auto la1 = lookahead(1);
|
auto la1 = lookahead(1);
|
||||||
auto la2 = lookahead(2);
|
auto la2 = lookahead(2);
|
||||||
|
// int name( → fonksiyon
|
||||||
if (la1.type == TokenType::IDENTIFIER && la2.type == TokenType::LPAREN)
|
if (la1.type == TokenType::IDENTIFIER && la2.type == TokenType::LPAREN)
|
||||||
return parseFunctionDecl();
|
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();
|
return parseVariableDecl();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -99,6 +106,11 @@ ASTNode* Parser::parseDeclaration() {
|
||||||
auto la2 = lookahead(2);
|
auto la2 = lookahead(2);
|
||||||
if (la1.type == TokenType::IDENTIFIER && la2.type == TokenType::LPAREN)
|
if (la1.type == TokenType::IDENTIFIER && la2.type == TokenType::LPAREN)
|
||||||
return parseFunctionDecl();
|
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)
|
if (la1.type == TokenType::IDENTIFIER)
|
||||||
return parseVariableDecl();
|
return parseVariableDecl();
|
||||||
}
|
}
|
||||||
|
|
@ -150,6 +162,23 @@ ASTNode* Parser::parseNullDenotation() {
|
||||||
return expr;
|
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({
|
if (ct.is({
|
||||||
TokenType::PLUS_PLUS, TokenType::MINUS_MINUS,
|
TokenType::PLUS_PLUS, TokenType::MINUS_MINUS,
|
||||||
TokenType::PLUS, TokenType::MINUS,
|
TokenType::PLUS, TokenType::MINUS,
|
||||||
|
|
@ -299,6 +328,10 @@ ASTNode* Parser::parseFunctionDecl() {
|
||||||
fn->returnType = currentToken().token->token;
|
fn->returnType = currentToken().token->token;
|
||||||
nextToken();
|
nextToken();
|
||||||
|
|
||||||
|
// ADR-021: nullable dönüş tipi — int? f()
|
||||||
|
if (currentToken().type == TokenType::TERNARY)
|
||||||
|
{ nextToken(); fn->returnType += "?"; }
|
||||||
|
|
||||||
fn->name = currentToken().token->token;
|
fn->name = currentToken().token->token;
|
||||||
nextToken();
|
nextToken();
|
||||||
|
|
||||||
|
|
@ -315,6 +348,16 @@ ASTNode* Parser::parseFunctionDecl() {
|
||||||
if (!isTypeKw || !typeTok.token) break;
|
if (!isTypeKw || !typeTok.token) break;
|
||||||
std::string paramType = typeTok.token->token;
|
std::string paramType = typeTok.token->token;
|
||||||
nextToken();
|
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;
|
if (currentToken().type != TokenType::IDENTIFIER || !currentToken().token) break;
|
||||||
VariableDeclNode* param = new VariableDeclNode();
|
VariableDeclNode* param = new VariableDeclNode();
|
||||||
param->loc = currentToken().token->loc;
|
param->loc = currentToken().token->loc;
|
||||||
|
|
@ -364,6 +407,18 @@ ASTNode* Parser::parseVariableDecl() {
|
||||||
vd->varType = currentToken().token->token;
|
vd->varType = currentToken().token->token;
|
||||||
nextToken();
|
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) {
|
if (currentToken().type != TokenType::IDENTIFIER) {
|
||||||
std::cerr << "Parser hatası: değişken ismi bekleniyor\n";
|
std::cerr << "Parser hatası: değişken ismi bekleniyor\n";
|
||||||
return vd;
|
return vd;
|
||||||
|
|
@ -372,6 +427,7 @@ ASTNode* Parser::parseVariableDecl() {
|
||||||
vd->name = currentToken().token->token;
|
vd->name = currentToken().token->token;
|
||||||
nextToken();
|
nextToken();
|
||||||
|
|
||||||
|
// C stili: int x[] — geriye dönük uyumluluk (postfix [])
|
||||||
if (currentToken().type == TokenType::LBRACKET) {
|
if (currentToken().type == TokenType::LBRACKET) {
|
||||||
nextToken();
|
nextToken();
|
||||||
while (currentToken().type != TokenType::RBRACKET &&
|
while (currentToken().type != TokenType::RBRACKET &&
|
||||||
|
|
@ -380,6 +436,7 @@ ASTNode* Parser::parseVariableDecl() {
|
||||||
nextToken();
|
nextToken();
|
||||||
if (currentToken().type == TokenType::RBRACKET)
|
if (currentToken().type == TokenType::RBRACKET)
|
||||||
nextToken();
|
nextToken();
|
||||||
|
if (vd->varType.back() != ']') vd->varType += "[]";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentToken().type == TokenType::EQUAL) {
|
if (currentToken().type == TokenType::EQUAL) {
|
||||||
|
|
@ -452,6 +509,12 @@ ASTNode* Parser::parseStatement() {
|
||||||
if (ct.type == TokenType::KW_CONTINUE)
|
if (ct.type == TokenType::KW_CONTINUE)
|
||||||
return parseContinueStatement();
|
return parseContinueStatement();
|
||||||
|
|
||||||
|
if (ct.type == TokenType::KW_TRY)
|
||||||
|
return parseTryStatement();
|
||||||
|
|
||||||
|
if (ct.type == TokenType::KW_THROW)
|
||||||
|
return parseThrowStatement();
|
||||||
|
|
||||||
if (ct.is({
|
if (ct.is({
|
||||||
TokenType::KW_VOID, TokenType::KW_INT, TokenType::KW_FLOAT_TYPE,
|
TokenType::KW_VOID, TokenType::KW_INT, TokenType::KW_FLOAT_TYPE,
|
||||||
TokenType::KW_DOUBLE, TokenType::KW_BOOL, TokenType::KW_CHAR,
|
TokenType::KW_DOUBLE, TokenType::KW_BOOL, TokenType::KW_CHAR,
|
||||||
|
|
@ -463,6 +526,15 @@ ASTNode* Parser::parseStatement() {
|
||||||
if (ct.type == TokenType::KW_STRUCT)
|
if (ct.type == TokenType::KW_STRUCT)
|
||||||
return parseStructDecl();
|
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();
|
return parseExpressionStatement();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -627,3 +699,43 @@ ASTNode* Parser::parseExpressionStatement() {
|
||||||
|
|
||||||
return es;
|
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;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,8 @@ private:
|
||||||
ASTNode* parseBreakStatement();
|
ASTNode* parseBreakStatement();
|
||||||
ASTNode* parseContinueStatement();
|
ASTNode* parseContinueStatement();
|
||||||
ASTNode* parseExpressionStatement();
|
ASTNode* parseExpressionStatement();
|
||||||
|
ASTNode* parseTryStatement();
|
||||||
|
ASTNode* parseThrowStatement();
|
||||||
|
|
||||||
// --- İfadeler (Pratt parser) ---
|
// --- İfadeler (Pratt parser) ---
|
||||||
ASTNode* parseExpression();
|
ASTNode* parseExpression();
|
||||||
|
|
|
||||||
|
|
@ -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ı
|
// check — giriş noktası
|
||||||
// ─────────────────────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
@ -62,21 +106,41 @@ bool TypeChecker::checkAssign(const Type& target, const Type& src,
|
||||||
const SourceLocation& loc,
|
const SourceLocation& loc,
|
||||||
const std::string& ctx) {
|
const std::string& ctx) {
|
||||||
if (target.isError() || src.isError()) return true; // önceki hata, sessiz geç
|
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 tRank = numericRank(target);
|
||||||
int sRank = numericRank(src);
|
int sRank = numericRank(src);
|
||||||
|
|
||||||
if (tRank >= 0 && sRank >= 0) {
|
if (tRank >= 0 && sRank >= 0) {
|
||||||
if (tRank > sRank) {
|
if (tRank > sRank) {
|
||||||
// Genişletme (widening): int→float, int→double, float→double
|
if (srcIsLiteral) return true;
|
||||||
if (srcIsLiteral) return true; // literal bağlama-göre tiplenir, uyarısız
|
|
||||||
diag_.report("W004", loc,
|
diag_.report("W004", loc,
|
||||||
"'" + ctx + "': " + src.toString() +
|
"'" + ctx + "': " + src.toString() +
|
||||||
" → " + target.toString() + " örtük genişletme");
|
" → " + target.toString() + " örtük genişletme");
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
// Daraltma (narrowing): float→int, double→float, vb.
|
|
||||||
diag_.report("E003", loc,
|
diag_.report("E003", loc,
|
||||||
"'" + ctx + "': " + src.toString() +
|
"'" + ctx + "': " + src.toString() +
|
||||||
" → " + target.toString() + " daraltma (veri kaybı)");
|
" → " + 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,
|
diag_.report("E003", loc,
|
||||||
"'" + ctx + "': " + src.toString() +
|
"'" + ctx + "': " + src.toString() +
|
||||||
" tipi " + target.toString() + " tipine atanamaz");
|
" tipi " + target.toString() + " tipine atanamaz");
|
||||||
|
|
@ -100,13 +163,32 @@ void TypeChecker::checkStmt(ASTNode* node) {
|
||||||
|
|
||||||
switch (node->kind) {
|
switch (node->kind) {
|
||||||
|
|
||||||
case ASTKind::Block:
|
case ASTKind::Block: {
|
||||||
for (ASTNode* child : node->getChildren()) checkStmt(child);
|
// 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;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case ASTKind::VariableDecl: {
|
case ASTKind::VariableDecl: {
|
||||||
auto* vd = (VariableDeclNode*)node;
|
auto* vd = (VariableDeclNode*)node;
|
||||||
Type targetType = Type::fromName(vd->varType);
|
Type targetType = Type::fromName(vd->varType);
|
||||||
|
if (targetType.isError() && table_.structLayouts.count(vd->varType))
|
||||||
|
targetType = Type::structType(vd->varType);
|
||||||
if (vd->initExpr) {
|
if (vd->initExpr) {
|
||||||
Type srcType = checkExpr(vd->initExpr, targetType);
|
Type srcType = checkExpr(vd->initExpr, targetType);
|
||||||
bool isLit = vd->initExpr->kind == ASTKind::Literal;
|
bool isLit = vd->initExpr->kind == ASTKind::Literal;
|
||||||
|
|
@ -142,9 +224,23 @@ void TypeChecker::checkStmt(ASTNode* node) {
|
||||||
|
|
||||||
case ASTKind::IfStatement: {
|
case ASTKind::IfStatement: {
|
||||||
auto* ifn = (IfStatementNode*)node;
|
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 (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 (ifn->elseBranch) checkStmt(ifn->elseBranch);
|
||||||
|
if (!narrowVar.empty() && !isNotNull)
|
||||||
|
narrowedNonNull_.erase(narrowVar);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -178,6 +274,21 @@ void TypeChecker::checkStmt(ASTNode* node) {
|
||||||
case ASTKind::ContinueStatement:
|
case ASTKind::ContinueStatement:
|
||||||
break; // yapısal doğrulama StructuralValidator'ın işi
|
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:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -220,7 +331,14 @@ Type TypeChecker::checkExpr(ASTNode* node, const Type& expected) {
|
||||||
break;
|
break;
|
||||||
case LiteralType::BOOLEAN: result = Type::Bool(); break;
|
case LiteralType::BOOLEAN: result = Type::Bool(); break;
|
||||||
case LiteralType::STRING: result = Type::String(); 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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -229,6 +347,12 @@ Type TypeChecker::checkExpr(ASTNode* node, const Type& expected) {
|
||||||
case ASTKind::Identifier: {
|
case ASTKind::Identifier: {
|
||||||
auto* id = (IdentifierNode*)node;
|
auto* id = (IdentifierNode*)node;
|
||||||
result = id->resolvedSymbol ? id->resolvedSymbol->type : Type::error();
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -265,23 +389,68 @@ Type TypeChecker::checkExpr(ASTNode* node, const Type& expected) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Type leftType = checkExpr(bin->Left);
|
Type leftType = checkExpr(bin->Left);
|
||||||
Type rightType = checkExpr(bin->Right);
|
|
||||||
|
|
||||||
// Mantıksal
|
// ADR-021: && kısa-devre sağ taraf narrowing — "a != null && a.field"
|
||||||
if (bin->Operator == TokenType::AMPERSAND_AMPERSAND ||
|
if (bin->Operator == TokenType::AMPERSAND_AMPERSAND) {
|
||||||
bin->Operator == TokenType::PIPE_PIPE) {
|
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();
|
result = Type::Bool();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Karşılaştırma
|
Type rightType = checkExpr(bin->Right);
|
||||||
if (bin->Operator == TokenType::EQUAL_EQUAL ||
|
|
||||||
bin->Operator == TokenType::BANG_EQUAL ||
|
// Mantıksal (||)
|
||||||
bin->Operator == TokenType::LESS ||
|
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::LESS_EQUAL ||
|
||||||
bin->Operator == TokenType::GREATER ||
|
bin->Operator == TokenType::GREATER ||
|
||||||
bin->Operator == TokenType::GREATER_EQUAL) {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -359,15 +528,34 @@ Type TypeChecker::checkExpr(ASTNode* node, const Type& expected) {
|
||||||
// ── MemberAccess / IndexExpression ─────────────────────────────────────
|
// ── MemberAccess / IndexExpression ─────────────────────────────────────
|
||||||
case ASTKind::MemberAccess: {
|
case ASTKind::MemberAccess: {
|
||||||
auto* ma = (MemberAccessNode*)node;
|
auto* ma = (MemberAccessNode*)node;
|
||||||
checkExpr(ma->object);
|
Type objType = checkExpr(ma->object);
|
||||||
result = Type::error(); // TODO(faz3+): struct alan çözümü
|
// 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;
|
break;
|
||||||
}
|
}
|
||||||
case ASTKind::IndexExpression: {
|
case ASTKind::IndexExpression: {
|
||||||
auto* ie = (IndexExpressionNode*)node;
|
auto* ie = (IndexExpressionNode*)node;
|
||||||
checkExpr(ie->object);
|
Type objType = checkExpr(ie->object);
|
||||||
if (ie->index) checkExpr(ie->index);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
#ifndef SAQUT_SEMANTIC_TYPE_CHECKER
|
#ifndef SAQUT_SEMANTIC_TYPE_CHECKER
|
||||||
#define SAQUT_SEMANTIC_TYPE_CHECKER
|
#define SAQUT_SEMANTIC_TYPE_CHECKER
|
||||||
|
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <string>
|
||||||
#include "symbol/symbol_table.hpp"
|
#include "symbol/symbol_table.hpp"
|
||||||
#include "diagnostic/diagnostic_engine.hpp"
|
#include "diagnostic/diagnostic_engine.hpp"
|
||||||
#include "parser/ast_node.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.
|
// İ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);
|
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_;
|
SymbolTable& table_;
|
||||||
DiagnosticEngine& diag_;
|
DiagnosticEngine& diag_;
|
||||||
|
|
||||||
Type currentReturnType_; // aktif fonksiyonun beklenen dönüş tipi
|
Type currentReturnType_; // aktif fonksiyonun beklenen dönüş tipi
|
||||||
bool inFunction_ = false;
|
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
|
#endif // SAQUT_SEMANTIC_TYPE_CHECKER
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,18 @@ void SymbolCollector::seedBuiltins() {
|
||||||
Type::function(Type::Void(), {}),
|
Type::function(Type::Void(), {}),
|
||||||
SourceLocation{});
|
SourceLocation{});
|
||||||
if (s) s->isBuiltin = true;
|
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ı");
|
"'" + st->name + "' zaten bu kapsamda tanımlı");
|
||||||
break;
|
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()) {
|
for (ASTNode* fieldNode : st->getChildren()) {
|
||||||
if (fieldNode->kind == ASTKind::VariableDecl) {
|
if (fieldNode->kind == ASTKind::VariableDecl) {
|
||||||
auto* vd = (VariableDeclNode*)fieldNode;
|
auto* vd = (VariableDeclNode*)fieldNode;
|
||||||
// yalnızca struct tipindeki alanları izle
|
Type ft = typeFromName(vd->varType, vd->loc);
|
||||||
Type ft = Type::fromName(vd->varType);
|
table_.structLayouts[st->name].push_back({vd->name, ft});
|
||||||
if (ft.isError()) // primitif değilse struct tipi olabilir
|
|
||||||
structFields_[st->name].push_back(vd->varType);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -124,44 +137,10 @@ void SymbolCollector::pass1Globals(ASTNode* program) {
|
||||||
// ─────────────────────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
void SymbolCollector::checkStructCycles() {
|
void SymbolCollector::checkStructCycles() {
|
||||||
// white=0 / gray=1 / black=2
|
// ADR-020: Struct alanları referans semantiği taşır (Object* pointer).
|
||||||
std::unordered_map<std::string, int> color;
|
// By-value gömme yok → sonsuz-boyut döngüsü imkânsız.
|
||||||
for (auto& kv : structFields_) color[kv.first] = 0;
|
// 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.
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─────────────────────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
@ -306,6 +285,29 @@ void SymbolCollector::walkStmt(ASTNode* node) {
|
||||||
case ASTKind::ContinueStatement:
|
case ASTKind::ContinueStatement:
|
||||||
break; // yaprak
|
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:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <unordered_map>
|
||||||
#include "symbol/scope.hpp"
|
#include "symbol/scope.hpp"
|
||||||
|
|
||||||
class SymbolTable {
|
class SymbolTable {
|
||||||
|
|
@ -50,6 +51,26 @@ public:
|
||||||
return result;
|
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:
|
private:
|
||||||
Scope* newScope(Scope* p) {
|
Scope* newScope(Scope* p) {
|
||||||
scopes_.push_back(std::make_unique<Scope>(p));
|
scopes_.push_back(std::make_unique<Scope>(p));
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,26 @@
|
||||||
#include "vm/interpreter.hpp"
|
#include "vm/interpreter.hpp"
|
||||||
|
#include "vm/object.hpp"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <stdexcept>
|
#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() {
|
int Interpreter::run() {
|
||||||
|
// Global slot'ları sıfırla
|
||||||
|
globalSlots_.assign(program_.globalCount, Value::fromInt(0));
|
||||||
|
|
||||||
IRFunction* mainFunction = program_.findFunction("main");
|
IRFunction* mainFunction = program_.findFunction("main");
|
||||||
if (!mainFunction)
|
if (!mainFunction)
|
||||||
throw std::runtime_error("Çalışma hatası: 'main' fonksiyonu bulunamadı");
|
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);
|
frame.slots[instr.dest] = Value::fromString(instr.stringValue);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Opcode::LOAD_NULL:
|
||||||
|
frame.slots[instr.dest] = Value::null();
|
||||||
|
break;
|
||||||
|
|
||||||
case Opcode::LOAD_SLOT:
|
case Opcode::LOAD_SLOT:
|
||||||
frame.slots[instr.dest] = frame.slots[instr.src];
|
frame.slots[instr.dest] = frame.slots[instr.src];
|
||||||
break;
|
break;
|
||||||
|
|
@ -59,17 +81,46 @@ int Interpreter::run() {
|
||||||
break;
|
break;
|
||||||
case Opcode::DIV: {
|
case Opcode::DIV: {
|
||||||
int d = frame.slots[instr.right].intValue;
|
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);
|
frame.slots[instr.dest] = Value::fromInt(frame.slots[instr.left].intValue / d);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Opcode::MOD: {
|
case Opcode::MOD: {
|
||||||
int d = frame.slots[instr.right].intValue;
|
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);
|
frame.slots[instr.dest] = Value::fromInt(frame.slots[instr.left].intValue % d);
|
||||||
break;
|
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 ─────────────────────────────────────────────────
|
// ── Karşılaştırma ─────────────────────────────────────────────────
|
||||||
case Opcode::LESS:
|
case Opcode::LESS:
|
||||||
frame.slots[instr.dest] = Value::fromInt(
|
frame.slots[instr.dest] = Value::fromInt(
|
||||||
|
|
@ -89,17 +140,25 @@ int Interpreter::run() {
|
||||||
break;
|
break;
|
||||||
case Opcode::EQUAL_EQUAL: {
|
case Opcode::EQUAL_EQUAL: {
|
||||||
auto& lv = frame.slots[instr.left]; auto& rv = frame.slots[instr.right];
|
auto& lv = frame.slots[instr.left]; auto& rv = frame.slots[instr.right];
|
||||||
int r = (lv.kind == ValueKind::String)
|
int r;
|
||||||
? (lv.stringValue == rv.stringValue ? 1 : 0)
|
if (lv.kind == ValueKind::Ref || rv.kind == ValueKind::Ref)
|
||||||
: (lv.intValue == rv.intValue ? 1 : 0);
|
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);
|
frame.slots[instr.dest] = Value::fromInt(r);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Opcode::NOT_EQUAL: {
|
case Opcode::NOT_EQUAL: {
|
||||||
auto& lv = frame.slots[instr.left]; auto& rv = frame.slots[instr.right];
|
auto& lv = frame.slots[instr.left]; auto& rv = frame.slots[instr.right];
|
||||||
int r = (lv.kind == ValueKind::String)
|
int r;
|
||||||
? (lv.stringValue != rv.stringValue ? 1 : 0)
|
if (lv.kind == ValueKind::Ref || rv.kind == ValueKind::Ref)
|
||||||
: (lv.intValue != rv.intValue ? 1 : 0);
|
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);
|
frame.slots[instr.dest] = Value::fromInt(r);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -112,6 +171,10 @@ int Interpreter::run() {
|
||||||
if (!frame.slots[instr.cond].isTruthy())
|
if (!frame.slots[instr.cond].isTruthy())
|
||||||
frame.instructionPointer = instr.jumpTarget;
|
frame.instructionPointer = instr.jumpTarget;
|
||||||
break;
|
break;
|
||||||
|
case Opcode::JIF_TRUE:
|
||||||
|
if (frame.slots[instr.cond].isTruthy())
|
||||||
|
frame.instructionPointer = instr.jumpTarget;
|
||||||
|
break;
|
||||||
|
|
||||||
// ── Fonksiyon çağrısı ─────────────────────────────────────────────
|
// ── Fonksiyon çağrısı ─────────────────────────────────────────────
|
||||||
case Opcode::CALL: {
|
case Opcode::CALL: {
|
||||||
|
|
@ -148,11 +211,170 @@ int Interpreter::run() {
|
||||||
continue;
|
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 ───────────────────────────────────────────────────────────
|
// ── FFI ───────────────────────────────────────────────────────────
|
||||||
case Opcode::CALLHOST:
|
case Opcode::CALLHOST:
|
||||||
executeHostFunction(instr.functionName, frame.slots, instr.argSlots);
|
executeHostFunction(instr.functionName, frame.slots, instr.argSlots);
|
||||||
break;
|
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;
|
return 0;
|
||||||
|
|
@ -164,8 +386,7 @@ void Interpreter::executeHostFunction(const std::string& name,
|
||||||
if (name == "print") {
|
if (name == "print") {
|
||||||
if (!argSlots.empty()) {
|
if (!argSlots.empty()) {
|
||||||
const Value& val = slots[argSlots[0]];
|
const Value& val = slots[argSlots[0]];
|
||||||
if (val.kind == ValueKind::String) std::cout << val.stringValue << "\n";
|
std::cout << val.toString() << "\n";
|
||||||
else std::cout << val.intValue << "\n";
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,17 @@
|
||||||
#define SAQUT_VM_INTERPRETER
|
#define SAQUT_VM_INTERPRETER
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <optional>
|
||||||
#include "ir/ir_program.hpp"
|
#include "ir/ir_program.hpp"
|
||||||
#include "vm/call_frame.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 {
|
class Interpreter {
|
||||||
public:
|
public:
|
||||||
|
|
@ -26,8 +35,17 @@ public:
|
||||||
int run();
|
int run();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IRProgram& program_;
|
IRProgram& program_;
|
||||||
std::vector<CallFrame> callStack_;
|
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
|
// Host (C++) fonksiyon çağrısı — şu an sadece "print" destekli
|
||||||
void executeHostFunction(const std::string& name,
|
void executeHostFunction(const std::string& name,
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
#ifndef SAQUT_VM_VALUE
|
||||||
#define SAQUT_VM_VALUE
|
#define SAQUT_VM_VALUE
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
// Gelecekte float/bool/string eklendiğinde burası genişleyecek.
|
// Forward — Object tam tanımı object.hpp'de; Value onu pointer olarak taşır.
|
||||||
// Şimdilik sadece int.
|
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 {
|
enum class ValueKind {
|
||||||
Int,
|
Int,
|
||||||
|
Float, // #44: float/double tek kind; floatValue alanı taşır
|
||||||
String,
|
String,
|
||||||
// Float, // TODO(vm-genişletme)
|
Ref, // ADR-020: array/struct nesnesine Object* referansı
|
||||||
// Bool, // TODO(vm-genişletme)
|
Null, // ADR-021: nullable referansın null değeri (saQut kaynağında `null`)
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Value {
|
struct Value {
|
||||||
ValueKind kind = ValueKind::Int;
|
ValueKind kind = ValueKind::Int;
|
||||||
int intValue = 0;
|
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) {
|
static Value fromInt(int n) {
|
||||||
Value v;
|
Value v; v.kind = ValueKind::Int; v.intValue = n; return 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) {
|
static Value fromString(std::string s) {
|
||||||
Value v;
|
Value v; v.kind = ValueKind::String; v.stringValue = std::move(s); return 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 {
|
bool isTruthy() const {
|
||||||
if (kind == ValueKind::Int) return intValue != 0;
|
switch (kind) {
|
||||||
if (kind == ValueKind::String) return !stringValue.empty();
|
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;
|
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 {
|
std::string typeName() const {
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case ValueKind::Int: return "int";
|
case ValueKind::Int: return "int";
|
||||||
|
case ValueKind::Float: return "float";
|
||||||
case ValueKind::String: return "string";
|
case ValueKind::String: return "string";
|
||||||
|
case ValueKind::Ref: return "ref";
|
||||||
|
case ValueKind::Null: return "null";
|
||||||
}
|
}
|
||||||
return "?";
|
return "?";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
5
|
||||||
|
6
|
||||||
|
12
|
||||||
|
3
|
||||||
|
1
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
int main() {
|
||||||
|
print(2 + 3);
|
||||||
|
print(10 - 4);
|
||||||
|
print(3 * 4);
|
||||||
|
print(10 / 3);
|
||||||
|
print(10 % 3);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
2
|
||||||
|
1
|
||||||
|
0
|
||||||
|
2
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
sıfıra bölme \(mod\)
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
7
|
||||||
|
9
|
||||||
|
3
|
||||||
|
3
|
||||||
|
1
|
||||||
|
11
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
99
|
||||||
|
1
|
||||||
|
0
|
||||||
|
2
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
8
|
||||||
|
14
|
||||||
|
24
|
||||||
|
6
|
||||||
|
-1
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
6
|
||||||
|
14
|
||||||
|
56
|
||||||
|
28
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
yakalandi
|
||||||
|
Sıfıra bölme
|
||||||
|
E_DIVZERO
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
OOB yakalandi
|
||||||
|
E_OOB
|
||||||
|
throw yakalandi
|
||||||
|
devam
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
55
|
||||||
|
55
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
5.14
|
||||||
|
6.28
|
||||||
|
1.14
|
||||||
|
1.57
|
||||||
|
1.0
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
5
|
||||||
|
105
|
||||||
|
8
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
10
|
||||||
|
20
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
int base = 10;
|
||||||
|
int doubled = 0;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
doubled = base * 2;
|
||||||
|
print(base);
|
||||||
|
print(doubled);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
1
|
||||||
|
0
|
||||||
|
1
|
||||||
|
0
|
||||||
|
1
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
S
|
||||||
|
evet_and
|
||||||
|
evet_or1
|
||||||
|
S
|
||||||
|
evet_or2
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
0
|
||||||
|
1
|
||||||
|
2
|
||||||
|
0
|
||||||
|
1
|
||||||
|
2
|
||||||
|
0
|
||||||
|
1
|
||||||
|
2
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
5
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
int main() {
|
||||||
|
int x = 5;
|
||||||
|
do {
|
||||||
|
print(x);
|
||||||
|
x = x + 1;
|
||||||
|
} while (x < 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
5
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
1
|
||||||
|
3
|
||||||
|
5
|
||||||
|
1
|
||||||
|
2
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
1
|
||||||
|
1
|
||||||
|
2
|
||||||
|
1
|
||||||
|
3
|
||||||
|
1
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
1
|
||||||
|
2
|
||||||
|
4
|
||||||
|
5
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
1
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
42
|
||||||
|
0
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue