test: golden-test koşucusu + Value audit + saqut ir pipeline fix

closes #113, #114, #75

- cmake/run_golden.cmake: BINARY/SOURCE/EXPECTED ile çalışan karşılaştırma betiği
- CMakeLists.txt: enable_testing(), golden test otomatik keşif (CONFIGURE_DEPENDS),
  unit_tests (tests/run.sh) ctest entegrasyonu
- tests/golden/: fibonacci, string, arithmetic — 4/4 yeşil (negatif doğrulama da geçti)
- value.hpp: stale yorum temizlendi, toString() eklendi, switch exhaustive hale getirildi
- ir.hpp: TypeChecker + StructuralValidator eklendi — run pipeline ile artık eşit
This commit is contained in:
saqut 2026-06-18 22:31:26 +03:00
parent d534410874
commit 27a5bc753e
10 changed files with 140 additions and 22 deletions

View File

@ -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()

33
cmake/run_golden.cmake Normal file
View File

@ -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=<saqut yolu> -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()

View File

@ -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);

View File

@ -1,29 +1,18 @@
// ============================================================================
// saQut VM — Value (Çalışma Zamanı Değer)
//
// Bir saQut değerinin bellekteki temsilidir.
//
// ŞU AN SADECE INT:
// fibonacci.sqt tamamen int kullanır, bu dikey dilim için int yeterli.
// İleride float, bool, string eklenmesi için "kind" alanı iskelet olarak bırakıldı.
//
// BOOLEAN OLARAK KULLANIM:
// JIF_FALSE talimatı değerin 0 olup olmadığına bakar.
// 0 = yanlış, sıfır-dışı = doğru. C geleneği.
// ============================================================================
#ifndef SAQUT_VM_VALUE
#define SAQUT_VM_VALUE
#include <string>
#include <stdexcept>
// 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 {
@ -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";

View File

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

View File

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

View File

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

View File

@ -0,0 +1,24 @@
int fibonacci(int n) {
if (n <= 1) {
return n;
}
return fibonacci(n - 1) + fibonacci(n - 2);
}
int fibonacciIterative(int n) {
int first = 0;
int second = 1;
for (int i = 0; i < n; i = i + 1) {
int next = first + second;
first = second;
second = next;
}
return first;
}
int main() {
int n = 10;
print(fibonacci(n));
print(fibonacciIterative(n));
return 0;
}

View File

@ -0,0 +1,2 @@
Merhaba
saQut calisiyor

View File

@ -0,0 +1,5 @@
int main() {
print("Merhaba");
print("saQut calisiyor");
return 0;
}