From f607f43cc8a08af5dc0180bd4e68408a3efc06a0 Mon Sep 17 00:00:00 2001 From: saqut Date: Tue, 16 Jun 2026 00:31:44 +0300 Subject: [PATCH] =?UTF-8?q?feat(faz0):=20tip=20sistemi=20+=20tan=C4=B1lama?= =?UTF-8?q?=20motoru=20(Type=20+=20DiagnosticEngine)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Faz 0 (#69) — frontend'in iki temel veri yapısı: - src/core/type.hpp: Type (Primitive/Array/Struct/Function/Error), equals() (katı yapısal, gizli dönüşüm yok — ADR-010), toString(), toJson() (cam ilkesi), factory'ler ve fromName() yardımcısı. - src/diagnostic/diagnostic.hpp: DiagLevel, Diagnostic (veri birincil), hata kataloğu (E001-E010, W001-W003) + jsonEscape + makeDiagnostic. - src/diagnostic/diagnostic_engine.hpp: toplar (ilk hatada durmaz, ADR-013), printAll() (insan-okur, sıralı) + toJson() (makine-okur). - tests/: çerçevesiz birim testleri + run.sh. Header-only (ADR-003). -Wall -Wextra temiz. Henüz pipeline'a bağlı değil; Faz 2/3 (sembol tablosu, tip denetleyici) bunları tüketecek. Co-Authored-By: Claude Opus 4.8 --- src/core/type.hpp | 250 +++++++++++++++++++++++++++ src/diagnostic/diagnostic.hpp | 178 +++++++++++++++++++ src/diagnostic/diagnostic_engine.hpp | 114 ++++++++++++ tests/run.sh | 16 ++ tests/test_diagnostic.cpp | 43 +++++ tests/test_type.cpp | 49 ++++++ 6 files changed, 650 insertions(+) create mode 100644 src/core/type.hpp create mode 100644 src/diagnostic/diagnostic.hpp create mode 100644 src/diagnostic/diagnostic_engine.hpp create mode 100755 tests/run.sh create mode 100644 tests/test_diagnostic.cpp create mode 100644 tests/test_type.cpp diff --git a/src/core/type.hpp b/src/core/type.hpp new file mode 100644 index 0000000..260a129 --- /dev/null +++ b/src/core/type.hpp @@ -0,0 +1,250 @@ +// ============================================================================ +// saQut Compiler — Tip Sistemi (Type System) +// ============================================================================ +// +// DİZİN: src/core/type.hpp +// KATMAN: Katman 0 — Tüm analiz katmanları tarafından kullanılır +// BAĞIMLI: Yok (sadece , , ) +// KULLANAN: Sembol tablosu (Faz 2), tip denetleyici (Faz 3), optimizasyon (Faz 4) +// +// AMAÇ: +// Kaynak koddaki her ifadenin/sembolün veri tipini temsil eder. Derleyicinin +// "bu değer ne?" sorusuna verdiği yapısal cevaptır. Tip, makine-okur (toJson) +// ve insan-okur (toString) olarak dışa açıktır — "veri birincil, metin bir +// görünümdür" ilkesine uyar (bkz. readme → Tasarım felsefesi). +// +// TİP TÜRLERİ (TypeKind): +// Primitive : int, float, double, char, string, bool, void +// Array : eleman tipi taşır (örn. int[]) +// Struct : struct adı taşır (örn. struct Point) +// Function : dönüş tipi + parametre tipleri taşır +// Error : hatalı/çözümlenememiş tip — ardışık sahte hataları bastırmak için +// (tip denetleyici, operandı Error olan ifadede yeni hata üretmez) +// +// NOT (kasıtlı sadelik): Gizli tip dönüşümü YOKTUR (ADR-010). equals() yapısal +// ve katıdır; "int, float'a uyar mı?" gibi kurallar tip denetleyicinin işidir, +// bu dosyanın değil. Tamsayı literalinin bağlama-göre tiplenmesi de (ADR-010) +// Faz 3'te ele alınır. +// +// ============================================================================ + +#ifndef SAQUT_CORE_TYPE +#define SAQUT_CORE_TYPE + +#include +#include +#include + +// ============================================================================ +// Enum'lar +// ============================================================================ + +enum class PrimitiveKind { Int, Float, Double, Char, String, Bool, Void }; + +enum class TypeKind { Primitive, Array, Struct, Function, Error }; + +// ============================================================================ +// Type — Bir veri tipi +// ============================================================================ +// +// KULLANIM: +// Type a = Type::Int(); // int +// Type b = Type::array(Type::Int()); // int[] +// Type c = Type::function(Type::Int(), {Type::Int(), Type::Int()}); // fn(int,int)->int +// Type d = Type::structType("Point"); // struct Point +// Type e = Type::error(); // +// +// a.equals(Type::Int()); // true +// a.equals(b); // false +// a.toString(); // "int" +// b.toString(); // "int[]" +// c.toJson(); // {"kind":"function",...} +// +// İç içe tipler (array elemanı, fonksiyon dönüşü) shared_ptr ile tutulur: +// Type değer-semantiğiyle kopyalanabilir kalır ama özyinelemeli olabilir. +// ============================================================================ + +struct Type { + TypeKind kind = TypeKind::Error; + + PrimitiveKind prim = PrimitiveKind::Void; // kind == Primitive + std::shared_ptr elementType; // kind == Array + std::shared_ptr returnType; // kind == Function + std::vector paramTypes; // kind == Function + std::string structName; // kind == Struct + + // ------------------------------------------------------------------ // + // Factory'ler + // ------------------------------------------------------------------ // + static Type primitive(PrimitiveKind p) { + Type t; + t.kind = TypeKind::Primitive; + t.prim = p; + return t; + } + static Type Int() { return primitive(PrimitiveKind::Int); } + static Type Float() { return primitive(PrimitiveKind::Float); } + static Type Double() { return primitive(PrimitiveKind::Double); } + static Type Char() { return primitive(PrimitiveKind::Char); } + static Type String() { return primitive(PrimitiveKind::String); } + static Type Bool() { return primitive(PrimitiveKind::Bool); } + static Type Void() { return primitive(PrimitiveKind::Void); } + + static Type array(Type elem) { + Type t; + t.kind = TypeKind::Array; + t.elementType = std::make_shared(std::move(elem)); + return t; + } + static Type function(Type ret, std::vector params) { + Type t; + t.kind = TypeKind::Function; + t.returnType = std::make_shared(std::move(ret)); + t.paramTypes = std::move(params); + return t; + } + static Type structType(std::string name) { + Type t; + t.kind = TypeKind::Struct; + t.structName = std::move(name); + return t; + } + static Type error() { + return Type{}; // varsayılan = Error + } + + // ------------------------------------------------------------------ // + // Yüklemler (predicates) + // ------------------------------------------------------------------ // + bool isError() const { return kind == TypeKind::Error; } + bool isPrimitive() const { return kind == TypeKind::Primitive; } + bool isArray() const { return kind == TypeKind::Array; } + bool isStruct() const { return kind == TypeKind::Struct; } + bool isFunction() const { return kind == TypeKind::Function; } + bool isVoid() const { return kind == TypeKind::Primitive && prim == PrimitiveKind::Void; } + + // Aritmetik/karşılaştırma operatörlerine uygun sayısal tip mi? + bool isNumeric() const { + return kind == TypeKind::Primitive && + (prim == PrimitiveKind::Int || + prim == PrimitiveKind::Float || + prim == PrimitiveKind::Double); + } + + // ------------------------------------------------------------------ // + // equals — Yapısal eşitlik (katı; gizli dönüşüm yok, ADR-010) + // ------------------------------------------------------------------ // + bool equals(const Type& o) const { + if (kind != o.kind) return false; + switch (kind) { + case TypeKind::Primitive: + return prim == o.prim; + case TypeKind::Array: + return elementType && o.elementType && + elementType->equals(*o.elementType); + case TypeKind::Struct: + return structName == o.structName; + case TypeKind::Function: { + if (!returnType || !o.returnType) return false; + if (!returnType->equals(*o.returnType)) return false; + if (paramTypes.size() != o.paramTypes.size()) return false; + for (size_t i = 0; i < paramTypes.size(); ++i) + if (!paramTypes[i].equals(o.paramTypes[i])) return false; + 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ı) + } + + // ------------------------------------------------------------------ // + // İsim yardımcıları + // ------------------------------------------------------------------ // + static const char* primName(PrimitiveKind p) { + switch (p) { + case PrimitiveKind::Int: return "int"; + case PrimitiveKind::Float: return "float"; + case PrimitiveKind::Double: return "double"; + case PrimitiveKind::Char: return "char"; + case PrimitiveKind::String: return "string"; + case PrimitiveKind::Bool: return "bool"; + case PrimitiveKind::Void: return "void"; + } + 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. + static Type fromName(const std::string& n) { + if (n == "int") return Int(); + if (n == "float") return Float(); + if (n == "double") return Double(); + if (n == "char") return Char(); + if (n == "string") return String(); + if (n == "bool") return Bool(); + if (n == "void") return Void(); + return error(); + } + + // ------------------------------------------------------------------ // + // toString — İnsan-okur ("int", "int[]", "fn(int,int)->int") + // ------------------------------------------------------------------ // + std::string toString() const { + switch (kind) { + case TypeKind::Primitive: + return primName(prim); + case TypeKind::Array: + return (elementType ? elementType->toString() : "") + "[]"; + case TypeKind::Struct: + return "struct " + structName; + case TypeKind::Function: { + std::string s = "fn("; + for (size_t i = 0; i < paramTypes.size(); ++i) { + if (i) s += ","; + s += paramTypes[i].toString(); + } + s += ")->"; + s += returnType ? returnType->toString() : ""; + return s; + } + case TypeKind::Error: + return ""; + } + return ""; + } + + // ------------------------------------------------------------------ // + // toJson — Makine-okur (cam ilkesi: her tip dışarıdan sorgulanabilir) + // ------------------------------------------------------------------ // + std::string toJson() const { + switch (kind) { + case TypeKind::Primitive: + return std::string("{\"kind\":\"primitive\",\"name\":\"") + primName(prim) + "\"}"; + case TypeKind::Array: + return std::string("{\"kind\":\"array\",\"element\":") + + (elementType ? elementType->toJson() : "null") + "}"; + case TypeKind::Struct: + return "{\"kind\":\"struct\",\"name\":\"" + structName + "\"}"; + case TypeKind::Function: { + std::string s = "{\"kind\":\"function\",\"returns\":"; + s += returnType ? returnType->toJson() : "null"; + s += ",\"params\":["; + for (size_t i = 0; i < paramTypes.size(); ++i) { + if (i) s += ","; + s += paramTypes[i].toJson(); + } + s += "]}"; + return s; + } + case TypeKind::Error: + return "{\"kind\":\"error\"}"; + } + return "null"; + } +}; + +#endif // SAQUT_CORE_TYPE diff --git a/src/diagnostic/diagnostic.hpp b/src/diagnostic/diagnostic.hpp new file mode 100644 index 0000000..43e296b --- /dev/null +++ b/src/diagnostic/diagnostic.hpp @@ -0,0 +1,178 @@ +// ============================================================================ +// saQut Compiler — Tanılama (Diagnostic) Veri Yapıları + Hata Kataloğu +// ============================================================================ +// +// DİZİN: src/diagnostic/diagnostic.hpp +// KATMAN: Katman 0 — Tüm analiz katmanları tarafından kullanılır +// BAĞIMLI: src/core/location.hpp +// KULLANAN: DiagnosticEngine, sembol toplayıcı (Faz 2), tip denetleyici (Faz 3) +// +// AMAÇ: +// Derleme sırasında bulunan hata/uyarıları YAPISAL veri olarak temsil eder. +// "Veri birincil, insan-okur metin bir görünümdür" (readme → Tasarım felsefesi): +// bir Diagnostic; seviye + kod + konum + mesaj taşır; ekrana basılan satır +// bunun yalnızca bir render'ıdır. Bu sayede aynı tanı LSP, AI veya `saqut +// explain` tarafından da tüketilebilir. +// +// HATA KATALOĞU (baştan sabitlenir — yeni kodlar buraya eklenir): +// E001 Tanımsız değişken/isim (declare-before-use ihlali dâhil) Faz 2/3 +// E002 Aynı scope'ta çift tanım Faz 2 +// E003 Tip uyuşmazlığı (gizli dönüşüm yok, ADR-010) Faz 3 +// E004 Döngü/switch dışı break/continue Faz 3 +// E005 Fonksiyon dışı return Faz 3 +// E006 Return tipi imzaya uymuyor Faz 3 +// E007 Tanımsız tip (bilinmeyen tip adı) Faz 2/3 +// E008 Fonksiyon çağrısı argüman sayısı/tipi uyuşmuyor Faz 3 +// E009 Array boyutu sabit değil / geçersiz Faz 3 +// E010 Özyinelemeli/döngüsel struct (by-value çevrim → sonsuz boyut) Faz 2/3 +// W001 Kullanılmayan değişken Faz 4 +// W002 Sıfıra bölme (sabit folding) Faz 4 +// W003 Erişilemez (ölü) kod Faz 4 +// +// ============================================================================ + +#ifndef SAQUT_DIAGNOSTIC_DIAGNOSTIC +#define SAQUT_DIAGNOSTIC_DIAGNOSTIC + +#include +#include +#include "core/location.hpp" + +// ============================================================================ +// DiagLevel — Tanı seviyesi +// ============================================================================ + +enum class DiagLevel { Error, Warning, Note, Hint }; + +inline const char* diagLevelName(DiagLevel l) { + switch (l) { + case DiagLevel::Error: return "error"; + case DiagLevel::Warning: return "warning"; + case DiagLevel::Note: return "note"; + case DiagLevel::Hint: return "hint"; + } + return "?"; +} + +// İnsan-okur çıktı için Türkçe karşılık +inline const char* diagLevelNameTr(DiagLevel l) { + switch (l) { + case DiagLevel::Error: return "hata"; + case DiagLevel::Warning: return "uyarı"; + case DiagLevel::Note: return "not"; + case DiagLevel::Hint: return "ipucu"; + } + return "?"; +} + +// JSON string kaçışı (mesaj/ipucu tırnak veya satır sonu içerebilir) +inline std::string jsonEscape(const std::string& s) { + std::string out; + out.reserve(s.size() + 8); + for (char c : s) { + switch (c) { + case '"': out += "\\\""; break; + case '\\': out += "\\\\"; break; + case '\n': out += "\\n"; break; + case '\r': out += "\\r"; break; + case '\t': out += "\\t"; break; + default: out += c; break; + } + } + return out; +} + +// ============================================================================ +// Diagnostic — Tek bir tanı (hata/uyarı/not/ipucu) +// ============================================================================ +// +// KULLANIM: +// Diagnostic d{DiagLevel::Error, "E003", loc, "int'e string atanamaz"}; +// d.hint = "açık dönüşüm gerekiyor"; +// std::cout << d.toJson(); +// ============================================================================ + +struct Diagnostic { + DiagLevel level = DiagLevel::Error; + std::string code; // "E003" (katalog kodu; boş olabilir) + SourceLocation loc; // hatanın kaynak koddaki yeri + std::string message; // bağlama özel açıklama + std::string hint; // opsiyonel "şunu dene" önerisi + + std::string toJson() const { + std::string s = "{"; + s += "\"level\":\""; s += diagLevelName(level); s += "\","; + s += "\"code\":\""; s += jsonEscape(code); s += "\","; + s += "\"location\":"; s += loc.toJson(); s += ","; + s += "\"message\":\""; s += jsonEscape(message); s += "\""; + if (!hint.empty()) { + s += ",\"hint\":\""; s += jsonEscape(hint); s += "\""; + } + s += "}"; + return s; + } +}; + +// ============================================================================ +// Hata Kataloğu — kod → (seviye, kanonik başlık) +// ============================================================================ +// +// Bağlama özel mesaj report sırasında verilir; buradaki başlık, kodun GENEL +// anlamıdır (ileride `saqut explain E003` bunu kullanabilir, #107/#98). +// ============================================================================ + +struct DiagInfo { + const char* code; + DiagLevel level; + const char* title; +}; + +inline const std::vector& diagnosticCatalog() { + static const std::vector catalog = { + {"E001", DiagLevel::Error, "Tanımsız değişken/isim"}, + {"E002", DiagLevel::Error, "Aynı scope'ta çift tanım"}, + {"E003", DiagLevel::Error, "Tip uyuşmazlığı"}, + {"E004", DiagLevel::Error, "Döngü/switch dışı break/continue"}, + {"E005", DiagLevel::Error, "Fonksiyon dışı return"}, + {"E006", DiagLevel::Error, "Return tipi imzaya uymuyor"}, + {"E007", DiagLevel::Error, "Tanımsız tip"}, + {"E008", DiagLevel::Error, "Fonksiyon çağrısı argümanı uyuşmuyor"}, + {"E009", DiagLevel::Error, "Array boyutu sabit değil / geçersiz"}, + {"E010", DiagLevel::Error, "Özyinelemeli/döngüsel struct tanımı"}, + {"W001", DiagLevel::Warning, "Kullanılmayan değişken"}, + {"W002", DiagLevel::Warning, "Sıfıra bölme (sabit ifade)"}, + {"W003", DiagLevel::Warning, "Erişilemez (ölü) kod"}, + }; + return catalog; +} + +// Kod kataloğda var mı? (yoksa nullptr) +inline const DiagInfo* findDiag(const std::string& code) { + for (const auto& d : diagnosticCatalog()) + if (code == d.code) return &d; + return nullptr; +} + +// Bir koddan Diagnostic üretir; seviye kataloğdan çözülür (yoksa: E→Error, +// W→Warning, diğer→Note). Bağlama özel mesajı çağıran verir. +inline Diagnostic makeDiagnostic(const std::string& code, + const SourceLocation& loc, + const std::string& message, + const std::string& hint = "") { + DiagLevel level = DiagLevel::Note; + if (const DiagInfo* info = findDiag(code)) { + level = info->level; + } else if (!code.empty()) { + if (code[0] == 'E') level = DiagLevel::Error; + else if (code[0] == 'W') level = DiagLevel::Warning; + } + Diagnostic d; + d.level = level; + d.code = code; + d.loc = loc; + d.message = message; + d.hint = hint; + return d; +} + +#endif // SAQUT_DIAGNOSTIC_DIAGNOSTIC diff --git a/src/diagnostic/diagnostic_engine.hpp b/src/diagnostic/diagnostic_engine.hpp new file mode 100644 index 0000000..baa7a10 --- /dev/null +++ b/src/diagnostic/diagnostic_engine.hpp @@ -0,0 +1,114 @@ +// ============================================================================ +// saQut Compiler — Tanılama Motoru (DiagnosticEngine) +// ============================================================================ +// +// DİZİN: src/diagnostic/diagnostic_engine.hpp +// KATMAN: Katman 0 — Tüm analiz katmanları tarafından kullanılır +// BAĞIMLI: src/diagnostic/diagnostic.hpp +// KULLANAN: sembol toplayıcı (Faz 2), tip denetleyici (Faz 3), pipeline (main) +// +// AMAÇ: +// Derleme boyunca üretilen tüm Diagnostic'leri EKLENME SIRASIYLA biriktirir. +// İlk hatada DURMAZ (ADR-013): bütün hatalar toplanır, faz sonunda topluca +// raporlanır; durdurma kararını pipeline verir (hasErrors()). +// +// İki çıktı yüzü vardır — aynı veriden: +// printAll() → insan-okur (terminal) +// toJson() → makine-okur (LSP / AI / araçlar) +// +// ============================================================================ + +#ifndef SAQUT_DIAGNOSTIC_ENGINE +#define SAQUT_DIAGNOSTIC_ENGINE + +#include +#include +#include +#include "diagnostic/diagnostic.hpp" + +// ============================================================================ +// DiagnosticEngine +// ============================================================================ +// +// KULLANIM: +// DiagnosticEngine diag; +// diag.report(makeDiagnostic("E001", loc, "x tanımsız")); +// diag.report(DiagLevel::Warning, "W001", loc2, "y kullanılmıyor"); +// if (diag.hasErrors()) diag.printAll(std::cerr); +// ============================================================================ + +class DiagnosticEngine { +public: + // --- Ekleme --- + void report(const Diagnostic& d) { + diagnostics_.push_back(d); + } + + // Kolaylık: koddan üret + ekle (seviye kataloğdan çözülür) + void report(const std::string& code, + const SourceLocation& loc, + const std::string& message, + const std::string& hint = "") { + diagnostics_.push_back(makeDiagnostic(code, loc, message, hint)); + } + + // Kolaylık: seviyeyi açıkça vererek + void report(DiagLevel level, + const std::string& code, + const SourceLocation& loc, + const std::string& message, + const std::string& hint = "") { + Diagnostic d; + d.level = level; d.code = code; d.loc = loc; d.message = message; d.hint = hint; + diagnostics_.push_back(d); + } + + // --- Sorgu --- + bool hasErrors() const { return errorCount() > 0; } + + int errorCount() const { return countLevel(DiagLevel::Error); } + int warningCount() const { return countLevel(DiagLevel::Warning); } + int count() const { return static_cast(diagnostics_.size()); } + bool empty() const { return diagnostics_.empty(); } + + const std::vector& all() const { return diagnostics_; } + + void clear() { diagnostics_.clear(); } + + // --- İnsan-okur çıktı (ekleme sırasıyla) --- + void printAll(std::ostream& os) const { + for (const auto& d : diagnostics_) { + os << d.loc.toString() << ": " + << diagLevelNameTr(d.level) << " [" << d.code << "]: " + << d.message << "\n"; + if (!d.hint.empty()) + os << " ipucu: " << d.hint << "\n"; + } + os << "— " << errorCount() << " hata, " << warningCount() << " uyarı\n"; + } + + // --- Makine-okur çıktı --- + std::string toJson() const { + std::string s = "{\"diagnostics\":["; + for (size_t i = 0; i < diagnostics_.size(); ++i) { + if (i) s += ","; + s += diagnostics_[i].toJson(); + } + s += "],\"errorCount\":" + std::to_string(errorCount()); + s += ",\"warningCount\":" + std::to_string(warningCount()); + s += "}"; + return s; + } + +private: + std::vector diagnostics_; + + int countLevel(DiagLevel level) const { + int n = 0; + for (const auto& d : diagnostics_) + if (d.level == level) ++n; + return n; + } +}; + +#endif // SAQUT_DIAGNOSTIC_ENGINE diff --git a/tests/run.sh b/tests/run.sh new file mode 100755 index 0000000..f694d23 --- /dev/null +++ b/tests/run.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +# saQut birim testleri — çerçevesiz (assert tabanlı), tek komutla. +# 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") + +for t in test_type test_diagnostic; do + echo "=== $t ===" + "$CXX" "${FLAGS[@]}" "$ROOT/tests/$t.cpp" -o "/tmp/saqut_$t" + "/tmp/saqut_$t" +done + +echo "=== TUM TESTLER GECTI ===" diff --git a/tests/test_diagnostic.cpp b/tests/test_diagnostic.cpp new file mode 100644 index 0000000..dcb28c0 --- /dev/null +++ b/tests/test_diagnostic.cpp @@ -0,0 +1,43 @@ +// Faz 0 — DiagnosticEngine birim testleri (çerçevesiz; assert + çıktı). +// Koşmak için: tests/run.sh +#include "diagnostic/diagnostic_engine.hpp" +#include +#include + +int main() { + DiagnosticEngine diag; + SourceLocation l1{"test.sqt", 3, 5, 40}; + SourceLocation l2{"test.sqt", 7, 9, 88}; + SourceLocation l3{"test.sqt", 12, 1, 150}; + + // Üç tanı — ekleme sırası korunmalı (ADR-013: ilk hatada durma, topla) + diag.report("E001", l1, "x tanımsız"); + diag.report("E003", l2, "int'e string atanamaz", "açık dönüşüm gerekiyor"); + diag.report("W001", l3, "y kullanılmıyor"); + + assert(diag.count() == 3); + assert(diag.hasErrors()); + assert(diag.errorCount() == 2); + assert(diag.warningCount() == 1); + + // Sıra korunmuş mu? + assert(diag.all()[0].code == "E001"); + assert(diag.all()[1].code == "E003"); + assert(diag.all()[2].code == "W001"); + + // Seviye kataloğdan çözülmüş mü? + assert(diag.all()[0].level == DiagLevel::Error); + assert(diag.all()[2].level == DiagLevel::Warning); + + // Katalog erişimi + assert(findDiag("E010") != nullptr); + assert(findDiag("E999") == nullptr); + + std::cout << "--- printAll ---\n"; + diag.printAll(std::cout); + std::cout << "--- toJson ---\n"; + std::cout << diag.toJson() << "\n"; + + std::cout << "test_diagnostic: TUM TESTLER GECTI\n"; + return 0; +} diff --git a/tests/test_type.cpp b/tests/test_type.cpp new file mode 100644 index 0000000..fcbf805 --- /dev/null +++ b/tests/test_type.cpp @@ -0,0 +1,49 @@ +// Faz 0 — Type birim testleri (çerçevesiz; assert + çıktı). +// Koşmak için: tests/run.sh (veya g++ -std=c++20 -Wall -Wextra -Isrc ...) +#include "core/type.hpp" +#include +#include + +int main() { + Type i = Type::Int(); + Type i2 = Type::Int(); + Type f = Type::Float(); + Type arrI = Type::array(Type::Int()); + Type arrI2 = Type::array(Type::Int()); + Type arrF = Type::array(Type::Float()); + Type fn = Type::function(Type::Int(), {Type::Int(), Type::Int()}); + Type st = Type::structType("Point"); + Type err = Type::error(); + + // equals — yapısal, katı (gizli dönüşüm yok) + assert(i.equals(i2)); + assert(!i.equals(f)); + assert(arrI.equals(arrI2)); + assert(!arrI.equals(arrF)); + assert(!arrI.equals(i)); + assert(fn.equals(Type::function(Type::Int(), {Type::Int(), Type::Int()}))); + assert(!fn.equals(Type::function(Type::Int(), {Type::Int()}))); + assert(st.equals(Type::structType("Point"))); + assert(!st.equals(Type::structType("Vec"))); + assert(err.equals(Type::error())); + + // yüklemler + assert(i.isNumeric() && !st.isNumeric()); + assert(Type::Void().isVoid()); + assert(err.isError()); + + // toString + assert(i.toString() == "int"); + assert(arrI.toString() == "int[]"); + assert(fn.toString() == "fn(int,int)->int"); + assert(st.toString() == "struct Point"); + assert(err.toString() == ""); + + // fromName + assert(Type::fromName("int").equals(Type::Int())); + assert(Type::fromName("bool").equals(Type::Bool())); + assert(Type::fromName("bogus").isError()); + + std::cout << "test_type: TUM TESTLER GECTI\n"; + return 0; +}