diff --git a/.gitignore b/.gitignore index 65b942d..38ac63c 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,4 @@ scripts/gitea.py __pycache__/ # CMake versiyona özgü dosyalar (otomatik üretilir, her güncellemede değişir) -build/CMakeFiles/[0-9]*/ -build/.cmake/ -build/compile_commands.json +build/* diff --git a/CLAUDE.md b/CLAUDE.md index d556c7a..bc58d9b 100644 --- a/CLAUDE.md +++ b/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 gerekirse libgccjit/LLVM'e bağlanılır (çok uzak). Bellek = host C++ heap; özel allocator yok. (ADR-015) -- **Dil kimliği:** prosedürel, C-ailesi sözdizimi, value semantics, zorunlu - class/main boilerplate yok. **Yok:** class/OOP, closure, generic, kullanıcı - pointer'ı (`*`/`&`), auto/tip çıkarımı, gizli int↔float (tek istisna sabit - folding). **Var:** struct, tipli fonksiyonlar, array (`int[]`). `interface` - **ertelendi** (reddedilmedi, ADR-018). +- **Dil kimliği:** prosedürel, C-ailesi sözdizimi, zorunlu class/main boilerplate + yok. **Semantik (ADR-020):** primitive (`int`/`float`/`bool`) = **değer**; + bileşik (`struct`/`array`/`string`) = **referans** (JS/Java/C# modeli). "Pointer + yok" = kullanıcıya `&`/`*` **sözdizimi** verilmez; derleyici/runtime içeride ve + çalışma zamanında referansı sonuna kadar kullanır. **Yok:** OOP, closure, + generic, auto/tip çıkarımı, gizli int↔float (tek istisna sabit folding). **Var:** + struct, tipli fonksiyonlar, array (`int[]`). `class`/`function` sözdizimsel + **rezerve** (semantik ileride). `interface` **ertelendi** (ADR-018). + ⚠️ Referans semantiği döngüsel-referans **sızıntısını** açtı → GC/döngü + toplayıcı borcu (**#56**, `karar-gerekli`). +- **Null güvenliği (ADR-021, REVİZE):** varsayılan non-null; nullable açıkça `Type?` + (Kotlin/Swift). `null` yalnızca `T?`'ye atanır; `T?` üstünde doğrudan erişim derleme + hatası. **Atama kuralı `T <: T?`** (notnull→nullable serbest, nullable→notnull yasak). + **Katı operand kuralı:** non-null bağlamda her operand statik non-null olmalı + (`int a=b+c+d`, biri nullable → hata). Aklama **yalnızca görünür `if` narrowing** + (nested + sıralı guard + `&&`; alias takibi yok). ⚠️ **`a!`/`??`/`?.` YASAK** (gizli + runtime null-aklama yok). Runtime maliyeti **sıfır**; frontend kesin çözer (backend + yeniden analiz etmez) → runtime null-deref esasen FFI backstop'u. SSA gerekmez (#2). +- **Bellek/GC (ADR-022):** **basit, taşımasız, stop-the-world, deterministik + mark-sweep** (döngüleri toplar, "cage" korunur). **`shared_ptr`'ı kalıcı model + YAPMA** (refcount döngüde sızar = topuğa-sıkma). Kural: nesne modelini **baştan + GC-hazır** kur (header: tip+mark biti+liste; VM kök sayar; nesne çocuk + referansları sayar). v1: toplamasız (arena); v2: aynı model üstünde mark-sweep. + Asıl perf-katili GC kararı → basit tutarak de-risk edildi. +- **Eşitlik (ADR-023):** `==` primitive'de değer, referans (struct/array) **kimlik** + (aynı nesne). Derin/yapısal eşitlik **asla** `==`'e bağlanmaz → ayrı görünür + `deepEquals()` (PHP `==`/`===`/`clone` ailesi gibi). **String istisnası:** `==` + **içerik** olmalı (Java gotcha'sından kaçın) → string'i immutable değer-tipi + modelle (#40). `obj==obj`'i hata yapmak + kullanıcı-tanımlı eşitlik = uzak gelecek. +- **String (ADR-024):** **immutable değer-tipi, iç temsil UTF-8.** `s = s + "x"` + yeni string üretir; `==` içerik (ADR-023). Bayt/scalar/grapheme erişimi açıkça + ayrı (sahte O(1) karakter indeksi YOK). Verimli birleştirme için ileride builder. + Çözdüğü: #40 (yüzey), #9 (iç temsil). Mevcut `Value` string'i inline tutuyor — + immutable olduğu için bu yeterli; heap/object-model'e taşımak zorunlu değil. +- **Hata yönetimi (ADR-025, #57):** **Swift-tarzı** yakalanabilir, **struct-tabanlı** + hata — OOP/extend YOK. Standart `Error { line; char; message; trace; code }` + (message=W/E metni, code=W/E kodu). **Klasik `try{}catch{}` bloğu, UNCHECKED** + (Java/C#/JS usulü): fonksiyon işaretlenmez (`noexcept`/`constexpr` tarzı YOK), + çağrıda `try f()` yok — developer'a güven, alışkanlık bozulmaz. Runtime null-deref + (NPE analoğu), array OOB, /0, `a!` patlaması → yakalanabilir hata (ADR-021'in runtime + backstop'u). `throw` ile kullanıcı da kaldırır. Deterministik stacktrace (IR satır + tablosu önkoşul). **Tuple → ertelendi** (ADR-014'teki "yok" gevşedi). `finally` yerine + ileride `defer`. +- **Tip dönüşümü (ADR-026, #42):** 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 **klon** üstünde dönüşüm. `ASTNode::clone()` yük taşıyan merkezi bileşen (parent pointer'lar + sembol tablosu remap edilir, ADR-007). Fixpoint döngüsü + iterasyon tavanı (`maxFixpointRounds`, ADR-009). - **Literal/tip kuralı:** tamsayı literali bağlama-göre tiplenir (`float x = 1;` geçerli; `int y = 1.5;`→E003; değişken→değişken gizli dönüşüm yok). Döngüsel - by-value struct → E010. (ADR-010/011) + by-value struct → E010 (⚠️ ADR-020 ile revize: referansla tutulan struct alanı + artık döngü kurabilir, `Node next` meşru). (ADR-010/011) - **FFI seam:** kasıtlı "host fonksiyonu çağır" mekanizması (`callhost`); `print` ilk müşteri (ADR-016). Batteries = sınır/FFI problemi, "zlib'i yeniden yaz" değil; kripto asla elle yazılmaz (ADR-017). ## Mevcut durum (yapılan vs planlanan) -- **Çalışıyor:** lexer, tokenizer, Pratt parser, AST, AST'nin JSON serileştirmesi, - CLI iskeleti (`tokens`/`ast`/`symbols`/`run`), konum takibi, basit aritmetiği - düşüren minimal IR deneyi. -- **Planlı (henüz YOK):** sembol tablosu, semantik analiz, tip sistemi, diagnostic - motoru, optimizasyon, IR+bytecode VM ile çalıştırma. -- **Birinci kilometre taşı ("bitti" tanımı):** `examples/fibonacci.sqt` - (recursive + iterative) derlenip çalıştırılabilmeli. +- **✅ Birinci kilometre taşı AŞILDI:** `examples/fibonacci.sqt` + (recursive + iterative) `saqut run` ile çalışıyor → `55\n55`. +- **Çalışıyor (tam pipeline):** + - Lexer, tokenizer, Pratt parser, AST + JSON serileştirmesi + - Sembol tablosu (iki-geçişli toplayıcı, döngüsel struct tespiti) + - Tip sistemi (`src/core/type.hpp`) + diagnostic motoru (`src/diagnostic/`) + - Tip denetleyici + yapısal doğrulayıcı (`src/semantic/`) + - Optimizasyon: constant folding (int/bool/logical) + dead code elimination + - IR üreteci (3-adresli, slot tabanlı) + bytecode VM (yorumlayıcı döngü) + - CLI: `tokens` / `ast` / `symbols` / `check` / `ir` / `run` (6 komut) +- **Henüz YOK (bilinen eksikler):** + - float/double codegen (tip sistemi var, IR opcode'u yok) + - struct IR (parse/semantik var, codegen yok) + - array IR (parse/semantik var, codegen yok) + - `%=` operatörü IR'da eksik (#37) + - Global değişken IR üretimi sessizce atlıyor (#38) + - W003 ölü kod uyarısı üretilmiyor (#36) + - DCE silinen düğümleri `delete` etmiyor — bellek sızıntısı (#35) - **İlke:** Önce uçtan uca tek **dikey dilim**, sonra çerçeve. Erken soyutlamadan kaçın. ## Belge haritası - `readme.md` — toolbox çerçevesi, built-vs-planned, dil kimliği, çalıştırma modeli. - `docs/fikirler.md` — ADR-001…005 (backend stratejisi, parser, header-only, token, IR). -- `docs/adr-frontend-analiz.md` — ADR-006…019 (frontend, analiz/optimizasyon, - çalıştırma modeli, FFI, interface, bellek). +- `docs/adr-frontend-analiz.md` — ADR-006…026 (frontend, analiz/optimizasyon, + çalıştırma modeli, FFI, interface, bellek, **değer/referans semantiği, null + güvenliği, mark-sweep GC, eşitlik, string, hata yönetimi, tip dönüşümü**). +- `docs/sonnet-handoff.md` — **Sonnet için uygulama promptu** (ADR-020…024'ü koda + döken sıralı görev planı; ilk görev: GC-hazır nesne modeli + array runtime). - `docs/roadmap-frontend.md` — faz-faz uygulama planı (Faz 0–4 → fibonacci). - `docs/transkript-frontend-tasarim.md` — tasarım oturumu transkripti. - `examples/fibonacci.sqt` — geçerli referans program. @@ -97,6 +155,6 @@ git'te izlenir. ## Çalışma konvansiyonları - Commit mesajları sonunda: `Co-Authored-By: Claude Opus 4.8 `. -- Ana dal `master`; commit/push kullanıcı isteyince yapılır. +- Ana dal `0.1.0`; `master` branch yok. commit/push kullanıcı isteyince yapılır. - Wiki API'si Gitea'da REST üzerinden çalışmadı; wiki içeriği `wiki.md`'ye yazılıp kullanıcı tarafından elle yapıştırılıyor. diff --git a/CMakeLists.txt b/CMakeLists.txt index 37cdcf9..3e6bf64 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,3 +20,99 @@ file(GLOB_RECURSE SOURCES "src/*.cpp") add_executable(saqut ${SOURCES}) target_include_directories(saqut PRIVATE src) + +# ── Testler ────────────────────────────────────────────────────────────────── +enable_testing() + +set(SAQUT_BINARY "${CMAKE_BINARY_DIR}/saqut") +set(GOLDEN_SCRIPT "${CMAKE_SOURCE_DIR}/cmake/run_golden.cmake") + +# Birim testleri (tests/run.sh) +add_test( + NAME unit_tests + COMMAND bash "${CMAKE_SOURCE_DIR}/tests/run.sh" +) + +# Golden testleri — tests/golden/**/*.sqt dosyalarını otomatik keşfet. +# Her .sqt için iki olası expected dosyası kontrol edilir: +# BASE.expected → saqut run (siyah-kutu çıktı testi) +# BASE.ir_opt.expected → saqut ir --optimized (beyaz-kutu IR testi) +file(GLOB_RECURSE ALL_GOLDEN_SQT CONFIGURE_DEPENDS + "${CMAKE_SOURCE_DIR}/tests/golden/*.sqt" +) +foreach(SQT_FILE ${ALL_GOLDEN_SQT}) + file(RELATIVE_PATH REL "${CMAKE_SOURCE_DIR}/tests/golden" "${SQT_FILE}") + string(REPLACE ".sqt" "" BASE "${REL}") + string(REPLACE "/" "_" TNAME "${BASE}") + + # Siyah-kutu: saqut run çıktısı + set(RUN_EXPECTED "${CMAKE_SOURCE_DIR}/tests/golden/${BASE}.expected") + if(EXISTS "${RUN_EXPECTED}") + add_test( + NAME "golden_${TNAME}" + COMMAND ${CMAKE_COMMAND} + -DBINARY=${SAQUT_BINARY} + -DSOURCE=${SQT_FILE} + -DEXPECTED=${RUN_EXPECTED} + -P "${GOLDEN_SCRIPT}" + ) + endif() + + # Beyaz-kutu: saqut ir --optimized çıktısı + set(IR_OPT_EXPECTED "${CMAKE_SOURCE_DIR}/tests/golden/${BASE}.ir_opt.expected") + if(EXISTS "${IR_OPT_EXPECTED}") + add_test( + NAME "golden_${TNAME}_ir_opt" + COMMAND ${CMAKE_COMMAND} + -DBINARY=${SAQUT_BINARY} + -DSOURCE=${SQT_FILE} + -DEXPECTED=${IR_OPT_EXPECTED} + -DCOMMAND=ir + -DOPTIMIZED=1 + -P "${GOLDEN_SCRIPT}" + ) + endif() + + # Doğruluk kalkanı: saqut run --optimized çıktısı == beklenen golden değer + # "Optimizasyon oldu" değil, "optimize IR doğru sonuç verdi" testleri. + set(RUN_OPT_EXPECTED "${CMAKE_SOURCE_DIR}/tests/golden/${BASE}.run_opt.expected") + if(EXISTS "${RUN_OPT_EXPECTED}") + add_test( + NAME "golden_${TNAME}_run_opt" + COMMAND ${CMAKE_COMMAND} + -DBINARY=${SAQUT_BINARY} + -DSOURCE=${SQT_FILE} + -DEXPECTED=${RUN_OPT_EXPECTED} + -DOPTIMIZED=1 + -P "${GOLDEN_SCRIPT}" + ) + endif() + + # Negatif test: .compile_error — derleme hatası beklenen golden testler. + # Dosya içeriği stderr'de aranır (regex/düz dize). + set(COMPILE_ERROR_EXPECTED "${CMAKE_SOURCE_DIR}/tests/golden/${BASE}.compile_error") + if(EXISTS "${COMPILE_ERROR_EXPECTED}") + add_test( + NAME "golden_${TNAME}_compile_error" + COMMAND ${CMAKE_COMMAND} + -DBINARY=${SAQUT_BINARY} + -DSOURCE=${SQT_FILE} + -DEXPECTED=${COMPILE_ERROR_EXPECTED} + -P "${CMAKE_SOURCE_DIR}/cmake/run_golden_error.cmake" + ) + endif() + + # Negatif test: .runtime_error — çalışma zamanı hatası beklenen golden testler. + # Aynı altyapı: exit code != 0 + stderr içeriği kontrolü. + set(RUNTIME_ERROR_EXPECTED "${CMAKE_SOURCE_DIR}/tests/golden/${BASE}.runtime_error") + if(EXISTS "${RUNTIME_ERROR_EXPECTED}") + add_test( + NAME "golden_${TNAME}_runtime_error" + COMMAND ${CMAKE_COMMAND} + -DBINARY=${SAQUT_BINARY} + -DSOURCE=${SQT_FILE} + -DEXPECTED=${RUNTIME_ERROR_EXPECTED} + -P "${CMAKE_SOURCE_DIR}/cmake/run_golden_error.cmake" + ) + endif() +endforeach() diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..62cc727 --- /dev/null +++ b/TODO.md @@ -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> 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. diff --git a/build/.ninja_deps b/build/.ninja_deps index 8eaeabe..6c0fa8c 100644 Binary files a/build/.ninja_deps and b/build/.ninja_deps differ diff --git a/build/.ninja_log b/build/.ninja_log index 266c597..1e4d8e1 100644 --- a/build/.ninja_log +++ b/build/.ninja_log @@ -1,23 +1,34 @@ # ninja log v7 -13 4576 1781796718440262330 CMakeFiles/saqut.dir/src/core/sourcefile.cpp.o 20f68631dd335029 -13 4805 1781796718441539505 CMakeFiles/saqut.dir/src/lexer/lexer.cpp.o 5fd259c0401f3e22 -1 2117 1781796771817437208 CMakeFiles/saqut.dir/src/tokenizer/tokenizer.cpp.o fbabe80dcb141239 -4580 9322 1781796723007277591 CMakeFiles/saqut.dir/src/parser/parser.cpp.o 59cdb5935c541b26 -21 6876 1781796718448262357 CMakeFiles/saqut.dir/src/parser/nodes/program.cpp.o 9313cba8d8daffed -16 6700 1781796718443848488 CMakeFiles/saqut.dir/src/parser/nodes/identifier.cpp.o e3b5b38d75fcd2ca -15 7814 1781796718443331391 CMakeFiles/saqut.dir/src/parser/nodes/expressions.cpp.o 5f5bb01381a3c3ad -16 7589 1781796718444498682 CMakeFiles/saqut.dir/src/parser/nodes/literal.cpp.o 55743f37408c5f -21 7502 1781796718449424977 CMakeFiles/saqut.dir/src/parser/nodes/statements.cpp.o 3c8869307381c930 -14 6864 1781796718442362341 CMakeFiles/saqut.dir/src/parser/nodes/binary_expr.cpp.o 5cc8b697133bcf64 -15 6733 1781796718442847556 CMakeFiles/saqut.dir/src/parser/nodes/declarations.cpp.o c3d262615ede4c95 -1 4629 1781801148234045650 CMakeFiles/saqut.dir/src/main.cpp.o 3cfef7a665d5bf87 -4629 4900 1781801152862380672 saqut f2e198803c4dbffb -0 22 1781801180493522122 build.ninja 1876a59d627a585 -0 22 1781801180493522122 /home/saqut/Masaüstü/saqutcompiler/build/cmake_install.cmake 1876a59d627a585 -6733 11112 1781796725160284765 CMakeFiles/saqut.dir/src/symbol/symbol_collector.cpp.o ec4e483b8ddb4007 -4805 9685 1781796723232278341 CMakeFiles/saqut.dir/src/semantic/structural_validator.cpp.o 248faa3675024351 -6700 10405 1781796725127284655 CMakeFiles/saqut.dir/src/semantic/type_checker.cpp.o b29c133293d988b0 -1 850 1781801148235507662 CMakeFiles/saqut.dir/src/vm/interpreter.cpp.o b7dd80e002d68a1d -2 957 1781800866770475511 CMakeFiles/saqut.dir/src/ir/ir_function.cpp.o 10f5e8dfd1461d69 -2 718 1781800866771246136 CMakeFiles/saqut.dir/src/ir/ir_program.cpp.o 9518231d970828da -2 3169 1781800866771136888 CMakeFiles/saqut.dir/src/ir/ir_generator.cpp.o 10a1ed4e1f52e530 +1 9 1781900092189939762 /home/saqut/Masaüstü/saqutcompiler/build/CMakeFiles/cmake.verify_globs 1813c41e0f312d7e +10 1691 1781900092199402809 CMakeFiles/saqut.dir/src/ir/ir_program.cpp.o d681b36458a6e5f5 +10 1957 1781900092199188672 CMakeFiles/saqut.dir/src/ir/ir_function.cpp.o 85cbc174284792d4 +10 5411 1781900092199511505 CMakeFiles/saqut.dir/src/lexer/lexer.cpp.o 90eeec811f2137e6 +10 5413 1781900092198939716 CMakeFiles/saqut.dir/src/core/sourcefile.cpp.o da6f5fc90e87e6b1 +10 6729 1781900092199847028 CMakeFiles/saqut.dir/src/parser/nodes/declarations.cpp.o b6c56f04a257f685 +15 7732 1781900092203939691 CMakeFiles/saqut.dir/src/parser/nodes/expressions.cpp.o 4057e3d63c63a1ab +10 8908 1781900092199302769 CMakeFiles/saqut.dir/src/ir/ir_generator.cpp.o 84c9f816f969cfa7 +10 9701 1781900092199743167 CMakeFiles/saqut.dir/src/parser/nodes/binary_expr.cpp.o d2e2bb2f8a63c6d2 +1709 9770 1781900093898639567 CMakeFiles/saqut.dir/src/parser/nodes/literal.cpp.o 78f2c4da7c9b2281 +15 10364 1781900092204948414 CMakeFiles/saqut.dir/src/parser/nodes/identifier.cpp.o eb96bb4b1eb4ad80 +1957 11871 1781900094145929879 CMakeFiles/saqut.dir/src/parser/nodes/program.cpp.o ac5bbcd74d87561a +9770 11899 1781900101958890478 CMakeFiles/saqut.dir/src/vm/interpreter.cpp.o 88078036625564ef +5413 11959 1781900097601912436 CMakeFiles/saqut.dir/src/parser/parser.cpp.o 2c65b7be26cead32 +10 12284 1781900092199621706 CMakeFiles/saqut.dir/src/main.cpp.o 110c26cb1d0c3a23 +6729 13187 1781900098917905800 CMakeFiles/saqut.dir/src/semantic/structural_validator.cpp.o 4bfec8abc0e9893e +5412 13356 1781900097601088348 CMakeFiles/saqut.dir/src/parser/nodes/statements.cpp.o b5c20724bbf3648c +7733 14099 1781900099922227854 CMakeFiles/saqut.dir/src/semantic/type_checker.cpp.o 15f44776b9c3e26d +9701 14179 1781900101889890826 CMakeFiles/saqut.dir/src/tokenizer/tokenizer.cpp.o a01677f8bb4f4dbc +8908 14635 1781900101096894819 CMakeFiles/saqut.dir/src/symbol/symbol_collector.cpp.o 3348f498f369213d +14635 14953 1781900106823866003 saqut 8f3d7184b374150b +2 17 1781900144964675644 /home/saqut/Masaüstü/saqutcompiler/build/CMakeFiles/cmake.verify_globs 1813c41e0f312d7e +18 4193 1781900144981580253 CMakeFiles/saqut.dir/src/semantic/structural_validator.cpp.o 4bfec8abc0e9893e +18 4260 1781900144981478187 CMakeFiles/saqut.dir/src/parser/parser.cpp.o 2c65b7be26cead32 +18 4852 1781900144981695435 CMakeFiles/saqut.dir/src/semantic/type_checker.cpp.o 15f44776b9c3e26d +18 4914 1781900144981374397 CMakeFiles/saqut.dir/src/parser/nodes/declarations.cpp.o b6c56f04a257f685 +18 5211 1781900144980675565 CMakeFiles/saqut.dir/src/ir/ir_generator.cpp.o 84c9f816f969cfa7 +18 5324 1781900144981813038 CMakeFiles/saqut.dir/src/symbol/symbol_collector.cpp.o 3348f498f369213d +18 6912 1781900144981279910 CMakeFiles/saqut.dir/src/main.cpp.o 110c26cb1d0c3a23 +6912 7184 1781900151874641436 saqut 8f3d7184b374150b +1 8 1781900314792856660 /home/saqut/Masaüstü/saqutcompiler/build/CMakeFiles/cmake.verify_globs 1813c41e0f312d7e +9 4869 1781900314800856623 CMakeFiles/saqut.dir/src/main.cpp.o 110c26cb1d0c3a23 +4869 5168 1781900319660833784 saqut 8f3d7184b374150b diff --git a/build/CMakeFiles/CMakeConfigureLog.yaml b/build/CMakeFiles/CMakeConfigureLog.yaml index d915375..7118f3c 100644 --- a/build/CMakeFiles/CMakeConfigureLog.yaml +++ b/build/CMakeFiles/CMakeConfigureLog.yaml @@ -1,4 +1,269 @@ +--- +events: + - + kind: "message-v1" + backtrace: + - "/usr/share/cmake-3.28/Modules/CMakeDetermineSystem.cmake:233 (message)" + - "CMakeLists.txt:2 (project)" + message: | + The system is: Linux - 6.18.5 - x86_64 + - + kind: "message-v1" + backtrace: + - "/usr/share/cmake-3.28/Modules/CMakeDetermineCompilerId.cmake:17 (message)" + - "/usr/share/cmake-3.28/Modules/CMakeDetermineCompilerId.cmake:64 (__determine_compiler_id_test)" + - "/usr/share/cmake-3.28/Modules/CMakeDetermineCXXCompiler.cmake:126 (CMAKE_DETERMINE_COMPILER_ID)" + - "CMakeLists.txt:2 (project)" + message: | + Compiling the CXX compiler identification source file "CMakeCXXCompilerId.cpp" succeeded. + Compiler: /usr/bin/c++ + Build flags: + Id flags: + + The output was: + 0 + + + Compilation of the CXX compiler identification source "CMakeCXXCompilerId.cpp" produced "a.out" + + The CXX compiler identification is GNU, found in: + /home/user/saqut/build/CMakeFiles/3.28.3/CompilerIdCXX/a.out + + - + kind: "try_compile-v1" + backtrace: + - "/usr/share/cmake-3.28/Modules/CMakeDetermineCompilerABI.cmake:57 (try_compile)" + - "/usr/share/cmake-3.28/Modules/CMakeTestCXXCompiler.cmake:26 (CMAKE_DETERMINE_COMPILER_ABI)" + - "CMakeLists.txt:2 (project)" + checks: + - "Detecting CXX compiler ABI info" + directories: + source: "/home/user/saqut/build/CMakeFiles/CMakeScratch/TryCompile-6ljCUz" + binary: "/home/user/saqut/build/CMakeFiles/CMakeScratch/TryCompile-6ljCUz" + cmakeVariables: + CMAKE_CXX_FLAGS: "" + CMAKE_CXX_FLAGS_DEBUG: "-g" + CMAKE_EXE_LINKER_FLAGS: "" + buildResult: + variable: "CMAKE_CXX_ABI_COMPILED" + cached: true + stdout: | + Change Dir: '/home/user/saqut/build/CMakeFiles/CMakeScratch/TryCompile-6ljCUz' + + Run Build Command(s): /usr/bin/ninja -v cmTC_b1346 + [1/2] /usr/bin/c++ -v -o CMakeFiles/cmTC_b1346.dir/CMakeCXXCompilerABI.cpp.o -c /usr/share/cmake-3.28/Modules/CMakeCXXCompilerABI.cpp + Using built-in specs. + COLLECT_GCC=/usr/bin/c++ + OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa + OFFLOAD_TARGET_DEFAULT=1 + Target: x86_64-linux-gnu + Configured with: ../src/configure -v --with-pkgversion='Ubuntu 13.3.0-6ubuntu2~24.04.1' --with-bugurl=file:///usr/share/doc/gcc-13/README.Bugs --enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++,m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-13 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/libexec --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-libstdcxx-backtrace --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --enable-cet --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-13-EldibY/gcc-13-13.3.0/debian/tmp-nvptx/usr,amdgcn-amdhsa=/build/gcc-13-EldibY/gcc-13-13.3.0/debian/tmp-gcn/usr --enable-offload-defaulted --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu --with-build-config=bootstrap-lto-lean --enable-link-serialization=2 + Thread model: posix + Supported LTO compression algorithms: zlib zstd + gcc version 13.3.0 (Ubuntu 13.3.0-6ubuntu2~24.04.1) + COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_b1346.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_b1346.dir/' + /usr/libexec/gcc/x86_64-linux-gnu/13/cc1plus -quiet -v -imultiarch x86_64-linux-gnu -D_GNU_SOURCE /usr/share/cmake-3.28/Modules/CMakeCXXCompilerABI.cpp -quiet -dumpdir CMakeFiles/cmTC_b1346.dir/ -dumpbase CMakeCXXCompilerABI.cpp.cpp -dumpbase-ext .cpp -mtune=generic -march=x86-64 -version -fasynchronous-unwind-tables -fstack-protector-strong -Wformat -Wformat-security -fstack-clash-protection -fcf-protection -o /tmp/ccKBrizP.s + GNU C++17 (Ubuntu 13.3.0-6ubuntu2~24.04.1) version 13.3.0 (x86_64-linux-gnu) + compiled by GNU C version 13.3.0, GMP version 6.3.0, MPFR version 4.2.1, MPC version 1.3.1, isl version isl-0.26-GMP + + GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 + ignoring duplicate directory "/usr/include/x86_64-linux-gnu/c++/13" + ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu" + ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/13/include-fixed/x86_64-linux-gnu" + ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/13/include-fixed" + ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/13/../../../../x86_64-linux-gnu/include" + #include "..." search starts here: + #include <...> search starts here: + /usr/include/c++/13 + /usr/include/x86_64-linux-gnu/c++/13 + /usr/include/c++/13/backward + /usr/lib/gcc/x86_64-linux-gnu/13/include + /usr/local/include + /usr/include/x86_64-linux-gnu + /usr/include + End of search list. + Compiler executable checksum: 7896445e4990772fdae9dc0659a99266 + COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_b1346.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_b1346.dir/' + as -v --64 -o CMakeFiles/cmTC_b1346.dir/CMakeCXXCompilerABI.cpp.o /tmp/ccKBrizP.s + GNU assembler version 2.42 (x86_64-linux-gnu) using BFD version (GNU Binutils for Ubuntu) 2.42 + COMPILER_PATH=/usr/libexec/gcc/x86_64-linux-gnu/13/:/usr/libexec/gcc/x86_64-linux-gnu/13/:/usr/libexec/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/13/:/usr/lib/gcc/x86_64-linux-gnu/ + LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/13/:/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/13/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/13/../../../:/lib/:/usr/lib/ + COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_b1346.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_b1346.dir/CMakeCXXCompilerABI.cpp.' + [2/2] : && /usr/bin/c++ -v CMakeFiles/cmTC_b1346.dir/CMakeCXXCompilerABI.cpp.o -o cmTC_b1346 && : + Using built-in specs. + COLLECT_GCC=/usr/bin/c++ + COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-linux-gnu/13/lto-wrapper + OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa + OFFLOAD_TARGET_DEFAULT=1 + Target: x86_64-linux-gnu + Configured with: ../src/configure -v --with-pkgversion='Ubuntu 13.3.0-6ubuntu2~24.04.1' --with-bugurl=file:///usr/share/doc/gcc-13/README.Bugs --enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++,m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-13 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/libexec --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-libstdcxx-backtrace --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --enable-cet --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-13-EldibY/gcc-13-13.3.0/debian/tmp-nvptx/usr,amdgcn-amdhsa=/build/gcc-13-EldibY/gcc-13-13.3.0/debian/tmp-gcn/usr --enable-offload-defaulted --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu --with-build-config=bootstrap-lto-lean --enable-link-serialization=2 + Thread model: posix + Supported LTO compression algorithms: zlib zstd + gcc version 13.3.0 (Ubuntu 13.3.0-6ubuntu2~24.04.1) + COMPILER_PATH=/usr/libexec/gcc/x86_64-linux-gnu/13/:/usr/libexec/gcc/x86_64-linux-gnu/13/:/usr/libexec/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/13/:/usr/lib/gcc/x86_64-linux-gnu/ + LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/13/:/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/13/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/13/../../../:/lib/:/usr/lib/ + COLLECT_GCC_OPTIONS='-v' '-o' 'cmTC_b1346' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'cmTC_b1346.' + /usr/libexec/gcc/x86_64-linux-gnu/13/collect2 -plugin /usr/libexec/gcc/x86_64-linux-gnu/13/liblto_plugin.so -plugin-opt=/usr/libexec/gcc/x86_64-linux-gnu/13/lto-wrapper -plugin-opt=-fresolution=/tmp/cci1AaX8.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=gnu --as-needed -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -z now -z relro -o cmTC_b1346 /usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/Scrt1.o /usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/13/crtbeginS.o -L/usr/lib/gcc/x86_64-linux-gnu/13 -L/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/13/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/13/../../.. CMakeFiles/cmTC_b1346.dir/CMakeCXXCompilerABI.cpp.o -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/lib/gcc/x86_64-linux-gnu/13/crtendS.o /usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/crtn.o + COLLECT_GCC_OPTIONS='-v' '-o' 'cmTC_b1346' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'cmTC_b1346.' + + exitCode: 0 + - + kind: "message-v1" + backtrace: + - "/usr/share/cmake-3.28/Modules/CMakeDetermineCompilerABI.cmake:127 (message)" + - "/usr/share/cmake-3.28/Modules/CMakeTestCXXCompiler.cmake:26 (CMAKE_DETERMINE_COMPILER_ABI)" + - "CMakeLists.txt:2 (project)" + message: | + Parsed CXX implicit include dir info: rv=done + found start of include info + found start of implicit include info + add: [/usr/include/c++/13] + add: [/usr/include/x86_64-linux-gnu/c++/13] + add: [/usr/include/c++/13/backward] + add: [/usr/lib/gcc/x86_64-linux-gnu/13/include] + add: [/usr/local/include] + add: [/usr/include/x86_64-linux-gnu] + add: [/usr/include] + end of search list found + collapse include dir [/usr/include/c++/13] ==> [/usr/include/c++/13] + collapse include dir [/usr/include/x86_64-linux-gnu/c++/13] ==> [/usr/include/x86_64-linux-gnu/c++/13] + collapse include dir [/usr/include/c++/13/backward] ==> [/usr/include/c++/13/backward] + collapse include dir [/usr/lib/gcc/x86_64-linux-gnu/13/include] ==> [/usr/lib/gcc/x86_64-linux-gnu/13/include] + collapse include dir [/usr/local/include] ==> [/usr/local/include] + collapse include dir [/usr/include/x86_64-linux-gnu] ==> [/usr/include/x86_64-linux-gnu] + collapse include dir [/usr/include] ==> [/usr/include] + implicit include dirs: [/usr/include/c++/13;/usr/include/x86_64-linux-gnu/c++/13;/usr/include/c++/13/backward;/usr/lib/gcc/x86_64-linux-gnu/13/include;/usr/local/include;/usr/include/x86_64-linux-gnu;/usr/include] + + + - + kind: "message-v1" + backtrace: + - "/usr/share/cmake-3.28/Modules/CMakeDetermineCompilerABI.cmake:159 (message)" + - "/usr/share/cmake-3.28/Modules/CMakeTestCXXCompiler.cmake:26 (CMAKE_DETERMINE_COMPILER_ABI)" + - "CMakeLists.txt:2 (project)" + message: | + Parsed CXX implicit link information: + link line regex: [^( *|.*[/\\])(ld|CMAKE_LINK_STARTFILE-NOTFOUND|([^/\\]+-)?ld|collect2)[^/\\]*( |$)] + ignore line: [Change Dir: '/home/user/saqut/build/CMakeFiles/CMakeScratch/TryCompile-6ljCUz'] + ignore line: [] + ignore line: [Run Build Command(s): /usr/bin/ninja -v cmTC_b1346] + ignore line: [[1/2] /usr/bin/c++ -v -o CMakeFiles/cmTC_b1346.dir/CMakeCXXCompilerABI.cpp.o -c /usr/share/cmake-3.28/Modules/CMakeCXXCompilerABI.cpp] + ignore line: [Using built-in specs.] + ignore line: [COLLECT_GCC=/usr/bin/c++] + ignore line: [OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa] + ignore line: [OFFLOAD_TARGET_DEFAULT=1] + ignore line: [Target: x86_64-linux-gnu] + ignore line: [Configured with: ../src/configure -v --with-pkgversion='Ubuntu 13.3.0-6ubuntu2~24.04.1' --with-bugurl=file:///usr/share/doc/gcc-13/README.Bugs --enable-languages=c ada c++ go d fortran objc obj-c++ m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-13 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/libexec --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-libstdcxx-backtrace --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --enable-cet --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32 m64 mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-13-EldibY/gcc-13-13.3.0/debian/tmp-nvptx/usr amdgcn-amdhsa=/build/gcc-13-EldibY/gcc-13-13.3.0/debian/tmp-gcn/usr --enable-offload-defaulted --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu --with-build-config=bootstrap-lto-lean --enable-link-serialization=2] + ignore line: [Thread model: posix] + ignore line: [Supported LTO compression algorithms: zlib zstd] + ignore line: [gcc version 13.3.0 (Ubuntu 13.3.0-6ubuntu2~24.04.1) ] + ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_b1346.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_b1346.dir/'] + ignore line: [ /usr/libexec/gcc/x86_64-linux-gnu/13/cc1plus -quiet -v -imultiarch x86_64-linux-gnu -D_GNU_SOURCE /usr/share/cmake-3.28/Modules/CMakeCXXCompilerABI.cpp -quiet -dumpdir CMakeFiles/cmTC_b1346.dir/ -dumpbase CMakeCXXCompilerABI.cpp.cpp -dumpbase-ext .cpp -mtune=generic -march=x86-64 -version -fasynchronous-unwind-tables -fstack-protector-strong -Wformat -Wformat-security -fstack-clash-protection -fcf-protection -o /tmp/ccKBrizP.s] + ignore line: [GNU C++17 (Ubuntu 13.3.0-6ubuntu2~24.04.1) version 13.3.0 (x86_64-linux-gnu)] + ignore line: [ compiled by GNU C version 13.3.0 GMP version 6.3.0 MPFR version 4.2.1 MPC version 1.3.1 isl version isl-0.26-GMP] + ignore line: [] + ignore line: [GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072] + ignore line: [ignoring duplicate directory "/usr/include/x86_64-linux-gnu/c++/13"] + ignore line: [ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"] + ignore line: [ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/13/include-fixed/x86_64-linux-gnu"] + ignore line: [ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/13/include-fixed"] + ignore line: [ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/13/../../../../x86_64-linux-gnu/include"] + ignore line: [#include "..." search starts here:] + ignore line: [#include <...> search starts here:] + ignore line: [ /usr/include/c++/13] + ignore line: [ /usr/include/x86_64-linux-gnu/c++/13] + ignore line: [ /usr/include/c++/13/backward] + ignore line: [ /usr/lib/gcc/x86_64-linux-gnu/13/include] + ignore line: [ /usr/local/include] + ignore line: [ /usr/include/x86_64-linux-gnu] + ignore line: [ /usr/include] + ignore line: [End of search list.] + ignore line: [Compiler executable checksum: 7896445e4990772fdae9dc0659a99266] + ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_b1346.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_b1346.dir/'] + ignore line: [ as -v --64 -o CMakeFiles/cmTC_b1346.dir/CMakeCXXCompilerABI.cpp.o /tmp/ccKBrizP.s] + ignore line: [GNU assembler version 2.42 (x86_64-linux-gnu) using BFD version (GNU Binutils for Ubuntu) 2.42] + ignore line: [COMPILER_PATH=/usr/libexec/gcc/x86_64-linux-gnu/13/:/usr/libexec/gcc/x86_64-linux-gnu/13/:/usr/libexec/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/13/:/usr/lib/gcc/x86_64-linux-gnu/] + ignore line: [LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/13/:/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/13/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/13/../../../:/lib/:/usr/lib/] + ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_b1346.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_b1346.dir/CMakeCXXCompilerABI.cpp.'] + ignore line: [[2/2] : && /usr/bin/c++ -v CMakeFiles/cmTC_b1346.dir/CMakeCXXCompilerABI.cpp.o -o cmTC_b1346 && :] + ignore line: [Using built-in specs.] + ignore line: [COLLECT_GCC=/usr/bin/c++] + ignore line: [COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-linux-gnu/13/lto-wrapper] + ignore line: [OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa] + ignore line: [OFFLOAD_TARGET_DEFAULT=1] + ignore line: [Target: x86_64-linux-gnu] + ignore line: [Configured with: ../src/configure -v --with-pkgversion='Ubuntu 13.3.0-6ubuntu2~24.04.1' --with-bugurl=file:///usr/share/doc/gcc-13/README.Bugs --enable-languages=c ada c++ go d fortran objc obj-c++ m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-13 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/libexec --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-libstdcxx-backtrace --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --enable-cet --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32 m64 mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-13-EldibY/gcc-13-13.3.0/debian/tmp-nvptx/usr amdgcn-amdhsa=/build/gcc-13-EldibY/gcc-13-13.3.0/debian/tmp-gcn/usr --enable-offload-defaulted --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu --with-build-config=bootstrap-lto-lean --enable-link-serialization=2] + ignore line: [Thread model: posix] + ignore line: [Supported LTO compression algorithms: zlib zstd] + ignore line: [gcc version 13.3.0 (Ubuntu 13.3.0-6ubuntu2~24.04.1) ] + ignore line: [COMPILER_PATH=/usr/libexec/gcc/x86_64-linux-gnu/13/:/usr/libexec/gcc/x86_64-linux-gnu/13/:/usr/libexec/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/13/:/usr/lib/gcc/x86_64-linux-gnu/] + ignore line: [LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/13/:/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/13/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/13/../../../:/lib/:/usr/lib/] + ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'cmTC_b1346' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'cmTC_b1346.'] + link line: [ /usr/libexec/gcc/x86_64-linux-gnu/13/collect2 -plugin /usr/libexec/gcc/x86_64-linux-gnu/13/liblto_plugin.so -plugin-opt=/usr/libexec/gcc/x86_64-linux-gnu/13/lto-wrapper -plugin-opt=-fresolution=/tmp/cci1AaX8.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=gnu --as-needed -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -z now -z relro -o cmTC_b1346 /usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/Scrt1.o /usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/13/crtbeginS.o -L/usr/lib/gcc/x86_64-linux-gnu/13 -L/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/13/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/13/../../.. CMakeFiles/cmTC_b1346.dir/CMakeCXXCompilerABI.cpp.o -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/lib/gcc/x86_64-linux-gnu/13/crtendS.o /usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/crtn.o] + arg [/usr/libexec/gcc/x86_64-linux-gnu/13/collect2] ==> ignore + arg [-plugin] ==> ignore + arg [/usr/libexec/gcc/x86_64-linux-gnu/13/liblto_plugin.so] ==> ignore + arg [-plugin-opt=/usr/libexec/gcc/x86_64-linux-gnu/13/lto-wrapper] ==> ignore + arg [-plugin-opt=-fresolution=/tmp/cci1AaX8.res] ==> ignore + arg [-plugin-opt=-pass-through=-lgcc_s] ==> ignore + arg [-plugin-opt=-pass-through=-lgcc] ==> ignore + arg [-plugin-opt=-pass-through=-lc] ==> ignore + arg [-plugin-opt=-pass-through=-lgcc_s] ==> ignore + arg [-plugin-opt=-pass-through=-lgcc] ==> ignore + arg [--build-id] ==> ignore + arg [--eh-frame-hdr] ==> ignore + arg [-m] ==> ignore + arg [elf_x86_64] ==> ignore + arg [--hash-style=gnu] ==> ignore + arg [--as-needed] ==> ignore + arg [-dynamic-linker] ==> ignore + arg [/lib64/ld-linux-x86-64.so.2] ==> ignore + arg [-pie] ==> ignore + arg [-znow] ==> ignore + arg [-zrelro] ==> ignore + arg [-o] ==> ignore + arg [cmTC_b1346] ==> ignore + arg [/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/Scrt1.o] ==> obj [/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/Scrt1.o] + arg [/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/crti.o] ==> obj [/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/crti.o] + arg [/usr/lib/gcc/x86_64-linux-gnu/13/crtbeginS.o] ==> obj [/usr/lib/gcc/x86_64-linux-gnu/13/crtbeginS.o] + arg [-L/usr/lib/gcc/x86_64-linux-gnu/13] ==> dir [/usr/lib/gcc/x86_64-linux-gnu/13] + arg [-L/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu] ==> dir [/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu] + arg [-L/usr/lib/gcc/x86_64-linux-gnu/13/../../../../lib] ==> dir [/usr/lib/gcc/x86_64-linux-gnu/13/../../../../lib] + arg [-L/lib/x86_64-linux-gnu] ==> dir [/lib/x86_64-linux-gnu] + arg [-L/lib/../lib] ==> dir [/lib/../lib] + arg [-L/usr/lib/x86_64-linux-gnu] ==> dir [/usr/lib/x86_64-linux-gnu] + arg [-L/usr/lib/../lib] ==> dir [/usr/lib/../lib] + arg [-L/usr/lib/gcc/x86_64-linux-gnu/13/../../..] ==> dir [/usr/lib/gcc/x86_64-linux-gnu/13/../../..] + arg [CMakeFiles/cmTC_b1346.dir/CMakeCXXCompilerABI.cpp.o] ==> ignore + arg [-lstdc++] ==> lib [stdc++] + arg [-lm] ==> lib [m] + arg [-lgcc_s] ==> lib [gcc_s] + arg [-lgcc] ==> lib [gcc] + arg [-lc] ==> lib [c] + arg [-lgcc_s] ==> lib [gcc_s] + arg [-lgcc] ==> lib [gcc] + arg [/usr/lib/gcc/x86_64-linux-gnu/13/crtendS.o] ==> obj [/usr/lib/gcc/x86_64-linux-gnu/13/crtendS.o] + arg [/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/crtn.o] ==> obj [/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/crtn.o] + collapse obj [/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/Scrt1.o] ==> [/usr/lib/x86_64-linux-gnu/Scrt1.o] + collapse obj [/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/crti.o] ==> [/usr/lib/x86_64-linux-gnu/crti.o] + collapse obj [/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/crtn.o] ==> [/usr/lib/x86_64-linux-gnu/crtn.o] + collapse library dir [/usr/lib/gcc/x86_64-linux-gnu/13] ==> [/usr/lib/gcc/x86_64-linux-gnu/13] + collapse library dir [/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu] ==> [/usr/lib/x86_64-linux-gnu] + collapse library dir [/usr/lib/gcc/x86_64-linux-gnu/13/../../../../lib] ==> [/usr/lib] + collapse library dir [/lib/x86_64-linux-gnu] ==> [/lib/x86_64-linux-gnu] + collapse library dir [/lib/../lib] ==> [/lib] + collapse library dir [/usr/lib/x86_64-linux-gnu] ==> [/usr/lib/x86_64-linux-gnu] + collapse library dir [/usr/lib/../lib] ==> [/usr/lib] + collapse library dir [/usr/lib/gcc/x86_64-linux-gnu/13/../../..] ==> [/usr/lib] + implicit libs: [stdc++;m;gcc_s;gcc;c;gcc_s;gcc] + implicit objs: [/usr/lib/x86_64-linux-gnu/Scrt1.o;/usr/lib/x86_64-linux-gnu/crti.o;/usr/lib/gcc/x86_64-linux-gnu/13/crtbeginS.o;/usr/lib/gcc/x86_64-linux-gnu/13/crtendS.o;/usr/lib/x86_64-linux-gnu/crtn.o] + implicit dirs: [/usr/lib/gcc/x86_64-linux-gnu/13;/usr/lib/x86_64-linux-gnu;/usr/lib;/lib/x86_64-linux-gnu;/lib] + implicit fwks: [] + + +... + --- events: - @@ -113,6 +378,65 @@ events: - "/usr/bin/site_perl" - "/usr/bin/vendor_perl" - "/usr/bin/core_perl" + - + kind: "find-v1" + backtrace: + - "/usr/share/cmake/Modules/CMakeDetermineCompiler.cmake:73 (find_program)" + - "/usr/share/cmake/Modules/CMakeDetermineCXXCompiler.cmake:69 (_cmake_find_compiler)" + - "CMakeLists.txt:2 (project)" + mode: "program" + variable: "CMAKE_CXX_COMPILER" + description: "CXX compiler" + settings: + SearchFramework: "NEVER" + SearchAppBundle: "NEVER" + CMAKE_FIND_USE_CMAKE_PATH: true + CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH: true + CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH: true + CMAKE_FIND_USE_CMAKE_SYSTEM_PATH: true + CMAKE_FIND_USE_INSTALL_PREFIX: true + names: + - "c++" + - "CC" + - "g++" + - "aCC" + - "cl" + - "bcc" + - "xlC" + - "icpx" + - "icx" + - "clang++" + candidate_directories: + - "/home/saqut/.local/bin/" + - "/usr/local/bin/" + - "/usr/bin/" + - "/bin/" + - "/usr/local/sbin/" + - "/opt/cuda/bin/" + - "/var/lib/flatpak/exports/bin/" + - "/usr/lib/jvm/default/bin/" + - "/usr/bin/site_perl/" + - "/usr/bin/vendor_perl/" + - "/usr/bin/core_perl/" + searched_directories: + - "/home/saqut/.local/bin/c++" + - "/usr/local/bin/c++" + found: "/usr/bin/c++" + search_context: + ENV{PATH}: + - "/home/saqut/.local/bin" + - "/home/saqut/.local/bin" + - "/home/saqut/.local/bin" + - "/usr/local/bin" + - "/usr/bin" + - "/bin" + - "/usr/local/sbin" + - "/opt/cuda/bin" + - "/var/lib/flatpak/exports/bin" + - "/usr/lib/jvm/default/bin" + - "/usr/bin/site_perl" + - "/usr/bin/vendor_perl" + - "/usr/bin/core_perl" - kind: "find-v1" backtrace: @@ -162,7 +486,7 @@ events: - "CMakeLists.txt:2 (project)" message: | Compiling the CXX compiler identification source file "CMakeCXXCompilerId.cpp" succeeded. - Compiler: /usr/bin/g++ + Compiler: /usr/bin/c++ Build flags: Id flags: @@ -893,8 +1217,8 @@ events: checks: - "Detecting CXX compiler ABI info" directories: - source: "/home/saqut/Masa\u00fcst\u00fc/saqutcompiler/build/CMakeFiles/CMakeScratch/TryCompile-KRXVj0" - binary: "/home/saqut/Masa\u00fcst\u00fc/saqutcompiler/build/CMakeFiles/CMakeScratch/TryCompile-KRXVj0" + source: "/home/saqut/Masa\u00fcst\u00fc/saqutcompiler/build/CMakeFiles/CMakeScratch/TryCompile-bNmRFu" + binary: "/home/saqut/Masa\u00fcst\u00fc/saqutcompiler/build/CMakeFiles/CMakeScratch/TryCompile-bNmRFu" cmakeVariables: CMAKE_CXX_FLAGS: "" CMAKE_CXX_FLAGS_DEBUG: "-g" @@ -905,19 +1229,19 @@ events: variable: "CMAKE_CXX_ABI_COMPILED" cached: true stdout: | - Change Dir: '/home/saqut/Masaüstü/saqutcompiler/build/CMakeFiles/CMakeScratch/TryCompile-KRXVj0' + Change Dir: '/home/saqut/Masaüstü/saqutcompiler/build/CMakeFiles/CMakeScratch/TryCompile-bNmRFu' - Run Build Command(s): /usr/bin/ninja -v cmTC_aae80 - [1/2] /usr/bin/g++ -v -o CMakeFiles/cmTC_aae80.dir/CMakeCXXCompilerABI.cpp.o -c /usr/share/cmake/Modules/CMakeCXXCompilerABI.cpp + Run Build Command(s): /usr/bin/ninja -v cmTC_a8847 + [1/2] /usr/bin/c++ -v -o CMakeFiles/cmTC_a8847.dir/CMakeCXXCompilerABI.cpp.o -c /usr/share/cmake/Modules/CMakeCXXCompilerABI.cpp Using built-in specs. - COLLECT_GCC=/usr/bin/g++ + COLLECT_GCC=/usr/bin/c++ Target: x86_64-pc-linux-gnu Configured with: /build/gcc/src/gcc/configure --enable-languages=ada,c,c++,d,fortran,go,lto,m2,objc,obj-c++,rust,cobol --enable-bootstrap --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=https://gitlab.archlinux.org/archlinux/packaging/packages/gcc/-/issues --with-build-config=bootstrap-lto --with-linker-hash-style=gnu --with-system-zlib --enable-cet=auto --enable-checking=release --enable-clocale=gnu --enable-default-pie --enable-default-ssp --enable-gnu-indirect-function --enable-gnu-unique-object --enable-libstdcxx-backtrace --enable-link-serialization=1 --enable-linker-build-id --enable-lto --enable-multilib --enable-plugin --enable-shared --enable-threads=posix --disable-libssp --disable-libstdcxx-pch --disable-werror --disable-fixincludes Thread model: posix Supported LTO compression algorithms: zlib zstd gcc version 16.1.1 20260430 (GCC) - COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_aae80.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_aae80.dir/' - /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/cc1plus -quiet -v -D_GNU_SOURCE /usr/share/cmake/Modules/CMakeCXXCompilerABI.cpp -quiet -dumpdir CMakeFiles/cmTC_aae80.dir/ -dumpbase CMakeCXXCompilerABI.cpp.cpp -dumpbase-ext .cpp -mtune=generic -march=x86-64 -version -o /tmp/ccmm6pzq.s + COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_a8847.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_a8847.dir/' + /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/cc1plus -quiet -v -D_GNU_SOURCE /usr/share/cmake/Modules/CMakeCXXCompilerABI.cpp -quiet -dumpdir CMakeFiles/cmTC_a8847.dir/ -dumpbase CMakeCXXCompilerABI.cpp.cpp -dumpbase-ext .cpp -mtune=generic -march=x86-64 -version -o /tmp/cch7GwnZ.s GNU C++20 (GCC) version 16.1.1 20260430 (x86_64-pc-linux-gnu) compiled by GNU C version 16.1.1 20260430, GMP version 6.3.0, MPFR version 4.2.2, MPC version 1.4.1, isl version isl-0.27-GMP @@ -934,15 +1258,15 @@ events: /usr/include End of search list. Compiler executable checksum: d47d0c990a24bc0dbaf3bd00656bd5f3 - COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_aae80.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_aae80.dir/' - as -v --64 -o CMakeFiles/cmTC_aae80.dir/CMakeCXXCompilerABI.cpp.o /tmp/ccmm6pzq.s + COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_a8847.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_a8847.dir/' + as -v --64 -o CMakeFiles/cmTC_a8847.dir/CMakeCXXCompilerABI.cpp.o /tmp/cch7GwnZ.s GNU assembler version 2.46.0 (x86_64-pc-linux-gnu) using BFD version (GNU Binutils) 2.46.0 COMPILER_PATH=/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/:/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/:/usr/lib/gcc/x86_64-pc-linux-gnu/:/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/:/usr/lib/gcc/x86_64-pc-linux-gnu/ LIBRARY_PATH=/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/:/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/:/lib/../lib/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../:/lib/:/usr/lib/ - COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_aae80.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_aae80.dir/CMakeCXXCompilerABI.cpp.' - [2/2] : && /usr/bin/g++ -v -Wl,-v CMakeFiles/cmTC_aae80.dir/CMakeCXXCompilerABI.cpp.o -o cmTC_aae80 && : + COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_a8847.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_a8847.dir/CMakeCXXCompilerABI.cpp.' + [2/2] : && /usr/bin/c++ -v -Wl,-v CMakeFiles/cmTC_a8847.dir/CMakeCXXCompilerABI.cpp.o -o cmTC_a8847 && : Using built-in specs. - COLLECT_GCC=/usr/bin/g++ + COLLECT_GCC=/usr/bin/c++ COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/lto-wrapper Target: x86_64-pc-linux-gnu Configured with: /build/gcc/src/gcc/configure --enable-languages=ada,c,c++,d,fortran,go,lto,m2,objc,obj-c++,rust,cobol --enable-bootstrap --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=https://gitlab.archlinux.org/archlinux/packaging/packages/gcc/-/issues --with-build-config=bootstrap-lto --with-linker-hash-style=gnu --with-system-zlib --enable-cet=auto --enable-checking=release --enable-clocale=gnu --enable-default-pie --enable-default-ssp --enable-gnu-indirect-function --enable-gnu-unique-object --enable-libstdcxx-backtrace --enable-link-serialization=1 --enable-linker-build-id --enable-lto --enable-multilib --enable-plugin --enable-shared --enable-threads=posix --disable-libssp --disable-libstdcxx-pch --disable-werror --disable-fixincludes @@ -951,12 +1275,12 @@ events: gcc version 16.1.1 20260430 (GCC) COMPILER_PATH=/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/:/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/:/usr/lib/gcc/x86_64-pc-linux-gnu/:/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/:/usr/lib/gcc/x86_64-pc-linux-gnu/ LIBRARY_PATH=/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/:/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/:/lib/../lib/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../:/lib/:/usr/lib/ - COLLECT_GCC_OPTIONS='-v' '-o' 'cmTC_aae80' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'cmTC_aae80.' - /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/collect2 -plugin /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/lto-wrapper -plugin-opt=-fresolution=/tmp/cce8QsNN.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-latomic_asneeded -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc --build-id --eh-frame-hdr --hash-style=gnu -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -o cmTC_aae80 /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/Scrt1.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/crti.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/crtbeginS.o -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1 -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../.. -L/lib -L/usr/lib -v CMakeFiles/cmTC_aae80.dir/CMakeCXXCompilerABI.cpp.o -lstdc++ -lm -lgcc_s -lgcc -latomic_asneeded -lc -lgcc_s -lgcc /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/crtendS.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/crtn.o + COLLECT_GCC_OPTIONS='-v' '-o' 'cmTC_a8847' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'cmTC_a8847.' + /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/collect2 -plugin /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/lto-wrapper -plugin-opt=-fresolution=/tmp/cce2Bg9n.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-latomic_asneeded -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc --build-id --eh-frame-hdr --hash-style=gnu -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -o cmTC_a8847 /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/Scrt1.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/crti.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/crtbeginS.o -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1 -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../.. -L/lib -L/usr/lib -v CMakeFiles/cmTC_a8847.dir/CMakeCXXCompilerABI.cpp.o -lstdc++ -lm -lgcc_s -lgcc -latomic_asneeded -lc -lgcc_s -lgcc /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/crtendS.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/crtn.o collect2 version 16.1.1 20260430 - /usr/bin/ld -plugin /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/lto-wrapper -plugin-opt=-fresolution=/tmp/cce8QsNN.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-latomic_asneeded -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc --build-id --eh-frame-hdr --hash-style=gnu -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -o cmTC_aae80 /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/Scrt1.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/crti.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/crtbeginS.o -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1 -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../.. -L/lib -L/usr/lib -v CMakeFiles/cmTC_aae80.dir/CMakeCXXCompilerABI.cpp.o -lstdc++ -lm -lgcc_s -lgcc -latomic_asneeded -lc -lgcc_s -lgcc /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/crtendS.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/crtn.o + /usr/bin/ld -plugin /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/lto-wrapper -plugin-opt=-fresolution=/tmp/cce2Bg9n.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-latomic_asneeded -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc --build-id --eh-frame-hdr --hash-style=gnu -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -o cmTC_a8847 /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/Scrt1.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/crti.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/crtbeginS.o -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1 -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../.. -L/lib -L/usr/lib -v CMakeFiles/cmTC_a8847.dir/CMakeCXXCompilerABI.cpp.o -lstdc++ -lm -lgcc_s -lgcc -latomic_asneeded -lc -lgcc_s -lgcc /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/crtendS.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/crtn.o GNU ld (GNU Binutils) 2.46.0 - COLLECT_GCC_OPTIONS='-v' '-o' 'cmTC_aae80' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'cmTC_aae80.' + COLLECT_GCC_OPTIONS='-v' '-o' 'cmTC_a8847' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'cmTC_a8847.' exitCode: 0 - @@ -995,19 +1319,19 @@ events: Parsed CXX implicit link information: link line regex: [^( *|.*[/\\])(ld[0-9]*(|\\.[a-rt-z][a-z]*|\\.s[a-np-z][a-z]*|\\.so[a-z]+)|CMAKE_LINK_STARTFILE-NOTFOUND|([^/\\]+-)?ld|collect2)[^/\\]*( |$)] linker tool regex: [^[ ]*(->|"|[0-9]+>[ -]*Build:[ 0-9]+ ms[ ]*)?[ ]*(([^"]*[/\\])?(ld[0-9]*(|\\.[a-rt-z][a-z]*|\\.s[a-np-z][a-z]*|\\.so[a-z]+)))("|,| |$)] - ignore line: [Change Dir: '/home/saqut/Masaüstü/saqutcompiler/build/CMakeFiles/CMakeScratch/TryCompile-KRXVj0'] + ignore line: [Change Dir: '/home/saqut/Masaüstü/saqutcompiler/build/CMakeFiles/CMakeScratch/TryCompile-bNmRFu'] ignore line: [] - ignore line: [Run Build Command(s): /usr/bin/ninja -v cmTC_aae80] - ignore line: [[1/2] /usr/bin/g++ -v -o CMakeFiles/cmTC_aae80.dir/CMakeCXXCompilerABI.cpp.o -c /usr/share/cmake/Modules/CMakeCXXCompilerABI.cpp] + ignore line: [Run Build Command(s): /usr/bin/ninja -v cmTC_a8847] + ignore line: [[1/2] /usr/bin/c++ -v -o CMakeFiles/cmTC_a8847.dir/CMakeCXXCompilerABI.cpp.o -c /usr/share/cmake/Modules/CMakeCXXCompilerABI.cpp] ignore line: [Using built-in specs.] - ignore line: [COLLECT_GCC=/usr/bin/g++] + ignore line: [COLLECT_GCC=/usr/bin/c++] ignore line: [Target: x86_64-pc-linux-gnu] ignore line: [Configured with: /build/gcc/src/gcc/configure --enable-languages=ada c c++ d fortran go lto m2 objc obj-c++ rust cobol --enable-bootstrap --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=https://gitlab.archlinux.org/archlinux/packaging/packages/gcc/-/issues --with-build-config=bootstrap-lto --with-linker-hash-style=gnu --with-system-zlib --enable-cet=auto --enable-checking=release --enable-clocale=gnu --enable-default-pie --enable-default-ssp --enable-gnu-indirect-function --enable-gnu-unique-object --enable-libstdcxx-backtrace --enable-link-serialization=1 --enable-linker-build-id --enable-lto --enable-multilib --enable-plugin --enable-shared --enable-threads=posix --disable-libssp --disable-libstdcxx-pch --disable-werror --disable-fixincludes] ignore line: [Thread model: posix] ignore line: [Supported LTO compression algorithms: zlib zstd] ignore line: [gcc version 16.1.1 20260430 (GCC) ] - ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_aae80.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_aae80.dir/'] - ignore line: [ /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/cc1plus -quiet -v -D_GNU_SOURCE /usr/share/cmake/Modules/CMakeCXXCompilerABI.cpp -quiet -dumpdir CMakeFiles/cmTC_aae80.dir/ -dumpbase CMakeCXXCompilerABI.cpp.cpp -dumpbase-ext .cpp -mtune=generic -march=x86-64 -version -o /tmp/ccmm6pzq.s] + ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_a8847.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_a8847.dir/'] + ignore line: [ /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/cc1plus -quiet -v -D_GNU_SOURCE /usr/share/cmake/Modules/CMakeCXXCompilerABI.cpp -quiet -dumpdir CMakeFiles/cmTC_a8847.dir/ -dumpbase CMakeCXXCompilerABI.cpp.cpp -dumpbase-ext .cpp -mtune=generic -march=x86-64 -version -o /tmp/cch7GwnZ.s] ignore line: [GNU C++20 (GCC) version 16.1.1 20260430 (x86_64-pc-linux-gnu)] ignore line: [ compiled by GNU C version 16.1.1 20260430 GMP version 6.3.0 MPFR version 4.2.2 MPC version 1.4.1 isl version isl-0.27-GMP] ignore line: [] @@ -1024,15 +1348,15 @@ events: ignore line: [ /usr/include] ignore line: [End of search list.] ignore line: [Compiler executable checksum: d47d0c990a24bc0dbaf3bd00656bd5f3] - ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_aae80.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_aae80.dir/'] - ignore line: [ as -v --64 -o CMakeFiles/cmTC_aae80.dir/CMakeCXXCompilerABI.cpp.o /tmp/ccmm6pzq.s] + ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_a8847.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_a8847.dir/'] + ignore line: [ as -v --64 -o CMakeFiles/cmTC_a8847.dir/CMakeCXXCompilerABI.cpp.o /tmp/cch7GwnZ.s] ignore line: [GNU assembler version 2.46.0 (x86_64-pc-linux-gnu) using BFD version (GNU Binutils) 2.46.0] ignore line: [COMPILER_PATH=/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/:/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/:/usr/lib/gcc/x86_64-pc-linux-gnu/:/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/:/usr/lib/gcc/x86_64-pc-linux-gnu/] ignore line: [LIBRARY_PATH=/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/:/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/:/lib/../lib/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../:/lib/:/usr/lib/] - ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_aae80.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_aae80.dir/CMakeCXXCompilerABI.cpp.'] - ignore line: [[2/2] : && /usr/bin/g++ -v -Wl -v CMakeFiles/cmTC_aae80.dir/CMakeCXXCompilerABI.cpp.o -o cmTC_aae80 && :] + ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles/cmTC_a8847.dir/CMakeCXXCompilerABI.cpp.o' '-c' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'CMakeFiles/cmTC_a8847.dir/CMakeCXXCompilerABI.cpp.'] + ignore line: [[2/2] : && /usr/bin/c++ -v -Wl -v CMakeFiles/cmTC_a8847.dir/CMakeCXXCompilerABI.cpp.o -o cmTC_a8847 && :] ignore line: [Using built-in specs.] - ignore line: [COLLECT_GCC=/usr/bin/g++] + ignore line: [COLLECT_GCC=/usr/bin/c++] ignore line: [COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/lto-wrapper] ignore line: [Target: x86_64-pc-linux-gnu] ignore line: [Configured with: /build/gcc/src/gcc/configure --enable-languages=ada c c++ d fortran go lto m2 objc obj-c++ rust cobol --enable-bootstrap --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=https://gitlab.archlinux.org/archlinux/packaging/packages/gcc/-/issues --with-build-config=bootstrap-lto --with-linker-hash-style=gnu --with-system-zlib --enable-cet=auto --enable-checking=release --enable-clocale=gnu --enable-default-pie --enable-default-ssp --enable-gnu-indirect-function --enable-gnu-unique-object --enable-libstdcxx-backtrace --enable-link-serialization=1 --enable-linker-build-id --enable-lto --enable-multilib --enable-plugin --enable-shared --enable-threads=posix --disable-libssp --disable-libstdcxx-pch --disable-werror --disable-fixincludes] @@ -1041,13 +1365,13 @@ events: ignore line: [gcc version 16.1.1 20260430 (GCC) ] ignore line: [COMPILER_PATH=/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/:/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/:/usr/lib/gcc/x86_64-pc-linux-gnu/:/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/:/usr/lib/gcc/x86_64-pc-linux-gnu/] ignore line: [LIBRARY_PATH=/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/:/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/:/lib/../lib/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../:/lib/:/usr/lib/] - ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'cmTC_aae80' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'cmTC_aae80.'] - link line: [ /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/collect2 -plugin /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/lto-wrapper -plugin-opt=-fresolution=/tmp/cce8QsNN.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-latomic_asneeded -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc --build-id --eh-frame-hdr --hash-style=gnu -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -o cmTC_aae80 /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/Scrt1.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/crti.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/crtbeginS.o -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1 -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../.. -L/lib -L/usr/lib -v CMakeFiles/cmTC_aae80.dir/CMakeCXXCompilerABI.cpp.o -lstdc++ -lm -lgcc_s -lgcc -latomic_asneeded -lc -lgcc_s -lgcc /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/crtendS.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/crtn.o] + ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'cmTC_a8847' '-shared-libgcc' '-mtune=generic' '-march=x86-64' '-dumpdir' 'cmTC_a8847.'] + link line: [ /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/collect2 -plugin /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/lto-wrapper -plugin-opt=-fresolution=/tmp/cce2Bg9n.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-latomic_asneeded -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc --build-id --eh-frame-hdr --hash-style=gnu -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -o cmTC_a8847 /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/Scrt1.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/crti.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/crtbeginS.o -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1 -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../.. -L/lib -L/usr/lib -v CMakeFiles/cmTC_a8847.dir/CMakeCXXCompilerABI.cpp.o -lstdc++ -lm -lgcc_s -lgcc -latomic_asneeded -lc -lgcc_s -lgcc /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/crtendS.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/crtn.o] arg [/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/collect2] ==> ignore arg [-plugin] ==> ignore arg [/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/liblto_plugin.so] ==> ignore arg [-plugin-opt=/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/lto-wrapper] ==> ignore - arg [-plugin-opt=-fresolution=/tmp/cce8QsNN.res] ==> ignore + arg [-plugin-opt=-fresolution=/tmp/cce2Bg9n.res] ==> ignore arg [-plugin-opt=-pass-through=-lgcc_s] ==> ignore arg [-plugin-opt=-pass-through=-lgcc] ==> ignore arg [-plugin-opt=-pass-through=-latomic_asneeded] ==> ignore @@ -1063,7 +1387,7 @@ events: arg [/lib64/ld-linux-x86-64.so.2] ==> ignore arg [-pie] ==> ignore arg [-o] ==> ignore - arg [cmTC_aae80] ==> ignore + arg [cmTC_a8847] ==> ignore arg [/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/Scrt1.o] ==> obj [/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/Scrt1.o] arg [/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/crti.o] ==> obj [/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/crti.o] arg [/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/crtbeginS.o] ==> obj [/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/crtbeginS.o] @@ -1075,7 +1399,7 @@ events: arg [-L/lib] ==> dir [/lib] arg [-L/usr/lib] ==> dir [/usr/lib] arg [-v] ==> ignore - arg [CMakeFiles/cmTC_aae80.dir/CMakeCXXCompilerABI.cpp.o] ==> ignore + arg [CMakeFiles/cmTC_a8847.dir/CMakeCXXCompilerABI.cpp.o] ==> ignore arg [-lstdc++] ==> lib [stdc++] arg [-lm] ==> lib [m] arg [-lgcc_s] ==> lib [gcc_s] @@ -1087,7 +1411,7 @@ events: arg [/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/crtendS.o] ==> obj [/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/crtendS.o] arg [/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/crtn.o] ==> obj [/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/crtn.o] ignore line: [collect2 version 16.1.1 20260430] - ignore line: [/usr/bin/ld -plugin /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/lto-wrapper -plugin-opt=-fresolution=/tmp/cce8QsNN.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-latomic_asneeded -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc --build-id --eh-frame-hdr --hash-style=gnu -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -o cmTC_aae80 /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/Scrt1.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/crti.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/crtbeginS.o -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1 -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../.. -L/lib -L/usr/lib -v CMakeFiles/cmTC_aae80.dir/CMakeCXXCompilerABI.cpp.o -lstdc++ -lm -lgcc_s -lgcc -latomic_asneeded -lc -lgcc_s -lgcc /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/crtendS.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/crtn.o] + ignore line: [/usr/bin/ld -plugin /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/lto-wrapper -plugin-opt=-fresolution=/tmp/cce2Bg9n.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-latomic_asneeded -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc --build-id --eh-frame-hdr --hash-style=gnu -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -o cmTC_a8847 /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/Scrt1.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/crti.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/crtbeginS.o -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1 -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../.. -L/lib -L/usr/lib -v CMakeFiles/cmTC_a8847.dir/CMakeCXXCompilerABI.cpp.o -lstdc++ -lm -lgcc_s -lgcc -latomic_asneeded -lc -lgcc_s -lgcc /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/crtendS.o /usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/crtn.o] linker tool for 'CXX': /usr/bin/ld collapse obj [/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/Scrt1.o] ==> [/usr/lib/Scrt1.o] collapse obj [/usr/lib/gcc/x86_64-pc-linux-gnu/16.1.1/../../../../lib/crti.o] ==> [/usr/lib/crti.o] diff --git a/build/CMakeFiles/TargetDirectories.txt b/build/CMakeFiles/TargetDirectories.txt index 014db8d..6832478 100644 --- a/build/CMakeFiles/TargetDirectories.txt +++ b/build/CMakeFiles/TargetDirectories.txt @@ -1,3 +1,4 @@ /home/saqut/Masaüstü/saqutcompiler/build/CMakeFiles/saqut.dir +/home/saqut/Masaüstü/saqutcompiler/build/CMakeFiles/test.dir /home/saqut/Masaüstü/saqutcompiler/build/CMakeFiles/edit_cache.dir /home/saqut/Masaüstü/saqutcompiler/build/CMakeFiles/rebuild_cache.dir diff --git a/build/CMakeFiles/VerifyGlobs.cmake b/build/CMakeFiles/VerifyGlobs.cmake new file mode 100644 index 0000000..17abf7c --- /dev/null +++ b/build/CMakeFiles/VerifyGlobs.cmake @@ -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() diff --git a/build/CMakeFiles/cmake.verify_globs b/build/CMakeFiles/cmake.verify_globs new file mode 100644 index 0000000..2b38fac --- /dev/null +++ b/build/CMakeFiles/cmake.verify_globs @@ -0,0 +1 @@ +# This file is generated by CMake for checking of the VerifyGlobs.cmake file diff --git a/build/CMakeFiles/rules.ninja b/build/CMakeFiles/rules.ninja index 5bf065a..f37793f 100644 --- a/build/CMakeFiles/rules.ninja +++ b/build/CMakeFiles/rules.ninja @@ -79,6 +79,15 @@ rule RERUN_CMAKE generator = 1 +############################################# +# Rule for re-checking globbed directories. + +rule VERIFY_GLOBS + command = /usr/bin/cmake -P /home/saqut/Masaüstü/saqutcompiler/build/CMakeFiles/VerifyGlobs.cmake + description = Re-checking globbed directories... + generator = 1 + + ############################################# # Rule for cleaning all built files. diff --git a/build/CTestTestfile.cmake b/build/CTestTestfile.cmake new file mode 100644 index 0000000..d29f701 --- /dev/null +++ b/build/CTestTestfile.cmake @@ -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;") diff --git a/build/build.ninja b/build/build.ninja index 60d00e8..36d1447 100644 --- a/build/build.ninja +++ b/build/build.ninja @@ -18,7 +18,7 @@ ############################################# # Minimal version of Ninja required by this file -ninja_required_version = 1.5 +ninja_required_version = 1.8 ############################################# @@ -56,6 +56,8 @@ build CMakeFiles/saqut.dir/src/core/sourcefile.cpp.o: CXX_COMPILER__saqut_unscan INCLUDES = -I/home/saqut/Masaüstü/saqutcompiler/src OBJECT_DIR = CMakeFiles/saqut.dir OBJECT_FILE_DIR = CMakeFiles/saqut.dir/src/core + TARGET_COMPILE_PDB = CMakeFiles/saqut.dir/ + TARGET_PDB = saqut.pdb TARGET_SUPPORT_DIR = CMakeFiles/saqut.dir build CMakeFiles/saqut.dir/src/ir/ir_function.cpp.o: CXX_COMPILER__saqut_unscanned_Debug /home/saqut/Masaüstü/saqutcompiler/src/ir/ir_function.cpp || cmake_object_order_depends_target_saqut @@ -65,6 +67,8 @@ build CMakeFiles/saqut.dir/src/ir/ir_function.cpp.o: CXX_COMPILER__saqut_unscann INCLUDES = -I/home/saqut/Masaüstü/saqutcompiler/src OBJECT_DIR = CMakeFiles/saqut.dir OBJECT_FILE_DIR = CMakeFiles/saqut.dir/src/ir + TARGET_COMPILE_PDB = CMakeFiles/saqut.dir/ + TARGET_PDB = saqut.pdb TARGET_SUPPORT_DIR = CMakeFiles/saqut.dir build CMakeFiles/saqut.dir/src/ir/ir_generator.cpp.o: CXX_COMPILER__saqut_unscanned_Debug /home/saqut/Masaüstü/saqutcompiler/src/ir/ir_generator.cpp || cmake_object_order_depends_target_saqut @@ -74,6 +78,8 @@ build CMakeFiles/saqut.dir/src/ir/ir_generator.cpp.o: CXX_COMPILER__saqut_unscan INCLUDES = -I/home/saqut/Masaüstü/saqutcompiler/src OBJECT_DIR = CMakeFiles/saqut.dir OBJECT_FILE_DIR = CMakeFiles/saqut.dir/src/ir + TARGET_COMPILE_PDB = CMakeFiles/saqut.dir/ + TARGET_PDB = saqut.pdb TARGET_SUPPORT_DIR = CMakeFiles/saqut.dir build CMakeFiles/saqut.dir/src/ir/ir_program.cpp.o: CXX_COMPILER__saqut_unscanned_Debug /home/saqut/Masaüstü/saqutcompiler/src/ir/ir_program.cpp || cmake_object_order_depends_target_saqut @@ -83,6 +89,8 @@ build CMakeFiles/saqut.dir/src/ir/ir_program.cpp.o: CXX_COMPILER__saqut_unscanne INCLUDES = -I/home/saqut/Masaüstü/saqutcompiler/src OBJECT_DIR = CMakeFiles/saqut.dir OBJECT_FILE_DIR = CMakeFiles/saqut.dir/src/ir + TARGET_COMPILE_PDB = CMakeFiles/saqut.dir/ + TARGET_PDB = saqut.pdb TARGET_SUPPORT_DIR = CMakeFiles/saqut.dir build CMakeFiles/saqut.dir/src/lexer/lexer.cpp.o: CXX_COMPILER__saqut_unscanned_Debug /home/saqut/Masaüstü/saqutcompiler/src/lexer/lexer.cpp || cmake_object_order_depends_target_saqut @@ -92,6 +100,8 @@ build CMakeFiles/saqut.dir/src/lexer/lexer.cpp.o: CXX_COMPILER__saqut_unscanned_ INCLUDES = -I/home/saqut/Masaüstü/saqutcompiler/src OBJECT_DIR = CMakeFiles/saqut.dir OBJECT_FILE_DIR = CMakeFiles/saqut.dir/src/lexer + TARGET_COMPILE_PDB = CMakeFiles/saqut.dir/ + TARGET_PDB = saqut.pdb TARGET_SUPPORT_DIR = CMakeFiles/saqut.dir build CMakeFiles/saqut.dir/src/main.cpp.o: CXX_COMPILER__saqut_unscanned_Debug /home/saqut/Masaüstü/saqutcompiler/src/main.cpp || cmake_object_order_depends_target_saqut @@ -101,6 +111,8 @@ build CMakeFiles/saqut.dir/src/main.cpp.o: CXX_COMPILER__saqut_unscanned_Debug / INCLUDES = -I/home/saqut/Masaüstü/saqutcompiler/src OBJECT_DIR = CMakeFiles/saqut.dir OBJECT_FILE_DIR = CMakeFiles/saqut.dir/src + TARGET_COMPILE_PDB = CMakeFiles/saqut.dir/ + TARGET_PDB = saqut.pdb TARGET_SUPPORT_DIR = CMakeFiles/saqut.dir build CMakeFiles/saqut.dir/src/parser/nodes/binary_expr.cpp.o: CXX_COMPILER__saqut_unscanned_Debug /home/saqut/Masaüstü/saqutcompiler/src/parser/nodes/binary_expr.cpp || cmake_object_order_depends_target_saqut @@ -110,6 +122,8 @@ build CMakeFiles/saqut.dir/src/parser/nodes/binary_expr.cpp.o: CXX_COMPILER__saq INCLUDES = -I/home/saqut/Masaüstü/saqutcompiler/src OBJECT_DIR = CMakeFiles/saqut.dir OBJECT_FILE_DIR = CMakeFiles/saqut.dir/src/parser/nodes + TARGET_COMPILE_PDB = CMakeFiles/saqut.dir/ + TARGET_PDB = saqut.pdb TARGET_SUPPORT_DIR = CMakeFiles/saqut.dir build CMakeFiles/saqut.dir/src/parser/nodes/declarations.cpp.o: CXX_COMPILER__saqut_unscanned_Debug /home/saqut/Masaüstü/saqutcompiler/src/parser/nodes/declarations.cpp || cmake_object_order_depends_target_saqut @@ -119,6 +133,8 @@ build CMakeFiles/saqut.dir/src/parser/nodes/declarations.cpp.o: CXX_COMPILER__sa INCLUDES = -I/home/saqut/Masaüstü/saqutcompiler/src OBJECT_DIR = CMakeFiles/saqut.dir OBJECT_FILE_DIR = CMakeFiles/saqut.dir/src/parser/nodes + TARGET_COMPILE_PDB = CMakeFiles/saqut.dir/ + TARGET_PDB = saqut.pdb TARGET_SUPPORT_DIR = CMakeFiles/saqut.dir build CMakeFiles/saqut.dir/src/parser/nodes/expressions.cpp.o: CXX_COMPILER__saqut_unscanned_Debug /home/saqut/Masaüstü/saqutcompiler/src/parser/nodes/expressions.cpp || cmake_object_order_depends_target_saqut @@ -128,6 +144,8 @@ build CMakeFiles/saqut.dir/src/parser/nodes/expressions.cpp.o: CXX_COMPILER__saq INCLUDES = -I/home/saqut/Masaüstü/saqutcompiler/src OBJECT_DIR = CMakeFiles/saqut.dir OBJECT_FILE_DIR = CMakeFiles/saqut.dir/src/parser/nodes + TARGET_COMPILE_PDB = CMakeFiles/saqut.dir/ + TARGET_PDB = saqut.pdb TARGET_SUPPORT_DIR = CMakeFiles/saqut.dir build CMakeFiles/saqut.dir/src/parser/nodes/identifier.cpp.o: CXX_COMPILER__saqut_unscanned_Debug /home/saqut/Masaüstü/saqutcompiler/src/parser/nodes/identifier.cpp || cmake_object_order_depends_target_saqut @@ -137,6 +155,8 @@ build CMakeFiles/saqut.dir/src/parser/nodes/identifier.cpp.o: CXX_COMPILER__saqu INCLUDES = -I/home/saqut/Masaüstü/saqutcompiler/src OBJECT_DIR = CMakeFiles/saqut.dir OBJECT_FILE_DIR = CMakeFiles/saqut.dir/src/parser/nodes + TARGET_COMPILE_PDB = CMakeFiles/saqut.dir/ + TARGET_PDB = saqut.pdb TARGET_SUPPORT_DIR = CMakeFiles/saqut.dir build CMakeFiles/saqut.dir/src/parser/nodes/literal.cpp.o: CXX_COMPILER__saqut_unscanned_Debug /home/saqut/Masaüstü/saqutcompiler/src/parser/nodes/literal.cpp || cmake_object_order_depends_target_saqut @@ -146,6 +166,8 @@ build CMakeFiles/saqut.dir/src/parser/nodes/literal.cpp.o: CXX_COMPILER__saqut_u INCLUDES = -I/home/saqut/Masaüstü/saqutcompiler/src OBJECT_DIR = CMakeFiles/saqut.dir OBJECT_FILE_DIR = CMakeFiles/saqut.dir/src/parser/nodes + TARGET_COMPILE_PDB = CMakeFiles/saqut.dir/ + TARGET_PDB = saqut.pdb TARGET_SUPPORT_DIR = CMakeFiles/saqut.dir build CMakeFiles/saqut.dir/src/parser/nodes/program.cpp.o: CXX_COMPILER__saqut_unscanned_Debug /home/saqut/Masaüstü/saqutcompiler/src/parser/nodes/program.cpp || cmake_object_order_depends_target_saqut @@ -155,6 +177,8 @@ build CMakeFiles/saqut.dir/src/parser/nodes/program.cpp.o: CXX_COMPILER__saqut_u INCLUDES = -I/home/saqut/Masaüstü/saqutcompiler/src OBJECT_DIR = CMakeFiles/saqut.dir OBJECT_FILE_DIR = CMakeFiles/saqut.dir/src/parser/nodes + TARGET_COMPILE_PDB = CMakeFiles/saqut.dir/ + TARGET_PDB = saqut.pdb TARGET_SUPPORT_DIR = CMakeFiles/saqut.dir build CMakeFiles/saqut.dir/src/parser/nodes/statements.cpp.o: CXX_COMPILER__saqut_unscanned_Debug /home/saqut/Masaüstü/saqutcompiler/src/parser/nodes/statements.cpp || cmake_object_order_depends_target_saqut @@ -164,6 +188,8 @@ build CMakeFiles/saqut.dir/src/parser/nodes/statements.cpp.o: CXX_COMPILER__saqu INCLUDES = -I/home/saqut/Masaüstü/saqutcompiler/src OBJECT_DIR = CMakeFiles/saqut.dir OBJECT_FILE_DIR = CMakeFiles/saqut.dir/src/parser/nodes + TARGET_COMPILE_PDB = CMakeFiles/saqut.dir/ + TARGET_PDB = saqut.pdb TARGET_SUPPORT_DIR = CMakeFiles/saqut.dir build CMakeFiles/saqut.dir/src/parser/parser.cpp.o: CXX_COMPILER__saqut_unscanned_Debug /home/saqut/Masaüstü/saqutcompiler/src/parser/parser.cpp || cmake_object_order_depends_target_saqut @@ -173,6 +199,8 @@ build CMakeFiles/saqut.dir/src/parser/parser.cpp.o: CXX_COMPILER__saqut_unscanne INCLUDES = -I/home/saqut/Masaüstü/saqutcompiler/src OBJECT_DIR = CMakeFiles/saqut.dir OBJECT_FILE_DIR = CMakeFiles/saqut.dir/src/parser + TARGET_COMPILE_PDB = CMakeFiles/saqut.dir/ + TARGET_PDB = saqut.pdb TARGET_SUPPORT_DIR = CMakeFiles/saqut.dir build CMakeFiles/saqut.dir/src/semantic/structural_validator.cpp.o: CXX_COMPILER__saqut_unscanned_Debug /home/saqut/Masaüstü/saqutcompiler/src/semantic/structural_validator.cpp || cmake_object_order_depends_target_saqut @@ -182,6 +210,8 @@ build CMakeFiles/saqut.dir/src/semantic/structural_validator.cpp.o: CXX_COMPILER INCLUDES = -I/home/saqut/Masaüstü/saqutcompiler/src OBJECT_DIR = CMakeFiles/saqut.dir OBJECT_FILE_DIR = CMakeFiles/saqut.dir/src/semantic + TARGET_COMPILE_PDB = CMakeFiles/saqut.dir/ + TARGET_PDB = saqut.pdb TARGET_SUPPORT_DIR = CMakeFiles/saqut.dir build CMakeFiles/saqut.dir/src/semantic/type_checker.cpp.o: CXX_COMPILER__saqut_unscanned_Debug /home/saqut/Masaüstü/saqutcompiler/src/semantic/type_checker.cpp || cmake_object_order_depends_target_saqut @@ -191,6 +221,8 @@ build CMakeFiles/saqut.dir/src/semantic/type_checker.cpp.o: CXX_COMPILER__saqut_ INCLUDES = -I/home/saqut/Masaüstü/saqutcompiler/src OBJECT_DIR = CMakeFiles/saqut.dir OBJECT_FILE_DIR = CMakeFiles/saqut.dir/src/semantic + TARGET_COMPILE_PDB = CMakeFiles/saqut.dir/ + TARGET_PDB = saqut.pdb TARGET_SUPPORT_DIR = CMakeFiles/saqut.dir build CMakeFiles/saqut.dir/src/symbol/symbol_collector.cpp.o: CXX_COMPILER__saqut_unscanned_Debug /home/saqut/Masaüstü/saqutcompiler/src/symbol/symbol_collector.cpp || cmake_object_order_depends_target_saqut @@ -200,6 +232,8 @@ build CMakeFiles/saqut.dir/src/symbol/symbol_collector.cpp.o: CXX_COMPILER__saqu INCLUDES = -I/home/saqut/Masaüstü/saqutcompiler/src OBJECT_DIR = CMakeFiles/saqut.dir OBJECT_FILE_DIR = CMakeFiles/saqut.dir/src/symbol + TARGET_COMPILE_PDB = CMakeFiles/saqut.dir/ + TARGET_PDB = saqut.pdb TARGET_SUPPORT_DIR = CMakeFiles/saqut.dir build CMakeFiles/saqut.dir/src/tokenizer/tokenizer.cpp.o: CXX_COMPILER__saqut_unscanned_Debug /home/saqut/Masaüstü/saqutcompiler/src/tokenizer/tokenizer.cpp || cmake_object_order_depends_target_saqut @@ -209,6 +243,8 @@ build CMakeFiles/saqut.dir/src/tokenizer/tokenizer.cpp.o: CXX_COMPILER__saqut_un INCLUDES = -I/home/saqut/Masaüstü/saqutcompiler/src OBJECT_DIR = CMakeFiles/saqut.dir OBJECT_FILE_DIR = CMakeFiles/saqut.dir/src/tokenizer + TARGET_COMPILE_PDB = CMakeFiles/saqut.dir/ + TARGET_PDB = saqut.pdb TARGET_SUPPORT_DIR = CMakeFiles/saqut.dir build CMakeFiles/saqut.dir/src/vm/interpreter.cpp.o: CXX_COMPILER__saqut_unscanned_Debug /home/saqut/Masaüstü/saqutcompiler/src/vm/interpreter.cpp || cmake_object_order_depends_target_saqut @@ -218,6 +254,8 @@ build CMakeFiles/saqut.dir/src/vm/interpreter.cpp.o: CXX_COMPILER__saqut_unscann INCLUDES = -I/home/saqut/Masaüstü/saqutcompiler/src OBJECT_DIR = CMakeFiles/saqut.dir OBJECT_FILE_DIR = CMakeFiles/saqut.dir/src/vm + TARGET_COMPILE_PDB = CMakeFiles/saqut.dir/ + TARGET_PDB = saqut.pdb TARGET_SUPPORT_DIR = CMakeFiles/saqut.dir @@ -236,11 +274,24 @@ build saqut: CXX_EXECUTABLE_LINKER__saqut_Debug CMakeFiles/saqut.dir/src/core/so OBJECT_DIR = CMakeFiles/saqut.dir POST_BUILD = : PRE_LINK = : + TARGET_COMPILE_PDB = CMakeFiles/saqut.dir/ TARGET_FILE = saqut - TARGET_PDB = saqut.dbg + TARGET_PDB = saqut.pdb TARGET_SUPPORT_DIR = CMakeFiles/saqut.dir +############################################# +# Utility command for test + +build CMakeFiles/test.util: CUSTOM_COMMAND + COMMAND = cd /home/saqut/Masaüstü/saqutcompiler/build && /usr/bin/ctest + DESC = Running tests... + pool = console + restat = 1 + +build test: phony CMakeFiles/test.util + + ############################################# # Utility command for edit_cache @@ -281,17 +332,31 @@ build all: phony saqut # Built-in targets +############################################# +# Phony target to force glob verification run. + +build /home/saqut/Masaüstü/saqutcompiler/build/CMakeFiles/VerifyGlobs.cmake_force: phony + + +############################################# +# Re-run CMake to check if globbed directories changed. + +build /home/saqut/Masaüstü/saqutcompiler/build/CMakeFiles/cmake.verify_globs: VERIFY_GLOBS | /home/saqut/Masaüstü/saqutcompiler/build/CMakeFiles/VerifyGlobs.cmake_force + pool = console + restat = 1 + + ############################################# # Re-run CMake if any of its inputs changed. -build build.ninja /home/saqut/Masaüstü/saqutcompiler/build/cmake_install.cmake: RERUN_CMAKE | /home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt /usr/share/cmake/Modules/CMakeCXXInformation.cmake /usr/share/cmake/Modules/CMakeCommonLanguageInclude.cmake /usr/share/cmake/Modules/CMakeGenericSystem.cmake /usr/share/cmake/Modules/CMakeInitializeConfigs.cmake /usr/share/cmake/Modules/CMakeLanguageInformation.cmake /usr/share/cmake/Modules/CMakeSystemSpecificInformation.cmake /usr/share/cmake/Modules/CMakeSystemSpecificInitialize.cmake /usr/share/cmake/Modules/Compiler/CMakeCommonCompilerMacros.cmake /usr/share/cmake/Modules/Compiler/GNU-CXX.cmake /usr/share/cmake/Modules/Compiler/GNU.cmake /usr/share/cmake/Modules/Internal/CMakeCXXLinkerInformation.cmake /usr/share/cmake/Modules/Internal/CMakeCommonLinkerInformation.cmake /usr/share/cmake/Modules/Linker/GNU-CXX.cmake /usr/share/cmake/Modules/Linker/GNU.cmake /usr/share/cmake/Modules/Platform/Linker/GNU.cmake /usr/share/cmake/Modules/Platform/Linker/Linux-GNU-CXX.cmake /usr/share/cmake/Modules/Platform/Linker/Linux-GNU.cmake /usr/share/cmake/Modules/Platform/Linux-GNU-CXX.cmake /usr/share/cmake/Modules/Platform/Linux-GNU.cmake /usr/share/cmake/Modules/Platform/Linux-Initialize.cmake /usr/share/cmake/Modules/Platform/Linux.cmake /usr/share/cmake/Modules/Platform/UnixPaths.cmake CMakeCache.txt CMakeFiles/4.3.3/CMakeCXXCompiler.cmake CMakeFiles/4.3.3/CMakeSystem.cmake +build build.ninja /home/saqut/Masaüstü/saqutcompiler/build/cmake_install.cmake /home/saqut/Masaüstü/saqutcompiler/build/CTestTestfile.cmake: RERUN_CMAKE /home/saqut/Masaüstü/saqutcompiler/build/CMakeFiles/cmake.verify_globs | /home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt /home/saqut/Masaüstü/saqutcompiler/build/CMakeFiles/VerifyGlobs.cmake /usr/share/cmake/Modules/CMakeCXXCompiler.cmake.in /usr/share/cmake/Modules/CMakeCXXCompilerABI.cpp /usr/share/cmake/Modules/CMakeCXXInformation.cmake /usr/share/cmake/Modules/CMakeCommonLanguageInclude.cmake /usr/share/cmake/Modules/CMakeCompilerIdDetection.cmake /usr/share/cmake/Modules/CMakeDetermineCXXCompiler.cmake /usr/share/cmake/Modules/CMakeDetermineCompiler.cmake /usr/share/cmake/Modules/CMakeDetermineCompilerABI.cmake /usr/share/cmake/Modules/CMakeDetermineCompilerId.cmake /usr/share/cmake/Modules/CMakeDetermineCompilerSupport.cmake /usr/share/cmake/Modules/CMakeDetermineSystem.cmake /usr/share/cmake/Modules/CMakeFindBinUtils.cmake /usr/share/cmake/Modules/CMakeGenericSystem.cmake /usr/share/cmake/Modules/CMakeInitializeConfigs.cmake /usr/share/cmake/Modules/CMakeLanguageInformation.cmake /usr/share/cmake/Modules/CMakeNinjaFindMake.cmake /usr/share/cmake/Modules/CMakeParseImplicitIncludeInfo.cmake /usr/share/cmake/Modules/CMakeParseImplicitLinkInfo.cmake /usr/share/cmake/Modules/CMakeParseLibraryArchitecture.cmake /usr/share/cmake/Modules/CMakeSystem.cmake.in /usr/share/cmake/Modules/CMakeSystemSpecificInformation.cmake /usr/share/cmake/Modules/CMakeSystemSpecificInitialize.cmake /usr/share/cmake/Modules/CMakeTestCXXCompiler.cmake /usr/share/cmake/Modules/CMakeTestCompilerCommon.cmake /usr/share/cmake/Modules/Compiler/ADSP-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/ARMCC-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/ARMClang-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/AppleClang-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/Borland-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/CMakeCommonCompilerMacros.cmake /usr/share/cmake/Modules/Compiler/Clang-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/Clang-DetermineCompilerInternal.cmake /usr/share/cmake/Modules/Compiler/Compaq-CXX-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/Cray-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/CrayClang-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/Diab-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/Embarcadero-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/Fujitsu-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/FujitsuClang-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/GHS-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/GNU-CXX-CXXImportStd.cmake /usr/share/cmake/Modules/Compiler/GNU-CXX-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/GNU-CXX.cmake /usr/share/cmake/Modules/Compiler/GNU-FindBinUtils.cmake /usr/share/cmake/Modules/Compiler/GNU.cmake /usr/share/cmake/Modules/Compiler/HP-CXX-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/IAR-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/IBMCPP-CXX-DetermineVersionInternal.cmake /usr/share/cmake/Modules/Compiler/IBMClang-CXX-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/Intel-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/IntelLLVM-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/LCC-CXX-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/MSVC-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/NVHPC-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/NVIDIA-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/OpenWatcom-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/OrangeC-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/PGI-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/PathScale-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/Renesas-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/SCO-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/SunPro-CXX-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/TI-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/TIClang-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/Tasking-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/VisualAge-CXX-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/Watcom-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/XL-CXX-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/XLClang-CXX-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/zOS-CXX-DetermineCompiler.cmake /usr/share/cmake/Modules/Internal/CMakeCXXLinkerInformation.cmake /usr/share/cmake/Modules/Internal/CMakeCommonLinkerInformation.cmake /usr/share/cmake/Modules/Internal/CMakeDetermineLinkerId.cmake /usr/share/cmake/Modules/Internal/CMakeInspectCXXLinker.cmake /usr/share/cmake/Modules/Internal/FeatureTesting.cmake /usr/share/cmake/Modules/Linker/GNU-CXX.cmake /usr/share/cmake/Modules/Linker/GNU.cmake /usr/share/cmake/Modules/Platform/Linker/GNU.cmake /usr/share/cmake/Modules/Platform/Linker/Linux-GNU-CXX.cmake /usr/share/cmake/Modules/Platform/Linker/Linux-GNU.cmake /usr/share/cmake/Modules/Platform/Linux-Determine-CXX.cmake /usr/share/cmake/Modules/Platform/Linux-GNU-CXX.cmake /usr/share/cmake/Modules/Platform/Linux-GNU.cmake /usr/share/cmake/Modules/Platform/Linux-Initialize.cmake /usr/share/cmake/Modules/Platform/Linux.cmake /usr/share/cmake/Modules/Platform/UnixPaths.cmake CMakeCache.txt CMakeFiles/4.3.3/CMakeCXXCompiler.cmake CMakeFiles/4.3.3/CMakeSystem.cmake pool = console ############################################# # A missing CMake input file is not an error. -build /home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt /usr/share/cmake/Modules/CMakeCXXInformation.cmake /usr/share/cmake/Modules/CMakeCommonLanguageInclude.cmake /usr/share/cmake/Modules/CMakeGenericSystem.cmake /usr/share/cmake/Modules/CMakeInitializeConfigs.cmake /usr/share/cmake/Modules/CMakeLanguageInformation.cmake /usr/share/cmake/Modules/CMakeSystemSpecificInformation.cmake /usr/share/cmake/Modules/CMakeSystemSpecificInitialize.cmake /usr/share/cmake/Modules/Compiler/CMakeCommonCompilerMacros.cmake /usr/share/cmake/Modules/Compiler/GNU-CXX.cmake /usr/share/cmake/Modules/Compiler/GNU.cmake /usr/share/cmake/Modules/Internal/CMakeCXXLinkerInformation.cmake /usr/share/cmake/Modules/Internal/CMakeCommonLinkerInformation.cmake /usr/share/cmake/Modules/Linker/GNU-CXX.cmake /usr/share/cmake/Modules/Linker/GNU.cmake /usr/share/cmake/Modules/Platform/Linker/GNU.cmake /usr/share/cmake/Modules/Platform/Linker/Linux-GNU-CXX.cmake /usr/share/cmake/Modules/Platform/Linker/Linux-GNU.cmake /usr/share/cmake/Modules/Platform/Linux-GNU-CXX.cmake /usr/share/cmake/Modules/Platform/Linux-GNU.cmake /usr/share/cmake/Modules/Platform/Linux-Initialize.cmake /usr/share/cmake/Modules/Platform/Linux.cmake /usr/share/cmake/Modules/Platform/UnixPaths.cmake CMakeCache.txt CMakeFiles/4.3.3/CMakeCXXCompiler.cmake CMakeFiles/4.3.3/CMakeSystem.cmake: phony +build /home/saqut/Masaüstü/saqutcompiler/CMakeLists.txt /home/saqut/Masaüstü/saqutcompiler/build/CMakeFiles/VerifyGlobs.cmake /usr/share/cmake/Modules/CMakeCXXCompiler.cmake.in /usr/share/cmake/Modules/CMakeCXXCompilerABI.cpp /usr/share/cmake/Modules/CMakeCXXInformation.cmake /usr/share/cmake/Modules/CMakeCommonLanguageInclude.cmake /usr/share/cmake/Modules/CMakeCompilerIdDetection.cmake /usr/share/cmake/Modules/CMakeDetermineCXXCompiler.cmake /usr/share/cmake/Modules/CMakeDetermineCompiler.cmake /usr/share/cmake/Modules/CMakeDetermineCompilerABI.cmake /usr/share/cmake/Modules/CMakeDetermineCompilerId.cmake /usr/share/cmake/Modules/CMakeDetermineCompilerSupport.cmake /usr/share/cmake/Modules/CMakeDetermineSystem.cmake /usr/share/cmake/Modules/CMakeFindBinUtils.cmake /usr/share/cmake/Modules/CMakeGenericSystem.cmake /usr/share/cmake/Modules/CMakeInitializeConfigs.cmake /usr/share/cmake/Modules/CMakeLanguageInformation.cmake /usr/share/cmake/Modules/CMakeNinjaFindMake.cmake /usr/share/cmake/Modules/CMakeParseImplicitIncludeInfo.cmake /usr/share/cmake/Modules/CMakeParseImplicitLinkInfo.cmake /usr/share/cmake/Modules/CMakeParseLibraryArchitecture.cmake /usr/share/cmake/Modules/CMakeSystem.cmake.in /usr/share/cmake/Modules/CMakeSystemSpecificInformation.cmake /usr/share/cmake/Modules/CMakeSystemSpecificInitialize.cmake /usr/share/cmake/Modules/CMakeTestCXXCompiler.cmake /usr/share/cmake/Modules/CMakeTestCompilerCommon.cmake /usr/share/cmake/Modules/Compiler/ADSP-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/ARMCC-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/ARMClang-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/AppleClang-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/Borland-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/CMakeCommonCompilerMacros.cmake /usr/share/cmake/Modules/Compiler/Clang-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/Clang-DetermineCompilerInternal.cmake /usr/share/cmake/Modules/Compiler/Compaq-CXX-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/Cray-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/CrayClang-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/Diab-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/Embarcadero-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/Fujitsu-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/FujitsuClang-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/GHS-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/GNU-CXX-CXXImportStd.cmake /usr/share/cmake/Modules/Compiler/GNU-CXX-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/GNU-CXX.cmake /usr/share/cmake/Modules/Compiler/GNU-FindBinUtils.cmake /usr/share/cmake/Modules/Compiler/GNU.cmake /usr/share/cmake/Modules/Compiler/HP-CXX-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/IAR-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/IBMCPP-CXX-DetermineVersionInternal.cmake /usr/share/cmake/Modules/Compiler/IBMClang-CXX-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/Intel-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/IntelLLVM-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/LCC-CXX-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/MSVC-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/NVHPC-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/NVIDIA-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/OpenWatcom-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/OrangeC-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/PGI-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/PathScale-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/Renesas-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/SCO-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/SunPro-CXX-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/TI-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/TIClang-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/Tasking-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/VisualAge-CXX-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/Watcom-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/XL-CXX-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/XLClang-CXX-DetermineCompiler.cmake /usr/share/cmake/Modules/Compiler/zOS-CXX-DetermineCompiler.cmake /usr/share/cmake/Modules/Internal/CMakeCXXLinkerInformation.cmake /usr/share/cmake/Modules/Internal/CMakeCommonLinkerInformation.cmake /usr/share/cmake/Modules/Internal/CMakeDetermineLinkerId.cmake /usr/share/cmake/Modules/Internal/CMakeInspectCXXLinker.cmake /usr/share/cmake/Modules/Internal/FeatureTesting.cmake /usr/share/cmake/Modules/Linker/GNU-CXX.cmake /usr/share/cmake/Modules/Linker/GNU.cmake /usr/share/cmake/Modules/Platform/Linker/GNU.cmake /usr/share/cmake/Modules/Platform/Linker/Linux-GNU-CXX.cmake /usr/share/cmake/Modules/Platform/Linker/Linux-GNU.cmake /usr/share/cmake/Modules/Platform/Linux-Determine-CXX.cmake /usr/share/cmake/Modules/Platform/Linux-GNU-CXX.cmake /usr/share/cmake/Modules/Platform/Linux-GNU.cmake /usr/share/cmake/Modules/Platform/Linux-Initialize.cmake /usr/share/cmake/Modules/Platform/Linux.cmake /usr/share/cmake/Modules/Platform/UnixPaths.cmake CMakeCache.txt CMakeFiles/4.3.3/CMakeCXXCompiler.cmake CMakeFiles/4.3.3/CMakeSystem.cmake: phony ############################################# diff --git a/cmake/run_golden.cmake b/cmake/run_golden.cmake new file mode 100644 index 0000000..768cf9e --- /dev/null +++ b/cmake/run_golden.cmake @@ -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() diff --git a/cmake/run_golden_error.cmake b/cmake/run_golden_error.cmake new file mode 100644 index 0000000..9ee0c04 --- /dev/null +++ b/cmake/run_golden_error.cmake @@ -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() diff --git a/docs/adr-frontend-analiz.md b/docs/adr-frontend-analiz.md index 17ece89..ac1432d 100644 --- a/docs/adr-frontend-analiz.md +++ b/docs/adr-frontend-analiz.md @@ -10,12 +10,11 @@ > Tartışmanın tam akışı için bkz. `docs/transkript-frontend-tasarim.md`. > Uygulama planı için bkz. `docs/roadmap-frontend.md`. > -> ⚠️ **Yapılan vs planlanan:** Bu belgedeki ADR-006…019 **tasarım kararlarıdır**; -> tarif edilen makine (sembol tablosu, semantik analiz, tip sistemi, diagnostic, -> optimizasyon, IR+VM) **henüz kodlanmamıştır.** Bugün çalışan: lexer, tokenizer, -> Pratt parser, AST, AST'nin JSON serileştirmesi, CLI iskeleti, konum takibi ve -> basit aritmetiği düşüren minimal bir IR deneyi. Hiçbir ADR, var olmayan bir -> mekanizmayı varmış gibi anlatmaz. +> ✅ **Uygulama durumu:** Bu belgedeki ADR-006…019 kararlarında tarif edilen +> makine **kodlandı ve çalışıyor.** Sembol tablosu, semantik analiz, tip sistemi, +> diagnostic motoru, optimizasyon (constant folding + DCE), IR üreteci ve bytecode +> VM'in tamamı uygulandı. `examples/fibonacci.sqt` uçtan uca çalışıyor. +> Güncel "çalışıyor / henüz yok" listesi için bkz. `CLAUDE.md`. --- @@ -105,46 +104,45 @@ sembol tablosunun optimizasyondan önceki ve sonraki halini ayrı ayrı görebil symbol bağı, erişilebilirlik, constness ekler). Ağacı **bozmaz**, zenginleştirir. Orijinal AST hâlâ kaynak kodun tam izdüşümüdür. -2. **Optimizasyon dönüşümü, ağacın bir KOPYASI (klon) üzerinde yapılır.** - Orijinal analizli AST = "öncesi"; klon + dönüştürülmüş AST = "sonrası". - Ağaç klonlamak ucuz ve basittir, yalnızca `--optimized` istendiğinde yapılır. +2. **Optimizasyon dönüşümü iki yolla yapılabilir:** -**Sonuç:** Hem "bellek canavarı" felsefesi korunur (orijinal AST her şeyi tutar), -hem optimizasyon yapılır, hem de öncesi/sonrası ayrı ayrı incelenebilir. + a. **`ast` komutu için klon:** orijinal AST dokunulmadan kalır, klon üstünde + pass'ler çalışır. Kullanıcı "öncesi" ve "sonrası" AST'yi ayrı ayrı + görebilir. `OptimizationManager::optimize()` bu yolu kullanır. + + b. **Diğer tüm komutlar için yerinde (in-place):** `run --optimized`, + `ir --optimized` vb. tek versiyon üretiyor — orijinali saklamaya gerek yok. + `OptimizationManager::runPassesInPlace()` bu yolu kullanır, klon maliyeti yok. + +**Sonuç:** "bellek canavarı" felsefesi `ast` komutunda korunur; diğer komutlar +gereksiz klon maliyeti taşımaz. ``` saqut ast file.sqt → ham + annotate edilmiş AST (1+2 burada durur) saqut ast file.sqt --optimized → klon, folding uygulanmış (3 var) +saqut run file.sqt --optimized → yerinde optimize → IR → VM (klon yok) +saqut ir file.sqt --optimized → yerinde optimize → IR dump (klon yok) ``` -### Güncelleme — Klon maliyeti yük taşır (load-bearing) +### Güncelleme — Klon ve sembol tablosu paylaşımı -İlk metin "ağaç klonlamak ucuz ve basittir" diyordu; bu **klon maliyetini hafife -alıyor** ve bir **tutarlılık (coherence) problemini** atlıyordu. Düzeltme: +`deepClone` sembol tablosunu yeniden eşlemez (remap etmez) — klondaki +`IdentifierNode::resolvedSymbol` orijinal `Symbol` nesnelerini gösterir. Bu +**güvenlidir**, çünkü: -`ASTNode::clone()` "belki gerekir" değil, **merkezi ve spesifiye edilmesi -zorunlu** bir bileşendir; tüm öncesi/sonrası hikâyesi ona dayanır (bkz. roadmap -Faz 4'te clone() yükseltildi). +- `Symbol::references` bir **konum listesi** (`std::vector`), + referans sayacı değildir. Klonda bir `IdentifierNode` silindiğinde bu liste + değişmez. +- `IdentifierNode` destructor'ı yoktur; `resolvedSymbol`'e dokunan hiçbir yıkıcı + kodu çalışmaz. +- Klondaki pass'ler Symbol nesnelerini **okur** (slot numarası, tip vb.), + **yazmaz** — paylaşım salt-okunur (read-only) kullanımdır. -**Klonlanırken karar verilmesi gereken iki nokta (açıkça belgele):** +**Parent pointer'lar** ise yeniden bağlanır — klon node'larının `parent`'ı +orijinali değil, klonu gösterir (deepClone bunu zaten yapar). -1. **Parent pointer'lar yeniden bağlanmalı.** Klon node'larının `parent`'ı - orijinali değil, klonu göstermeli; yoksa yapısal doğrulama ve dönüşümler - yanlış ağaçta gezinir. - -2. **`IdentifierNode → Symbol` bağları: paylaş mı, yeniden eşle mi?** - - **Paylaş** (klon ve orijinal aynı sembol tablosuna işaret eder): ucuz, ama - klonu optimize etmek orijinalin **referans sayımlarını bozar** (DCE klonda - bir kullanımı silince orijinalin Symbol ref-count'u da düşer). - - **Yeniden eşle** (klona ait bir sembol tablosu kopyası): doğru, ama ucuz - değil. - - **Karar:** `--optimized` istendiğinde sembol tablosu da **klonlanır ve - yeniden eşlenir** (remap). Doğruluk, ucuzluğa tercih edilir; klon zaten - yalnızca optimizasyon istendiğinde üretilir, sıcak yol değildir. "Ucuz" - iddiası kaldırıldı. - -Bu, ADR-013'teki "ref-count Symbol'da yaşar" kararıyla tutarlıdır: ref-count -Symbol'da olduğu için, klonun kendi Symbol'larına sahip olması şarttır. +Önceki versiyon "sembol tablosu klonlanır ve remap edilir" diyordu; bu hem hiç +implement edilmedi hem de gerekli değildi. Düzeltildi. --- @@ -513,6 +511,11 @@ bir yükümlülüktür ama **frontend'i bloklamaz** ve kolay yolu vardır: ### Güncelleme — Scope-tabanlı bellek artık GEREKÇELİ (bağımlılığı belgele) +> ⚠️ **İPTAL — bu güncelleme ADR-020 ile geçersiz kılındı.** Bileşik tipler artık +> runtime'da referans (JS/Java/C# modeli); bileşikler scope'tan kaçar, bellek +> erişilebilirliğe bağlı, geri-kazanım stratejisi (#56) gerekecek. Aşağıdaki +> "GC gerekmez" sonucu **artık geçerli değildir** — tarihsel bağlam için bırakıldı. + Önceki kaygı ("scope çıkışında free, aliasing/escape altında bozulur") kilitli dil kimliğiyle **lehte çözüldü:** @@ -662,12 +665,457 @@ modelini birlikte zorlar — ikisi de bu yüzden ertelendi. --- +## ADR-020: Değer vs Referans Semantiği — Bileşik Tipler Runtime'da Referanstır + +### Bağlam + +ADR-014/018/019 boyunca bellek modeli tek bir **taşıyıcı varsayıma** dayanıyordu: + +> "kullanıcı pointer'ı yok + kaçan referans yok → array/struct scope'tan kaçamaz +> → scope-tabanlı bellek çalışır, **GC gerekmez**." + +Bu varsayım, `interface`'in (ADR-018) ve closure'ın ertelenmesinin de ikinci +gerekçesiydi. Tasarım oturumunda **bilinçli olarak değiştirildi.** "Pointer yok" +ilkesinin gerçekte ne demek olduğu netleşti: + +> **"Pointer/referans yok" = kullanıcıya `&`/`*` *sözdizimi* verilmez.** +> Bu bir *value-semantics* iddiası değildi; amacı sözdizimsel pointer kontrolünü +> kullanıcıdan almaktı. Derleyici ve runtime, bileşik değerleri her aşamada +> **referansla** taşır — aksi halde her atama/çağrı/dönüşte derin kopya yaşanır +> ve bağlı yapılar (node) imkânsızlaşırdı. + +### Karar + +✅ **İki katmanlı semantik (JavaScript / Java / C# nesne modeli):** + +| Kategori | Tipler | Atama / parametre semantiği | +|---|---|---| +| **Primitive** | `int`, `float`, `bool`, (`char` vb.) | **Saf değer** — kopyalanır | +| **Bileşik (referans)** | `struct`, `array`, `string`\*, (ileride `class`, `function`) | **Referans** — paylaşılır | + +- `a=0; b=a; b=5` → `a` hâlâ `0` (primitive kopya). Fonksiyon parametresinde de aynı. +- `func(arr)` → array'in **kendisi** geçer; `func` içinde değişen çağıranı **etkiler**. +- `func(arr[0])` → eleman primitive → **kopya**; çağıranı **etkilemez**. +- \* `string`'in primitive-gibi mi (immutable değer) yoksa referans mı sayılacağı + ayrı bir alt-karar; #40 ile beraber netleşecek. + +✅ **`class` ve `function` tipleri sözdizimsel olarak rezerve** — şu an semantik +yok, backend'i ilgilendirmez; ileride referans tip olarak gelecekler. Lexer/parser +keyword'leri tanıyıp "henüz desteklenmiyor" diyebilir. (ADR-014'teki "class yok +sayılır" maddesi bu yönde yumuşatıldı: yok sayılmaz, rezerve edilir.) + +### Bilinçli geri açtığımız problem: kaçma / yaşam-süresi + +Bu karar, ADR-014'ün "scope-tabanlı bellek GEREKÇELİ / GC gerekmez" sonucunu +**iptal eder.** Referansla: + +1. **Aliasing gerçek.** `b = a; b.x = 5` → `a.x` de değişir. "Takma ad yok, akıl + yürütmesi kolay" sadeliği takas edildi. **Determinizm korunur** — tek + iş-parçacığı, deterministik kayıt-tekrar / time-travel debug hâlâ doğal; takas + edilen yalnızca aliasing-özgürlüğüdür. +2. **Bileşikler scope'tan kaçar.** Bir node `return` edilebilir veya başka bir + struct'ın alanında saklanabilir → "scope çıkışında free" **artık yanlış.** + Sahiplik scope'a değil **erişilebilirliğe** bağlı. +3. **Döngüsel yapılar artık meşru ve istenen.** `struct Node { Node next; }` + ADR-011/014'te `E010` ile yasaktı (by-value → sonsuz boyut). Referansla alan + pointer-boyutlu → **sonlu** → bağlı liste / ağaç / graf **yazılabilir.** Bunlar + dilin hedef kullanımının kalbi: XML node'ları, JSON kalıpları, class'sız ORM. + **Sonuç:** `E010` revize edilmeli — referansla tutulan struct alanı için döngü + artık hata değildir. + +### Bunun açtığı zorunlu problem (ayrı issue) + +Döngüsel referans → naif **referans sayımı (`shared_ptr`) sızdırır.** Bu artık +"olabilir" değil, dilin **hedeflediği** yapıların (graf/döngü) doğrudan sonucu. +Bir geri-kazanım stratejisi (izleyici GC / döngü toplayıcı) **kesinlikle** +gerekecek. Bu güçlü mimari borç **#56**'da izlenir ve `karar-gerekli`. v1 motoru +`shared_ptr` ile başlayıp döngüyü **bilinçli ve belgeleyerek** sızdırabilir, ama +ürünleşmeden önce çözülmek zorundadır. + +### İptal/revize edilen önceki kararlar + +- **ADR-014** — "scope-tabanlı bellek GEREKÇELİ / GC gerekmez" sonucu **iptal.** + Bellek artık scope'a değil erişilebilirliğe bağlı; geri-kazanım stratejisi #56. +- **ADR-018 / ADR-019** — `interface` / closure'ı ertelemenin "kaçma problemini + yeniden açar" gerekçesi **artık geçersiz** (problem zaten açık). Bu ikisini + *daha kolay* alınabilir kılar — ama hâlâ kapsam dışı, sadece engeli değişti. +- **ADR-011** — `E010` döngüsel struct kuralı revize edilecek (yukarı bkz.). + +--- + +## ADR-021: Null Güvenliği — `Type?` Nullable + Akış-Duyarlı Null Analizi + +### Bağlam + +ADR-020 ile bileşik tipler referans oldu. Referans, "gösterecek bir şey yok" +durumunu (bağlı listenin sonu, başlatılmamış alan) **zorunlu** kılar. "null her +yerde" (Java/C#/JS) milyar dolarlık hatadır: null-deref çalışma zamanında patlar. +saQut'un kimliği "kafes — derleyici/VM seni korur" → bunu derleme zamanında +yakalamak istiyoruz. + +### Karar + +✅ **Kotlin/Swift modeli: varsayılan null-OLAMAZ, nullable açıkça `?` ile.** + +- `Node a` → asla null olamaz; başlatılması zorunlu. +- `Node? a` → null olabilir; başlatılmazsa değeri **`null`**. +- `null` literali yalnızca `T?` tipine atanabilir; `Node a = null` → **derleme hatası**. +- `T?` üstünde doğrudan alan/eleman erişimi (`a.next`) → **derleme hatası** + (önce null-kontrolü şart). + +### Atama/operand kuralı — `T <: T?` (tek yönlü), katı + +✅ **Alt-tip:** `T <: T?`. Yani: +- `int? a = 5;` → ✓ (int → int?, **genişletme serbest**). +- `int a = bir_int?;` → ✗ (int? → int, **daraltma yasak**). + +✅ **Katı operand kuralı:** non-null bir bağlamda — atamanın sol tarafı, **her +operatör operandı**, non-null bekleyen bir argüman — değer **statik olarak non-null** +olmalı. `int a = b + c + d`'de `b/c/d`'den **biri bile** nullable ise → **derleme +hatası.** Sembol tablosu/akış görünümü seviyesinde: `notnull = notnull + notnull + …`. +Sezgi yok, deterministik. (`notnull + notnull` → `notnull`.) + +### Akış-duyarlı null analizi (flow-sensitive narrowing) + +`T?` bir değişken **program noktasına göre** "kesin non-null" kanıtlandıysa +daraltılır: + +```c +Node? a = ...; +// a.next; // E0xx: a null olabilir +if (a != null) { + a.next; // OK — bu dalda a, Node'a daraltıldı +} +// a.next; // yine hata (daldan çıkıldı) + +if (a == null) return; // guard / erken çıkış +a.next; // OK — buradan sonrası kesin non-null +``` + +`if` bu sistemin **bel kemiğidir** — sadece büyük/küçük/eşitlik değil, nullable +aklamanın da aracı. **İki form da desteklenir:** + +1. **Nested (blok-kapsamlı):** `if (a != null) { /* a: T burada */ }`. Ayrıca + `if/else`'in zıt dalı, `while (a != null) { … }`. +2. **Sıralı (guard / erken-çıkış):** `if (a == null) return; /* a: T bundan sonra */`. + Dal kesin çıkıyorsa (`return`/`throw`/`break`/`continue`) negasyonu **ardışık** + koda taşınır. + +**Mekanik:** CFG üzerinde ileri-yönlü dataflow; her nullable değişken için kafes +`{MaybeNull, NonNull}`. Koşullarda daraltma (`!= null`, `== null` guard, `&&` +kısa-devre sağ tarafı); kesin-çıkış dalları negasyonu ardına taşır; birleşme (join) +muhafazakâr (bir daldan MaybeNull gelirse MaybeNull); atama RHS'e göre sıfırlar. + +> **Karmaşıklaştırma sınırı:** narrowing yalnızca **doğrudan test edilen değişken** +> için tanınır (`x == null`/`x != null`). **Alias takibi YOK** (`y = x; if (y != null)` +> → x daralmaz) ve keyfi teorem-ispatı yok. Bu, derleyiciyi basit tutarken yaygın +> durumların hepsini kapsar → developer **uzun/karmaşık kod yazmak zorunda kalmaz.** + +> **Runtime maliyeti SIFIR** — tamamen derleme-zamanı analizi; üretilen kodda +> fazladan kontrol yok. + +### Kaçış kapısı YOK — `!` ve `??` YASAK + +Null **yalnızca görünür kontrol akışıyla** (yukarıdaki `if` narrowing) aklanır. +Gizli runtime null-aklama operatörleri **yasaktır:** + +- ❌ **`x!`** (non-null iddiası) — "compiler'a güvenme, runtime'da kontrol et" + = statik garantiyi delen gizli backdoor. *(ADR-021'in ilk taslağındaki `a!` + KALDIRILDI.)* +- ❌ **`x ?? default`** (elvis), **`x?.field`** (güvenli çağrı) — null durumunu + sessizce gizleyen şeker. + +> Ayrım: `as int`'in başarısızlıkta fırlatması yasak **değil** — o bir null-backdoor +> değil, kendiliğinden başarısız olabilen bir *dönüşüm* (ADR-026). + +### Frontend her şeyi kesin çözer (backend-bağımsızlık) + +Nullability **tamamen frontend'de** çözülür; tüm null-güvenlik hataları IR'den +**önce** verilir. Backend'ler (IR+VM, ileride C-transpile) null-güvenliği **yeniden +analiz etmez** — garantiyi hazır devralır (ADR-006/019). Bu sayede: well-typed saf +saQut kodu **statik null-güvenlidir** → non-null referans deref'i runtime null-kontrolü +**gerektirmez** (perf + sadelik). Runtime null-deref hatası (ADR-025) bu yüzden +geriye esas olarak **FFI sınırı** (host non-null sözünü çiğnerse) ve savunma amaçlı +backstop olarak kalır — saf saQut kodu bunu üretmez. + +### Mimari yeri + +Bu, saQut'un ilk gerçek **akış-duyarlı** analizidir. **Yapısal kontrol akışı** +üstünde (AST + structured CFG) yapılabilir; tam SSA gerektirmez → **#2 (CFG/SSA +gerekli mi?)** için somut veri: şimdilik yapısal akış analizi yeter. **#20** +(akıllı diagnostic) bu analizden beslenir ("burada null olabilir, çünkü …"). + +--- + +## ADR-022: Bellek Geri-Kazanımı — Basit Deterministik Mark-Sweep + GC-Hazır Nesne Modeli + +### Bağlam + +ADR-020 referans semantiği → döngüsel yapılar (#56). Kısıtlar: GC **basit ve +deterministik** olmalı, "karmaşık ve rastgele" istenmiyor. Ayrıca bu, **geç +değiştirilmesi en pahalı** karardır (nesne modeline işler) → topuğa sıkmamak +kritik. + +### Önce yanlış-eşleştirmeyi temizle + +**`null`/`?` GC'yi zorlaştırmaz.** Nullable tamamen derleme-zamanı/tip meselesidir; +runtime'da null referans sadece "boş işaretçi" → GC için *daha kolay* (izlenecek +nesne yok). null ile GC **dik (orthogonal)**; aralarında gerilim yoktur. + +### Seçenekler ve neden mark-sweep + +| Strateji | Döngü | Basitlik | Topuğa-sıkma riski | +|---|---|---|---| +| Refcount (`shared_ptr` her yerde) | ❌ sızdırır | başta basit | **Yüksek** — node dilinde döngü kaçınılmaz; üstüne döngü toplayıcı = CPython karmaşıklığı (tam "karmaşık/rastgele") | +| **Mark-sweep, taşımasız, stop-the-world** | ✅ | **en basit *doğru* GC** | **Düşük** — gelişmiş GC'lerin tabanı; üstüne eklenir, yeniden yazılmaz | +| Generational / incremental / compacting | ✅ | karmaşık (write barrier, remembered set) | pause'lar belirsizleşir = istenmeyen "rastgele" | + +✅ **Karar: taşımasız (non-moving), stop-the-world, basit mark-sweep.** +- Döngüleri **bedavaya** toplar (izleme döngü umursamaz) → #56'yı gerçekten çözer. +- **Deterministik:** GC belirli safepoint'lerde çalışır (ör. her N tahsiste) → + kayıt-tekrar / time-travel bit-aynı kalır ("cage" korunur). "Rastgele" değil. +- Taşımasız → işaretçi düzeltme / barrier yok → VM'in geri kalanı GC'ye katılmak + zorunda değil. *Crafting Interpreters*'ın `clox`'u tam bunu yapar (~birkaç yüz satır). + +### Topuğa-sıkmama kuralı — nesne modelini ŞİMDİ GC-hazır kur + +Asıl risk GC'yi *yazmak* değil, nesne modelini sonradan ona uyduramamaktır. O +yüzden **bugünden** (toplama yokken bile): + +1. Her heap nesnesine küçük **header**: tip tag + mark biti + tüm-nesneler listesi için `next`. +2. VM **kök (root) sayımı** yapabilsin: operand stack, frame local'leri, global'ler. +3. Bir nesne **içerdiği referansları** sayabilsin: referans-tipli struct alanları, + referans-tipli array elemanları. + +Bu üçü hazırsa "mark-sweep'i aç" **lokal bir ekleme** olur, nesne-modeli yeniden +yazımı değil. + +### Aşamalandırma (#56'nın yönü) + +- **v1 (şimdi):** GC-header'lı tahsis + intrusive tüm-nesneler listesi + kök sayımı. + **Toplama yok** (program sonunda hepsini bırak / arena). Fibonacci/test ölçeğinde + sorunsuz; kısa programlar sızıntıdan etkilenmez. +- **v2 (#56 ciddileşince):** aynı header+kök+çocuk-sayımı üstünde mark-sweep'i aç. + Model yeniden yazılmaz. +- **`shared_ptr`'dan kaçın:** v1'de bile her referansa refcount gömmek, sonra + mark-sweep için **sökmek** ayrı bir topuğa-sıkmadır. Baştan GC-header modeli kur, + sadece henüz toplama. + +### Performans notu — asıl "katil" nerede? + +- **Nullability / null:** runtime maliyeti **sıfır** — katil değil. +- **Referans modeli:** her bileşik heap'te + işaretçi dolaylılığı → düzenli ama + yönetilebilir maliyet; ileride **escape analizi** ile kaçmayan nesneleri stack'e + alıp *semantiği bozmadan* hızlandırılır (opt-in, sonra). +- **Tek yüksek-değişim-maliyetli karar = GC.** Onu da (a) basit mark-sweep seçip + (b) modeli baştan GC-hazır kurarak de-risk ettik. **Kaçınılacak gerçek katil: + refcount'u kalıcı model yapmak.** + +--- + +## ADR-023: Eşitlik Semantiği — Referanslarda Kimlik Eşitliği (`==`) + +### Bağlam + +ADR-020 ile bileşik tipler referans. `==` / `!=` referans tipler için ne yapsın? +Yapısal (derin) eşitlik sezgisel ama üç sorunu var: (1) büyük yapıda **derin +gezinme maliyeti**, (2) yeni açtığımız **döngüsel grafta sonsuz döngü** riski +(ziyaret-takibi şart), (3) seçtiğimiz referans modeliyle **tutarsız**. + +### Karar + +✅ **Kimlik eşitliği (A):** + +| Kategori | `==` davranışı | +|---|---| +| Primitive (`int`/`float`/`bool`) | **değer** karşılaştırması (`3 == 3`) | +| Referans (`struct`, `array`) | **kimlik** — aynı nesne mi? (işaretçi aynılığı) | +| `string` | ⏸️ **#40'a bağlı** — aşağıdaki nota bak | +| `null` | `null == null` → true; `null == nesne` → false; `a == null` null-daraltma deyimi (ADR-021) | + +İçerik karşılaştırması istenirse **ayrı, niyeti görünür** bir mekanizmayla gelir +(ileride builtin `deepEquals()` / PHP'nin `==` vs `===` vs `clone` ailesi gibi) — +asla sessizce `==`'e bağlanmaz. Gerekçe: deepEqual'ı `==`'e bağlamak büyük/döngüsel +yapılarda performans ve sonsuz-döngü tuzağıdır; "cam kutu, sürpriz yok" kimliğiyle +de çelişir. + +### ⚠️ String istisnası (Java gotcha'sı) + +Saf kimlik eşitliğini string'e de uygularsak `"abc" == "abc"` → **false** olur — +Java'nın en çok sövülen hatası. Çoğu dil string'i istisna yapar (JS'te string +primitive → içerik; C# overload; Python intern). Bu yüzden **string'in `==`'i +içerik eşitliği olmalı**, ki bu string'i **immutable değer-tipi** olarak modellemeyi +güçlü biçimde öneriyor (bkz. #40). ADR-023 struct/array'i kilitler; string'in `==`'i +#40'ta netleşir ama **varsayılan yön: içerik eşitliği.** + +### Açık (ileride, çok uzak — şimdi karar değil) + +- **`obj == obj`'i hata/uyarı yapmak:** kullanıcıyı niyetini açık yazmaya zorlamak + (kimlik mi içerik mi). Daha katı bir duruş; v0'da `==` = kimlik serbest. +- **Kullanıcı-tanımlı eşitlik (OOP'siz):** ileride bir tip için `equals(T,T)->bool` + konvansiyonu veya benzeri ile `==`'i kullanıcının tanımlamasına izin vermek — + operator-overload'un OOP'siz karşılığı. Çok uzak. + +--- + +## ADR-024: String — Immutable Değer-Tipi, İç Temsil UTF-8 + +### Bağlam + +ADR-020 string'i "bileşik (referans)" listesine `?` ile koymuştu; ADR-023 string +`==`'inin **içerik** olmasını istedi (Java gotcha'sından kaçınmak için). İkisi de +string'i değişmez-değer modeline itti. + +### Karar + +✅ **String = immutable (değişmez) değer-tipi; iç temsil UTF-8 bayt.** + +- **Immutable:** oluşturulduktan sonra içeriği değişmez; `s = s + "x"` **yeni** + string üretir, eskisini değiştirmez. +- **`==` içerik eşitliği** (ADR-023 istisnası). Paylaşılınca değişmediği için + içerik-eşitliği güvenlidir; aliasing sürprizi yok (JS'in string'i primitive gibi + davranmasının sebebi budur). +- **GC dostu:** serbestçe paylaşılır / intern edilebilir. +- **İç temsil UTF-8** (Rust/Go/Swift hattı): kompakt, web-doğal, ASCII'de ucuz. + `s[i]` **karakter** indeksi O(1) **değildir** → bayt / scalar / grapheme erişimi + **açıkça** ayrılır; sahte O(1) vaat edilmez (Java/JS'in "uzunluk emoji'de yalan + söylüyor" sürprizinden kaçın). Host tarafında `std::string` ham bayt olarak oturur. +- **Verimli birleştirme** için ileride ayrı **builder** tipi (StringBuilder / `join`) + — çekirdeği kirletmeden, döngüde O(n²)'den kaçınmak için. + +### Etkilenen + +- **#40** (string işlem yüzeyi) bu kararla netleşti; **#9** (iç temsil) = UTF-8. +- ADR-020'deki string `?` işareti → "değer-tipi" olarak çözüldü. + +--- + +## ADR-025: Hata Yönetim Modeli — Struct-Tabanlı Yakalanabilir Hatalar (Swift-tarzı) + +### Bağlam + +ADR-020 (struct = referans) → null bir struct alanına erişim/yazma ihtimali doğdu: +klasik NullPointerException. ADR-021 statik analizi *kanıtlayabildiğini* derleme +zamanında yakalar, ama `!` iddiası ve kanıtlanamayan durumlar (struct alanı, +cross-fonksiyon) için bir **runtime backstop** gerekir. Ayrıca array OOB, /0 gibi +faults. Java/C#/JS bunları **yakalanabilir** hata yapar — ama OOP exception +hiyerarşisi (`extends Exception`) bizde yok. + +### Karar + +✅ **Yakalanabilir, struct-tabanlı hata modeli — OOP'siz.** +Hata *değeri* Swift gibi (düz struct, hiyerarşi/extend yok); *görünürlük* Java/C#/JS +gibi (**unchecked** — fonksiyon işaretlenmez, klasik `try{}catch{}`). "Exception'ın +tanıdık catch-and-jump ergonomisi + OOP'suz değer." + +1. **Hata değeri = standart built-in struct** — extend yok, OOP yok, deterministik: + ``` + struct Error { + int line; // hata satırı + int col; // sütun ("char" tip adıyla çakışmaması için col) + string message; // insan-okunur (derleyicinin W/E kataloğundan) + string trace; // stacktrace, en içten dışa + string code; // makine-okunur W/E kodu (E010 vb.) — JSON/toolbox filtresi + } + ``` +2. **try/catch (unwind + jump):** hata oluşunca en yakın çevreleyen `catch`'e + zıplanır; `catch (e)` → `e : Error`. +3. **Runtime null-deref = yakalanabilir hata** (NPE analoğu). ADR-021 statik + analizinin **backstop'u**: `a!` patlayınca + analizin kanıtlayamadığı durumlar. + Array OOB ve /0 da aynı kapıdan. +4. **`throw`** ile kullanıcı da hata kaldırabilir (`Error` doldurup). +5. **Determinizm:** unwind deterministik; stacktrace frame'lerden üretilir; + time-travel/replay handle eklenebilir. + +### Görünürlük — KARAR: (ii) görünmez / unchecked (Java/C#/JS usulü) + +✅ **Fonksiyonlar işaretlenmez.** "Bu hata yapabilir / yapamaz" anotasyonu **YOK** +(C++'ın `noexcept`/`constexpr` benzeri kirlilik istenmiyor). Çağrıda `try f()` +işareti de yok. **Klasik `try { ... } catch (e) { ... }` bloğu** — "anam babam usulü". + +**Gerekçe:** developer'a **güven** + insanların derin try-catch alışkanlığını bozmamak +(sözdizimini tanıdık tut, içgüdüye dokunma). Hatalar zaten çoğunlukla FFI, bellek +dolması ve derleyici-içi durumlardan doğar; her çağrıyı işaretlemenin bedeli faydadan +büyük. + +> Not: Bu, `Type?` (explicit nullable) ile **bilinçli** felsefi ayrışmadır — null +> *tipte* görünür, ama hata akışı *blok* düzeyinde tanıdık tutulur. Reddedilen (i): +> Swift/Zig'in imza-işaretli + çağrıda `try f()` modeli. + +### Stacktrace mekaniği (modelden bağımsız önkoşul) + +- Her `CallFrame` → `IRFunction` + komut işaretçisi; **IR'a satır tablosu** + (komut index → kaynak konum) eklenir (önce taşıyıp taşımadığı doğrulanmalı). +- panic/throw'da frame stack gezilir → `fonksiyon + konum`, en içten dışa → `trace`. +- Sunum: derleme-zamanı diagnostic ile **aynı kabuk** (kod + mesaj + konum + + "nasıl düzelt" #20), hem insan hem **JSON** (toolbox: her hata yapılandırılmış nesne). +- Farklılaştırıcı: deterministik → trace'e adım indeksi → hataya **geri sar**. + +### İlişkili güncellemeler + +- **ADR-014 "tuple yok" → "tuple ERTELENDİ"** (reddedilmedi; çoklu-dönüş kodu + spagettileştirir, şimdilik uzak ama masada — `interface` gibi). +- **`finally` yerine ileride `defer`** (GC'li, RAII'siz dilde daha temiz). Ayrı küçük karar. +- ADR-021 ile uyum: statik analiz provable null'ı yakalar; bu hata onun backstop'u + `!`. + +--- + +## ADR-026: Tip Dönüşümü — `as` (Skaler/String), Başarısızlık Hedef Tipinin Nullable'lığıyla + +### Bağlam + +ADR-010 "gizli int↔float yok" → değişken-değişken dönüşüm **açık** olmalı. float +runtime'ı var ama cast sözdizimi yoktu → int↔float dönüşümü imkânsızdı. Ayrıca +elimizde null (ADR-021) + hata (ADR-025) modelleri var; cast bunlarla örtüşmeli. + +### Karar + +✅ **Sözdizimi: `as` (infix, sola-bağlı).** `deger as int`. +- Sola-bağlı olduğu için zincir **lineer** okunur: `a as int as string` = + `((a as int) as string)`, parantez gerekmez (fonksiyon-stili `int(float(a))`'nın + iç içe çirkinliği yok). +- `int(x)` fonksiyon-stili **reddedildi** ("int adlı fonksiyon mu, cast mı" + belirsizliği); C-tarzı `(int)x` ve `static_cast<>` reddedildi. + +✅ **Kapsam: yalnızca skaler + string** (`int`/`float`/`bool`/`string` arası). +- **Struct/array cast'e GİRMEZ.** Farklı struct'lar ayrı tiplerdir; "dönüşümleri" + geliştiricinin yazdığı **açık yapıcı fonksiyonlarla** olur (`Employee yap(Person p)`). + Gerekçe: yapısal/duck eşleme veya reinterpret = derleyiciyi karmaşıklaştırır + + sessiz alan kaybı = hataya açık. OOP'siz "cage" kimliğiyle uyumsuz. + +✅ **Başarısızlık davranışı = HEDEF TİPİN nullable'lığı** (ayrı `as?` operatörü YOK): +- `x as int` → hedef non-null → başarısızsa **`Error` fırlatır** (ADR-025), sonuç `int`. +- `x as int?` → hedef nullable → başarısızsa **`null` döner**, sonuç `int?`. + +Nullable her zaman **tipte** (`?`) yaşar, ayrı operatör icat edilmez. Sonra `int?`'i +`int`'e çevirmek için **narrowing** (`if`) gerekir — `!`/`??` yasak (ADR-021). + +### Dönüşüm matrisi + +| Dönüşüm | Hatasız mı? | Not | +|---|---|---| +| `int → float` | ✅ hatasız | büyük int'te kesinlik kaybı olabilir, patlamaz | +| `int → string`, `float → string` | ✅ hatasız | biçimlendirme | +| `string → int`/`float` | ⚠️ fallible | parse; `"abc"` → `as int` fırlatır / `as int?` null | +| `float → int` | ⚠️ fallible | sonlu & aralık-içi: **sıfıra doğru kırpılır** (`1.71→1`, `-1.71→-1`); NaN/Inf/taşma → fırlatır / null | +| `bool ↔ int` | (karar) | başta yasak tutmak en güvenlisi; gerekirse açılır | + +### Örnek (ADR-021 ile birlikte) + +``` +int a = 1.71 as int?; // ✗ DERLEME HATASI: int? → int (daraltma); cast başarılı olsa bile statik tip int? +int a = 1.71 as int; // ✓ a = 1 (kırpma); başarısızsa Error +int? a = 1.71 as int?; // ✓ tipler eşit +``` + +--- + ## Kararların Özet Tablosu | ADR | Konu | Karar | |---|---|---| | 006 | Frontend mimarisi | Çok-aşamalı; frontend/middle-end/backend katmanları | -| 007 | Analiz vs optimizasyon | Analiz yerinde işaretler; optimizasyon klonda dönüştürür; `clone()` merkezi, sembol tablosu remap edilir | +| 007 | Analiz vs optimizasyon | Analiz yerinde; `ast` komutu klon üstünde dönüştürür (öncesi/sonrası karşılaştırması); `run`/`ir` yerinde optimize eder (klon yok); sembol bağları salt-okunur paylaşım (remap gerekmez) | | 008 | Optimizasyon konumu | Basitler AST'de, dataflow gerektirenler IR'de | | 009 | Pass yönetimi | Fixpoint döngüsü, toggle'lı; monotonluk/iterasyon-tavanı değişmezi; akışa-bağlı analiz tur başına tazelenir | | 010 | Tip sistemi | Minimal+genişletilebilir Type; gizli dönüşüm yok; Error tipi; tamsayı literali bağlama-göre tiplenir | @@ -680,3 +1128,10 @@ modelini birlikte zorlar — ikisi de bu yüzden ertelendi. | 017 | Batteries/stdlib | Sınır problemi; küçük builtin + FFI/kütüphane; ertelendi | | 018 | `interface` | Ertelendi (reddedilmedi); struct+fonksiyon yeter | | 019 | Frontend↔runtime | Frontend yapı+anlam; çekirdek/cihaz/çıktı runtime'a ait | +| 020 | Değer/referans semantiği | Primitive=değer, bileşik (struct/array/string)=referans; "pointer yok"=`&`/`*` sözdizimi yok; kaçma/lifetime problemi bilinçli açıldı → GC borcu (#56); ADR-014'ün "GC gerekmez" sonucu iptal | +| 021 | Null güvenliği | `Type?` nullable, varsayılan non-null; akış-duyarlı null analizi (compile-time, runtime maliyeti sıfır); `!` runtime-kontrollü non-null iddiası | +| 022 | Bellek geri-kazanımı | Basit taşımasız stop-the-world mark-sweep (deterministik); nesne modeli baştan GC-hazır (header+root+child); v1 toplamasız, v2 mark-sweep; refcount kalıcı model DEĞİL; #56'nın yönü | +| 023 | Eşitlik semantiği | `==` = primitive değer / referans (struct,array) **kimlik**; deepEqual asla `==`'e bağlanmaz (ayrı `deepEquals()`); string `==` içerik (→ #40, Java gotcha'sından kaçın); `obj==obj` hata + kullanıcı-tanımlı eşitlik = uzak gelecek | +| 024 | String | Immutable değer-tipi, iç temsil **UTF-8**; `==` içerik; mutasyon yeni string üretir; bayt/scalar/grapheme açıkça ayrı; verimli birleştirme için ileride builder; #40/#9'u çözer | +| 025 | Hata yönetimi | Struct-tabanlı yakalanabilir hata (değer Swift gibi, OOP yok); standart `Error{line,col,message,trace,code}`; klasik `try{}catch{}` **unchecked** (fonksiyon işaretsiz, Java usulü); runtime null-deref/OOB yakalanabilir (esasen FFI backstop); deterministik stacktrace (IR satır tablosu); tuple→ertelendi; finally→`defer`; #57 | +| 026 | Tip dönüşümü | `as` (infix, sola-bağlı), yalnızca skaler+string; struct/array cast YOK (elle yapıcı fonksiyon); başarısızlık hedef nullable'lığıyla (`as int` fırlatır / `as int?` null); float→int kırpma; #42 | diff --git a/docs/adr/ADR-008-kisa-devre-mantiksal-operatorler.md b/docs/adr/ADR-008-kisa-devre-mantiksal-operatorler.md new file mode 100644 index 0000000..9c490c3 --- /dev/null +++ b/docs/adr/ADR-008-kisa-devre-mantiksal-operatorler.md @@ -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. diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 0000000..7039123 --- /dev/null +++ b/docs/architecture.md @@ -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. diff --git a/docs/fikirler.md b/docs/fikirler.md index e129375..712a31f 100644 --- a/docs/fikirler.md +++ b/docs/fikirler.md @@ -18,9 +18,10 @@ > **çok uzak gelecektir**. ADR-001'deki karşılaştırmalar o gün için geçerli. > - "HeavyIR/LightIR" ikiliği (ADR-005) bir **gelecek fikri** olarak durur; v0'ın > IR+VM hedefi tek, basit bir IR'dir + **FFI seam** (ADR-016). -> - **Yapılan vs planlanan:** ADR-001'deki "mevcut durum" listesi hâlâ doğrudur -> (lexer/tokenizer/parser/AST + minimal IR deneyi çalışır); kod üretimi ve VM -> **henüz yoktur.** +> - **Yapılan vs planlanan:** Tüm pipeline uygulandı. `examples/fibonacci.sqt` +> uçtan uca çalışıyor (lexer → tokenizer → parser → sembol tablosu → tip +> denetleyici → optimizasyon → IR üreteci → bytecode VM). ADR-001'deki +> "mevcut durum" listesi artık tarihseldir; güncel durum için bkz. `CLAUDE.md`. --- diff --git a/docs/roadmap-frontend.md b/docs/roadmap-frontend.md index 897b73d..8d03264 100644 --- a/docs/roadmap-frontend.md +++ b/docs/roadmap-frontend.md @@ -10,21 +10,12 @@ > yorum satırlarıyla takip edilebilir olmalıdır (header-only tarzı korunur, > bkz. ADR-003). > -> ⚠️ **Yapılan vs planlanan:** Bugün çalışan = lexer, tokenizer, Pratt parser, -> AST, AST'nin JSON serileştirmesi, CLI iskeleti, konum takibi, basit aritmetiği -> düşüren minimal IR deneyi. Bu yol haritasındaki **her şey planlıdır** (sembol -> tablosu, semantik analiz, tip sistemi, diagnostic, optimizasyon). +> ✅ **Birinci kilometre taşı AŞILDI.** Faz 0–4 uygulandı; `examples/fibonacci.sqt` +> uçtan uca çalışıyor. Bu yol haritası artık tarihsel bir referanstır. > -> 🎯 **Bu haftanın işi:** **sembol tablosu + iki-geçişli toplayıcı** (Faz 2), -> hedef **"fibonacci'yi derle ve çalıştır"** (`examples/fibonacci.sqt`). Faz 0–1 -> bunun önkoşuludur. -> -> 🧭 **Önce dikey dilim, sonra çerçeve.** Bir şey çalışmadan önce genel pass -> manager / evrensel config / ağır soyutlama inşa etme. Uçtan uca tek bir dilim -> (kaynak → IR → çalıştır; tamsayı + değişken + kontrol akışı + tek `print`) -> önce çalışsın. Faz 4'ün framework'ü (OptimizationManager, fixpoint, config) -> ancak Faz 0–3 fibonacci'yi geçirdikten **sonra** anlam kazanır — erken -> soyutlama daha az değil, daha çok karmaşıklıktır. +> **Sonraki hedefler:** float/double codegen, struct IR, array IR, açık bug'lar +> (#35 bellek sızıntısı, #36 W003 uyarısı, #37 `%=` IR, #38 global değişken IR). +> Güncel "çalışıyor / henüz yok" listesi için bkz. `CLAUDE.md`. --- @@ -46,7 +37,7 @@ Katman eşlemesi (ADR-006): --- -## Faz 0 — Temeller (Type + Diagnostic + Hata Kataloğu) +## ✅ Faz 0 — Temeller (Type + Diagnostic + Hata Kataloğu) — TAMAMLANDI **Bağımlılık:** yok. **Hedef:** her şeyin üstüne kurulacağı temel veri yapıları. İlgili ADR: 010 (Type), 013 (Diagnostic). @@ -91,7 +82,7 @@ Katman eşlemesi (ADR-006): --- -## Faz 1 — AST Refactor (ExpressionNode / StatementNode + analiz alanları) +## ✅ Faz 1 — AST Refactor (ExpressionNode / StatementNode + analiz alanları) — TAMAMLANDI **Bağımlılık:** Faz 0 (Type). **Hedef:** node hiyerarşisini ifade/deyim olarak ayır, analiz alanlarını ekle. İlgili ADR: 012, 013. @@ -116,7 +107,7 @@ ayır, analiz alanlarını ekle. İlgili ADR: 012, 013. --- -## Faz 2 — Symbol Table (scope'lu, iki-geçişli toplama) +## ✅ Faz 2 — Symbol Table (scope'lu, iki-geçişli toplama) — TAMAMLANDI **Bağımlılık:** Faz 0, 1. **Hedef:** isim çözümleme + scope + referans toplama. İlgili ADR: 011, 013. @@ -150,7 +141,7 @@ ayır, analiz alanlarını ekle. İlgili ADR: 012, 013. --- -## Faz 3 — Semantic Analiz (Tip Kontrolü + Yapısal Doğrulama) +## ✅ Faz 3 — Semantic Analiz (Tip Kontrolü + Yapısal Doğrulama) — TAMAMLANDI **Bağımlılık:** Faz 2. **Hedef:** tipleri ata/kontrol et, yapısal kuralları doğrula. İlgili ADR: 010, 013. @@ -173,7 +164,7 @@ doğrula. İlgili ADR: 010, 013. --- -## Faz 4 — Optimizasyon Framework +## ✅ Faz 4 — Optimizasyon Framework — TAMAMLANDI **Bağımlılık:** Faz 3. **Hedef:** opsiyonel, iteratif, toggle'lı kaynak-seviyesi optimizasyon. **Orijinali bozmaz — klon üstünde** (ADR-007). İlgili ADR: 007, 008, 009. diff --git a/docs/sonnet-handoff.md b/docs/sonnet-handoff.md new file mode 100644 index 0000000..d978ee1 --- /dev/null +++ b/docs/sonnet-handoff.md @@ -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 +> `; dal `0.1.0`. + +--- + +## 0. Nerede kaldık (bağlam) + +Bu oturumda kilitlenen mimari kararlar (tümü `docs/adr-frontend-analiz.md`): + +| ADR | Karar (özet) | +|---|---| +| **020** | Primitive (`int`/`float`/`bool`) = **değer**; bileşik (`struct`/`array`/`string`) = **referans** (JS/Java/C# modeli). "Pointer yok" = kullanıcıya `&`/`*` *sözdizimi* yok; runtime referansı kullanır. | +| **021** | Null güvenliği: varsayılan **non-null**; nullable açıkça `Type?`. Akış-duyarlı null analizi (compile-time, runtime sıfır). `a!` = runtime-kontrollü iddia. | +| **022** | GC: basit **taşımasız, stop-the-world, deterministik mark-sweep**. Nesne modeli **baştan GC-hazır** (header + kök sayımı + çocuk sayımı). v1: toplama YOK. **`shared_ptr`'ı kalıcı sahiplik modeli YAPMA.** | +| **023** | `==`: primitive değer; referans (struct/array) **kimlik** (aynı nesne); string **içerik**. Derin eşitlik asla `==`'e bağlanmaz → ayrı `deepEquals()`. | +| **024** | String = **immutable değer-tipi, iç temsil UTF-8**. `s+"x"` yeni string üretir; `==` içerik. | + +Açık mimari borç: **#56** (döngüsel referans → mark-sweep GC v2). Şimdilik toplama yok, bilinçli. + +**Mevcut kod durumu:** +- int-only pipeline uçtan uca çalışıyor (`examples/fibonacci.sqt`). +- `src/vm/value.hpp` → `Value` = `{ ValueKind kind; int intValue; std::string stringValue; }`. String **inline** (immutable olduğu için yeterli — taşıma zorunlu değil). +- `src/ir/` → 3-adresli IR, slot tabanlı. `instruction.hpp`, `ir_generator.cpp`, `ir_program.hpp`. +- `src/vm/interpreter.cpp` → bytecode yorumlayıcı döngü. `call_frame.hpp` çağrı çerçevesi. +- struct/array: parser + semantik **var**, IR/VM codegen **YOK**. + +--- + +## 1. İlk görev — GC-hazır nesne modeli + ARRAY runtime (dikey dilim) + +**Neden array, string değil:** string zaten immutable-değer olarak inline çalışıyor; +asıl kararları (referans semantiği + GC-hazır nesne modeli + kimlik eşitliği) +**doğrulayan** ilk gerçek referans-tipi array'dir. Bu görev, struct'ın da oturacağı +temeli atar. + +### KAPSAM DIŞI (bu görevde YAPMA — sonraki görevler) +- ❌ Gerçek çöp toplama (mark-sweep). ADR-022 v1 = toplama yok. Sadece header + + all-objects listesi + kök-sayımı *kancasını* kur. +- ❌ Tam null akış-analizi (ADR-021). `int[]?` parse edilebilir ama flow-narrowing + bu görevde değil. +- ❌ struct codegen, string UTF-8 cilası, builder. Ayrı görevler (Bölüm 2). +- ❌ `shared_ptr` ile nesne sahipliği. Düz `Object*` + intrusive liste. + +### Adım 1.1 — Nesne modeli temeli (`src/vm/object.hpp` veya benzeri) +```cpp +enum class ObjectType { Array /*, Struct, String (ileride) */ }; + +struct Object { + ObjectType type; + bool marked = false; // mark-sweep için (v2); şimdilik kullanılmaz + Object* next = nullptr; // intrusive "tüm nesneler" listesi (mark-sweep tarayışı için) +}; +``` +- Bir **Heap/allocator**: `Object* allocate(...)` her yeni nesneyi `next` zincirine + ekler. **Free yok** (v1). Yıkıcıda/process exit'te toptan bırak. +- **Kök sayımı kancası:** VM'in operand stack + frame local'leri + global slot'lar + üstünden referansları gezebileceği bir yol bırak (şimdilik imza/TODO yeterli; içini + doldurmak v2). `// TODO(#56): mark-sweep kök taraması buradan` ile işaretle. + +### Adım 1.2 — `Value`'yu referans taşıyacak şekilde genişlet (`src/vm/value.hpp`) +- `ValueKind`'a `Ref` ekle (array/struct nesnelerine `Object*`). +- `Value`'ya `Object* ref = nullptr;` alanı + `static Value fromRef(Object*)`. +- `Nil` kind ekle (ADR-021 null: `Type?` null değeri ve referans varsayılanı). +- `isTruthy`/`toString`/`typeName`'i yeni kind'lar için genişlet. +- String inline kalsın (`ValueKind::String`), dokunma. + +### Adım 1.3 — ArrayObject +```cpp +struct ArrayObject : Object { // type = ObjectType::Array + std::vector elements; // homojen (int[] → hepsi Int) +}; +``` +- Array literali (`[1,2,3]` — **parser'ın mevcut sözdizimini doğrula**, Bölüm 4'e bak) + → ArrayObject tahsis, `elements` doldur, `Value::fromRef` ile slot'a koy. + +### Adım 1.4 — IR opcode'ları + IR üreteci +- `ARRAY_NEW` (literal/boyuttan array oluştur), `ARRAY_GET dest, arr, idx`, + `ARRAY_SET arr, idx, val`, `ARRAY_LEN dest, arr`. (`instruction.hpp` + üreteç.) +- **Referans semantiği:** array bir fonksiyona geçince/atanınca `Value` (içindeki + `Object*`) **kopyalanır ama nesne paylaşılır** → `func(arr)` içindeki `ARRAY_SET` + çağıranı etkiler. (Bu, kararın doğrulandığı kritik testtir.) +- **`==` (ADR-023):** array'de **kimlik** → iki `Value`'nun `ref`'i aynı `Object*` mı? + (İçerik DEĞİL.) Mevcut EQ opcode'unu tip-bazlı dallandır veya `REF_EQ` ekle. + +### Adım 1.5 — Sınır kontrolü (kafes felsefesi) +- `ARRAY_GET`/`ARRAY_SET` index sınır dışıysa → **temiz runtime hatası** (sessiz UB + değil). saQut "cage" — koruma şart. + +### Doğrulama (golden test — `tests/` veya `examples/`) +```c +func degistir(int[] a) { + a[0] = 99; +} +func main() { + int[] x = [1, 2, 3]; + degistir(x); + print(x[0]); // 99 ← referans semantiği (ADR-020) + int[] y = x; + print(y == x); // true ← kimlik (aynı nesne, ADR-023) + int[] z = [1, 2, 3]; + print(z == x); // false ← içerikçe aynı ama farklı nesne + print(x[1]); // 2 + // x[5] → runtime sınır hatası +} +``` +`saqut run` ile beklenen çıktı doğrulanmalı. `saqut ir` çıktısı yeni opcode'ları göstermeli. + +--- + +## 2. Sonraki görevler (sıralı — ilk görev bitince) + +1. **Struct runtime.** Alanlar (isimli), `StructObject : Object { std::vector fields; }`. + `struct Node { Node next; }` artık **meşru** (referans → sonlu boyut). **E010 + revizyonu:** referansla tutulan struct alanı için döngü artık hata DEĞİL (ADR-020). + Bu görev #56'yı *canlı* hale getirir (döngü kurulabilir, henüz toplanmaz). +2. **String cilası (ADR-024).** İçerik `==`'i doğrula; UTF-8 çok-baytlı pass-through + (`"şğü"` concat+print bozulmasın); bayt-uzunluğu vs karakter ayrımını açık API + olarak işaretle. (İstege bağlı: string'i de Object modeline taşıyıp intern et — + zorunlu değil.) +3. **Null akış-analizi (ADR-021 — 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`~~, ~~`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`~~ | +| 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. diff --git a/examples/test_bitwise.sqt b/examples/test_bitwise.sqt new file mode 100644 index 0000000..dcba988 --- /dev/null +++ b/examples/test_bitwise.sqt @@ -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; +} diff --git a/readme.md b/readme.md index 01498b3..eee1e64 100644 --- a/readme.md +++ b/readme.md @@ -1,225 +1,186 @@ # saQut -**Programlanabilir, incelenebilir bir derleyici — bir "alet çantası" (toolbox).** +> **A compiler built as a toolbox, not a black box —** +> every internal phase is a first-class, inspectable output. -saQut'un asıl varlık sebebi dilin kendisinden çok, **derleme sürecinin her -aşamasının dışarıdan görülebilir ve müdahale edilebilir olmasıdır.** Token'lar, -AST, sembol tablosu, optimizasyonun öncesi/sonrası ve IR — hepsi ayrı ayrı -incelenebilir. Dil, bu aletin üzerinde çalıştığı küçük, prosedürel bir -örnektir; vitrin değil, alet. +``` +saqut tokens file:fib.sqt → token stream, JSON +saqut ast file:fib.sqt → full AST, JSON +saqut ast file:fib.sqt --optimized → constant-folded + DCE'd AST +saqut run file:fib.sqt → execute via IR + bytecode VM +``` -Uygulama dili **C++**'tır (header-only eğilimli, bkz. `docs/fikirler.md` ADR-003). +Most compilers are black boxes. saQut is a **glass box.** --- -## Şu an ne çalışıyor, ne çalışmıyor +## What is it? -Belgeler **planlanan** ile **yapılan**ı net ayırır. Bugünkü gerçek durum: +saQut is a **procedural language compiler** written in C++. +The language is small and C-flavoured on purpose — it is a vehicle, not the product. +The product is **a compilation pipeline where every stage is named, queryable, and machine-readable.** -### ✅ Çalışıyor (built) -- **Lexer** — karakter seviyesi tarama, konum takibi. -- **Tokenizer** — token üretimi (6 token tipi), yorum satırı desteği. -- **Pratt parser** — ifade (Pratt) + statement (recursive descent) ayrıştırma. -- **AST** — fonksiyon, blok, değişken tanımı, if/for/while/do-while/return, - ifade node'ları. -- **AST'nin JSON serileştirmesi** — `saqut ast` ile incelenebilir. -- **CLI komut yapısı** — `tokens`, `ast`, `symbols`, `run` iskeletleri. -- **Kaynak konum takibi** (SourceLocation) — offset → (satır, sütun). -- **Minimal IR deneyi** — basit aritmetiği düşürür (örn. `1 + (7/3)` → kısa - doğrusal komut dizisi). Henüz tam bir backend değil, bir deneydir. - -### 🚧 Henüz yok (planned) -- Sembol tablosu -- Semantik analiz -- Tip sistemi -- Diagnostic (hata raporlama) motoru -- Optimizasyon -- IR + bytecode VM ile çalıştırma - -> `feature/frontend-analysis` dalı şu an yalnızca bu yapılmamış işin **tasarım -> belgelerini** içerir, kodunu değil. - -**Birinci kilometre taşı ("bitti" tanımı):** derleyici **fibonacci'yi** -(recursive + iterative) ve basit matematik/döngü programlarını **derleyip -çalıştırabilmeli.** Referans program: `examples/fibonacci.sqt`. +You can pipe `saqut ast` into your own tool. +You can hand the optimized AST diff to a review script. +A stranger with no access to source could write an LSP from `saqut symbols` output alone. +That is the test saQut is designed to pass. --- -## Dil kimliği (kilitli) +## The language looks like this -Prosedürel, **C ailesi sözdizimi**, **value semantics**. İlk ifade doğrudan bir -işlem/tanım olabilir; zorunlu class/`main` boilerplate'i yoktur (Java'nın aksine). +```c +int fibonacci(int n) { + if (n <= 1) { + return n; + } + return fibonacci(n - 1) + fibonacci(n - 2); +} -| Özellik | Karar | +int fibonacciIterative(int n) { + int first = 0; + int second = 1; + for (int i = 0; i < n; i = i + 1) { + int next = first + second; + first = second; + second = next; + } + return first; +} + +int main() { + int n = 10; + print(fibonacci(n)); + print(fibonacciIterative(n)); + return 0; +} +``` + +- No mandatory `class` / `main` boilerplate +- Typed functions, `struct`, `int[]` arrays +- `int`, `float`, `bool`, `string` literal types +- Value semantics — no user-visible pointers +- Single FFI seam (`callhost`) — the only door to the outside world + +**Deliberately absent:** OOP, closures, generics, implicit int↔float coercion, `auto`. + +--- + +## Build + +**Requirements:** C++17, CMake ≥ 3.16, Ninja + +```bash +git clone https://github.com/abdussamedulutas/saqut +cd saqut +cmake -B build -G Ninja +cmake --build build +``` + +Binary lands at `build/saqut`. + +**Tested on:** Linux (x86-64, Manjaro). macOS and Windows untested but no platform-specific code. + +--- + +## CLI + +| Command | What you get | |---|---| -| Class / OOP / kalıtım | **Yok** | -| Closure | **Yok** | -| Generic | **Yok** | -| Kullanıcıya açık pointer (`*` / `&`) | **Yok** — derleyici/runtime içeride pointer'ı serbestçe kullanır | -| `struct` | **Var** | -| Tipli fonksiyonlar (dönüş + parametre) | **Var** | -| Array (`int[]`) | **Var** | -| `interface` | **Ertelendi** (v0 değil — gerekçe ADR-018) | -| `auto` / tip çıkarımı | **Yok** | -| Gizli int↔float dönüşümü | **Yok** (tek istisna: sabit folding) | +| `saqut tokens file:src.sqt` | Token stream with positions | +| `saqut ast file:src.sqt` | Full AST as JSON | +| `saqut ast file:src.sqt --optimized` | AST after constant folding + dead-code elimination | +| `saqut symbols file:src.sqt` | Symbol table dump | +| `saqut check file:src.sqt` | Semantic analysis only — errors and warnings, JSON | +| `saqut ir file:src.sqt` | IR instruction dump | +| `saqut run file:src.sqt` | Compile and run via bytecode VM | -Gerekçe: prosedürel tasarım semantik karmaşıklığı en aza indirir ve hedeflerle -(fibonacci, matematik, sıralama, ayrıştırma) örtüşür. Standart C'de `class` -yoktur (o C++'tır); C, struct + fonksiyonun yettiğini kanıtlar. +Every output is designed to be piped, diffed, or consumed by other tools. --- -## Çalıştırma modeli (kilitli): IR + bytecode VM - -saQut, kendi **IR**'sine derler ve bu IR'yi bir **yorumlayıcı döngü (bytecode -VM)** ile çalıştırır. - -- **Tree-walker DEĞİL** (çok yavaş). -- **Gerçek makine-kodu JIT DEĞİL.** Makine kodu üretimi (register allocation, - ABI/çağırma sözleşmeleri, çalıştırılabilir `mmap` bellek) **kapsam dışıdır** — - tek faydası ham hızdır ve hız burada öncelik değildir. Öncelikler - **determinizm** ve **incelenebilirliktir**; bytecode VM ikisini de doğrudan - sağlar. -- **Bellek bu modelde kolaydır:** host (C++) heap'i kullanılır; v0 için özel - runtime allocator gerekmez. -- **C'ye transpile, geçerli bir İKİNCİ backend olarak ileride kalır** (frontend - backend-bağımsızdır — middle-end ayrımının amacı budur, ADR-006). İleride - makine kodu istenirse elle code generator yazmak yerine **libgccjit / LLVM'e - bağlanılır** — ama bu çok uzak gelecektir. - -> Eski belge/konuşmalarda geçen "JIT" terimi yanlış yönlendiricidir; doğru -> çerçeve **IR + VM**'dir. - ---- - -## Tasarım felsefesi — neden saQut farklı? - -saQut "daha iyi bir dil" iddiasında değil. Farkı, **derleyiciyi bir platform** -olarak ele almasında. İki taahhüt üstüne kuruludur: - -**1. Cam (gör + sorgula + içine müdahale et).** Her aşama — token, AST, sembol -tablosu, tip, IR — kararlı, makine-okur ve **çift yönlü** bir arayüzden -erişilebilir olmalıdır. Sadece "dök ve göster" değil: kendi AST'ini verip tip -kontrolü isteyebilmeli, IR verip çalıştırabilmelisin. **Turnusol testi:** bir -yabancı, yalnızca `saqut ast` + `saqut symbols` çıktısından, bizden habersiz bir -LSP yazabiliyor mu? Cevap "evet" ise platform gerçektir. - -**2. Kafes (deterministik + yetenek-güvenli çalıştırma).** Pointer yok, value -semantics, scope-tabanlı bellek ve **tek dış-dünya kapısı olan FFI seam** -(ADR-016) sayesinde saQut kodu, host'un açıkça izin verdiği fonksiyonlar dışında -dünyaya dokunamaz. Bytecode VM deterministiktir (ADR-015): aynı girdi → aynı -çıktı → aynı çalışma. "Sadelik" diye tasarlanan bu kararlar aslında bir -**yetenek-güvenliği (capability sandbox)** kurar — güvenilmeyen veya -AI-üretimi kodu güvenle çalıştırmak için biçilmiş kaftan. - -**Bu ikisinin ödülü — kayıt & tekrar (record-replay).** 🚧 *(vizyon, v0 değil; -bkz. issue #94.)* Belirsizliğin tek kaynağı (kullanıcı girdisi, zaman, IO, -GC/thread kararları) FFI kapısından geçtiği için, mükemmel tekrar oynatma için -**her değişkeni her adımda kaydetmek gerekmez** — yalnızca kapıdan geçen değerler -kaydedilir, gerisi VM deterministik olarak yeniden çalıştırılarak üretilir. Boyut -gigabayttan kilobayta düşer. Replay modunda FFI çağrıları gerçekten çalışmaz, -kaydedilmiş değeri döndürür (dosyayı tekrar silmez, sunucuya tekrar istek atmaz). -Böylece "benim makinemde çalışıyor, müşteride patlıyor" sorunu: müşteri bir dump -yollar, sen çöküşü adım adım, aynı verilerle geri sararsın. - -> Log, önceden sormayı akıl ettiğin sorulara cevap verir; **tekrar-oynatma, -> çöküşten *sonra* aklına gelen sorulara.** Zaman-yolculuğu hata ayıklama ayrı -> bir altyapı değildir — cam sorgularına bir **zaman koordinatı** eklemektir. - -⚠️ Bu ödülün bedeli v0'da ödenir: **determinizm kutsaldır ve her belirsizlik -kaynağı kayıt-altına-alınabilir tek kapıdan geçmelidir.** Sonradan eklenemez; -baştan korunur. - ---- - -## Mimari hatlar +## Pipeline ``` -KAYNAK KOD - │ lexer - ▼ -TOKEN'LAR ────────────── saqut tokens - │ parser (Pratt + recursive descent) - ▼ -AST ──────────────────── saqut ast - │ sembol toplama (iki geçişli) ┐ - ▼ │ -SEMBOL TABLOSU ───────── saqut symbols │ FRONTEND - │ semantik analiz (annotation) │ (yapı + anlam) - ▼ │ -ANNOTATE EDİLMİŞ AST ─── saqut ast ┘ - │ optimizasyon (opsiyonel, klon üstünde) ── MIDDLE-END - ▼ -IR ───────────────────── (planlanan) ┐ - │ bytecode VM / yorumlayıcı döngü │ BACKEND - ▼ │ (çalıştırma + FFI seam) -ÇALIŞTIRMA / ÇIKTI ───── saqut run ┘ +Source + │ Lexer + Tokenizer + ▼ +Tokens ──────────────────── saqut tokens + │ Pratt parser + recursive descent + ▼ +AST ─────────────────────── saqut ast + │ Symbol collector (two-pass) + ▼ +Symbol Table ────────────── saqut symbols + │ Type checker + structural validator + ▼ +Annotated AST + │ Optimization Manager (clone — original untouched) + │ ├─ Constant Folding pass + │ └─ Dead Code Elimination pass + ▼ +Optimized AST ───────────── saqut ast --optimized + │ IR Generator + ▼ +IR ──────────────────────── saqut ir + │ Bytecode VM (interpreter loop) + ▼ +Output ──────────────────── saqut run ``` -- **Frontend** yapıyı ve anlamı modeller (tip, scope, dataflow). -- **"Hangi çekirdek, hangi cihaz, ne zaman, hangi çıktı formatı"** runtime/backend - meselesidir — frontend'e yüklenmez. +The optimizer works on a **clone** of the AST — the original is preserved. +Constant folding and DCE run in a fixpoint loop until nothing changes. --- -## CLI (mevcut + planlanan) +## What works right now -``` -# --- çalışıyor --- -saqut tokens file:kaynak.sqt # token listesi -saqut ast file:kaynak.sqt # AST (JSON) -saqut symbols file:kaynak.sqt # sembol tablosu (iskelet) - -# --- planlanan --- -saqut run file:kaynak.sqt # IR üret + bytecode VM ile çalıştır -saqut ast file:kaynak.sqt --optimized # klon, optimize edilmiş AST (öncesi/sonrası) -saqut transpile file:kaynak.sqt -o prog.c # ikinci backend (ileride) -``` - -Tasarım gereği her aşamanın çıktısı erken bir noktada dosyalanabilir/loglanabilir -(programlanabilir derleyici). Token, ham AST, optimize AST ve IR ayrı ayrı -kaydedilebilir. - ---- - -## Batteries / stdlib — kuzey yıldızı, ertelendi - -Gerçek bir genel sürüm pil ile gelmeli (sıralama, sıkıştırma, kripto, -JSON/XML/HTML ayrıştırma). Ama bu **bugünün işi ve v0.1 değildir.** - -Mimari çerçeve (monolit korkusunu önler): derleyici pilleri çekirdeğine -gömmez. Bunun yerine **küçük bir gerçek builtin kümesi** (`print`, temel -zorunlular) + **gerisi kütüphane/FFI** ile gelir. "Batteries" sorunu aslında -bir **sınır (FFI/link seam) sorunudur**, "zlib'i yeniden yaz" sorunu değil. -Sınır bir kez çizilir, piller üstünde sonsuza dek birikir. - -- **JSON/XML/HTML ayrıştırıcıları saQut'un kendisinde yazılabilir** (string + - struct + fonksiyon + kontrol akışı yeter). İlk gerçek demo programları. -- **Sıkıştırma/kripto:** denenmiş C kütüphanelerine FFI ile bağlan. **Kripto - asla elle yazılmaz.** -- **Bugüne tek yansıması:** IR/runtime tasarlanırken **bilinçli bir FFI seam** - ("host fonksiyonu çağır" deliği) bırakılır. `print` bunu zaten zorlar — bunu - kaza değil, **kasıtlı bir mekanizma** yapıyoruz (ADR-016). - ---- - -## Belge haritası - -| Belge | İçerik | +| Stage | Status | |---|---| -| `docs/fikirler.md` | ADR-001…005: backend stratejisi, parser, header-only, token, IR | -| `docs/adr-frontend-analiz.md` | ADR-006…019: frontend, analiz/optimizasyon, çalıştırma modeli, FFI, interface, bellek | -| `docs/roadmap-frontend.md` | Faz-faz uygulama planı (sembol tablosu → fibonacci) | -| `docs/transkript-frontend-tasarim.md` | Tasarım oturumunun transkripti | -| `examples/fibonacci.sqt` | Geçerli referans program (semantik + kod üretimi fixture'ı) | -| `examples/parser-stress/` | Yalnızca parser'ı zorlayan, **geçerli olmayan** fixture'lar | +| Lexer / Tokenizer | ✅ | +| Pratt parser | ✅ | +| AST + JSON serialization | ✅ | +| Symbol table (two-pass collector) | ✅ | +| Type checker | ✅ | +| Structural validator | ✅ | +| Constant folding (int, bool, logical, unary) | ✅ | +| Dead code elimination | ✅ | +| IR generator + bytecode VM | ✅ | +| `saqut run` executes fibonacci | ✅ | +| `string` type | ✅ | +| `struct` | 🚧 | +| `int[]` arrays | 🚧 | +| Standard library / FFI beyond `print` | 🚧 | --- -## İlke +## Philosophy in two sentences -Bir şey çalışmadan önce çerçeve inşa etmekten kaçın. Önce **uçtan uca tek bir -dikey dilim** çalıştır (kaynak → IR → çalıştır; tamsayı aritmetiği + değişken + -kontrol akışı + tek bir `print`). Modülerlik bir kuzey yıldızıdır, v0.1 -gereksinimi değil; ihtiyaç doğmadan eklenen her soyutlama **daha az değil, daha -çok** karmaşıklıktır. +**Glass:** every compilation stage is a stable, queryable output — tokens, AST, symbols, IR — all separately inspectable and pipeable. +**Cage:** no user pointers, value semantics, single FFI door — the VM is deterministic, which makes record-replay and time-travel debugging a natural extension, not an afterthought. + +The long version is in [`docs/architecture.md`](docs/architecture.md). + +--- + +## Design records + +Architectural decisions live in `docs/`: + +| File | Coverage | +|---|---| +| [`docs/fikirler.md`](docs/fikirler.md) | ADR-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 diff --git a/src/cli/commands/ir.hpp b/src/cli/commands/ir.hpp index 640f576..7ff1dbd 100644 --- a/src/cli/commands/ir.hpp +++ b/src/cli/commands/ir.hpp @@ -7,8 +7,12 @@ #include "parser/parser.hpp" #include "symbol/symbol_table.hpp" #include "symbol/symbol_collector.hpp" +#include "semantic/type_checker.hpp" +#include "semantic/structural_validator.hpp" #include "diagnostic/diagnostic_engine.hpp" #include "ir/ir_generator.hpp" +#include "core/config.hpp" +#include "opt/optimization_manager.hpp" inline int cmdIr(const CliArgs& args) { std::string filePath = inputFilePath(args); @@ -29,6 +33,8 @@ inline int cmdIr(const CliArgs& args) { SymbolTable symbolTable; DiagnosticEngine diag; SymbolCollector(symbolTable, diag).collect(ast); + TypeChecker(symbolTable, diag).check(ast); + StructuralValidator(diag).validate(ast); if (diag.hasErrors()) { diag.printAll(std::cerr); @@ -37,9 +43,18 @@ inline int cmdIr(const CliArgs& args) { return 1; } + // --optimized: constant folding + DCE yerinde uygulanır, klon yok. + // IR dump için tek versiyon yeterli — ast komutu gibi karşılaştırma yok. + if (args.optimized) { + CompilerConfig cfg; + DiagnosticEngine optDiag; + OptimizationManager(cfg, optDiag).runPassesInPlace(ast, &symbolTable); + if (optDiag.errorCount() + optDiag.warningCount() > 0) + optDiag.printAll(std::cerr); // W002 vb. uyarılar stderr'e + } + IRGenerator irGenerator; IRProgram program = irGenerator.generate(ast, symbolTable); - program.dump(); delete ast; diff --git a/src/cli/commands/run.hpp b/src/cli/commands/run.hpp index 565a729..1675d51 100644 --- a/src/cli/commands/run.hpp +++ b/src/cli/commands/run.hpp @@ -2,12 +2,11 @@ // saQut CLI — run komutu // // Tam derleme + çalıştırma pipeline'ı: -// tokenize → parse → sembol topla → IR üret → VM çalıştır +// tokenize → parse → sembol topla → [opsiyonel: optimize] → IR üret → VM çalıştır // -// Başarı kriteri: -// build/saqut run file:examples/fibonacci.sqt -// → 55 -// → 55 +// --optimized bayrağı: AST yerinde optimize edilir (klon yok — sadece tek versiyon +// gerekiyor). ast komutu orijinali saklaması gerektiği için klon kullanır; run/ir +// kullanmaz. Aynı pattern ir.hpp'de de var — paralel değişikliklerde ikisine bak. // ============================================================================ #ifndef SAQUT_CLI_RUN @@ -22,6 +21,8 @@ #include "semantic/type_checker.hpp" #include "semantic/structural_validator.hpp" #include "diagnostic/diagnostic_engine.hpp" +#include "core/config.hpp" +#include "opt/optimization_manager.hpp" #include "ir/ir_generator.hpp" #include "vm/interpreter.hpp" @@ -43,7 +44,7 @@ inline int cmdRun(const CliArgs& args) { return 1; } - // ── Aşama 3: Sembol toplama ─────────────────────────────────────────── + // ── Aşama 3: Sembol toplama + semantik analiz ───────────────────────── // Identifier'ların resolvedSymbol'ü doldurulur — IR generator buna ihtiyaç duyar. SymbolTable symbolTable; DiagnosticEngine diag; @@ -59,11 +60,22 @@ inline int cmdRun(const CliArgs& args) { return 1; } - // ── Aşama 4: IR üretimi ─────────────────────────────────────────────── + // ── Aşama 4 (opsiyonel): Optimizasyon ──────────────────────────────── + // --optimized: constant folding + DCE yerinde uygulanır, klon yok. + // Tek versiyon (optimize edilmiş) yeterli — ast komutu gibi karşılaştırma yok. + if (args.optimized) { + CompilerConfig cfg; + DiagnosticEngine optDiag; + OptimizationManager(cfg, optDiag).runPassesInPlace(ast, &symbolTable); + if (optDiag.errorCount() + optDiag.warningCount() > 0) + optDiag.printAll(std::cerr); // W002 (derleme zamanı sıfıra bölme) vb. + } + + // ── Aşama 5: IR üretimi ─────────────────────────────────────────────── IRGenerator irGenerator; IRProgram program = irGenerator.generate(ast, symbolTable); - // ── Aşama 5: VM çalıştırma ──────────────────────────────────────────── + // ── Aşama 6: VM çalıştırma ──────────────────────────────────────────── int exitCode = 0; try { Interpreter vm(program); diff --git a/src/core/type.hpp b/src/core/type.hpp index d8e07af..4e8a770 100644 --- a/src/core/type.hpp +++ b/src/core/type.hpp @@ -73,6 +73,7 @@ struct Type { std::shared_ptr returnType; // kind == Function std::vector paramTypes; // kind == Function std::string structName; // kind == Struct + bool nullable = false; // ADR-021: Type? sözdizimi // ------------------------------------------------------------------ // // Factory'ler @@ -132,11 +133,26 @@ struct Type { prim == PrimitiveKind::Double); } + bool isString() const { + return kind == TypeKind::Primitive && prim == PrimitiveKind::String; + } + + // ADR-021: "null" literal tipi — yalnızca nullable değişkene atanabilir + bool isNullLiteral() const { + return kind == TypeKind::Primitive && prim == PrimitiveKind::Void && nullable; + } + + // Nullable kopyası döndür + Type asNullable() const { Type t = *this; t.nullable = true; return t; } + Type asNonNull() const { Type t = *this; t.nullable = false; return t; } + // ------------------------------------------------------------------ // // equals — Yapısal eşitlik (katı; gizli dönüşüm yok, ADR-010) // ------------------------------------------------------------------ // + // Yapısal eşitlik — nullable dahil (ADR-021: int ≠ int?) bool equals(const Type& o) const { if (kind != o.kind) return false; + if (nullable != o.nullable) return false; switch (kind) { case TypeKind::Primitive: return prim == o.prim; @@ -154,13 +170,14 @@ struct Type { return true; } case TypeKind::Error: - // Error == Error: ardışık sahte hataların bastırılması tip - // denetleyicinin sorumluluğundadır (operandı Error ise hata üretme). return true; } - return false; // erişilemez (tüm enum değerleri kapsandı) + return false; } + // Temel yapısal eşitlik — nullable farkını yok say (T == T? üstün çakışma için) + bool equalsBase(const Type& o) const { return asNonNull().equals(o.asNonNull()); } + // ------------------------------------------------------------------ // // İsim yardımcıları // ------------------------------------------------------------------ // @@ -177,10 +194,15 @@ struct Type { return "?"; } - // Bir tip adından (parser tipleri string olarak tutar) primitif Type üretir. - // Bilinen primitif değilse Error döner — bilinmeyen tip adının teşhisi - // (E007) çağıranın (Faz 2/3) işidir; bu fonksiyon sessizce Error verir. + // Bir tip adından (parser tipleri string olarak tutar) Type üretir. + // "int?" → nullable int; "int[]" → int array; bilinen değilse Error. static Type fromName(const std::string& n) { + // Nullable soneki: "int?", "string?" vb. (ADR-021) + if (!n.empty() && n.back() == '?') { + Type base = fromName(n.substr(0, n.size() - 1)); + if (!base.isError()) return base.asNullable(); + return error(); + } if (n == "int") return Int(); if (n == "float") return Float(); if (n == "double") return Double(); @@ -188,6 +210,11 @@ struct Type { if (n == "string") return String(); if (n == "bool") return Bool(); if (n == "void") return Void(); + // "int[]", "float[]" vb. — suffix [] ile dizi tipi + if (n.size() > 2 && n.substr(n.size() - 2) == "[]") { + Type elem = fromName(n.substr(0, n.size() - 2)); + if (!elem.isError()) return array(elem); + } return error(); } @@ -195,27 +222,28 @@ struct Type { // toString — İnsan-okur ("int", "int[]", "fn(int,int)->int") // ------------------------------------------------------------------ // std::string toString() const { + std::string base; switch (kind) { case TypeKind::Primitive: - return primName(prim); + base = primName(prim); break; case TypeKind::Array: - return (elementType ? elementType->toString() : "") + "[]"; + base = (elementType ? elementType->toString() : "") + "[]"; break; case TypeKind::Struct: - return "struct " + structName; + base = "struct " + structName; break; case TypeKind::Function: { - std::string s = "fn("; + base = "fn("; for (size_t i = 0; i < paramTypes.size(); ++i) { - if (i) s += ","; - s += paramTypes[i].toString(); + if (i) base += ","; + base += paramTypes[i].toString(); } - s += ")->"; - s += returnType ? returnType->toString() : ""; - return s; + base += ")->"; + base += returnType ? returnType->toString() : ""; + break; } case TypeKind::Error: return ""; } - return ""; + return nullable ? base + "?" : base; } // ------------------------------------------------------------------ // diff --git a/src/ir/instruction.hpp b/src/ir/instruction.hpp index 9ce720f..07aaf4b 100644 --- a/src/ir/instruction.hpp +++ b/src/ir/instruction.hpp @@ -20,6 +20,7 @@ // LESS/LEQ/... : dest, left, right (sonuç: 1=doğru, 0=yanlış) // JMP : jumpTarget // JIF_FALSE : cond, jumpTarget +// JIF_TRUE : cond, jumpTarget // CALL : dest, functionName, argSlots // RETURN : src // CALLHOST : functionName, argSlots @@ -41,6 +42,7 @@ enum class Opcode { // Örnek: LOAD_CONST dest=3 val=10 → slot[3] = 10 LOAD_STRING, // slots[dest] = stringValue (metin sabitini slota yükle) + LOAD_NULL, // slots[dest] = null (ADR-021: ValueKind::Null) // Örnek: LOAD_STRING dest=2 val="Merhaba" → slot[2] = "Merhaba" LOAD_SLOT, // slots[dest] = slots[src] @@ -54,6 +56,13 @@ enum class Opcode { DIV, // UYARI: sıfıra bölme → runtime_error fırlatılır MOD, + // --- Bitsel (tümü: slots[dest] = slots[left] OP slots[right]) --- + BAND, // slots[left] & slots[right] + BOR, // slots[left] | slots[right] + SHL, // slots[left] << slots[right] + SHR, // slots[left] >> slots[right] + BNOT, // ~slots[src] → slots[dest] (tekli operatör; src kullanır, left/right değil) + // --- Karşılaştırma (sonuç: 1 = doğru, 0 = yanlış) --- LESS, // slots[left] < slots[right] LESS_EQUAL, // slots[left] <= slots[right] @@ -64,7 +73,8 @@ enum class Opcode { // --- Kontrol akışı --- JMP, // Koşulsuz atlama: ip = jumpTarget - JIF_FALSE, // Koşullu atlama: slots[cond] == 0 ise ip = jumpTarget + JIF_FALSE, // Koşullu atlama: slots[cond] falsy ise ip = jumpTarget + JIF_TRUE, // Koşullu atlama: slots[cond] truthy ise ip = jumpTarget // --- Fonksiyon çağrısı --- CALL, // Başka bir saQut fonksiyonunu çağır. @@ -73,6 +83,47 @@ enum class Opcode { RETURN, // Bu frame'i kapat, slots[src]'yi caller'a ilet. + // --- Float aritmetik (#44) --- + LOAD_FLOAT, // slots[dest] = floatValue (double sabit yükle) + FADD, // slots[dest] = slots[left] + slots[right] (float) + FSUB, // slots[dest] = slots[left] - slots[right] (float) + FMUL, // slots[dest] = slots[left] * slots[right] (float) + FDIV, // slots[dest] = slots[left] / slots[right] (float; sıfır → runtime_error) + FNEG, // slots[dest] = -slots[src] (float tekli eksi) + INT_TO_FLOAT, // slots[dest] = (double)slots[src] — gizli int→float çevrimi (literal atamasında) + FLOAT_TO_INT, // slots[dest] = (int)slots[src] — açık cast (ileride: int(x)) + + // --- Struct (ADR-020: referans semantiği) --- + STRUCT_NEW, // slots[dest] = yeni StructObject(intValue alan sayısı); functionName = struct tipi adı + FIELD_GET, // slots[dest] = slots[src].fields[intValue] (src=nesne, intValue=alan indeksi) + FIELD_SET, // slots[dest].fields[intValue] = slots[right] (dest=nesne, intValue=alan indeksi, right=değer) + + // --- Array (ADR-020: referans semantiği) --- + ARRAY_NEW, // slots[dest] = yeni ArrayObject(intValue eleman kapasitesi) + ARRAY_GET, // slots[dest] = slots[left][slots[right]] — sınır kontrolü + ARRAY_SET, // slots[dest][slots[left]] = slots[right] — sınır kontrolü (dest=dizi, left=idx, right=değer) + ARRAY_LEN, // slots[dest] = slots[src].uzunluk() + + // --- Modül-düzeyi değişken erişimi --- + // "Global" değil: her değişken kendi dosyasına (modülüne) aittir. + // Başka modüller bu alana doğrudan erişemez; yalnızca export/import ile ulaşabilir. + // TODO(#modül-scope): IRFunction.moduleId eklenerek çok-modüllü derlemede + // her fonksiyonun kendi modülünün slot alanına bakması sağlanacak (bkz. TODO.md). + LOAD_GLOBAL, // slots[dest] = moduleSlots[intValue] (bu modülün modül-düzeyi değişkeni) + STORE_GLOBAL, // moduleSlots[intValue] = slots[src] + + // --- String işlemleri (ADR-024: immutable değer-tipi, içerik ==) --- + STRING_CONCAT, // slots[dest] = slots[left] + slots[right] (yeni string üretir) + + // --- Hata yönetimi (ADR-025: UNCHECKED try/catch/throw) --- + ENTER_TRY, // try bloğuna giriş: TryFrame'i yığına it + // dest = catch bloğundaki Error değerinin yazılacağı slot + // jumpTarget = catch bloğunun IR konumu (-1 → backpatch) + // callDepth = VM, callStack.size()'ı kayıt altına alır (unwind için) + LEAVE_TRY, // try bloğundan normal çıkış: TryFrame'i çıkar (istisna olmadı) + THROW, // slots[src] değerini fırlat → en yakın ENTER_TRY'a unwind + // Yakalanmamışsa C++ exception olarak yükseltilir + // --- Dış dünya (FFI — Foreign Function Interface) --- CALLHOST, // Host (C++) fonksiyonunu çağır. Şu an sadece "print" destekli. // Dönüş değeri yok; sadece yan etki (stdout'a yazmak gibi). @@ -83,12 +134,35 @@ inline const char* opcodeName(Opcode op) { switch (op) { case Opcode::LOAD_CONST: return "LOAD_CONST"; case Opcode::LOAD_STRING: return "LOAD_STRING"; + case Opcode::LOAD_NULL: return "LOAD_NULL"; case Opcode::LOAD_SLOT: return "LOAD_SLOT"; case Opcode::ADD: return "ADD"; case Opcode::SUB: return "SUB"; case Opcode::MUL: return "MUL"; case Opcode::DIV: return "DIV"; case Opcode::MOD: return "MOD"; + case Opcode::BAND: return "BAND"; + case Opcode::BOR: return "BOR"; + case Opcode::SHL: return "SHL"; + case Opcode::SHR: return "SHR"; + case Opcode::BNOT: return "BNOT"; + case Opcode::LOAD_FLOAT: return "LOAD_FLOAT"; + case Opcode::FADD: return "FADD"; + case Opcode::FSUB: return "FSUB"; + case Opcode::FMUL: return "FMUL"; + case Opcode::FDIV: return "FDIV"; + case Opcode::FNEG: return "FNEG"; + case Opcode::INT_TO_FLOAT: return "INT_TO_FLOAT"; + case Opcode::FLOAT_TO_INT: return "FLOAT_TO_INT"; + case Opcode::STRUCT_NEW: return "STRUCT_NEW"; + case Opcode::FIELD_GET: return "FIELD_GET"; + case Opcode::FIELD_SET: return "FIELD_SET"; + case Opcode::ARRAY_NEW: return "ARRAY_NEW"; + case Opcode::ARRAY_GET: return "ARRAY_GET"; + case Opcode::ARRAY_SET: return "ARRAY_SET"; + case Opcode::ARRAY_LEN: return "ARRAY_LEN"; + case Opcode::LOAD_GLOBAL: return "LOAD_GLOBAL"; + case Opcode::STORE_GLOBAL: return "STORE_GLOBAL"; case Opcode::LESS: return "LESS"; case Opcode::LESS_EQUAL: return "LESS_EQUAL"; case Opcode::GREATER: return "GREATER"; @@ -97,8 +171,13 @@ inline const char* opcodeName(Opcode op) { case Opcode::NOT_EQUAL: return "NOT_EQUAL"; case Opcode::JMP: return "JMP"; case Opcode::JIF_FALSE: return "JIF_FALSE"; + case Opcode::JIF_TRUE: return "JIF_TRUE"; case Opcode::CALL: return "CALL"; case Opcode::RETURN: return "RETURN"; + case Opcode::STRING_CONCAT: return "STRING_CONCAT"; + case Opcode::ENTER_TRY: return "ENTER_TRY"; + case Opcode::LEAVE_TRY: return "LEAVE_TRY"; + case Opcode::THROW: return "THROW"; case Opcode::CALLHOST: return "CALLHOST"; } return "UNKNOWN"; @@ -128,6 +207,9 @@ struct Instruction { // LOAD_CONST için yüklenecek tam sayı sabiti int intValue = 0; + // LOAD_FLOAT için yüklenecek double sabiti (#44) + double floatValue = 0.0; + // LOAD_STRING için yüklenecek metin sabiti (tırnak işaretleri olmadan) std::string stringValue; diff --git a/src/ir/ir_function.cpp b/src/ir/ir_function.cpp index 690b566..7bef87c 100644 --- a/src/ir/ir_function.cpp +++ b/src/ir/ir_function.cpp @@ -20,7 +20,15 @@ static const char* opSymbol(Opcode op) { case Opcode::SUB: return "-"; case Opcode::MUL: return "*"; case Opcode::DIV: return "/"; + case Opcode::FADD: return "+."; + case Opcode::FSUB: return "-."; + case Opcode::FMUL: return "*."; + case Opcode::FDIV: return "/."; case Opcode::MOD: return "%"; + case Opcode::BAND: return "&"; + case Opcode::BOR: return "|"; + case Opcode::SHL: return "<<"; + case Opcode::SHR: return ">>"; case Opcode::LESS: return "<"; case Opcode::LESS_EQUAL: return "<="; case Opcode::GREATER: return ">"; @@ -35,6 +43,8 @@ static bool isBinaryOp(Opcode op) { switch (op) { case Opcode::ADD: case Opcode::SUB: case Opcode::MUL: case Opcode::DIV: case Opcode::MOD: + case Opcode::FADD: case Opcode::FSUB: case Opcode::FMUL: case Opcode::FDIV: + case Opcode::BAND: case Opcode::BOR: case Opcode::SHL: case Opcode::SHR: case Opcode::LESS: case Opcode::LESS_EQUAL: case Opcode::GREATER: case Opcode::GREATER_EQUAL: case Opcode::EQUAL_EQUAL: case Opcode::NOT_EQUAL: @@ -113,6 +123,48 @@ void IRFunction::dump() const { } std::cout << ")"; + } else if (ins.opcode == Opcode::BNOT) { + std::cout << slot(ins.dest) << " = ~" << slot(ins.src); + + } else if (ins.opcode == Opcode::LOAD_FLOAT) { + std::cout << slot(ins.dest) << " = " << ins.floatValue; + + } else if (ins.opcode == Opcode::INT_TO_FLOAT) { + std::cout << slot(ins.dest) << " = (float)" << slot(ins.src); + + } else if (ins.opcode == Opcode::FLOAT_TO_INT) { + std::cout << slot(ins.dest) << " = (int)" << slot(ins.src); + + } else if (ins.opcode == Opcode::FNEG) { + std::cout << slot(ins.dest) << " = -" << slot(ins.src); + + } else if (ins.opcode == Opcode::STRUCT_NEW) { + std::cout << slot(ins.dest) << " = struct<" << ins.functionName << ">[" << ins.intValue << " alan]"; + + } else if (ins.opcode == Opcode::FIELD_GET) { + std::cout << slot(ins.dest) << " = " << slot(ins.src) << "." << ins.intValue; + + } else if (ins.opcode == Opcode::FIELD_SET) { + std::cout << slot(ins.dest) << "." << ins.intValue << " = " << slot(ins.right); + + } else if (ins.opcode == Opcode::ARRAY_NEW) { + std::cout << slot(ins.dest) << " = array[" << ins.intValue << "]"; + + } else if (ins.opcode == Opcode::ARRAY_GET) { + std::cout << slot(ins.dest) << " = " << slot(ins.left) << "[" << slot(ins.right) << "]"; + + } else if (ins.opcode == Opcode::ARRAY_SET) { + std::cout << slot(ins.dest) << "[" << slot(ins.left) << "] = " << slot(ins.right); + + } else if (ins.opcode == Opcode::ARRAY_LEN) { + std::cout << slot(ins.dest) << " = len(" << slot(ins.src) << ")"; + + } else if (ins.opcode == Opcode::LOAD_GLOBAL) { + std::cout << slot(ins.dest) << " = global[" << ins.intValue << "]"; + + } else if (ins.opcode == Opcode::STORE_GLOBAL) { + std::cout << "global[" << ins.intValue << "] = " << slot(ins.src); + } else if (ins.opcode == Opcode::RETURN) { std::cout << slot(ins.src); } diff --git a/src/ir/ir_generator.cpp b/src/ir/ir_generator.cpp index 947355d..290fd96 100644 --- a/src/ir/ir_generator.cpp +++ b/src/ir/ir_generator.cpp @@ -10,32 +10,55 @@ #include #include +// Error struct alan sırası (ADR-025): makeError için IR tarafından bilinir +// 0=line, 1=col, 2=message, 3=trace, 4=code +static constexpr int ERROR_FIELD_COUNT = 5; + // ───────────────────────────────────────────────────────────────────────────── // generate — Ana giriş noktası // ───────────────────────────────────────────────────────────────────────────── -IRProgram IRGenerator::generate(ASTNode* programNode, SymbolTable& /*symbolTable*/) { +IRProgram IRGenerator::generate(ASTNode* programNode, SymbolTable& symbolTable) { IRProgram program; - // ProgramNode'un her çocuğunu gez. - // Bizi ilgilendiren: FunctionDecl. StructDecl/GlobalVar → TODO. + // 0. Geçiş: struct layout haritasını sembol tablosundan al + structLayouts_ = symbolTable.structLayouts; + + // 1. Geçiş: modül-düzeyi VariableDecl'leri topla ve kayıt et + // "Global" değil — bu dosyanın (modülün) kendi değişkenleri. + std::vector globalVars; + for (ASTNode* child : programNode->getChildren()) { + if (child->kind == ASTKind::VariableDecl) { + auto* vd = (VariableDeclNode*)child; + nameToGlobal_[vd->name] = globalCount_++; + program.globalCount++; + program.globalNames.push_back(vd->name); + globalVars.push_back(vd); + } + } + + // 2. Geçiş: fonksiyonları üret for (ASTNode* child : programNode->getChildren()) { if (child->kind == ASTKind::FunctionDecl) { - // Her fonksiyon üretimi için sıfırla nameToSlot_.clear(); nextSlot_ = 0; - // IRFunction oluştur, currentFunction_ olarak işaretle auto* fnDecl = (FunctionDeclNode*)child; IRFunction irFn(fnDecl->name, (int)fnDecl->params.size()); program.addFunction(std::move(irFn)); - - // addFunction std::move yaptığı için pointer'ı haritadan alalım currentFunction_ = program.findFunction(fnDecl->name); - generateFunction(child); + // main'in başında global değişkenlerin init ifadelerini üret + if (fnDecl->name == "main") { + for (VariableDeclNode* gv : globalVars) { + if (gv->initExpr) { + int initSlot = generateExpression(gv->initExpr); + emitStoreGlobal(initSlot, nameToGlobal_[gv->name]); + } + } + } - // Fonksiyon bitti — toplam slot sayısını kaydet + generateFunction(child); currentFunction_->slotCount = nextSlot_; } } @@ -81,7 +104,7 @@ void IRGenerator::generateStatement(ASTNode* node) { break; } - // ── Değişken bildirimi: int x = ────────────────────────────── + // ── Değişken bildirimi: int x = / Point p; ──────────────── case ASTKind::VariableDecl: { auto* vd = (VariableDeclNode*)node; @@ -90,14 +113,22 @@ void IRGenerator::generateStatement(ASTNode* node) { registerVariable(vd->name, varSlot); if (vd->initExpr) { - // Başlatma ifadesini üret, sonucu bir slotta al int initSlot = generateExpression(vd->initExpr); - - if (initSlot != varSlot) { - // Sonuç başka bir slotta, değişkenin slotuna kopyala - emitLoadSlot(varSlot, initSlot); + // float/double değişkenine int sabit atama → INT_TO_FLOAT + bool targetIsFloat = (vd->varType == "float" || vd->varType == "double"); + bool srcIsInt = false; + if (auto* e = dynamic_cast(vd->initExpr)) + srcIsInt = e->resolvedType.isPrimitive() && e->resolvedType.prim == PrimitiveKind::Int; + if (targetIsFloat && srcIsInt) { + int conv = freshSlot(); + emitIntToFloat(conv, initSlot); + initSlot = conv; } - // initSlot == varSlot: LOAD_CONST doğrudan varSlot'a yazıldı, kopya gerekmez + if (initSlot != varSlot) emitLoadSlot(varSlot, initSlot); + } else if (structLayouts_.count(vd->varType)) { + // Struct değişkeni: init ifadesi yoksa boş StructObject oluştur + int fc = getStructFieldCount(vd->varType); + emitStructNew(varSlot, vd->varType, fc); } // Sibling VariableDecl'ler: int a, b; → children'da diğer VariableDecl'ler @@ -153,84 +184,101 @@ void IRGenerator::generateStatement(ASTNode* node) { case ASTKind::WhileStatement: { auto* ws = (WhileStatementNode*)node; - // Döngü başının konumu — geri-jump buraya gelecek int loopStart = currentInstrIndex(); + loopContextStack_.push_back({}); - int condSlot = generateExpression(ws->condition); - int exitJump = emitJumpIfFalse(condSlot); // ileri, backpatch bekliyor + int condSlot = generateExpression(ws->condition); + int exitJump = emitJumpIfFalse(condSlot); if (ws->body) generateStatement(ws->body); - // Geri-jump: hedef zaten biliniyor (loopStart) - emitJumpUnconditional(loopStart); + // continue → LOOP_START (hedef baştan beri biliniyor) + for (int idx : loopContextStack_.back().continueJumps) + currentFunction_->instructions[idx].jumpTarget = loopStart; - // Döngü çıkış noktası → exitJump'ı doldur - patchJump(exitJump); + emitJumpUnconditional(loopStart); + patchJump(exitJump); // OUT burası + + // break → OUT + int outTarget = currentInstrIndex(); + for (int idx : loopContextStack_.back().breakJumps) + currentFunction_->instructions[idx].jumpTarget = outTarget; + + loopContextStack_.pop_back(); break; } // ── for (init; koşul; güncelleme) { gövde } ───────────────────────── // - // Üretilen IR yapısı: + // IR yapısı (continue C_LABEL'a, break OUT'a atlar): // [init] // LOOP_START: - // [koşul] → condSlot - // JIF_FALSE condSlot → LOOP_END (ileri-jump, backpatch) + // [koşul] → JIF_FALSE OUT // [gövde] + // C_LABEL: // [güncelleme] - // JMP → LOOP_START (geri-jump, hedef biliniyor) - // LOOP_END: + // JMP LOOP_START + // OUT: // ───────────────────────────────────────────────────────────────────── case ASTKind::ForStatement: { auto* fs = (ForStatementNode*)node; - // Init: genellikle "int i = 0" gibi bir VariableDecl if (fs->init) generateStatement(fs->init); - // Döngü başı konumu — geri-jump'ın hedefi int loopStart = currentInstrIndex(); + loopContextStack_.push_back({}); - // Koşul int condSlot = fs->condition ? generateExpression(fs->condition) : -1; int exitJump = (condSlot != -1) ? emitJumpIfFalse(condSlot) : -1; - // Gövde if (fs->body) generateStatement(fs->body); - // Güncelleme (ör: i = i + 1) — ifade deyimi, sonuç önemsiz + // C_LABEL: güncelleme başlangıcı — continue buraya atlar + int cLabel = currentInstrIndex(); + for (int idx : loopContextStack_.back().continueJumps) + currentFunction_->instructions[idx].jumpTarget = cLabel; + if (fs->update) generateExpression(fs->update); - // Geri-jump: hedef loopStart, zaten biliniyor emitJumpUnconditional(loopStart); - // Döngü çıkışı → exitJump'ı doldur - if (exitJump != -1) patchJump(exitJump); + if (exitJump != -1) patchJump(exitJump); // OUT burası + + // break → OUT + int outTarget = currentInstrIndex(); + for (int idx : loopContextStack_.back().breakJumps) + currentFunction_->instructions[idx].jumpTarget = outTarget; + + loopContextStack_.pop_back(); break; } // ── do { gövde } while (koşul) ─────────────────────────────────────── case ASTKind::DoWhileStatement: { auto* dw = (DoWhileStatementNode*)node; + int loopStart = currentInstrIndex(); + loopContextStack_.push_back({}); if (dw->body) generateStatement(dw->body); + // COND_LABEL: koşul değerlendirmesi — continue buraya atlar + int condLabel = currentInstrIndex(); + for (int idx : loopContextStack_.back().continueJumps) + currentFunction_->instructions[idx].jumpTarget = condLabel; + int condSlot = generateExpression(dw->condition); - // Koşul doğruysa geri atla (1 = doğru → atla; 0 = yanlış → devam) - // JIF_FALSE koşul yanlışsa atlar; biz doğruysa atlamak istiyoruz. - // Bu yüzden JIF_FALSE yerine "doğruysa atla" mantığı lazım. - // Basit çözüm: koşulun tersini al (0→1, diğer→0) ve JIF_FALSE kullan. - // NOT: saQut'ta "!" operatörü yok henüz; NOT talimatı eklenebilir. - // Şimdilik: koşul slotuna bak, sıfır değilse geri atla. - // TODO(vm-genişletme): JIF_TRUE talimatı ekle - // Geçici çözüm: sabit 1 ile karşılaştır (condSlot != 0 → geri) - int oneSlot = freshSlot(); - emitLoadConst(oneSlot, 1); - int eqSlot = freshSlot(); - emitBinaryOp(Opcode::EQUAL_EQUAL, eqSlot, condSlot, oneSlot); - int skipJump = emitJumpIfFalse(eqSlot); // koşul yanlışsa döngüden çık - emitJumpUnconditional(loopStart); // geri atla - patchJump(skipJump); + Instruction jit(Opcode::JIF_TRUE); + jit.cond = condSlot; + jit.jumpTarget = loopStart; + currentFunction_->instructions.push_back(std::move(jit)); + + // break → OUT (JIF_TRUE'dan sonraki konum) + int outTarget = currentInstrIndex(); + for (int idx : loopContextStack_.back().breakJumps) + currentFunction_->instructions[idx].jumpTarget = outTarget; + + loopContextStack_.pop_back(); break; } @@ -244,10 +292,66 @@ void IRGenerator::generateStatement(ASTNode* node) { break; } - case ASTKind::BreakStatement: - case ASTKind::ContinueStatement: - // TODO(vm-genişletme): break/continue için JMP + label mekanizması gerekir + case ASTKind::BreakStatement: { + int jumpIdx = emitJumpUnconditional(-1); + if (!loopContextStack_.empty()) + loopContextStack_.back().breakJumps.push_back(jumpIdx); break; + } + case ASTKind::ContinueStatement: { + int jumpIdx = emitJumpUnconditional(-1); + if (!loopContextStack_.empty()) + loopContextStack_.back().continueJumps.push_back(jumpIdx); + break; + } + + // ── try { body } catch (Error e) { handler } (ADR-025) ──────────── + case ASTKind::TryStatement: { + auto* ts = (TryStatementNode*)node; + + // Catch değişkeni için slot; VM bu slota Error nesnesini yazar + int errorSlot = freshSlot(); + if (!ts->catchVar.empty()) + registerVariable(ts->catchVar, errorSlot); + + // ENTER_TRY: catch hedefi henüz bilinmiyor (-1), sonradan patchlanır + Instruction enterTry(Opcode::ENTER_TRY); + enterTry.dest = errorSlot; + enterTry.jumpTarget = -1; + currentFunction_->instructions.push_back(std::move(enterTry)); + int enterTryIdx = (int)currentFunction_->instructions.size() - 1; + + // Try gövdesi + if (ts->body) generateStatement(ts->body); + + // Normal çıkış: try frame'ini çıkar + Instruction leaveTry(Opcode::LEAVE_TRY); + currentFunction_->instructions.push_back(std::move(leaveTry)); + + // Catch bloğunu atla (normal akışta) + int jumpOverCatch = emitJumpUnconditional(-1); + + // Catch etiketi: ENTER_TRY buraya atlayacak + int catchLabel = currentInstrIndex(); + currentFunction_->instructions[enterTryIdx].jumpTarget = catchLabel; + + // Catch gövdesi + if (ts->handler) generateStatement(ts->handler); + + // Catch bitti + patchJump(jumpOverCatch); + break; + } + + // ── throw ; (ADR-025) ──────────────────────────────────────── + case ASTKind::ThrowStatement: { + auto* th = (ThrowStatementNode*)node; + int valSlot = th->value ? generateExpression(th->value) : freshSlot(); + Instruction ins(Opcode::THROW); + ins.src = valSlot; + currentFunction_->instructions.push_back(std::move(ins)); + break; + } default: break; @@ -270,14 +374,29 @@ int IRGenerator::generateExpression(ASTNode* node) { switch (lit->literalType) { case LiteralType::INTEGER: { - int value = 0; - if (lit->parserToken.token) - value = std::stoi(lit->parserToken.token->token); - emitLoadConst(slot, value); + // Float/double bağlamında tam sayı literali → LOAD_FLOAT (bağlama-göre tip, ADR-010) + bool asFloat = lit->resolvedType.isPrimitive() && + (lit->resolvedType.prim == PrimitiveKind::Float || + lit->resolvedType.prim == PrimitiveKind::Double); + if (asFloat) { + double val = 0.0; + if (lit->hasDirectValue) val = (double)lit->directIntValue; + else if (lit->parserToken.token) val = std::stod(lit->parserToken.token->token); + emitLoadFloat(slot, val); + } else { + int value = 0; + if (lit->hasDirectValue) value = lit->directIntValue; + else if (lit->parserToken.token) value = std::stoi(lit->parserToken.token->token); + emitLoadConst(slot, value); + } break; } case LiteralType::BOOLEAN: { - int value = (lit->parserToken.token && + int value = 0; + if (lit->hasDirectValue) + value = lit->directIntValue ? 1 : 0; + else + value = (lit->parserToken.token && lit->parserToken.token->token == "true") ? 1 : 0; emitLoadConst(slot, value); break; @@ -301,25 +420,32 @@ int IRGenerator::generateExpression(ASTNode* node) { currentFunction_->instructions.push_back(std::move(ins)); break; } - case LiteralType::FLOAT: - throw std::runtime_error( - "IR üretim hatası: float literal şu an VM tarafından desteklenmiyor. " - "Tam sayı kullanın veya float desteği eklenene kadar bekleyin."); + case LiteralType::FLOAT: { + double val = 0.0; + if (lit->parserToken.token) + val = std::stod(lit->parserToken.token->token); + emitLoadFloat(slot, val); + break; + } case LiteralType::BOŞ: - throw std::runtime_error( - "IR üretim hatası: null literal şu an VM tarafından desteklenmiyor."); + // null literal → ValueKind::Null (ADR-021) + { Instruction ins(Opcode::LOAD_NULL); ins.dest = slot; + currentFunction_->instructions.push_back(std::move(ins)); } + break; } return slot; } // ── Değişken ismi: n, first, second ... ────────────────────────────── - // Bu değişkenin değeri zaten bir slotta. O slotu döndür. case ASTKind::Identifier: { auto* id = (IdentifierNode*)node; std::string name = id->parserToken.token ? id->parserToken.token->token : ""; - // Önce builtin mi? (print gibi) — identifier olarak gelen builtin fonksiyon - // çağrıları CallExpression içinde yakalanıyor, burada sadece değişken kalır + if (isGlobal(name)) { + int tempSlot = freshSlot(); + emitLoadGlobal(tempSlot, getGlobalIndex(name)); + return tempSlot; + } return lookupVariable(name); } @@ -327,42 +453,87 @@ int IRGenerator::generateExpression(ASTNode* node) { case ASTKind::BinaryExpression: { auto* bin = (BinaryExpressionNode*)node; - // Atama operatörleri: x = expr, x += expr ... - // Sol taraf bir değişken, sağ taraf hesaplanır ve o değişkene yazılır. + // Atama operatörleri: x = expr ve a[i] = expr if (bin->Operator == TokenType::EQUAL) { - // Sağ tarafı hesapla int rhsSlot = generateExpression(bin->Right); - // Sol taraf değişkenin slotunu bul + // a[i] = val → ARRAY_SET + if (bin->Left && bin->Left->kind == ASTKind::IndexExpression) { + auto* idx = (IndexExpressionNode*)bin->Left; + int arrSlot = generateExpression(idx->object); + int idxSlot = generateExpression(idx->index); + emitArraySet(arrSlot, idxSlot, rhsSlot); + return rhsSlot; + } + + // p.field = val → FIELD_SET + if (bin->Left && bin->Left->kind == ASTKind::MemberAccess) { + auto* ma = (MemberAccessNode*)bin->Left; + int objSlot = generateExpression(ma->object); + std::string structName; + if (auto* exprObj = dynamic_cast(ma->object)) + structName = exprObj->resolvedType.structName; + int idx2 = getStructFieldIndex(structName, ma->member); + if (idx2 >= 0) emitFieldSet(objSlot, idx2, rhsSlot); + return rhsSlot; + } + auto* lhsId = (IdentifierNode*)bin->Left; std::string varName = lhsId->parserToken.token->token; - int varSlot = lookupVariable(varName); - // Sonucu değişkenin slotuna kopyala - if (rhsSlot != varSlot) { - emitLoadSlot(varSlot, rhsSlot); + if (isGlobal(varName)) { + emitStoreGlobal(rhsSlot, getGlobalIndex(varName)); + return rhsSlot; } + + int varSlot = lookupVariable(varName); + if (rhsSlot != varSlot) emitLoadSlot(varSlot, rhsSlot); return varSlot; } - // Birleşik atama: += -= *= /= - // x += y ≡ x = x + y - if (bin->Operator == TokenType::PLUS_EQUAL || - bin->Operator == TokenType::MINUS_EQUAL || - bin->Operator == TokenType::STAR_EQUAL || - bin->Operator == TokenType::SLASH_EQUAL) { + // Birleşik atama: += -= *= /= %= &= |= <<= >>= + // x OP= y ≡ x = x OP y + if (bin->Operator == TokenType::PLUS_EQUAL || + bin->Operator == TokenType::MINUS_EQUAL || + bin->Operator == TokenType::STAR_EQUAL || + bin->Operator == TokenType::SLASH_EQUAL || + bin->Operator == TokenType::PERCENT_EQUAL || + bin->Operator == TokenType::AMPERSAND_EQUAL || + bin->Operator == TokenType::PIPE_EQUAL || + bin->Operator == TokenType::LSHIFT_EQUAL || + bin->Operator == TokenType::RSHIFT_EQUAL) { auto* lhsId = (IdentifierNode*)bin->Left; std::string varName = lhsId->parserToken.token->token; - int varSlot = lookupVariable(varName); int rhsSlot = generateExpression(bin->Right); Opcode arithOp = Opcode::ADD; - if (bin->Operator == TokenType::MINUS_EQUAL) arithOp = Opcode::SUB; - else if (bin->Operator == TokenType::STAR_EQUAL) arithOp = Opcode::MUL; - else if (bin->Operator == TokenType::SLASH_EQUAL) arithOp = Opcode::DIV; + if (bin->Operator == TokenType::MINUS_EQUAL) arithOp = Opcode::SUB; + else if (bin->Operator == TokenType::STAR_EQUAL) arithOp = Opcode::MUL; + else if (bin->Operator == TokenType::SLASH_EQUAL) arithOp = Opcode::DIV; + else if (bin->Operator == TokenType::PERCENT_EQUAL) arithOp = Opcode::MOD; + else if (bin->Operator == TokenType::AMPERSAND_EQUAL) arithOp = Opcode::BAND; + else if (bin->Operator == TokenType::PIPE_EQUAL) arithOp = Opcode::BOR; + else if (bin->Operator == TokenType::LSHIFT_EQUAL) arithOp = Opcode::SHL; + else if (bin->Operator == TokenType::RSHIFT_EQUAL) arithOp = Opcode::SHR; + + // string += string → STRING_CONCAT (ADR-024) + if (bin->Operator == TokenType::PLUS_EQUAL) { + if (auto* e = dynamic_cast(bin->Right)) + if (e->resolvedType.isString()) arithOp = Opcode::STRING_CONCAT; + } int resultSlot = freshSlot(); + + if (isGlobal(varName)) { + int currentSlot = freshSlot(); + emitLoadGlobal(currentSlot, getGlobalIndex(varName)); + emitBinaryOp(arithOp, resultSlot, currentSlot, rhsSlot); + emitStoreGlobal(resultSlot, getGlobalIndex(varName)); + return resultSlot; + } + + int varSlot = lookupVariable(varName); emitBinaryOp(arithOp, resultSlot, varSlot, rhsSlot); emitLoadSlot(varSlot, resultSlot); return varSlot; @@ -378,8 +549,18 @@ int IRGenerator::generateExpression(ASTNode* node) { int zeroSlot = freshSlot(); emitLoadConst(zeroSlot, 0); emitBinaryOp(Opcode::SUB, resultSlot, zeroSlot, operandSlot); + } else if (bin->Operator == TokenType::BANG) { + // !x → (x == 0): sıfırsa 1, değilse 0 + int zeroSlot = freshSlot(); + emitLoadConst(zeroSlot, 0); + emitBinaryOp(Opcode::EQUAL_EQUAL, resultSlot, operandSlot, zeroSlot); + } else if (bin->Operator == TokenType::TILDE) { + // ~x — bitsel değil + Instruction ins(Opcode::BNOT); + ins.dest = resultSlot; + ins.src = operandSlot; + currentFunction_->instructions.push_back(std::move(ins)); } else { - // Diğer unary operatörler → TODO emitLoadSlot(resultSlot, operandSlot); } return resultSlot; @@ -399,6 +580,36 @@ int IRGenerator::generateExpression(ASTNode* node) { case TokenType::GREATER_EQUAL: return generateBinaryArithmetic(Opcode::GREATER_EQUAL, bin->Left, bin->Right); case TokenType::EQUAL_EQUAL: return generateBinaryArithmetic(Opcode::EQUAL_EQUAL, bin->Left, bin->Right); case TokenType::BANG_EQUAL: return generateBinaryArithmetic(Opcode::NOT_EQUAL, bin->Left, bin->Right); + + // Bitsel operatörler + case TokenType::AMPERSAND: return generateBinaryArithmetic(Opcode::BAND, bin->Left, bin->Right); + case TokenType::PIPE: return generateBinaryArithmetic(Opcode::BOR, bin->Left, bin->Right); + case TokenType::LSHIFT: return generateBinaryArithmetic(Opcode::SHL, bin->Left, bin->Right); + case TokenType::RSHIFT: return generateBinaryArithmetic(Opcode::SHR, bin->Left, bin->Right); + + // Mantıksal operatörler: kısa devre dallanmasıyla üretilir (ADR-008). + // NOT: sıradan ikili işlem değil — b, a'nın değerine göre atlanabilir. + case TokenType::AMPERSAND_AMPERSAND: { + int slotA = generateExpression(bin->Left); + int result = freshSlot(); + emitLoadConst(result, 0); // varsayılan: false + int skipB = emitJumpIfFalse(slotA); // a false → b'yi atla + int slotB = generateExpression(bin->Right); + emitLoadSlot(result, slotB); // result = b + patchJump(skipB); + return result; + } + case TokenType::PIPE_PIPE: { + int slotA = generateExpression(bin->Left); + int result = freshSlot(); + emitLoadConst(result, 1); // varsayılan: true + int skipB = emitJumpIfTrue(slotA); // a true → b'yi atla + int slotB = generateExpression(bin->Right); + emitLoadSlot(result, slotB); // result = b + patchJump(skipB); + return result; + } + default: { // Bilinmeyen operatör — boş slot döndür int slot = freshSlot(); @@ -473,6 +684,42 @@ int IRGenerator::generateExpression(ASTNode* node) { return resultSlot; // artırmadan önceki değer } + // ── Üye erişimi okuma: p.x ─────────────────────────────────────────── + case ASTKind::MemberAccess: { + auto* ma = (MemberAccessNode*)node; + int objSlot = generateExpression(ma->object); + int destSlot = freshSlot(); + // Nesnenin struct adını resolvedType üstünden al (tip denetleyici yazdı) + std::string structName; + if (auto* exprObj = dynamic_cast(ma->object)) + structName = exprObj->resolvedType.structName; + int idx = getStructFieldIndex(structName, ma->member); + if (idx >= 0) emitFieldGet(destSlot, objSlot, idx); + return destSlot; + } + case ASTKind::ArrayLiteral: { + auto* al = (ArrayLiteralNode*)node; + int arrSlot = freshSlot(); + emitArrayNew(arrSlot, (int)al->elements.size()); + for (int i = 0; i < (int)al->elements.size(); i++) { + int idxSlot = freshSlot(); + emitLoadConst(idxSlot, i); + int valSlot = generateExpression(al->elements[i]); + emitArraySet(arrSlot, idxSlot, valSlot); + } + return arrSlot; + } + + // ── Index erişimi okuma: a[i] ───────────────────────────────────────── + case ASTKind::IndexExpression: { + auto* idx = (IndexExpressionNode*)node; + int arrSlot = generateExpression(idx->object); + int idxSlot = generateExpression(idx->index); + int destSlot = freshSlot(); + emitArrayGet(destSlot, arrSlot, idxSlot); + return destSlot; + } + default: // Bilinmeyen ifade türü return freshSlot(); // boş slot (0 değeriyle) @@ -487,7 +734,52 @@ int IRGenerator::generateBinaryArithmetic(Opcode opcode, ASTNode* leftNode, ASTN int leftSlot = generateExpression(leftNode); int rightSlot = generateExpression(rightNode); int destSlot = freshSlot(); - emitBinaryOp(opcode, destSlot, leftSlot, rightSlot); + + // Float tip kontrolü — resolvedType üstünden (tip denetleyici tarafından yazıldı) + bool leftIsFloat = false, rightIsFloat = false; + bool leftIsString = false, rightIsString = false; + if (auto* e = dynamic_cast(leftNode)) { + leftIsFloat = e->resolvedType.isPrimitive() && + (e->resolvedType.prim == PrimitiveKind::Float || + e->resolvedType.prim == PrimitiveKind::Double); + leftIsString = e->resolvedType.isString(); + } + if (auto* e = dynamic_cast(rightNode)) { + rightIsFloat = e->resolvedType.isPrimitive() && + (e->resolvedType.prim == PrimitiveKind::Float || + e->resolvedType.prim == PrimitiveKind::Double); + rightIsString = e->resolvedType.isString(); + } + + // String birleştirme (ADR-024): + → STRING_CONCAT + if ((leftIsString || rightIsString) && opcode == Opcode::ADD) { + emitBinaryOp(Opcode::STRING_CONCAT, destSlot, leftSlot, rightSlot); + return destSlot; + } + + if (leftIsFloat || rightIsFloat) { + // Int operandı float'a çevir + if (!leftIsFloat) { + int conv = freshSlot(); + emitIntToFloat(conv, leftSlot); + leftSlot = conv; + } + if (!rightIsFloat) { + int conv = freshSlot(); + emitIntToFloat(conv, rightSlot); + rightSlot = conv; + } + // Float opcode eşleştirmesi + Opcode floatOp = opcode; + if (opcode == Opcode::ADD) floatOp = Opcode::FADD; + else if (opcode == Opcode::SUB) floatOp = Opcode::FSUB; + else if (opcode == Opcode::MUL) floatOp = Opcode::FMUL; + else if (opcode == Opcode::DIV) floatOp = Opcode::FDIV; + // karşılaştırma opcodeları aynı kalır (LESS, GREATER, vb.) + emitBinaryOp(floatOp, destSlot, leftSlot, rightSlot); + } else { + emitBinaryOp(opcode, destSlot, leftSlot, rightSlot); + } return destSlot; } @@ -531,6 +823,111 @@ void IRGenerator::emitLoadSlot(int destSlot, int srcSlot) { currentFunction_->instructions.push_back(std::move(ins)); } +void IRGenerator::emitLoadGlobal(int destSlot, int globalIndex) { + Instruction ins(Opcode::LOAD_GLOBAL); + ins.dest = destSlot; + ins.intValue = globalIndex; + currentFunction_->instructions.push_back(std::move(ins)); +} + +void IRGenerator::emitStoreGlobal(int srcSlot, int globalIndex) { + Instruction ins(Opcode::STORE_GLOBAL); + ins.src = srcSlot; + ins.intValue = globalIndex; + currentFunction_->instructions.push_back(std::move(ins)); +} + +void IRGenerator::emitLoadFloat(int destSlot, double value) { + Instruction ins(Opcode::LOAD_FLOAT); + ins.dest = destSlot; + ins.floatValue = value; + currentFunction_->instructions.push_back(std::move(ins)); +} + +void IRGenerator::emitIntToFloat(int destSlot, int srcSlot) { + Instruction ins(Opcode::INT_TO_FLOAT); + ins.dest = destSlot; + ins.src = srcSlot; + currentFunction_->instructions.push_back(std::move(ins)); +} + +void IRGenerator::emitStructNew(int destSlot, const std::string& structType, int fieldCount) { + Instruction ins(Opcode::STRUCT_NEW); + ins.dest = destSlot; + ins.intValue = fieldCount; + ins.functionName = structType; // struct tip adı + currentFunction_->instructions.push_back(std::move(ins)); +} + +void IRGenerator::emitFieldGet(int destSlot, int objSlot, int fieldIdx) { + Instruction ins(Opcode::FIELD_GET); + ins.dest = destSlot; + ins.src = objSlot; + ins.intValue = fieldIdx; + currentFunction_->instructions.push_back(std::move(ins)); +} + +void IRGenerator::emitFieldSet(int objSlot, int fieldIdx, int valSlot) { + Instruction ins(Opcode::FIELD_SET); + ins.dest = objSlot; + ins.intValue = fieldIdx; + ins.right = valSlot; + currentFunction_->instructions.push_back(std::move(ins)); +} + +void IRGenerator::emitArrayNew(int destSlot, int capacity) { + Instruction ins(Opcode::ARRAY_NEW); + ins.dest = destSlot; + ins.intValue = capacity; + currentFunction_->instructions.push_back(std::move(ins)); +} + +void IRGenerator::emitArrayGet(int destSlot, int arrSlot, int idxSlot) { + Instruction ins(Opcode::ARRAY_GET); + ins.dest = destSlot; + ins.left = arrSlot; + ins.right = idxSlot; + currentFunction_->instructions.push_back(std::move(ins)); +} + +void IRGenerator::emitArraySet(int arrSlot, int idxSlot, int valSlot) { + Instruction ins(Opcode::ARRAY_SET); + ins.dest = arrSlot; + ins.left = idxSlot; + ins.right = valSlot; + currentFunction_->instructions.push_back(std::move(ins)); +} + +void IRGenerator::emitArrayLen(int destSlot, int arrSlot) { + Instruction ins(Opcode::ARRAY_LEN); + ins.dest = destSlot; + ins.src = arrSlot; + currentFunction_->instructions.push_back(std::move(ins)); +} + +int IRGenerator::getStructFieldIndex(const std::string& structType, const std::string& fieldName) const { + auto it = structLayouts_.find(structType); + if (it == structLayouts_.end()) return -1; + for (int i = 0; i < (int)it->second.size(); i++) + if (it->second[i].first == fieldName) return i; + return -1; +} + +int IRGenerator::getStructFieldCount(const std::string& structType) const { + auto it = structLayouts_.find(structType); + if (it == structLayouts_.end()) return 0; + return (int)it->second.size(); +} + +bool IRGenerator::isGlobal(const std::string& name) const { + return nameToGlobal_.count(name) > 0; +} + +int IRGenerator::getGlobalIndex(const std::string& name) const { + auto it = nameToGlobal_.find(name); + return (it != nameToGlobal_.end()) ? it->second : -1; +} + void IRGenerator::emitBinaryOp(Opcode op, int destSlot, int leftSlot, int rightSlot) { Instruction ins(op); ins.dest = destSlot; @@ -557,7 +954,14 @@ int IRGenerator::emitJumpIfFalse(int condSlot) { ins.cond = condSlot; ins.jumpTarget = -1; // henüz bilinmiyor — patchJump() bekliyor currentFunction_->instructions.push_back(std::move(ins)); - // Bu instruction'ın indeksini döndür (backpatch için) + return (int)currentFunction_->instructions.size() - 1; +} + +int IRGenerator::emitJumpIfTrue(int condSlot) { + Instruction ins(Opcode::JIF_TRUE); + ins.cond = condSlot; + ins.jumpTarget = -1; + currentFunction_->instructions.push_back(std::move(ins)); return (int)currentFunction_->instructions.size() - 1; } diff --git a/src/ir/ir_generator.hpp b/src/ir/ir_generator.hpp index f3329ce..a720509 100644 --- a/src/ir/ir_generator.hpp +++ b/src/ir/ir_generator.hpp @@ -22,8 +22,11 @@ #include #include +#include +#include #include "ir/ir_program.hpp" #include "symbol/symbol_table.hpp" +#include "core/type.hpp" #include "parser/ast_node.hpp" class IRGenerator { @@ -55,7 +58,18 @@ private: // Talimatları currentFunction_->instructions'a ekler. void emitLoadConst(int destSlot, int value); + void emitLoadFloat(int destSlot, double value); + void emitIntToFloat(int destSlot, int srcSlot); void emitLoadSlot(int destSlot, int srcSlot); + void emitLoadGlobal(int destSlot, int globalIndex); + void emitStoreGlobal(int srcSlot, int globalIndex); + void emitStructNew(int destSlot, const std::string& structType, int fieldCount); + void emitFieldGet(int destSlot, int objSlot, int fieldIdx); + void emitFieldSet(int objSlot, int fieldIdx, int valSlot); + void emitArrayNew(int destSlot, int capacity); + void emitArrayGet(int destSlot, int arrSlot, int idxSlot); + void emitArraySet(int arrSlot, int idxSlot, int valSlot); + void emitArrayLen(int destSlot, int arrSlot); void emitBinaryOp(Opcode op, int destSlot, int leftSlot, int rightSlot); void emitReturn(int srcSlot); // Koşulsuz atlama yazar; instruction indeksini döndürür (backpatch için). @@ -66,19 +80,44 @@ private: // Döndürülen indeks ileride patchJump() ile doldurulur (backpatch). int emitJumpIfFalse(int condSlot); + // JIF_TRUE talimatını -1 hedefle yazar, instruction indeksini döndürür. + int emitJumpIfTrue(int condSlot); + // Daha önce -1 hedefle yazılan jump'ın hedefini şu anki pozisyona doldur. void patchJump(int instrIndex); // Şu an kaç talimat üretildi? (jump hedefi belirlemek için) int currentInstrIndex() const; + // ── Döngü bağlamı yığını — break/continue hedefleri ───────────────── + // Her döngüye girerken bir giriş push'lanır, çıkınca pop'lanır. + // İç içe döngülerde en üstteki giriş en içteki döngüye aittir. + struct LoopContext { + std::vector breakJumps; // patch bekleyen break JMP indeksleri + std::vector continueJumps; // patch bekleyen continue JMP indeksleri + }; + std::vector loopContextStack_; + // ── Per-function üretim durumu ──────────────────────────────────────── IRFunction* currentFunction_ = nullptr; // şu an üretilen fonksiyon int nextSlot_ = 0; // sıradaki boş slot numarası - // Değişken ismi → slot numarası. - // Sınırlama: aynı isimdeki farklı scope değişkenleri çakışır (TODO). + // Değişken ismi → slot numarası (lokal). std::unordered_map nameToSlot_; + + // Global değişken ismi → global index + std::unordered_map 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>> 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 diff --git a/src/ir/ir_program.cpp b/src/ir/ir_program.cpp index 38014b6..43d1af7 100644 --- a/src/ir/ir_program.cpp +++ b/src/ir/ir_program.cpp @@ -3,6 +3,14 @@ void IRProgram::dump() const { std::cout << "IR DUMP\n\n"; + + if (globalCount > 0) { + std::cout << "GLOBALS (" << globalCount << ")\n"; + for (int i = 0; i < (int)globalNames.size(); i++) + std::cout << " global[" << i << "] = " << globalNames[i] << "\n"; + std::cout << "\n"; + } + for (const auto& name : functionOrder) { auto it = functions.find(name); if (it != functions.end()) it->second.dump(); diff --git a/src/ir/ir_program.hpp b/src/ir/ir_program.hpp index a60e1a4..7fcb838 100644 --- a/src/ir/ir_program.hpp +++ b/src/ir/ir_program.hpp @@ -29,6 +29,14 @@ struct IRProgram { // Ekleme sırası (dump'ta orijinal sırayla göstermek için) std::vector 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 globalNames; // index → isim (dump için) + // Yeni fonksiyon ekle void addFunction(IRFunction fn) { functionOrder.push_back(fn.name); diff --git a/src/opt/constant_folding.hpp b/src/opt/constant_folding.hpp index f09426a..9e413c4 100644 --- a/src/opt/constant_folding.hpp +++ b/src/opt/constant_folding.hpp @@ -104,6 +104,10 @@ private: case TokenType::GREATER: case TokenType::LESS_EQUAL: case TokenType::GREATER_EQUAL: + case TokenType::AMPERSAND: + case TokenType::PIPE: + case TokenType::LSHIFT: + case TokenType::RSHIFT: case TokenType::AMPERSAND_AMPERSAND: case TokenType::PIPE_PIPE: return true; @@ -125,6 +129,10 @@ private: case TokenType::GREATER: return l > r ? 1 : 0; case TokenType::LESS_EQUAL: return l <= r ? 1 : 0; case TokenType::GREATER_EQUAL: return l >= r ? 1 : 0; + case TokenType::AMPERSAND: return l & r; + case TokenType::PIPE: return l | r; + case TokenType::LSHIFT: return l << r; + case TokenType::RSHIFT: return l >> r; case TokenType::AMPERSAND_AMPERSAND: return (l && r) ? 1 : 0; case TokenType::PIPE_PIPE: return (l || r) ? 1 : 0; default: return 0; diff --git a/src/opt/dead_code_elim.hpp b/src/opt/dead_code_elim.hpp index 6662c88..c7f918f 100644 --- a/src/opt/dead_code_elim.hpp +++ b/src/opt/dead_code_elim.hpp @@ -15,9 +15,12 @@ #include "parser/nodes/declarations.hpp" #include "parser/nodes/expressions.hpp" #include "parser/nodes/program.hpp" +#include "diagnostic/diagnostic_engine.hpp" class DeadCodeElimPass : public OptimizationPass { public: + explicit DeadCodeElimPass(DiagnosticEngine& diag) : diag_(diag) {} + bool run(ASTNode* root, SymbolTable*) override { changed_ = false; visit(root); @@ -30,6 +33,7 @@ public: } private: + DiagnosticEngine& diag_; bool changed_ = false; void visit(ASTNode* node) { @@ -45,11 +49,12 @@ private: for (auto* child : ch) { if (term) { - // Bu deyim erişilemez if (auto* sn = dynamic_cast(child)) { if (sn->isReachable) { sn->isReachable = false; changed_ = true; + diag_.report("W003", sn->loc, + "Bu kod hiçbir zaman çalışmaz (return/break/continue sonrası)"); } } } @@ -59,12 +64,14 @@ private: term = true; } - // Erişilemez çocukları sil ve vektörden çıkar - ch.erase(std::remove_if(ch.begin(), ch.end(), + // remove_if erişilemez düğümleri sona taşır (silmez), sonra delete + auto toErase = std::remove_if(ch.begin(), ch.end(), [](ASTNode* n) { auto* sn = dynamic_cast(n); return sn && !sn->isReachable; - }), ch.end()); + }); + for (auto it = toErase; it != ch.end(); ++it) delete *it; + ch.erase(toErase, ch.end()); // Alt bloklara da in for (auto* child : ch) visit(child); diff --git a/src/opt/optimization_manager.hpp b/src/opt/optimization_manager.hpp index af0c661..1cf467f 100644 --- a/src/opt/optimization_manager.hpp +++ b/src/opt/optimization_manager.hpp @@ -1,9 +1,18 @@ // ============================================================================ // saQut — Optimizasyon Yöneticisi (ADR-007, ADR-009) // -// 1. AST'yi klonlar (orijinal dokunulmaz). -// 2. Etkin pass'leri fixpoint döngüsüyle çalıştırır. -// 3. Optimize edilmiş klon sahipliğini döndürür (caller delete eder). +// İKİ KULLANIM YOLU: +// +// 1. runPassesInPlace(root, table) +// Pass'leri verilen AST üstünde doğrudan çalıştırır — klon yok. +// run / ir / transpile gibi "tek seferlik" komutlar bu yolu kullanır: +// AST'nin tek versiyonu gerekiyor, orijinali saklamaya gerek yok. +// +// 2. optimize(root, table) [sadece ast komutu için] +// Önce deepClone, sonra runPassesInPlace. Orijinali dokunulmaz bırakır. +// Çıktı: optimize edilmiş klon (caller delete eder). +// ast komutunun "öncesi / sonrası" karşılaştırması için zorunlu. +// Diğer komutlar bu yolu ÇAĞIRMAMALI — gereksiz klon maliyeti. // // Fixpoint garantisi: her pass yalnızca küçülten dönüşümler yapar // (katlama: n düğüm → 1 düğüm; DCE: düğüm siler). Büyüten pass @@ -29,22 +38,27 @@ public: if (cfg.optConstantFolding) passes_.push_back(std::make_unique(diag)); if (cfg.optDeadCodeElim) - passes_.push_back(std::make_unique()); + passes_.push_back(std::make_unique(diag)); maxRounds_ = cfg.maxFixpointRounds; } - // optimize: AST'yi klonlar ve optimize edilmiş kopyayı döndürür. - // Dönen pointer caller'a aittir (delete edilmeli). - ASTNode* optimize(ASTNode* root, SymbolTable* table) { - ASTNode* clone = deepClone(root); - + // Pass'leri verilen AST üstünde yerinde çalıştırır — klon yok. + // run / ir ve diğer tek-versiyon komutları bu yolu kullanır. + void runPassesInPlace(ASTNode* root, SymbolTable* table) { for (int round = 0; round < maxRounds_; ++round) { bool anyChange = false; for (auto& pass : passes_) - if (pass->run(clone, table)) anyChange = true; + if (pass->run(root, table)) anyChange = true; if (!anyChange) break; } + } + // Önce deepClone, sonra runPassesInPlace. Orijinal dokunulmaz. + // SADECE ast komutu kullanır — öncesi/sonrası karşılaştırması için. + // Dönen pointer caller'a aittir (delete edilmeli). + ASTNode* optimize(ASTNode* root, SymbolTable* table) { + ASTNode* clone = deepClone(root); + runPassesInPlace(clone, table); return clone; } diff --git a/src/parser/ast_node.hpp b/src/parser/ast_node.hpp index d41053a..c79820f 100644 --- a/src/parser/ast_node.hpp +++ b/src/parser/ast_node.hpp @@ -87,6 +87,8 @@ enum class ASTKind { ExpressionStatement, // ifade + noktalı virgül (;) // children: [expression] // Örn: x = 5; veya foo(); + TryStatement, // try { body } catch (Error e) { handler } (ADR-025) + ThrowStatement, // throw ; (ADR-025) /* ====== İfadeler (Expressions) ====== */ BinaryExpression, // İkili işlem: sol OP sağ. @@ -107,6 +109,8 @@ enum class ASTKind { // children: [object], [member] IndexExpression, // Dizi/indeks erişimi: a[i]. // children: [object], [index] + ArrayLiteral, // Dizi literali: [1, 2, 3]. + // children: [element0, element1, ...] }; // ============================================================================ @@ -236,10 +240,12 @@ public: // KARMAŞIKLIK: O(1) — referans döndürür std::vector& getChildren() { return children; } - // ~ASTNode() — Sanal yıkıcı (polimorfik silme için) - // delete ASTNode* yapıldığında doğru alt sınıf yıkıcısı çağrılır. - // Bu olmazsa türetilmiş sınıfların kaynakları sızdırılır. - virtual ~ASTNode() = default; + // ~ASTNode() — children vektörünü özyinelemeli siler. + // Typed pointer'lar (condition, thenBranch vb.) alt sınıf yıkıcılarına bırakılır; + // children vektörü ile typed pointer'lar örtüşmediği için double-delete olmaz. + virtual ~ASTNode() { + for (auto* ch : children) delete ch; + } protected: // children — Alt düğümlerin vektörü. diff --git a/src/parser/nodes/binary_expr.hpp b/src/parser/nodes/binary_expr.hpp index b67ee35..83b3b01 100644 --- a/src/parser/nodes/binary_expr.hpp +++ b/src/parser/nodes/binary_expr.hpp @@ -10,6 +10,7 @@ public: ASTNode* Right = nullptr; BinaryExpressionNode(); + ~BinaryExpressionNode() override { delete Left; delete Right; } void log(int indent = 0) override; std::string toJson(int depth = 0) override; }; diff --git a/src/parser/nodes/declarations.cpp b/src/parser/nodes/declarations.cpp index 994f81e..7356e32 100644 --- a/src/parser/nodes/declarations.cpp +++ b/src/parser/nodes/declarations.cpp @@ -3,6 +3,7 @@ // FunctionDeclNode FunctionDeclNode::FunctionDeclNode() { kind = ASTKind::FunctionDecl; } +FunctionDeclNode::~FunctionDeclNode() { for (auto* p : params) delete p; } void FunctionDeclNode::log(int indent) { std::cout << jsonIndent(indent) << "FunctionDecl (" << name << " : " << returnType << ")\n"; for (auto* child : children) child->log(indent + 1); diff --git a/src/parser/nodes/declarations.hpp b/src/parser/nodes/declarations.hpp index 8779b82..03c180e 100644 --- a/src/parser/nodes/declarations.hpp +++ b/src/parser/nodes/declarations.hpp @@ -11,6 +11,7 @@ public: std::string returnType; std::vector params; // TODO(faz2): parametreler FunctionDeclNode(); + ~FunctionDeclNode() override; void log(int indent = 0) override; std::string toJson(int depth = 0) override; }; @@ -21,6 +22,7 @@ public: std::string name; ASTNode* initExpr = nullptr; VariableDeclNode(); + ~VariableDeclNode() override { delete initExpr; } void log(int indent = 0) override; std::string toJson(int depth = 0) override; }; diff --git a/src/parser/nodes/expressions.cpp b/src/parser/nodes/expressions.cpp index 9c68517..5b56d7b 100644 --- a/src/parser/nodes/expressions.cpp +++ b/src/parser/nodes/expressions.cpp @@ -53,6 +53,23 @@ std::string MemberAccessNode::toJson(int depth) { return obj.str(); } +// ArrayLiteralNode +ArrayLiteralNode::ArrayLiteralNode() { kind = ASTKind::ArrayLiteral; } +void ArrayLiteralNode::log(int indent) { + std::cout << jsonIndent(indent) << "ArrayLiteral [" << elements.size() << " eleman]\n"; + for (auto* e : elements) e->log(indent + 1); +} +std::string ArrayLiteralNode::toJson(int depth) { + JsonObject obj(depth); + obj.add("kind", "ArrayLiteral"); + obj.addArray("elements", [&]() { + for (auto* e : elements) obj.addItem(e->toJson(depth + 2)); + }); + obj.addRaw("resolvedType", resolvedTypeJson()); + obj.addRaw("location", loc.toJson()); + return obj.str(); +} + // IndexExpressionNode IndexExpressionNode::IndexExpressionNode() { kind = ASTKind::IndexExpression; } void IndexExpressionNode::log(int indent) { diff --git a/src/parser/nodes/expressions.hpp b/src/parser/nodes/expressions.hpp index 731a6a3..8cdad0d 100644 --- a/src/parser/nodes/expressions.hpp +++ b/src/parser/nodes/expressions.hpp @@ -8,6 +8,7 @@ public: ASTNode* operand = nullptr; TokenType Operator; PostfixNode(); + ~PostfixNode() override { delete operand; } void log(int indent = 0) override; std::string toJson(int depth = 0) override; }; @@ -17,6 +18,7 @@ public: ASTNode* callee = nullptr; std::vector arguments; CallExpressionNode(); + ~CallExpressionNode() override { delete callee; for (auto* a : arguments) delete a; } void log(int indent = 0) override; std::string toJson(int depth = 0) override; }; @@ -27,6 +29,7 @@ public: std::string member; bool arrow = false; MemberAccessNode(); + ~MemberAccessNode() override { delete object; } void log(int indent = 0) override; std::string toJson(int depth = 0) override; }; @@ -36,6 +39,16 @@ public: ASTNode* object = nullptr; ASTNode* index = nullptr; IndexExpressionNode(); + ~IndexExpressionNode() override { delete object; delete index; } + void log(int indent = 0) override; + std::string toJson(int depth = 0) override; +}; + +class ArrayLiteralNode : public ExpressionNode { +public: + std::vector elements; + ArrayLiteralNode(); + ~ArrayLiteralNode() override { for (auto* e : elements) delete e; } void log(int indent = 0) override; std::string toJson(int depth = 0) override; }; diff --git a/src/parser/nodes/identifier.cpp b/src/parser/nodes/identifier.cpp index f2286de..f30b3b7 100644 --- a/src/parser/nodes/identifier.cpp +++ b/src/parser/nodes/identifier.cpp @@ -1,6 +1,5 @@ #include "parser/nodes/identifier.hpp" #include -#include #include "parser/ast_json.hpp" IdentifierNode::IdentifierNode() { kind = ASTKind::Identifier; } @@ -11,14 +10,10 @@ void IdentifierNode::log(int indent) { } std::string IdentifierNode::toJson(int depth) { - std::string in = jsonIndent(depth); - std::string name = parserToken.token ? parserToken.token->token : "?"; - std::ostringstream ss; - ss << "{\n" - << in << " \"kind\": \"Identifier\",\n" - << in << " \"name\": \"" << jsonEscape(name) << "\",\n" - << in << " \"resolvedType\": " << resolvedTypeJson() << ",\n" - << in << " \"location\": " << loc.toJson() << "\n" - << in << "}"; - return ss.str(); + JsonObject obj(depth); + obj.add("kind", "Identifier"); + obj.add("name", parserToken.token ? parserToken.token->token : "?"); + obj.addRaw("resolvedType", resolvedTypeJson()); + obj.addRaw("location", loc.toJson()); + return obj.str(); } diff --git a/src/parser/nodes/literal.cpp b/src/parser/nodes/literal.cpp index 4b9db1e..73d8983 100644 --- a/src/parser/nodes/literal.cpp +++ b/src/parser/nodes/literal.cpp @@ -1,6 +1,5 @@ #include "parser/nodes/literal.hpp" #include -#include #include "parser/ast_json.hpp" LiteralNode::LiteralNode() { kind = ASTKind::Literal; } @@ -18,22 +17,17 @@ void LiteralNode::log(int indent) { } std::string LiteralNode::toJson(int depth) { - std::string in = jsonIndent(depth); std::string val = hasDirectValue ? std::to_string(directIntValue) : (parserToken.token ? parserToken.token->token : "?"); - std::ostringstream ss; - ss << "{\n" - << in << " \"kind\": \"Literal\",\n" - << in << " \"literalType\": \"" << literalTypeToString(literalType) << "\",\n" - << in << " \"value\": \"" << jsonEscape(val) << "\""; - if (literalType == LiteralType::INTEGER && literalBase != 10) { - ss << ",\n" << in << " \"base\": " << literalBase; - } - if (literalType == LiteralType::FLOAT) { - ss << ",\n" << in << " \"isFloat\": true"; - } - ss << ",\n" << in << " \"resolvedType\": " << resolvedTypeJson(); - ss << ",\n" << in << " \"location\": " << loc.toJson() << "\n" - << in << "}"; - return ss.str(); + JsonObject obj(depth); + obj.add("kind", "Literal"); + obj.add("literalType", literalTypeToString(literalType)); + obj.add("value", val); + if (literalType == LiteralType::INTEGER && literalBase != 10) + obj.add("base", literalBase); + if (literalType == LiteralType::FLOAT) + obj.add("isFloat", true); + obj.addRaw("resolvedType", resolvedTypeJson()); + obj.addRaw("location", loc.toJson()); + return obj.str(); } diff --git a/src/parser/nodes/statements.cpp b/src/parser/nodes/statements.cpp index a395bbe..dc29dad 100644 --- a/src/parser/nodes/statements.cpp +++ b/src/parser/nodes/statements.cpp @@ -147,3 +147,36 @@ std::string ExpressionStatementNode::toJson(int depth) { obj.addRaw("location", loc.toJson()); return obj.str(); } + +// TryStatementNode (ADR-025) +TryStatementNode::TryStatementNode() { kind = ASTKind::TryStatement; } +void TryStatementNode::log(int indent) { + std::cout << jsonIndent(indent) << "TryStatement (catch " << catchVar << ")\n"; + if (body) body->log(indent + 1); + if (handler) handler->log(indent + 1); +} +std::string TryStatementNode::toJson(int depth) { + JsonObject obj(depth); + obj.add("kind", "TryStatement"); + obj.add("catchVar", catchVar); + if (body) obj.addRaw("body", body->toJson(depth + 1)); + if (handler) obj.addRaw("handler", handler->toJson(depth + 1)); + obj.add("isReachable", isReachable); + obj.addRaw("location", loc.toJson()); + return obj.str(); +} + +// ThrowStatementNode (ADR-025) +ThrowStatementNode::ThrowStatementNode() { kind = ASTKind::ThrowStatement; } +void ThrowStatementNode::log(int indent) { + std::cout << jsonIndent(indent) << "ThrowStatement\n"; + if (value) value->log(indent + 1); +} +std::string ThrowStatementNode::toJson(int depth) { + JsonObject obj(depth); + obj.add("kind", "ThrowStatement"); + if (value) obj.addRaw("value", value->toJson(depth + 1)); + obj.add("isReachable", isReachable); + obj.addRaw("location", loc.toJson()); + return obj.str(); +} diff --git a/src/parser/nodes/statements.hpp b/src/parser/nodes/statements.hpp index 5b68b49..6f58612 100644 --- a/src/parser/nodes/statements.hpp +++ b/src/parser/nodes/statements.hpp @@ -16,6 +16,7 @@ public: ASTNode* thenBranch = nullptr; ASTNode* elseBranch = nullptr; IfStatementNode(); + ~IfStatementNode() override { delete condition; delete thenBranch; delete elseBranch; } void log(int indent = 0) override; std::string toJson(int depth = 0) override; }; @@ -25,6 +26,7 @@ public: ASTNode* condition = nullptr; ASTNode* body = nullptr; WhileStatementNode(); + ~WhileStatementNode() override { delete condition; delete body; } void log(int indent = 0) override; std::string toJson(int depth = 0) override; }; @@ -36,6 +38,7 @@ public: ASTNode* update = nullptr; ASTNode* body = nullptr; ForStatementNode(); + ~ForStatementNode() override { delete init; delete condition; delete update; delete body; } void log(int indent = 0) override; std::string toJson(int depth = 0) override; }; @@ -45,6 +48,7 @@ public: ASTNode* condition = nullptr; ASTNode* body = nullptr; DoWhileStatementNode(); + ~DoWhileStatementNode() override { delete body; delete condition; } void log(int indent = 0) override; std::string toJson(int depth = 0) override; }; @@ -53,6 +57,7 @@ class ReturnStatementNode : public StatementNode { public: ASTNode* value = nullptr; ReturnStatementNode(); + ~ReturnStatementNode() override { delete value; } void log(int indent = 0) override; std::string toJson(int depth = 0) override; }; @@ -75,6 +80,29 @@ class ExpressionStatementNode : public StatementNode { public: ASTNode* expression = nullptr; ExpressionStatementNode(); + ~ExpressionStatementNode() override { delete expression; } + void log(int indent = 0) override; + std::string toJson(int depth = 0) override; +}; + +// ADR-025: try { body } catch (Error catchVar) { handler } +class TryStatementNode : public StatementNode { +public: + ASTNode* body = nullptr; + std::string catchVar; // catch değişken adı (ör. "e") + ASTNode* handler = nullptr; + TryStatementNode(); + ~TryStatementNode() override { delete body; delete handler; } + void log(int indent = 0) override; + std::string toJson(int depth = 0) override; +}; + +// ADR-025: throw ; +class ThrowStatementNode : public StatementNode { +public: + ASTNode* value = nullptr; + ThrowStatementNode(); + ~ThrowStatementNode() override { delete value; } void log(int indent = 0) override; std::string toJson(int depth = 0) override; }; diff --git a/src/parser/parser.cpp b/src/parser/parser.cpp index 714ef48..0350d87 100644 --- a/src/parser/parser.cpp +++ b/src/parser/parser.cpp @@ -85,8 +85,15 @@ ASTNode* Parser::parseDeclaration() { })) { auto la1 = lookahead(1); auto la2 = lookahead(2); + // int name( → fonksiyon if (la1.type == TokenType::IDENTIFIER && la2.type == TokenType::LPAREN) return parseFunctionDecl(); + // int? name( → nullable dönüş tipli fonksiyon (ADR-021) + if (la1.type == TokenType::TERNARY) { + auto la3 = lookahead(3); + if (la2.type == TokenType::IDENTIFIER && la3.type == TokenType::LPAREN) + return parseFunctionDecl(); + } return parseVariableDecl(); } @@ -99,6 +106,11 @@ ASTNode* Parser::parseDeclaration() { auto la2 = lookahead(2); if (la1.type == TokenType::IDENTIFIER && la2.type == TokenType::LPAREN) return parseFunctionDecl(); + if (la1.type == TokenType::TERNARY) { + auto la3 = lookahead(3); + if (la2.type == TokenType::IDENTIFIER && la3.type == TokenType::LPAREN) + return parseFunctionDecl(); + } if (la1.type == TokenType::IDENTIFIER) return parseVariableDecl(); } @@ -150,6 +162,23 @@ ASTNode* Parser::parseNullDenotation() { return expr; } + // Array literal: [expr, expr, ...] + if (ct.type == TokenType::LBRACKET) { + nextToken(); + ArrayLiteralNode* arr = new ArrayLiteralNode(); + arr->loc = ct.token ? ct.token->loc : SourceLocation{}; + if (currentToken().type != TokenType::RBRACKET) { + arr->elements.push_back(parseExpression(0)); + while (currentToken().type == TokenType::COMMA) { + nextToken(); + arr->elements.push_back(parseExpression(0)); + } + } + if (currentToken().type == TokenType::RBRACKET) + nextToken(); + return arr; + } + if (ct.is({ TokenType::PLUS_PLUS, TokenType::MINUS_MINUS, TokenType::PLUS, TokenType::MINUS, @@ -299,6 +328,10 @@ ASTNode* Parser::parseFunctionDecl() { fn->returnType = currentToken().token->token; nextToken(); + // ADR-021: nullable dönüş tipi — int? f() + if (currentToken().type == TokenType::TERNARY) + { nextToken(); fn->returnType += "?"; } + fn->name = currentToken().token->token; nextToken(); @@ -315,6 +348,16 @@ ASTNode* Parser::parseFunctionDecl() { if (!isTypeKw || !typeTok.token) break; std::string paramType = typeTok.token->token; nextToken(); + // int[] a — tip sonrasında [] varsa array tipi + if (currentToken().type == TokenType::LBRACKET) { + nextToken(); + if (currentToken().type == TokenType::RBRACKET) + nextToken(); + paramType += "[]"; + } + // ADR-021: nullable parametre — int? a + if (currentToken().type == TokenType::TERNARY) + { nextToken(); paramType += "?"; } if (currentToken().type != TokenType::IDENTIFIER || !currentToken().token) break; VariableDeclNode* param = new VariableDeclNode(); param->loc = currentToken().token->loc; @@ -364,6 +407,18 @@ ASTNode* Parser::parseVariableDecl() { vd->varType = currentToken().token->token; nextToken(); + // Java/C# stili: int[] x — tip adından hemen sonra [] gelir + if (currentToken().type == TokenType::LBRACKET) { + nextToken(); + if (currentToken().type == TokenType::RBRACKET) + nextToken(); + vd->varType += "[]"; + } + + // ADR-021: nullable soneki — int? x + if (currentToken().type == TokenType::TERNARY) + { nextToken(); vd->varType += "?"; } + if (currentToken().type != TokenType::IDENTIFIER) { std::cerr << "Parser hatası: değişken ismi bekleniyor\n"; return vd; @@ -372,6 +427,7 @@ ASTNode* Parser::parseVariableDecl() { vd->name = currentToken().token->token; nextToken(); + // C stili: int x[] — geriye dönük uyumluluk (postfix []) if (currentToken().type == TokenType::LBRACKET) { nextToken(); while (currentToken().type != TokenType::RBRACKET && @@ -380,6 +436,7 @@ ASTNode* Parser::parseVariableDecl() { nextToken(); if (currentToken().type == TokenType::RBRACKET) nextToken(); + if (vd->varType.back() != ']') vd->varType += "[]"; } if (currentToken().type == TokenType::EQUAL) { @@ -452,6 +509,12 @@ ASTNode* Parser::parseStatement() { if (ct.type == TokenType::KW_CONTINUE) return parseContinueStatement(); + if (ct.type == TokenType::KW_TRY) + return parseTryStatement(); + + if (ct.type == TokenType::KW_THROW) + return parseThrowStatement(); + if (ct.is({ TokenType::KW_VOID, TokenType::KW_INT, TokenType::KW_FLOAT_TYPE, TokenType::KW_DOUBLE, TokenType::KW_BOOL, TokenType::KW_CHAR, @@ -463,6 +526,15 @@ ASTNode* Parser::parseStatement() { if (ct.type == TokenType::KW_STRUCT) return parseStructDecl(); + // Kullanıcı tanımlı struct tipiyle değişken bildirimi: Point p; veya Point p = ...; + if (ct.type == TokenType::IDENTIFIER) { + auto la1 = lookahead(1); + // "TypeName varName" veya "TypeName varName = ..." → değişken bildirimi + // (TypeName LPAREN → ifade; o durumda parseExpressionStatement devam eder) + if (la1.type == TokenType::IDENTIFIER) + return parseVariableDecl(); + } + return parseExpressionStatement(); } @@ -627,3 +699,43 @@ ASTNode* Parser::parseExpressionStatement() { return es; } + +// ADR-025: try { body } catch (Error catchVar) { handler } +ASTNode* Parser::parseTryStatement() { + TryStatementNode* ts = new TryStatementNode(); + ts->loc = currentToken().token->loc; + nextToken(); // tüket: try + + ts->body = parseBlock(); + + // catch (Error e) + if (currentToken().type == TokenType::KW_CATCH) { + nextToken(); // tüket: catch + if (currentToken().type == TokenType::LPAREN) + nextToken(); // tüket: ( + // "Error" tip adını atla + if (currentToken().type == TokenType::IDENTIFIER || + currentToken().type == TokenType::KW_STRING_TYPE) + nextToken(); // tüket: Error (ya da herhangi bir tip adı) + // catch değişken adını al + if (currentToken().type == TokenType::IDENTIFIER && currentToken().token) + ts->catchVar = currentToken().token->token; + nextToken(); // tüket: değişken adı + if (currentToken().type == TokenType::RPAREN) + nextToken(); // tüket: ) + ts->handler = parseBlock(); + } + + return ts; +} + +// ADR-025: throw ; +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; +} diff --git a/src/parser/parser_base.hpp b/src/parser/parser_base.hpp index 838910f..96e9864 100644 --- a/src/parser/parser_base.hpp +++ b/src/parser/parser_base.hpp @@ -51,6 +51,8 @@ private: ASTNode* parseBreakStatement(); ASTNode* parseContinueStatement(); ASTNode* parseExpressionStatement(); + ASTNode* parseTryStatement(); + ASTNode* parseThrowStatement(); // --- İfadeler (Pratt parser) --- ASTNode* parseExpression(); diff --git a/src/semantic/type_checker.cpp b/src/semantic/type_checker.cpp index f037b53..61f94f3 100644 --- a/src/semantic/type_checker.cpp +++ b/src/semantic/type_checker.cpp @@ -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 TypeChecker::extractNullCheck(ASTNode* cond) { + if (!cond || cond->kind != ASTKind::BinaryExpression) return {"", false}; + auto* bin = (BinaryExpressionNode*)cond; + bool isNE = (bin->Operator == TokenType::BANG_EQUAL); + bool isEE = (bin->Operator == TokenType::EQUAL_EQUAL); + if (!isNE && !isEE) return {"", false}; + + // Hangi taraf null literal? + auto isNullLit = [](ASTNode* n) -> bool { + if (!n || n->kind != ASTKind::Literal) return false; + return ((LiteralNode*)n)->literalType == LiteralType::BOŞ; + }; + auto identName = [](ASTNode* n) -> std::string { + if (!n || n->kind != ASTKind::Identifier) return ""; + auto* id = (IdentifierNode*)n; + return id->parserToken.token ? id->parserToken.token->token : ""; + }; + + std::string var; + if (isNullLit(bin->Right)) var = identName(bin->Left); + else if (isNullLit(bin->Left)) var = identName(bin->Right); + if (var.empty()) return {"", false}; + return {var, isNE}; // isNE=true → "a != null"; false → "a == null" +} + +// ADR-021: guard pattern — bu statement her zaman çıkış yapıyor mu? +bool TypeChecker::alwaysExits(ASTNode* stmt) { + if (!stmt) return false; + switch (stmt->kind) { + case ASTKind::ReturnStatement: + case ASTKind::ThrowStatement: + case ASTKind::BreakStatement: + case ASTKind::ContinueStatement: + return true; + case ASTKind::Block: { + auto& ch = stmt->getChildren(); + return !ch.empty() && alwaysExits(ch.back()); + } + default: return false; + } +} + // ───────────────────────────────────────────────────────────────────────────── // check — giriş noktası // ───────────────────────────────────────────────────────────────────────────── @@ -62,21 +106,41 @@ bool TypeChecker::checkAssign(const Type& target, const Type& src, const SourceLocation& loc, const std::string& ctx) { if (target.isError() || src.isError()) return true; // önceki hata, sessiz geç - if (target.equals(src)) return true; + + // ADR-021: null literal ataması + if (src.isNullLiteral()) { + if (target.nullable) return true; // T? ← null → OK + diag_.report("E003", loc, + "'" + ctx + "': null non-null tipine (" + target.toString() + ") atanamaz"); + return false; + } + + // ADR-021: nullable uyumu + // T? ← T → OK (widening: non-null, nullable'a gider) + // T ← T? → E (narrowing: nullable, non-null'a gidemez; narrowing gerekli) + if (src.nullable && !target.nullable && src.equalsBase(target)) { + diag_.report("E003", loc, + "'" + ctx + "': " + src.toString() + + " nullable tipi non-null " + target.toString() + " tipine atanamaz" + " (if ile null kontrolü yapın)"); + return false; + } + // T? ← T → OK (equalsBase eşleşiyorsa, nullable farkı widening) + if (!src.nullable && target.nullable && src.equalsBase(target)) return true; + + if (target.equals(src)) return true; int tRank = numericRank(target); int sRank = numericRank(src); if (tRank >= 0 && sRank >= 0) { if (tRank > sRank) { - // Genişletme (widening): int→float, int→double, float→double - if (srcIsLiteral) return true; // literal bağlama-göre tiplenir, uyarısız + if (srcIsLiteral) return true; diag_.report("W004", loc, "'" + ctx + "': " + src.toString() + " → " + target.toString() + " örtük genişletme"); return true; } else { - // Daraltma (narrowing): float→int, double→float, vb. diag_.report("E003", loc, "'" + ctx + "': " + src.toString() + " → " + target.toString() + " daraltma (veri kaybı)"); @@ -84,7 +148,6 @@ bool TypeChecker::checkAssign(const Type& target, const Type& src, } } - // Tamamen farklı tipler diag_.report("E003", loc, "'" + ctx + "': " + src.toString() + " tipi " + target.toString() + " tipine atanamaz"); @@ -100,13 +163,32 @@ void TypeChecker::checkStmt(ASTNode* node) { switch (node->kind) { - case ASTKind::Block: - for (ASTNode* child : node->getChildren()) checkStmt(child); + case ASTKind::Block: { + // ADR-021: guard/sıralı narrowing — if (a == null) return; → sonrasında a non-null + std::vector guardNarrowed; // bu blokta guard'la daraltılanlar + for (ASTNode* child : node->getChildren()) { + checkStmt(child); + // guard kontrolü: if (a == null) { return/throw/break/continue; } + if (child->kind == ASTKind::IfStatement) { + auto* ifn = (IfStatementNode*)child; + if (!ifn->elseBranch && ifn->thenBranch && alwaysExits(ifn->thenBranch)) { + auto [var, isNotNull] = extractNullCheck(ifn->condition); + if (!var.empty() && !isNotNull) { // "a == null" → guard + narrowedNonNull_.insert(var); + guardNarrowed.push_back(var); + } + } + } + } + for (auto& v : guardNarrowed) narrowedNonNull_.erase(v); break; + } case ASTKind::VariableDecl: { auto* vd = (VariableDeclNode*)node; Type targetType = Type::fromName(vd->varType); + if (targetType.isError() && table_.structLayouts.count(vd->varType)) + targetType = Type::structType(vd->varType); if (vd->initExpr) { Type srcType = checkExpr(vd->initExpr, targetType); bool isLit = vd->initExpr->kind == ASTKind::Literal; @@ -142,9 +224,23 @@ void TypeChecker::checkStmt(ASTNode* node) { case ASTKind::IfStatement: { auto* ifn = (IfStatementNode*)node; - if (ifn->condition) checkExpr(ifn->condition); + if (ifn->condition) checkExpr(ifn->condition); + + // ADR-021: nested narrowing — if (a != null) { a non-null } else { a null } + auto [narrowVar, isNotNull] = extractNullCheck(ifn->condition); + + if (!narrowVar.empty() && isNotNull) // "a != null" → then'de non-null + narrowedNonNull_.insert(narrowVar); if (ifn->thenBranch) checkStmt(ifn->thenBranch); + if (!narrowVar.empty() && isNotNull) + narrowedNonNull_.erase(narrowVar); + + if (!narrowVar.empty() && !isNotNull) // "a == null" → else'de non-null + narrowedNonNull_.insert(narrowVar); if (ifn->elseBranch) checkStmt(ifn->elseBranch); + if (!narrowVar.empty() && !isNotNull) + narrowedNonNull_.erase(narrowVar); + break; } @@ -178,6 +274,21 @@ void TypeChecker::checkStmt(ASTNode* node) { case ASTKind::ContinueStatement: break; // yapısal doğrulama StructuralValidator'ın işi + // ADR-025: try { body } catch (Error e) { handler } + case ASTKind::TryStatement: { + auto* ts = (TryStatementNode*)node; + if (ts->body) checkStmt(ts->body); + if (ts->handler) checkStmt(ts->handler); + break; + } + + // ADR-025: throw ; — unchecked, herhangi bir değer atılabilir + case ASTKind::ThrowStatement: { + auto* th = (ThrowStatementNode*)node; + if (th->value) checkExpr(th->value); + break; + } + default: break; } @@ -220,7 +331,14 @@ Type TypeChecker::checkExpr(ASTNode* node, const Type& expected) { break; case LiteralType::BOOLEAN: result = Type::Bool(); break; case LiteralType::STRING: result = Type::String(); break; - default: result = Type::error(); break; + case LiteralType::BOŞ: + // null literal: bağlam nullable ise o tip, değilse Void+nullable (null sentinel) + if (!expected.isError() && expected.nullable) + result = expected; + else + result = Type::Void().asNullable(); // null sentinel + break; + default: result = Type::error(); break; } break; } @@ -229,6 +347,12 @@ Type TypeChecker::checkExpr(ASTNode* node, const Type& expected) { case ASTKind::Identifier: { auto* id = (IdentifierNode*)node; result = id->resolvedSymbol ? id->resolvedSymbol->type : Type::error(); + // ADR-021: narrowing — bu değişken null kontrolünden geçtiyse non-null say + if (result.nullable && id->parserToken.token) { + std::string name = id->parserToken.token->token; + if (narrowedNonNull_.count(name)) + result = result.asNonNull(); + } break; } @@ -265,23 +389,68 @@ Type TypeChecker::checkExpr(ASTNode* node, const Type& expected) { } Type leftType = checkExpr(bin->Left); - Type rightType = checkExpr(bin->Right); - // Mantıksal - if (bin->Operator == TokenType::AMPERSAND_AMPERSAND || - bin->Operator == TokenType::PIPE_PIPE) { + // ADR-021: && kısa-devre sağ taraf narrowing — "a != null && a.field" + if (bin->Operator == TokenType::AMPERSAND_AMPERSAND) { + auto [narrowVar, isNotNull] = extractNullCheck(bin->Left); + if (!narrowVar.empty() && isNotNull) + narrowedNonNull_.insert(narrowVar); + checkExpr(bin->Right); + if (!narrowVar.empty() && isNotNull) + narrowedNonNull_.erase(narrowVar); result = Type::Bool(); break; } - // Karşılaştırma - if (bin->Operator == TokenType::EQUAL_EQUAL || - bin->Operator == TokenType::BANG_EQUAL || - bin->Operator == TokenType::LESS || + Type rightType = checkExpr(bin->Right); + + // Mantıksal (||) + if (bin->Operator == TokenType::PIPE_PIPE) { + result = Type::Bool(); + break; + } + + // Eşitlik karşılaştırması: string dahil herhangi tiple çalışır + if (bin->Operator == TokenType::EQUAL_EQUAL || + bin->Operator == TokenType::BANG_EQUAL) { + result = Type::Bool(); + break; + } + + // Sıralama karşılaştırması: YALNIZCA sayısal tipler + if (bin->Operator == TokenType::LESS || bin->Operator == TokenType::LESS_EQUAL || bin->Operator == TokenType::GREATER || bin->Operator == TokenType::GREATER_EQUAL) { - result = Type::Bool(); + if (leftType.isError() || rightType.isError()) { + result = Type::error(); // önceki hata, sessiz geç + } else if (leftType.isNumeric() && rightType.isNumeric()) { + result = Type::Bool(); + } else { + diag_.report("E003", bin->loc, + "Sıralama operatörü yalnızca sayısal tiplerle kullanılabilir: " + + leftType.toString() + + " — string için yalnızca == ve != kullanın"); + result = Type::error(); + } + break; + } + + // ADR-021: katı operand kuralı — non-null bağlamda nullable operand yasak + // (eşitlik / null karşılaştırmaları için geçerli değil) + if (!leftType.isError() && !rightType.isError() && + (leftType.nullable || rightType.nullable)) { + diag_.report("E003", bin->loc, + "Nullable operand: '" + leftType.toString() + "' ve '" + + rightType.toString() + "' — null kontrolü yapın veya daraltın"); + result = Type::error(); + break; + } + + // String birleştirme: yalnızca + operatörü (ADR-024) + if (bin->Operator == TokenType::PLUS && + leftType.isString() && rightType.isString()) { + result = Type::String(); break; } @@ -359,15 +528,34 @@ Type TypeChecker::checkExpr(ASTNode* node, const Type& expected) { // ── MemberAccess / IndexExpression ───────────────────────────────────── case ASTKind::MemberAccess: { auto* ma = (MemberAccessNode*)node; - checkExpr(ma->object); - result = Type::error(); // TODO(faz3+): struct alan çözümü + Type objType = checkExpr(ma->object); + // ADR-021: nullable nesne üstünde doğrudan alan erişimi yasak + if (objType.nullable) { + diag_.report("E003", node->loc, + "Nullable tip '" + objType.toString() + "' üstünde doğrudan erişim" + " — if ile null kontrolü yapın"); + result = Type::error(); + break; + } + if (objType.isStruct()) { + result = table_.getFieldType(objType.structName, ma->member); + if (result.isError()) + diag_.report("E001", node->loc, + "'" + objType.structName + "' struct'ında '" + ma->member + "' alanı yok"); + } else { + result = Type::error(); + } break; } case ASTKind::IndexExpression: { auto* ie = (IndexExpressionNode*)node; - checkExpr(ie->object); + Type objType = checkExpr(ie->object); if (ie->index) checkExpr(ie->index); - result = Type::error(); // TODO(faz3+): array eleman tipi + // array eleman tipi + if (objType.isArray() && objType.elementType) + result = *objType.elementType; + else + result = Type::Int(); // varsayılan (tip çıkarımı tam değil) break; } diff --git a/src/semantic/type_checker.hpp b/src/semantic/type_checker.hpp index cc7febf..47552b6 100644 --- a/src/semantic/type_checker.hpp +++ b/src/semantic/type_checker.hpp @@ -1,6 +1,8 @@ #ifndef SAQUT_SEMANTIC_TYPE_CHECKER #define SAQUT_SEMANTIC_TYPE_CHECKER +#include +#include #include "symbol/symbol_table.hpp" #include "diagnostic/diagnostic_engine.hpp" #include "parser/ast_node.hpp" @@ -31,11 +33,20 @@ private: // İki sayısal tipin genişlik sırası: int=0, float=1, double=2; -1 = sayısal değil. static int numericRank(const Type& t); + // ADR-021: if-narrowing — null kontrolü kalıbını ayrıştır + // Dönüş: {varName, isNotNull} — "a != null" → {a, true}; "a == null" → {a, false}; {"", _} = kalıp yok + static std::pair extractNullCheck(ASTNode* cond); + // Bir statement her zaman çıkış yapıyor mu? (return/throw/break/continue) + static bool alwaysExits(ASTNode* stmt); + SymbolTable& table_; DiagnosticEngine& diag_; Type currentReturnType_; // aktif fonksiyonun beklenen dönüş tipi bool inFunction_ = false; + + // ADR-021: akış-duyarlı null daraltma — bu kapsamda non-null olduğu bilinen değişkenler + std::unordered_set narrowedNonNull_; }; #endif // SAQUT_SEMANTIC_TYPE_CHECKER diff --git a/src/symbol/symbol_collector.cpp b/src/symbol/symbol_collector.cpp index c4295b6..a7af8be 100644 --- a/src/symbol/symbol_collector.cpp +++ b/src/symbol/symbol_collector.cpp @@ -29,6 +29,18 @@ void SymbolCollector::seedBuiltins() { Type::function(Type::Void(), {}), SourceLocation{}); if (s) s->isBuiltin = true; + + // ADR-025: Error builtin struct — try/catch için + // Alan sırası VM makeErrorValue() ile eşleşmeli: [line, col, message, trace, code] + table_.structLayouts["Error"] = { + {"line", Type::Int()}, + {"col", Type::Int()}, + {"message", Type::String()}, + {"trace", Type::String()}, + {"code", Type::String()} + }; + table_.define("Error", SymbolKind::Struct, Type::structType("Error"), {}); + structFields_["Error"]; // cycle checker'a tanıt } // ───────────────────────────────────────────────────────────────────────────── @@ -77,14 +89,15 @@ void SymbolCollector::pass1Globals(ASTNode* program) { "'" + st->name + "' zaten bu kapsamda tanımlı"); break; } - // struct alan isimlerini cycle check için kaydet + // structFields_'e her zaman bir giriş aç (typeFromName için gerekli) + structFields_[st->name]; // boş vektör oluşturur; by-value döngü artık referans semantiğiyle meşru (ADR-020) + + // structLayouts: tüm alanlar (isim + tip) sırayla — IR üreteci ve tip denetleyici için for (ASTNode* fieldNode : st->getChildren()) { if (fieldNode->kind == ASTKind::VariableDecl) { auto* vd = (VariableDeclNode*)fieldNode; - // yalnızca struct tipindeki alanları izle - Type ft = Type::fromName(vd->varType); - if (ft.isError()) // primitif değilse struct tipi olabilir - structFields_[st->name].push_back(vd->varType); + Type ft = typeFromName(vd->varType, vd->loc); + table_.structLayouts[st->name].push_back({vd->name, ft}); } } break; @@ -124,44 +137,10 @@ void SymbolCollector::pass1Globals(ASTNode* program) { // ───────────────────────────────────────────────────────────────────────────── void SymbolCollector::checkStructCycles() { - // white=0 / gray=1 / black=2 - std::unordered_map color; - for (auto& kv : structFields_) color[kv.first] = 0; - - std::function dfs = [&](const std::string& name) -> bool { - auto it = color.find(name); - if (it == color.end()) return false; // primitif / bilinmeyen → çevrim değil - if (it->second == 1) return true; // gray → back-edge → çevrim! - if (it->second == 2) return false; // black → zaten işlendi - - it->second = 1; // gri yap - auto fit = structFields_.find(name); - if (fit != structFields_.end()) { - for (const std::string& dep : fit->second) { - if (dfs(dep)) return true; - } - } - it->second = 2; // siyah yap - return false; - }; - - for (auto& kv : structFields_) { - if (color[kv.first] == 0) { - // DFS başlat - color[kv.first] = 1; - for (const std::string& dep : kv.second) { - if (dfs(dep)) { - // tanımlama konumunu bulmak için global scope'ta ara - Symbol* s = table_.global()->lookupLocal(kv.first); - SourceLocation loc = s ? s->definitionLoc : SourceLocation{}; - diag_.report("E010", loc, - "Döngüsel struct: '" + kv.first + "' by-value sonsuz boyut oluşturur"); - break; - } - } - color[kv.first] = 2; - } - } + // ADR-020: Struct alanları referans semantiği taşır (Object* pointer). + // By-value gömme yok → sonsuz-boyut döngüsü imkânsız. + // E010 artık üretilmez; bu metot koşullu olarak devre dışı. + // TODO(gelecek): Primitive tipler için by-value gömme eklenirse E010 geri açılır. } // ───────────────────────────────────────────────────────────────────────────── @@ -306,6 +285,29 @@ void SymbolCollector::walkStmt(ASTNode* node) { case ASTKind::ContinueStatement: break; // yaprak + // ADR-025: try { body } catch (Error e) { handler } + case ASTKind::TryStatement: { + auto* ts = (TryStatementNode*)node; + if (ts->body) walkStmt(ts->body); + // catch değişkeni catch bloğu kapsamında görünür + if (ts->handler) { + table_.enterScope(); + if (!ts->catchVar.empty()) + table_.define(ts->catchVar, SymbolKind::Variable, + Type::structType("Error"), {}); + walkStmt(ts->handler); + table_.exitScope(); + } + break; + } + + // ADR-025: throw ; + case ASTKind::ThrowStatement: { + auto* th = (ThrowStatementNode*)node; + if (th->value) walkExpr(th->value); + break; + } + default: break; } diff --git a/src/symbol/symbol_table.hpp b/src/symbol/symbol_table.hpp index 8ff6624..996c441 100644 --- a/src/symbol/symbol_table.hpp +++ b/src/symbol/symbol_table.hpp @@ -3,6 +3,7 @@ #include #include +#include #include "symbol/scope.hpp" class SymbolTable { @@ -50,6 +51,26 @@ public: return result; } + // Struct alan düzeni: struct adı → sıralı [(alan adı, tip)] listesi + // Sembol toplayıcı doldurur; tip denetleyici ve IR üreteci okur. + std::unordered_map>> structLayouts; + + int getFieldIndex(const std::string& structName, const std::string& fieldName) const { + auto it = structLayouts.find(structName); + if (it == structLayouts.end()) return -1; + for (int i = 0; i < (int)it->second.size(); i++) + if (it->second[i].first == fieldName) return i; + return -1; + } + + Type getFieldType(const std::string& structName, const std::string& fieldName) const { + auto it = structLayouts.find(structName); + if (it == structLayouts.end()) return Type::error(); + for (auto& p : it->second) + if (p.first == fieldName) return p.second; + return Type::error(); + } + private: Scope* newScope(Scope* p) { scopes_.push_back(std::make_unique(p)); diff --git a/src/vm/interpreter.cpp b/src/vm/interpreter.cpp index be466c2..60071b2 100644 --- a/src/vm/interpreter.cpp +++ b/src/vm/interpreter.cpp @@ -1,8 +1,26 @@ #include "vm/interpreter.hpp" +#include "vm/object.hpp" #include #include +// ── makeErrorValue ───────────────────────────────────────────────────────────── +// ADR-025: Error struct oluşturur — alan sırası: [line, col, message, trace, code] +Value Interpreter::makeErrorValue(const std::string& message, + const std::string& code, + int line, int col) { + StructObject* obj = heap_.allocStruct(5); + obj->fields[0] = Value::fromInt(line); + obj->fields[1] = Value::fromInt(col); + obj->fields[2] = Value::fromString(message); + obj->fields[3] = Value::fromString(""); // trace — ileride IR satır tablosuyla doldurulacak + obj->fields[4] = Value::fromString(code); + return Value::fromRef(obj); +} + int Interpreter::run() { + // Global slot'ları sıfırla + globalSlots_.assign(program_.globalCount, Value::fromInt(0)); + IRFunction* mainFunction = program_.findFunction("main"); if (!mainFunction) throw std::runtime_error("Çalışma hatası: 'main' fonksiyonu bulunamadı"); @@ -38,6 +56,10 @@ int Interpreter::run() { frame.slots[instr.dest] = Value::fromString(instr.stringValue); break; + case Opcode::LOAD_NULL: + frame.slots[instr.dest] = Value::null(); + break; + case Opcode::LOAD_SLOT: frame.slots[instr.dest] = frame.slots[instr.src]; break; @@ -59,17 +81,46 @@ int Interpreter::run() { break; case Opcode::DIV: { int d = frame.slots[instr.right].intValue; - if (d == 0) throw std::runtime_error("Çalışma hatası: sıfıra bölme"); + if (d == 0) { pendingThrow_ = makeErrorValue("Sıfıra bölme", "E_DIVZERO"); break; } frame.slots[instr.dest] = Value::fromInt(frame.slots[instr.left].intValue / d); break; } case Opcode::MOD: { int d = frame.slots[instr.right].intValue; - if (d == 0) throw std::runtime_error("Çalışma hatası: sıfıra bölme (mod)"); + if (d == 0) { pendingThrow_ = makeErrorValue("Sıfıra bölme (mod)", "E_DIVZERO"); break; } frame.slots[instr.dest] = Value::fromInt(frame.slots[instr.left].intValue % d); break; } + // ── Bitsel ──────────────────────────────────────────────────────── + case Opcode::BAND: + frame.slots[instr.dest] = Value::fromInt( + frame.slots[instr.left].intValue & frame.slots[instr.right].intValue); + break; + case Opcode::BOR: + frame.slots[instr.dest] = Value::fromInt( + frame.slots[instr.left].intValue | frame.slots[instr.right].intValue); + break; + case Opcode::SHL: + frame.slots[instr.dest] = Value::fromInt( + frame.slots[instr.left].intValue << frame.slots[instr.right].intValue); + break; + case Opcode::SHR: + frame.slots[instr.dest] = Value::fromInt( + frame.slots[instr.left].intValue >> frame.slots[instr.right].intValue); + break; + case Opcode::BNOT: + frame.slots[instr.dest] = Value::fromInt(~frame.slots[instr.src].intValue); + break; + + // ── Global değişken erişimi ──────────────────────────────────────── + case Opcode::LOAD_GLOBAL: + frame.slots[instr.dest] = globalSlots_[instr.intValue]; + break; + case Opcode::STORE_GLOBAL: + globalSlots_[instr.intValue] = frame.slots[instr.src]; + break; + // ── Karşılaştırma ───────────────────────────────────────────────── case Opcode::LESS: frame.slots[instr.dest] = Value::fromInt( @@ -89,17 +140,25 @@ int Interpreter::run() { break; case Opcode::EQUAL_EQUAL: { auto& lv = frame.slots[instr.left]; auto& rv = frame.slots[instr.right]; - int r = (lv.kind == ValueKind::String) - ? (lv.stringValue == rv.stringValue ? 1 : 0) - : (lv.intValue == rv.intValue ? 1 : 0); + int r; + if (lv.kind == ValueKind::Ref || rv.kind == ValueKind::Ref) + r = (lv.ref == rv.ref ? 1 : 0); // ADR-023: array/struct kimlik karşılaştırması + else if (lv.kind == ValueKind::String) + r = (lv.stringValue == rv.stringValue ? 1 : 0); + else + r = (lv.intValue == rv.intValue ? 1 : 0); frame.slots[instr.dest] = Value::fromInt(r); break; } case Opcode::NOT_EQUAL: { auto& lv = frame.slots[instr.left]; auto& rv = frame.slots[instr.right]; - int r = (lv.kind == ValueKind::String) - ? (lv.stringValue != rv.stringValue ? 1 : 0) - : (lv.intValue != rv.intValue ? 1 : 0); + int r; + if (lv.kind == ValueKind::Ref || rv.kind == ValueKind::Ref) + r = (lv.ref != rv.ref ? 1 : 0); + else if (lv.kind == ValueKind::String) + r = (lv.stringValue != rv.stringValue ? 1 : 0); + else + r = (lv.intValue != rv.intValue ? 1 : 0); frame.slots[instr.dest] = Value::fromInt(r); break; } @@ -112,6 +171,10 @@ int Interpreter::run() { if (!frame.slots[instr.cond].isTruthy()) frame.instructionPointer = instr.jumpTarget; break; + case Opcode::JIF_TRUE: + if (frame.slots[instr.cond].isTruthy()) + frame.instructionPointer = instr.jumpTarget; + break; // ── Fonksiyon çağrısı ───────────────────────────────────────────── case Opcode::CALL: { @@ -148,11 +211,170 @@ int Interpreter::run() { continue; } + // ── Float aritmetik (#44) ───────────────────────────────────────── + case Opcode::LOAD_FLOAT: + frame.slots[instr.dest] = Value::fromFloat(instr.floatValue); + break; + case Opcode::FADD: + frame.slots[instr.dest] = Value::fromFloat( + frame.slots[instr.left].floatValue + frame.slots[instr.right].floatValue); + break; + case Opcode::FSUB: + frame.slots[instr.dest] = Value::fromFloat( + frame.slots[instr.left].floatValue - frame.slots[instr.right].floatValue); + break; + case Opcode::FMUL: + frame.slots[instr.dest] = Value::fromFloat( + frame.slots[instr.left].floatValue * frame.slots[instr.right].floatValue); + break; + case Opcode::FDIV: { + double r = frame.slots[instr.right].floatValue; + if (r == 0.0) { pendingThrow_ = makeErrorValue("Float sıfıra bölme", "E_DIVZERO"); break; } + frame.slots[instr.dest] = Value::fromFloat(frame.slots[instr.left].floatValue / r); + break; + } + case Opcode::FNEG: + frame.slots[instr.dest] = Value::fromFloat(-frame.slots[instr.src].floatValue); + break; + case Opcode::INT_TO_FLOAT: + frame.slots[instr.dest] = Value::fromFloat((double)frame.slots[instr.src].intValue); + break; + case Opcode::FLOAT_TO_INT: + frame.slots[instr.dest] = Value::fromInt((int)frame.slots[instr.src].floatValue); + break; + + // ── Struct (ADR-020: referans semantiği) ────────────────────────── + case Opcode::STRUCT_NEW: { + StructObject* obj = heap_.allocStruct(instr.intValue); + frame.slots[instr.dest] = Value::fromRef(obj); + break; + } + case Opcode::FIELD_GET: { + Value& objVal = frame.slots[instr.src]; + if (objVal.kind != ValueKind::Ref || !objVal.ref) + throw std::runtime_error("Çalışma hatası: struct değil"); + auto* obj = (StructObject*)objVal.ref; + int idx = instr.intValue; + if (idx < 0 || idx >= (int)obj->fields.size()) + throw std::runtime_error("Çalışma hatası: geçersiz struct alan indeksi " + std::to_string(idx)); + frame.slots[instr.dest] = obj->fields[idx]; + break; + } + case Opcode::FIELD_SET: { + Value& objVal = frame.slots[instr.dest]; + if (objVal.kind != ValueKind::Ref || !objVal.ref) + throw std::runtime_error("Çalışma hatası: struct değil"); + auto* obj = (StructObject*)objVal.ref; + int idx = instr.intValue; + if (idx < 0 || idx >= (int)obj->fields.size()) + throw std::runtime_error("Çalışma hatası: geçersiz struct alan indeksi " + std::to_string(idx)); + obj->fields[idx] = frame.slots[instr.right]; + break; + } + + // ── Array (ADR-020: referans semantiği) ─────────────────────────── + case Opcode::ARRAY_NEW: { + ArrayObject* arr = heap_.allocArray(instr.intValue); + arr->elements.resize(instr.intValue, Value::fromInt(0)); + frame.slots[instr.dest] = Value::fromRef(arr); + break; + } + case Opcode::ARRAY_GET: { + Value& arrVal = frame.slots[instr.left]; + if (arrVal.kind != ValueKind::Ref || !arrVal.ref) { + pendingThrow_ = makeErrorValue("Dizi beklendi, farklı tip alındı", "E_TYPE"); break; + } + auto* arr = (ArrayObject*)arrVal.ref; + int idx = frame.slots[instr.right].intValue; + if (idx < 0 || idx >= (int)arr->elements.size()) { + pendingThrow_ = makeErrorValue( + "Dizi sınır dışı (indeks=" + std::to_string(idx) + + ", uzunluk=" + std::to_string(arr->elements.size()) + ")", "E_OOB"); + break; + } + frame.slots[instr.dest] = arr->elements[idx]; + break; + } + case Opcode::ARRAY_SET: { + Value& arrVal = frame.slots[instr.dest]; + if (arrVal.kind != ValueKind::Ref || !arrVal.ref) { + pendingThrow_ = makeErrorValue("Dizi beklendi, farklı tip alındı", "E_TYPE"); break; + } + auto* arr = (ArrayObject*)arrVal.ref; + int idx = frame.slots[instr.left].intValue; + if (idx < 0 || idx >= (int)arr->elements.size()) { + pendingThrow_ = makeErrorValue( + "Dizi sınır dışı (indeks=" + std::to_string(idx) + + ", uzunluk=" + std::to_string(arr->elements.size()) + ")", "E_OOB"); + break; + } + arr->elements[idx] = frame.slots[instr.right]; + break; + } + case Opcode::ARRAY_LEN: { + Value& arrVal = frame.slots[instr.src]; + if (arrVal.kind != ValueKind::Ref || !arrVal.ref) + throw std::runtime_error("Çalışma hatası: dizi değil"); + auto* arr = (ArrayObject*)arrVal.ref; + frame.slots[instr.dest] = Value::fromInt((int)arr->elements.size()); + break; + } + + // ── String (ADR-024: immutable değer-tipi, içerik ==) ──────────── + case Opcode::STRING_CONCAT: + frame.slots[instr.dest] = Value::fromString( + frame.slots[instr.left].stringValue + + frame.slots[instr.right].stringValue); + break; + + // ── Hata yönetimi (ADR-025) ────────────────────────────────────── + case Opcode::ENTER_TRY: + tryStack_.push_back({callStack_.size(), instr.jumpTarget, instr.dest}); + break; + + case Opcode::LEAVE_TRY: + if (!tryStack_.empty()) tryStack_.pop_back(); + break; + + case Opcode::THROW: + pendingThrow_ = frame.slots[instr.src]; + break; + // ── FFI ─────────────────────────────────────────────────────────── case Opcode::CALLHOST: executeHostFunction(instr.functionName, frame.slots, instr.argSlots); break; } + + // ── pendingThrow_ işle: try varsa catch'e unwind, yoksa fırlat ─── + if (pendingThrow_.has_value()) { + Value errVal = std::move(*pendingThrow_); + pendingThrow_.reset(); + + if (!tryStack_.empty()) { + TryFrame tf = tryStack_.back(); + tryStack_.pop_back(); + // catch bloğunun bulunduğu frame'e unwind + while (callStack_.size() > tf.callStackDepth) + callStack_.pop_back(); + // Error'ı catch değişkenine bağla ve catch etiketine atla + callStack_.back().slots[tf.errorSlot] = errVal; + callStack_.back().instructionPointer = tf.catchTarget; + } else { + // Yakalanmamış hata — mesajı çıkar ve C++ exception olarak yükselt + std::string msg = "Yakalanmamış hata"; + if (errVal.kind == ValueKind::Ref && errVal.ref) { + auto* s = static_cast(errVal.ref); + if ((int)s->fields.size() > 2 && + s->fields[2].kind == ValueKind::String) + msg = s->fields[2].stringValue; + } else if (errVal.kind == ValueKind::String) { + msg = errVal.stringValue; + } + throw std::runtime_error(msg); + } + continue; + } } return 0; @@ -164,8 +386,7 @@ void Interpreter::executeHostFunction(const std::string& name, if (name == "print") { if (!argSlots.empty()) { const Value& val = slots[argSlots[0]]; - if (val.kind == ValueKind::String) std::cout << val.stringValue << "\n"; - else std::cout << val.intValue << "\n"; + std::cout << val.toString() << "\n"; } return; } diff --git a/src/vm/interpreter.hpp b/src/vm/interpreter.hpp index d7fb687..b2f8bb2 100644 --- a/src/vm/interpreter.hpp +++ b/src/vm/interpreter.hpp @@ -14,8 +14,17 @@ #define SAQUT_VM_INTERPRETER #include +#include #include "ir/ir_program.hpp" #include "vm/call_frame.hpp" +#include "vm/object.hpp" + +// ADR-025: try bloğu girişinde yığına eklenen kayıt +struct TryFrame { + size_t callStackDepth; // ENTER_TRY anındaki callStack_.size() — unwind için + int catchTarget; // catch bloğunun IR instruction indeksi + int errorSlot; // catch değişkeninin slot numarası (catch frame'inde) +}; class Interpreter { public: @@ -26,8 +35,17 @@ public: int run(); private: - IRProgram& program_; + IRProgram& program_; std::vector callStack_; + std::vector globalSlots_; + Heap heap_; + std::vector tryStack_; // ADR-025: aktif try çerçeveleri + std::optional pendingThrow_; // bekleyen istisna değeri + + // Error StructObject oluştur (ADR-025): [line, col, message, trace, code] + Value makeErrorValue(const std::string& message, + const std::string& code = "", + int line = 0, int col = 0); // Host (C++) fonksiyon çağrısı — şu an sadece "print" destekli void executeHostFunction(const std::string& name, diff --git a/src/vm/object.hpp b/src/vm/object.hpp new file mode 100644 index 0000000..800c176 --- /dev/null +++ b/src/vm/object.hpp @@ -0,0 +1,78 @@ +#ifndef SAQUT_VM_OBJECT +#define SAQUT_VM_OBJECT + +#include + +// 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 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 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 diff --git a/src/vm/value.hpp b/src/vm/value.hpp index 70b93df..957d0c1 100644 --- a/src/vm/value.hpp +++ b/src/vm/value.hpp @@ -1,62 +1,90 @@ -// ============================================================================ -// saQut VM — Value (Çalışma Zamanı Değer) -// -// Bir saQut değerinin bellekteki temsilidir. -// -// ŞU AN SADECE INT: -// fibonacci.sqt tamamen int kullanır, bu dikey dilim için int yeterli. -// İleride float, bool, string eklenmesi için "kind" alanı iskelet olarak bırakıldı. -// -// BOOLEAN OLARAK KULLANIM: -// JIF_FALSE talimatı değerin 0 olup olmadığına bakar. -// 0 = yanlış, sıfır-dışı = doğru. C geleneği. -// ============================================================================ - #ifndef SAQUT_VM_VALUE #define SAQUT_VM_VALUE #include +#include +#include +#include -// Gelecekte float/bool/string eklendiğinde burası genişleyecek. -// Şimdilik sadece int. +// Forward — Object tam tanımı object.hpp'de; Value onu pointer olarak taşır. +struct Object; + +// ADR-020: Primitive (int/bool) = değer; bileşik (array/struct/string) = referans. +// ADR-021: Null = nullable referansların null değeri (saQut'ta `null` anahtar sözcüğü). +// Bool ayrı kind değil — boolean sonuçlar int olarak saklanır (0=yanlış, sıfır-dışı=doğru). enum class ValueKind { Int, + Float, // #44: float/double tek kind; floatValue alanı taşır String, - // Float, // TODO(vm-genişletme) - // Bool, // TODO(vm-genişletme) + Ref, // ADR-020: array/struct nesnesine Object* referansı + Null, // ADR-021: nullable referansın null değeri (saQut kaynağında `null`) }; struct Value { ValueKind kind = ValueKind::Int; int intValue = 0; - std::string stringValue; // yalnızca kind == String için geçerli + double floatValue = 0.0; // kind == Float için + std::string stringValue; // kind == String için + Object* ref = nullptr; // kind == Ref için static Value fromInt(int n) { - Value v; - v.kind = ValueKind::Int; - v.intValue = n; - return v; + Value v; v.kind = ValueKind::Int; v.intValue = n; return v; + } + + static Value fromFloat(double d) { + Value v; v.kind = ValueKind::Float; v.floatValue = d; return v; } static Value fromString(std::string s) { - Value v; - v.kind = ValueKind::String; - v.stringValue = std::move(s); - return v; + Value v; v.kind = ValueKind::String; v.stringValue = std::move(s); return v; + } + + static Value fromRef(Object* obj) { + Value v; v.kind = ValueKind::Ref; v.ref = obj; return v; + } + + static Value null() { + Value v; v.kind = ValueKind::Null; return v; } - // JIF_FALSE için: int 0 = yanlış, boş string = yanlış, diğer = doğru bool isTruthy() const { - if (kind == ValueKind::Int) return intValue != 0; - if (kind == ValueKind::String) return !stringValue.empty(); + switch (kind) { + case ValueKind::Int: return intValue != 0; + case ValueKind::Float: return floatValue != 0.0; + case ValueKind::String: return !stringValue.empty(); + case ValueKind::Ref: return ref != nullptr; + case ValueKind::Null: return false; + } return false; } - // Okunabilir metin — dump ve hata mesajları için + std::string toString() const { + switch (kind) { + case ValueKind::Int: return std::to_string(intValue); + case ValueKind::Float: { + // Tam sayıysa "3.0", değilse "3.14" gibi — gereksiz sıfırları kırp + std::ostringstream oss; + oss << std::setprecision(10) << floatValue; + std::string s = oss.str(); + // Nokta yoksa ".0" ekle (saQut float değerleri her zaman nokta içerir) + if (s.find('.') == std::string::npos && s.find('e') == std::string::npos) + s += ".0"; + return s; + } + case ValueKind::String: return stringValue; + case ValueKind::Ref: return ""; + case ValueKind::Null: return "null"; + } + return "?"; + } + std::string typeName() const { switch (kind) { case ValueKind::Int: return "int"; + case ValueKind::Float: return "float"; case ValueKind::String: return "string"; + case ValueKind::Ref: return "ref"; + case ValueKind::Null: return "null"; } return "?"; } diff --git a/tests/golden/arithmetic/basic.expected b/tests/golden/arithmetic/basic.expected new file mode 100644 index 0000000..de628f9 --- /dev/null +++ b/tests/golden/arithmetic/basic.expected @@ -0,0 +1,5 @@ +5 +6 +12 +3 +1 diff --git a/tests/golden/arithmetic/basic.sqt b/tests/golden/arithmetic/basic.sqt new file mode 100644 index 0000000..bbd4c3d --- /dev/null +++ b/tests/golden/arithmetic/basic.sqt @@ -0,0 +1,8 @@ +int main() { + print(2 + 3); + print(10 - 4); + print(3 * 4); + print(10 / 3); + print(10 % 3); + return 0; +} diff --git a/tests/golden/arithmetic/compound_mod.expected b/tests/golden/arithmetic/compound_mod.expected new file mode 100644 index 0000000..9efd8d1 --- /dev/null +++ b/tests/golden/arithmetic/compound_mod.expected @@ -0,0 +1,4 @@ +2 +1 +0 +2 diff --git a/tests/golden/arithmetic/compound_mod.sqt b/tests/golden/arithmetic/compound_mod.sqt new file mode 100644 index 0000000..05a8172 --- /dev/null +++ b/tests/golden/arithmetic/compound_mod.sqt @@ -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; +} diff --git a/tests/golden/arithmetic/mod_by_zero.runtime_error b/tests/golden/arithmetic/mod_by_zero.runtime_error new file mode 100644 index 0000000..db826d9 --- /dev/null +++ b/tests/golden/arithmetic/mod_by_zero.runtime_error @@ -0,0 +1 @@ +sıfıra bölme \(mod\) diff --git a/tests/golden/arithmetic/mod_by_zero.sqt b/tests/golden/arithmetic/mod_by_zero.sqt new file mode 100644 index 0000000..2866db9 --- /dev/null +++ b/tests/golden/arithmetic/mod_by_zero.sqt @@ -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; +} diff --git a/tests/golden/arithmetic/precedence.expected b/tests/golden/arithmetic/precedence.expected new file mode 100644 index 0000000..7738093 --- /dev/null +++ b/tests/golden/arithmetic/precedence.expected @@ -0,0 +1,6 @@ +7 +9 +3 +3 +1 +11 diff --git a/tests/golden/arithmetic/precedence.sqt b/tests/golden/arithmetic/precedence.sqt new file mode 100644 index 0000000..c028751 --- /dev/null +++ b/tests/golden/arithmetic/precedence.sqt @@ -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; +} diff --git a/tests/golden/array/ref_semantics.expected b/tests/golden/array/ref_semantics.expected new file mode 100644 index 0000000..d4789db --- /dev/null +++ b/tests/golden/array/ref_semantics.expected @@ -0,0 +1,4 @@ +99 +1 +0 +2 diff --git a/tests/golden/array/ref_semantics.sqt b/tests/golden/array/ref_semantics.sqt new file mode 100644 index 0000000..d14d5dd --- /dev/null +++ b/tests/golden/array/ref_semantics.sqt @@ -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; +} diff --git a/tests/golden/bitwise/basic.expected b/tests/golden/bitwise/basic.expected new file mode 100644 index 0000000..26d186e --- /dev/null +++ b/tests/golden/bitwise/basic.expected @@ -0,0 +1,5 @@ +8 +14 +24 +6 +-1 diff --git a/tests/golden/bitwise/basic.sqt b/tests/golden/bitwise/basic.sqt new file mode 100644 index 0000000..6ca9317 --- /dev/null +++ b/tests/golden/bitwise/basic.sqt @@ -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; +} diff --git a/tests/golden/bitwise/compound.expected b/tests/golden/bitwise/compound.expected new file mode 100644 index 0000000..b810a1e --- /dev/null +++ b/tests/golden/bitwise/compound.expected @@ -0,0 +1,4 @@ +6 +14 +56 +28 diff --git a/tests/golden/bitwise/compound.sqt b/tests/golden/bitwise/compound.sqt new file mode 100644 index 0000000..9364d76 --- /dev/null +++ b/tests/golden/bitwise/compound.sqt @@ -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; +} diff --git a/tests/golden/error/basic_catch.expected b/tests/golden/error/basic_catch.expected new file mode 100644 index 0000000..b32216e --- /dev/null +++ b/tests/golden/error/basic_catch.expected @@ -0,0 +1,3 @@ +yakalandi +Sıfıra bölme +E_DIVZERO diff --git a/tests/golden/error/basic_catch.sqt b/tests/golden/error/basic_catch.sqt new file mode 100644 index 0000000..a9c3830 --- /dev/null +++ b/tests/golden/error/basic_catch.sqt @@ -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; +} diff --git a/tests/golden/error/throw_and_nested.expected b/tests/golden/error/throw_and_nested.expected new file mode 100644 index 0000000..e40ef42 --- /dev/null +++ b/tests/golden/error/throw_and_nested.expected @@ -0,0 +1,4 @@ +OOB yakalandi +E_OOB +throw yakalandi +devam diff --git a/tests/golden/error/throw_and_nested.sqt b/tests/golden/error/throw_and_nested.sqt new file mode 100644 index 0000000..f32fa60 --- /dev/null +++ b/tests/golden/error/throw_and_nested.sqt @@ -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; +} diff --git a/tests/golden/fibonacci/fib.expected b/tests/golden/fibonacci/fib.expected new file mode 100644 index 0000000..7a165da --- /dev/null +++ b/tests/golden/fibonacci/fib.expected @@ -0,0 +1,2 @@ +55 +55 diff --git a/tests/golden/fibonacci/fib.sqt b/tests/golden/fibonacci/fib.sqt new file mode 100644 index 0000000..860b559 --- /dev/null +++ b/tests/golden/fibonacci/fib.sqt @@ -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; +} diff --git a/tests/golden/float/basic.expected b/tests/golden/float/basic.expected new file mode 100644 index 0000000..3e6cb18 --- /dev/null +++ b/tests/golden/float/basic.expected @@ -0,0 +1,5 @@ +5.14 +6.28 +1.14 +1.57 +1.0 diff --git a/tests/golden/float/basic.sqt b/tests/golden/float/basic.sqt new file mode 100644 index 0000000..9952426 --- /dev/null +++ b/tests/golden/float/basic.sqt @@ -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; +} diff --git a/tests/golden/global/basic.expected b/tests/golden/global/basic.expected new file mode 100644 index 0000000..e191f63 --- /dev/null +++ b/tests/golden/global/basic.expected @@ -0,0 +1,3 @@ +5 +105 +8 diff --git a/tests/golden/global/basic.sqt b/tests/golden/global/basic.sqt new file mode 100644 index 0000000..2671704 --- /dev/null +++ b/tests/golden/global/basic.sqt @@ -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; +} diff --git a/tests/golden/global/init_expr.expected b/tests/golden/global/init_expr.expected new file mode 100644 index 0000000..3b86147 --- /dev/null +++ b/tests/golden/global/init_expr.expected @@ -0,0 +1,2 @@ +10 +20 diff --git a/tests/golden/global/init_expr.sqt b/tests/golden/global/init_expr.sqt new file mode 100644 index 0000000..9a4d130 --- /dev/null +++ b/tests/golden/global/init_expr.sqt @@ -0,0 +1,9 @@ +int base = 10; +int doubled = 0; + +int main() { + doubled = base * 2; + print(base); + print(doubled); + return 0; +} diff --git a/tests/golden/logic/not_operator.expected b/tests/golden/logic/not_operator.expected new file mode 100644 index 0000000..33f911e --- /dev/null +++ b/tests/golden/logic/not_operator.expected @@ -0,0 +1,5 @@ +1 +0 +1 +0 +1 diff --git a/tests/golden/logic/not_operator.sqt b/tests/golden/logic/not_operator.sqt new file mode 100644 index 0000000..ac6d93c --- /dev/null +++ b/tests/golden/logic/not_operator.sqt @@ -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; +} diff --git a/tests/golden/logic/short_circuit.expected b/tests/golden/logic/short_circuit.expected new file mode 100644 index 0000000..765931f --- /dev/null +++ b/tests/golden/logic/short_circuit.expected @@ -0,0 +1,5 @@ +S +evet_and +evet_or1 +S +evet_or2 diff --git a/tests/golden/logic/short_circuit.sqt b/tests/golden/logic/short_circuit.sqt new file mode 100644 index 0000000..71f25c3 --- /dev/null +++ b/tests/golden/logic/short_circuit.sqt @@ -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; +} diff --git a/tests/golden/loops/basic.expected b/tests/golden/loops/basic.expected new file mode 100644 index 0000000..7278d7b --- /dev/null +++ b/tests/golden/loops/basic.expected @@ -0,0 +1,9 @@ +0 +1 +2 +0 +1 +2 +0 +1 +2 diff --git a/tests/golden/loops/basic.sqt b/tests/golden/loops/basic.sqt new file mode 100644 index 0000000..aa532ad --- /dev/null +++ b/tests/golden/loops/basic.sqt @@ -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; +} diff --git a/tests/golden/loops/do_while_once.expected b/tests/golden/loops/do_while_once.expected new file mode 100644 index 0000000..7ed6ff8 --- /dev/null +++ b/tests/golden/loops/do_while_once.expected @@ -0,0 +1 @@ +5 diff --git a/tests/golden/loops/do_while_once.sqt b/tests/golden/loops/do_while_once.sqt new file mode 100644 index 0000000..8f386b8 --- /dev/null +++ b/tests/golden/loops/do_while_once.sqt @@ -0,0 +1,8 @@ +int main() { + int x = 5; + do { + print(x); + x = x + 1; + } while (x < 0); + return 0; +} diff --git a/tests/golden/loops/do_while_truthy.expected b/tests/golden/loops/do_while_truthy.expected new file mode 100644 index 0000000..e0d13b0 --- /dev/null +++ b/tests/golden/loops/do_while_truthy.expected @@ -0,0 +1,4 @@ +1 +2 +3 +5 diff --git a/tests/golden/loops/do_while_truthy.sqt b/tests/golden/loops/do_while_truthy.sqt new file mode 100644 index 0000000..83db024 --- /dev/null +++ b/tests/golden/loops/do_while_truthy.sqt @@ -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; +} diff --git a/tests/golden/loops/for_break_continue.expected b/tests/golden/loops/for_break_continue.expected new file mode 100644 index 0000000..3134c5a --- /dev/null +++ b/tests/golden/loops/for_break_continue.expected @@ -0,0 +1,5 @@ +1 +3 +5 +1 +2 diff --git a/tests/golden/loops/for_break_continue.sqt b/tests/golden/loops/for_break_continue.sqt new file mode 100644 index 0000000..961302f --- /dev/null +++ b/tests/golden/loops/for_break_continue.sqt @@ -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; +} diff --git a/tests/golden/loops/nested_break.expected b/tests/golden/loops/nested_break.expected new file mode 100644 index 0000000..570bd9e --- /dev/null +++ b/tests/golden/loops/nested_break.expected @@ -0,0 +1,6 @@ +1 +1 +2 +1 +3 +1 diff --git a/tests/golden/loops/nested_break.sqt b/tests/golden/loops/nested_break.sqt new file mode 100644 index 0000000..cf2b75c --- /dev/null +++ b/tests/golden/loops/nested_break.sqt @@ -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; +} diff --git a/tests/golden/loops/while_break_continue.expected b/tests/golden/loops/while_break_continue.expected new file mode 100644 index 0000000..f71f392 --- /dev/null +++ b/tests/golden/loops/while_break_continue.expected @@ -0,0 +1,7 @@ +1 +2 +4 +5 +1 +2 +3 diff --git a/tests/golden/loops/while_break_continue.sqt b/tests/golden/loops/while_break_continue.sqt new file mode 100644 index 0000000..34d976d --- /dev/null +++ b/tests/golden/loops/while_break_continue.sqt @@ -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; +} diff --git a/tests/golden/null/and_narrowing.expected b/tests/golden/null/and_narrowing.expected new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/tests/golden/null/and_narrowing.expected @@ -0,0 +1 @@ +1 diff --git a/tests/golden/null/and_narrowing.sqt b/tests/golden/null/and_narrowing.sqt new file mode 100644 index 0000000..5841534 --- /dev/null +++ b/tests/golden/null/and_narrowing.sqt @@ -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; +} diff --git a/tests/golden/null/narrowing.expected b/tests/golden/null/narrowing.expected new file mode 100644 index 0000000..a8e497c --- /dev/null +++ b/tests/golden/null/narrowing.expected @@ -0,0 +1,2 @@ +42 +0 diff --git a/tests/golden/null/narrowing.sqt b/tests/golden/null/narrowing.sqt new file mode 100644 index 0000000..02d4e88 --- /dev/null +++ b/tests/golden/null/narrowing.sqt @@ -0,0 +1,30 @@ +// ADR-021: akış-duyarlı null analizi +// nested + guard narrowing + +int? maybeGet(bool flag) { + if (flag) { + return 42; + } + return null; +} + +int main() { + int? a = maybeGet(true); + + // nested: if (a != null) { a non-null } + if (a != null) { + int x = a; // OK: narrowed + print(x); + } + + // guard: if (a == null) return; sonrasında a non-null + int? b = maybeGet(false); + if (b == null) { + print(0); + return 0; + } + // burada b non-null (guard geçti) + int y = b; + print(y); + return 0; +} diff --git a/tests/golden/null/nullable_assign_error.compile_error b/tests/golden/null/nullable_assign_error.compile_error new file mode 100644 index 0000000..ea41fcc --- /dev/null +++ b/tests/golden/null/nullable_assign_error.compile_error @@ -0,0 +1 @@ +E003 \ No newline at end of file diff --git a/tests/golden/null/nullable_assign_error.sqt b/tests/golden/null/nullable_assign_error.sqt new file mode 100644 index 0000000..9897cb2 --- /dev/null +++ b/tests/golden/null/nullable_assign_error.sqt @@ -0,0 +1,6 @@ +// ADR-021: nullable → non-null atama hata vermeli +int main() { + int? a = 5; + int b = a; // HATA: int? → int atanamaz + return 0; +} diff --git a/tests/golden/null/nullable_operand_error.compile_error b/tests/golden/null/nullable_operand_error.compile_error new file mode 100644 index 0000000..ea41fcc --- /dev/null +++ b/tests/golden/null/nullable_operand_error.compile_error @@ -0,0 +1 @@ +E003 \ No newline at end of file diff --git a/tests/golden/null/nullable_operand_error.sqt b/tests/golden/null/nullable_operand_error.sqt new file mode 100644 index 0000000..e11a41e --- /dev/null +++ b/tests/golden/null/nullable_operand_error.sqt @@ -0,0 +1,6 @@ +// ADR-021: nullable operand aritmetikte hata vermeli +int main() { + int? a = 5; + int b = a + 1; // HATA: a nullable + return 0; +} diff --git a/tests/golden/opt/dce.ir_opt.expected b/tests/golden/opt/dce.ir_opt.expected new file mode 100644 index 0000000..722683b --- /dev/null +++ b/tests/golden/opt/dce.ir_opt.expected @@ -0,0 +1,26 @@ +IR DUMP + +NAME=hesapla PARAMS=1 SLOTS=6 + 0 LOAD_CONST s1 = 0 + 1 GREATER s2 = s0 > s1 + 2 JIF_FALSE !s2 → 6 + 3 LOAD_CONST s3 = 2 + 4 MUL s4 = s0 * s3 + 5 RETURN s4 + 6 LOAD_CONST s5 = 0 + 7 RETURN s5 + +NAME=main PARAMS=0 SLOTS=7 + 0 LOAD_CONST s0 = 5 + 1 CALL s1 = hesapla(s0) + 2 CALLHOST print(s1) + 3 LOAD_CONST s2 = 0 + 4 CALL s3 = hesapla(s2) + 5 CALLHOST print(s3) + 6 LOAD_CONST s4 = -3 + 7 CALL s5 = hesapla(s4) + 8 CALLHOST print(s5) + 9 LOAD_CONST s6 = 0 + 10 RETURN s6 + +END diff --git a/tests/golden/opt/dce.sqt b/tests/golden/opt/dce.sqt new file mode 100644 index 0000000..30b7176 --- /dev/null +++ b/tests/golden/opt/dce.sqt @@ -0,0 +1,14 @@ +int hesapla(int n) { + if (n > 0) { + return n * 2; + print(99); + } + return 0; +} + +int main() { + print(hesapla(5)); + print(hesapla(0)); + print(hesapla(-3)); + return 0; +} diff --git a/tests/golden/opt/folding.ir_opt.expected b/tests/golden/opt/folding.ir_opt.expected new file mode 100644 index 0000000..dd47bd4 --- /dev/null +++ b/tests/golden/opt/folding.ir_opt.expected @@ -0,0 +1,21 @@ +IR DUMP + +NAME=main PARAMS=0 SLOTS=8 + 0 LOAD_CONST s0 = 14 + 1 CALLHOST print(s0) + 2 LOAD_CONST s1 = 3 + 3 CALLHOST print(s1) + 4 LOAD_CONST s2 = 1 + 5 CALLHOST print(s2) + 6 LOAD_CONST s3 = 0 + 7 CALLHOST print(s3) + 8 LOAD_CONST s4 = 1 + 9 CALLHOST print(s4) + 10 LOAD_CONST s5 = 0 + 11 CALLHOST print(s5) + 12 LOAD_CONST s6 = 1 + 13 CALLHOST print(s6) + 14 LOAD_CONST s7 = 0 + 15 RETURN s7 + +END diff --git a/tests/golden/opt/folding.sqt b/tests/golden/opt/folding.sqt new file mode 100644 index 0000000..a428d9b --- /dev/null +++ b/tests/golden/opt/folding.sqt @@ -0,0 +1,10 @@ +int main() { + print(2 + 3 * 4); + print((10 - 4) / 2); + print(1 == 1); + print(0 == 1); + print(1 + 2 == 3); + print(0 && 1); + print(1 || 0); + return 0; +} diff --git a/tests/golden/opt/run_opt.expected b/tests/golden/opt/run_opt.expected new file mode 100644 index 0000000..ed4da39 --- /dev/null +++ b/tests/golden/opt/run_opt.expected @@ -0,0 +1,4 @@ +14 +1 +0 +25 diff --git a/tests/golden/opt/run_opt.run_opt.expected b/tests/golden/opt/run_opt.run_opt.expected new file mode 100644 index 0000000..ed4da39 --- /dev/null +++ b/tests/golden/opt/run_opt.run_opt.expected @@ -0,0 +1,4 @@ +14 +1 +0 +25 diff --git a/tests/golden/opt/run_opt.sqt b/tests/golden/opt/run_opt.sqt new file mode 100644 index 0000000..e97e6e3 --- /dev/null +++ b/tests/golden/opt/run_opt.sqt @@ -0,0 +1,31 @@ +// Optimize edilmiş çalıştırmanın doğruluğunu kanıtlayan golden test. +// +// Tetiklenen optimizasyonlar: +// - Constant folding: 100 - 6*15 + 4, 3*3 + 4*4 derleme zamanında hesaplanır +// - DCE: return sonrası print(999) ve print(888) silinir +// - Folding zincirleme: iç fonksiyon çağrısı olmaksızın tüm sabit ifadeler katlanır +// +// saqut run ve saqut run --optimized AYNI çıktıyı vermeli. +// Eğer optimizasyon bir değeri yanlış katlarsa veya canlı kodu silerse bu test kırılır. + +int compute() { + int result = 100 - 6 * 15 + 4; + return result; + print(999); +} + +int classify(int n) { + if (n > 0) { + return 1; + print(888); + } + return 0; +} + +int main() { + print(compute()); + print(classify(5)); + print(classify(-3)); + print(3 * 3 + 4 * 4); + return 0; +} diff --git a/tests/golden/string/concat.expected b/tests/golden/string/concat.expected new file mode 100644 index 0000000..e33a3b7 --- /dev/null +++ b/tests/golden/string/concat.expected @@ -0,0 +1,4 @@ +Merhaba Dünya +foobar +1 +1 diff --git a/tests/golden/string/concat.sqt b/tests/golden/string/concat.sqt new file mode 100644 index 0000000..76e7a53 --- /dev/null +++ b/tests/golden/string/concat.sqt @@ -0,0 +1,24 @@ +// ADR-024: string birleştirme (+, +=) — immutable değer-tipi, içerik == + +int main() { + string a = "Merhaba"; + string b = " Dünya"; + string c = a + b; + print(c); + + string s = "foo"; + s += "bar"; + print(s); + + // İki farklı değişken, aynı içerik → true (ADR-023/024) + string x = "abc"; + string y = "abc"; + print(x == y); + + // Birleştirme sonucu eşitlik + string p = "Hello" + " World"; + string q = "Hello World"; + print(p == q); + + return 0; +} diff --git a/tests/golden/string/equality.expected b/tests/golden/string/equality.expected new file mode 100644 index 0000000..d80fc78 --- /dev/null +++ b/tests/golden/string/equality.expected @@ -0,0 +1,4 @@ +1 +0 +1 +0 diff --git a/tests/golden/string/equality.sqt b/tests/golden/string/equality.sqt new file mode 100644 index 0000000..872ddb5 --- /dev/null +++ b/tests/golden/string/equality.sqt @@ -0,0 +1,16 @@ +// Regresyon testi: string == ve != çalışmaya devam etmeli. +// TypeChecker string sıralama operatörlerini bloklamasına rağmen +// eşitlik operatörleri string ile kullanılabilmeli. + +int main() { + string a = "merhaba"; + string b = "merhaba"; + string c = "dunya"; + + print(a == b); + print(a == c); + print(a != c); + print(b != b); + + return 0; +} diff --git a/tests/golden/string/hello.expected b/tests/golden/string/hello.expected new file mode 100644 index 0000000..e2ed9ca --- /dev/null +++ b/tests/golden/string/hello.expected @@ -0,0 +1,2 @@ +Merhaba +saQut calisiyor diff --git a/tests/golden/string/hello.sqt b/tests/golden/string/hello.sqt new file mode 100644 index 0000000..79f2a9e --- /dev/null +++ b/tests/golden/string/hello.sqt @@ -0,0 +1,5 @@ +int main() { + print("Merhaba"); + print("saQut calisiyor"); + return 0; +} diff --git a/tests/golden/string/ordering_error.compile_error b/tests/golden/string/ordering_error.compile_error new file mode 100644 index 0000000..e8b2dab --- /dev/null +++ b/tests/golden/string/ordering_error.compile_error @@ -0,0 +1 @@ +E003 diff --git a/tests/golden/string/ordering_error.sqt b/tests/golden/string/ordering_error.sqt new file mode 100644 index 0000000..0750cb7 --- /dev/null +++ b/tests/golden/string/ordering_error.sqt @@ -0,0 +1,10 @@ +// Negatif test: string sıralama operatörleri derleme hatası vermeli. +// Bu dosya DERLENMEMELI — TypeChecker E003 üretmeli. +// < > <= >= operatörlerinin her biri string ile bloklanır. + +int main() { + string a = "merhaba"; + string b = "dunya"; + if (a < b) { return 1; } + return 0; +} diff --git a/tests/golden/struct/basic.expected b/tests/golden/struct/basic.expected new file mode 100644 index 0000000..df4a4a1 --- /dev/null +++ b/tests/golden/struct/basic.expected @@ -0,0 +1,3 @@ +10 +20 +99 diff --git a/tests/golden/struct/basic.sqt b/tests/golden/struct/basic.sqt new file mode 100644 index 0000000..92a15c8 --- /dev/null +++ b/tests/golden/struct/basic.sqt @@ -0,0 +1,19 @@ +struct Point { + int x; + int y; +} + +void setX(Point p, int val) { + p.x = val; +} + +int main() { + Point p; + p.x = 10; + p.y = 20; + print(p.x); + print(p.y); + setX(p, 99); + print(p.x); + return 0; +} diff --git a/tests/run.sh b/tests/run.sh index f694d23..b91f4d3 100755 --- a/tests/run.sh +++ b/tests/run.sh @@ -1,16 +1,49 @@ #!/usr/bin/env bash -# saQut birim testleri — çerçevesiz (assert tabanlı), tek komutla. +# saQut test koşucusu — birim testler + golden testler # Kullanım: bash tests/run.sh set -euo pipefail ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" CXX="${CXX:-g++}" FLAGS=(-std=c++20 -Wall -Wextra -I"$ROOT/src") +SAQUT="$ROOT/build/saqut" +# ── Birim testler ───────────────────────────────────────────────────────────── for t in test_type test_diagnostic; do echo "=== $t ===" "$CXX" "${FLAGS[@]}" "$ROOT/tests/$t.cpp" -o "/tmp/saqut_$t" "/tmp/saqut_$t" done +# ── Golden testler ──────────────────────────────────────────────────────────── +echo "=== golden ===" + +if [ ! -x "$SAQUT" ]; then + echo "HATA: $SAQUT bulunamadı — önce derleyin (cmake --build build)" + exit 1 +fi + +PASS=0; FAIL=0 +while IFS= read -r -d '' sqt; do + dir=$(dirname "$sqt") + base=$(basename "$sqt" .sqt) + exp="$dir/$base.expected" + [ -f "$exp" ] || continue + + actual=$("$SAQUT" run "$sqt" 2>/dev/null) || true + expected=$(cat "$exp") + + if [ "$actual" = "$expected" ]; then + PASS=$((PASS + 1)) + else + echo " FAIL: ${sqt#"$ROOT"/}" + echo " beklenen : $(echo "$expected" | head -1)" + echo " gerçek : $(echo "$actual" | head -1)" + FAIL=$((FAIL + 1)) + fi +done < <(find "$ROOT/tests/golden" -name "*.sqt" -print0 | sort -z) + +echo " $PASS geçti, $FAIL başarısız" +[ "$FAIL" -eq 0 ] || exit 1 + echo "=== TUM TESTLER GECTI ==="