diff --git a/CMakeLists.txt b/CMakeLists.txt index 37cdcf9..b9deca8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,3 +20,38 @@ 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 + .expected çiftlerini otomatik keşfet +file(GLOB_RECURSE ALL_GOLDEN_SQT CONFIGURE_DEPENDS + "${CMAKE_SOURCE_DIR}/tests/golden/*.sqt" +) +foreach(SQT_FILE ${ALL_GOLDEN_SQT}) + # Göreli yoldan test adı üret: fibonacci/fib.sqt → golden_fibonacci_fib + file(RELATIVE_PATH REL "${CMAKE_SOURCE_DIR}/tests/golden" "${SQT_FILE}") + string(REPLACE ".sqt" "" BASE "${REL}") + string(REPLACE "/" "_" TNAME "${BASE}") + set(EXPECTED_FILE "${CMAKE_SOURCE_DIR}/tests/golden/${BASE}.expected") + + if(EXISTS "${EXPECTED_FILE}") + add_test( + NAME "golden_${TNAME}" + COMMAND ${CMAKE_COMMAND} + -DBINARY=${SAQUT_BINARY} + -DSOURCE=${SQT_FILE} + -DEXPECTED=${EXPECTED_FILE} + -P "${GOLDEN_SCRIPT}" + ) + endif() +endforeach() diff --git a/cmake/run_golden.cmake b/cmake/run_golden.cmake new file mode 100644 index 0000000..6da0399 --- /dev/null +++ b/cmake/run_golden.cmake @@ -0,0 +1,33 @@ +# run_golden.cmake — tek bir golden test çalıştırır ve çıktıyı karşılaştırır. +# +# Kullanım (CMake add_test içinden): +# cmake -DBINARY= -DSOURCE=<.sqt yolu> -DEXPECTED=<.expected yolu> +# [-DCOMMAND=run] -P run_golden.cmake +# +# COMMAND varsayılanı "run". IR testleri için COMMAND=ir geçilir. + +if(NOT DEFINED COMMAND) + set(COMMAND "run") +endif() + +execute_process( + COMMAND "${BINARY}" "${COMMAND}" "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/src/cli/commands/ir.hpp b/src/cli/commands/ir.hpp index 640f576..d11b193 100644 --- a/src/cli/commands/ir.hpp +++ b/src/cli/commands/ir.hpp @@ -7,6 +7,8 @@ #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" @@ -29,6 +31,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); diff --git a/src/vm/value.hpp b/src/vm/value.hpp index 70b93df..7ee8a33 100644 --- a/src/vm/value.hpp +++ b/src/vm/value.hpp @@ -1,35 +1,24 @@ -// ============================================================================ -// 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 -// Gelecekte float/bool/string eklendiğinde burası genişleyecek. -// Şimdilik sadece int. +// Çalışma zamanı değer tipi. +// +// Bool ayrı bir kind değil — boolean sonuçlar int olarak saklanır +// (0 = yanlış, sıfır-dışı = doğru; C geleneği, JIF_FALSE buna dayanır). +// Float henüz implement edilmedi — IR'de float opcode yok. enum class ValueKind { Int, String, - // Float, // TODO(vm-genişletme) - // Bool, // TODO(vm-genişletme) + // Float, // TODO: float literal + aritmetik eklenince }; struct Value { ValueKind kind = ValueKind::Int; int intValue = 0; - std::string stringValue; // yalnızca kind == String için geçerli + std::string stringValue; // yalnızca kind == String için geçerli static Value fromInt(int n) { Value v; @@ -47,12 +36,23 @@ struct Value { // 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::String: return !stringValue.empty(); + } return false; } - // Okunabilir metin — dump ve hata mesajları için + // Yazdırma ve hata mesajları için okunabilir temsil + std::string toString() const { + switch (kind) { + case ValueKind::Int: return std::to_string(intValue); + case ValueKind::String: return stringValue; + } + return "?"; + } + + // Tip adı — hata mesajları için std::string typeName() const { switch (kind) { case ValueKind::Int: return "int"; 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/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/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; +}