diff --git a/MISSION-FAZ3.md b/MISSION-FAZ3.md deleted file mode 100644 index 40bb6cd..0000000 --- a/MISSION-FAZ3.md +++ /dev/null @@ -1,326 +0,0 @@ -# MISSION — Faz 3: Semantik Analiz (Gitea #72) - -> **Bu dosya kendi kendine yeter.** "MISSION-FAZ3'ü oku ve yap" denince -> doğrudan uygula. Bitince DOĞRULAMA bölümünü çalıştır, #72'ye tamamlanma -> yorumu düş, bu dosyayı sil veya MISSION-FAZ4.md ile değiştir. -> `Co-Authored-By: Claude Opus 4.8` trailer'ı unutma. - ---- - -## 0) HEDEF & BAŞARI KRİTERLERİ (#72) - -İki modül: **TypeChecker** (her ExpressionNode'a tip ata) + -**StructuralValidator** (kontrol akışı kuralları). - -Bitti tanımı: -1. `build/saqut check file:examples/fibonacci.sqt` → 0 hata 0 uyarı; her - expression node'unun `resolvedType` alanı JSON'da dolu. -2. `examples/semantic/` test fixture'ları doğru hata/uyarı üretiyor. -3. `-Wall -Wextra` temiz. Faz 0/1/2 testleri hâlâ geçer. - ---- - -## 1) DÖNÜŞÜM KURALLARI (ADR-010 özeti) - -| Durum | Sonuç | Kod | -|---|---|---| -| `float x = 1` | Geçerli — literal 1.0 sayılır | — | -| `double x = 1` | Geçerli | — | -| `float x = intVar` | **Uyarı** — örtük genişletme, veri kaybı yok | W004 | -| `double x = intVar` | **Uyarı** | W004 | -| `double x = floatVar` | **Uyarı** | W004 | -| `int x = 1.5` | **Hata** — literal'den veri kaybı | E003 | -| `int x = floatVar` | **Hata** — daraltma | E003 | -| `float x = doubleVar` | **Hata** — daraltma | E003 | -| `int x = intVar` | Geçerli | — | - -**Kural özeti:** -- Literal bağlama-göre tiplenir: hedef tip daha geniş veya aynıysa uyarısız geçer. -- Değişken→değişken: genişletme (widening) = W004, daraltma (narrowing) = E003. -- Aynı tip = her zaman geçerli. - -**Yardımcı fonksiyon (type_checker içinde):** -```cpp -enum class ConvResult { Ok, Warn_W004, Error_E003 }; -ConvResult checkAssignCompat(const Type& target, const Type& src, bool srcIsLiteral); -``` - ---- - -## 2) KATALOG GÜNCELLEMESİ - -`src/diagnostic/diagnostic.hpp` → W004 ekle: -```cpp -{"W004", DiagLevel::Warning, "Örtük sayısal genişletme (widening)"}, -``` - ---- - -## 3) DOSYA DOSYA PLAN - -Yeni dizin: `src/semantic/`. CMake GLOB_RECURSE → yeni `.cpp`'ler otomatik -alınır ama `build.sh` ile derle (cmake yeniden config eder). - ---- - -### 3.1 `src/semantic/type_checker.hpp` - -```cpp -#ifndef SAQUT_SEMANTIC_TYPE_CHECKER -#define SAQUT_SEMANTIC_TYPE_CHECKER - -#include "symbol/symbol_table.hpp" -#include "diagnostic/diagnostic_engine.hpp" -#include "parser/ast_node.hpp" -#include "core/type.hpp" - -class TypeChecker { -public: - TypeChecker(SymbolTable& table, DiagnosticEngine& diag) - : table_(table), diag_(diag) {} - - void check(ASTNode* program); - -private: - // İfadeyi gez, resolvedType ata, tipi döndür. - // expectedType: bağlam tipi (literal genişletme için); boş = bilinmiyor. - Type checkExpr(ASTNode* node, const Type& expected = Type::error()); - - // Deyimi gez (statement'lar tip döndürmez). - void checkStmt(ASTNode* node); - - // Fonksiyon gövdesini gez; dönüş tipi bağlamını stack'te tut. - void checkFunction(ASTNode* fnNode); - - // Atama uyumunu denetle; uyarı/hata raporla. true = geçerli. - bool checkAssign(const Type& target, const Type& src, - bool srcIsLiteral, const SourceLocation& loc, - const std::string& context); - - SymbolTable& table_; - DiagnosticEngine& diag_; - - // Aktif fonksiyonun beklenen dönüş tipi (iç içe fonksiyon yok, stack - // yerine tek değer yeterli). - Type currentReturnType_; - bool inFunction_ = false; -}; - -#endif // SAQUT_SEMANTIC_TYPE_CHECKER -``` - ---- - -### 3.2 `src/semantic/type_checker.cpp` - -`check(program)`: -- Program children'ı gez: FunctionDecl → `checkFunction`, VariableDecl → - `checkStmt`, StructDecl → atla. - -`checkFunction(fnNode)`: -- `inFunction_ = true; currentReturnType_ = typeFromReturnType(fn->returnType);` -- `checkStmt(body)` (body = children[0]) -- `inFunction_ = false;` - -`checkStmt(node)` — switch(node->kind): -- **Block**: her child → `checkStmt`. -- **VariableDecl**: initExpr varsa `checkExpr(initExpr, typeFromName(vd->varType))`; - sonucu target tiple `checkAssign` ile denetle. -- **ExpressionStatement**: `checkExpr(es->expression)`. -- **ReturnStatement**: value varsa `checkExpr(value, currentReturnType_)`; - sonucu `checkAssign(currentReturnType_, valueType, isLiteral, loc, "return")`. - Değer yok ve returnType != void → E006. -- **IfStatement**: condition checkExpr (bool beklenir, ama şimdilik herhangi - sayısal tip de geçerli — E003 değil, TODO Faz3+); then/else checkStmt. -- **WhileStatement / DoWhileStatement**: condition checkExpr; body checkStmt. -- **ForStatement**: init checkStmt; condition checkExpr; update checkExpr; body checkStmt. -- **Break / Continue / ExpressionStatement**: içerik checkExpr. -- **ReturnStatement**: yukarıda. - -`checkExpr(node, expected)` — switch(node->kind) → Type döndürür: -- **Literal(INTEGER)**: - - expected sayısal ve daha geniş veya aynıysa → `expected` tipini döndür - (literal 1.0 olarak tiplenir, uyarısız). - - expected int veya error → `Type::Int()`. - - expected float literal'e uymuyor (ör. expected=int, literal=FLOAT) → E003. -- **Literal(FLOAT)**: expected double ise double döndür (kayıpsız); expected int → E003; - aksi → `Type::Float()`. -- **Literal(BOOLEAN)**: `Type::Bool()`. -- **Literal(STRING)**: `Type::String()`. -- **Literal(BOŞ)**: `Type::error()` (null — Faz 3+ kapsam dışı). -- **Identifier**: `id->resolvedSymbol ? id->resolvedSymbol->type : Type::error()`. - Type::error() ise E001 zaten Faz 2'de raporlandı, sessiz geç. -- **BinaryExpression**: - - Atama operatörü (EQUAL, +=, -=, vb.): - - left = `checkExpr(left)`, right = `checkExpr(right, leftType)`. - - `checkAssign(leftType, rightType, isLiteralRight, loc, "atama")`. - - `resolvedType = leftType`. - - Aritmetik (+, -, *, /, %): - - Her iki operandı `checkExpr` et. - - İkisi de sayısal ve aynı tip → sonuç o tip. - - İkisi sayısal farklı tip → `checkAssign` mantığıyla uyar/hata; sonuç - daha geniş tip (veya E003 durumunda error). - - Sayısal değil → E003, `Type::error()`. - - Karşılaştırma (==, !=, <, <=, >, >=): - - Operandları checkExpr; uyumlu sayısal veya aynı tip → `Type::Bool()`. - - Uyumsuz → E003, `Type::Bool()` (hata yayılmasın, bool olarak devam). - - Mantıksal (&&, ||): - - Her iki operand bool beklenir; değilse E003. - - Sonuç `Type::Bool()`. - - Unary prefix (-, +, !): - - Left = nullptr; Right = operand. - - `-`/`+`: sayısal beklenir; `!`: bool beklenir. - - resolvedType'a sonucu ata. -- **Call**: - - callee = `checkExpr(callee)` → Function tipi beklenir. - - Argüman sayısı imzayla eşleşmeli → E008. - - Her argüman: `checkExpr(arg, paramType[i])` → `checkAssign(paramType, argType, ...)`. - - resolvedType = callee tipi's `returnType`. -- **Postfix (++/--)**: operand sayısal → sonuç aynı tip; değilse E003. -- **MemberAccess**: `Type::error()` + TODO (struct alan çözümü Faz 3+). -- **IndexExpression**: TODO; `Type::error()`. - -`checkAssign(target, src, srcIsLiteral, loc, ctx)`: -- target veya src = error → `return true` (sessiz geç, hata zaten raporlandı). -- target == src → `return true`. -- Genişletme (widening): - - `int → float`: srcIsLiteral → geçerli (**uyarısız**); değil → **W004**. - - `int → double`, `float → double`: aynı kural. - - srcIsLiteral ve kayıpsız → `return true`. - - srcIsLiteral değil → W004 raporla, `return true` (yine de geçerli). -- Daraltma (narrowing): - - `float → int`, `double → int`, `double → float` → **E003**, `return false`. -- Tamamen farklı tipler (int ↔ string, vb.) → **E003**, `return false`. - -> `srcIsLiteral`: `node->kind == ASTKind::Literal` ise true. - ---- - -### 3.3 `src/semantic/structural_validator.hpp` - -```cpp -#ifndef SAQUT_SEMANTIC_STRUCTURAL_VALIDATOR -#define SAQUT_SEMANTIC_STRUCTURAL_VALIDATOR - -#include "diagnostic/diagnostic_engine.hpp" -#include "parser/ast_node.hpp" - -class StructuralValidator { -public: - StructuralValidator(DiagnosticEngine& diag) : diag_(diag) {} - void validate(ASTNode* program); - -private: - void walkDecl(ASTNode* node); - void walkStmt(ASTNode* node); - - DiagnosticEngine& diag_; - int loopDepth_ = 0; - bool inFunction_ = false; -}; - -#endif // SAQUT_SEMANTIC_STRUCTURAL_VALIDATOR -``` - ---- - -### 3.4 `src/semantic/structural_validator.cpp` - -`validate(program)`: her top-level child → `walkDecl`. - -`walkDecl`: -- FunctionDecl: `inFunction_=true`, `walkStmt(body)`, `inFunction_=false`. -- VariableDecl / StructDecl: atla. - -`walkStmt(node)` — switch: -- **Block**: her child `walkStmt`. -- **IfStatement**: then/else `walkStmt`. -- **WhileStatement / DoWhileStatement**: `loopDepth_++; walkStmt(body); loopDepth_--;` -- **ForStatement**: `loopDepth_++; walkStmt(init?); walkStmt(body); loopDepth_--;` -- **BreakStatement**: `loopDepth_ == 0` → E004. -- **ContinueStatement**: `loopDepth_ == 0` → E004. -- **ReturnStatement**: `!inFunction_` → E005. - (Return tip uyumu TypeChecker'ın işi; burada sadece yapısal kural.) -- **ExpressionStatement / VariableDecl**: `walkStmt` çocukları için yinele. -- Diğer: atla. - ---- - -## 4) CLI — `saqut check` KOMUTU - -### 4.1 `src/cli/commands/check.hpp` - -```cpp -inline int cmdCheck(const CliArgs& args) { - // tokenize → parse → symbolCollect → typeCheck → structValidate - // Tüm hatalar DiagnosticEngine'de toplanır. - // Çıktı: JSON (--compact destekli) - // {"file":"...","diagnostics":{...}} - // exit code: hasErrors() ? 1 : 0 -} -``` - -### 4.2 `src/cli/cli.hpp` veya `main.cpp` - -`check` komutu kaydet; `parseArgs` tanımlı komutlar listesine ekle. - ---- - -## 5) TEST FIXTURE'LARI — `examples/semantic/` - -| Dosya | İçerik | Beklenen | -|---|---|---| -| `widening.sqt` | `float x = 1;` (OK) + `float y = someInt;` | W004 | -| `narrowing.sqt` | `int x = 1.5;` | E003 | -| `bad_return.sqt` | `int foo() { return 1.5; }` | E003 | -| `break_outside.sqt` | top-level `break;` | E004 | -| `return_outside.sqt` | top-level `return 0;` | E005 | -| `bad_args.sqt` | `fibonacci(1, 2)` (1 parametre bekliyor) | E008 | - ---- - -## 6) DOĞRULAMA KOMUTLARI - -```bash -bash scripts/build.sh - -# Başarı: 0 hata 0 uyarı -build/saqut check file:examples/fibonacci.sqt - -# Her expression tipli mi? -build/saqut ast file:examples/fibonacci.sqt | python3 -c " -import json,sys -def walk(n): - if 'resolvedType' in n and n['resolvedType'] is None: - print('UNTIPPED:', n.get('kind'), n.get('name','')) - for v in n.values(): - if isinstance(v, dict): walk(v) - elif isinstance(v, list): [walk(i) for i in v if isinstance(i, dict)] -walk(json.load(sys.stdin))" - -# Hata fixture'ları -build/saqut check file:examples/semantic/widening.sqt # W004 -build/saqut check file:examples/semantic/narrowing.sqt # E003 -build/saqut check file:examples/semantic/break_outside.sqt # E004 -build/saqut check file:examples/semantic/bad_args.sqt # E008 - -# Regresyon -bash tests/run.sh -build/saqut ast file:examples/fibonacci.sqt | python3 -m json.tool >/dev/null && echo AST-OK -``` - ---- - -## 7) HAFIZA İPUÇLARI - -- `ASTKind::BinaryExpression` → `BinaryExpressionNode{Left, Right, Operator(TokenType)}` -- Atama operatörleri: `EQUAL, PLUS_EQUAL, MINUS_EQUAL, STAR_EQUAL, SLASH_EQUAL, ...` -- `ASTKind::Call` → `CallExpressionNode{callee, arguments}` -- `ASTKind::Literal` → `LiteralNode{literalType(INTEGER/FLOAT/...), parserToken}` -- `ASTKind::Identifier` → `IdentifierNode{resolvedSymbol}` (Faz 2'de set edildi) -- `FunctionDeclNode{name, returnType(string), params, children=[body]}` -- `Type::fromName(str)` primitifi çözer; `Type::function(ret, params)` fonksiyon tipi -- `diag_.report("E003", loc, "mesaj")` → katalogdan seviye otomatik çözülür -- `resolvedType` → `ExpressionNode`'un alanı (ast_node.hpp) -- Literal'ın literal tipi: `((LiteralNode*)node)->literalType` -- İki sayısal tipin genişliği: int < float < double (basit sıralama yeterli)