From 79c51af501c4315e08462280fb51e4757cdf94e5 Mon Sep 17 00:00:00 2001 From: saqut Date: Thu, 18 Jun 2026 16:11:34 +0300 Subject: [PATCH] =?UTF-8?q?feat(symbols):=20JSON=20=C3=A7=C4=B1kt=C4=B1=20?= =?UTF-8?q?+=20syntax=20hata=20tolerans=C4=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - symbols komutu artık JSON üretiyor: file, symbols[], diagnostics Her sembol: name, kind, type, typeDetail, definition (file+satır+sütun), references[], isBuiltin — LSP tüketimine hazır format - parser: parseProgram() ilerleme olmayana token atla (guard ekle) Bozuk top-level syntax (ör: `}`, eksik parametre listesi) artık ayrıştırmayı durdurmak yerine sonraki geçerli bildirimi bulmaya devam eder Co-Authored-By: Claude Opus 4.8 --- build/.ninja_deps | Bin 31712 -> 34236 bytes build/.ninja_log | 3 ++ src/cli/commands/symbols.hpp | 98 ++++++++++++++++++++++++----------- src/parser/parser.cpp | 6 ++- 4 files changed, 75 insertions(+), 32 deletions(-) diff --git a/build/.ninja_deps b/build/.ninja_deps index 5664a6a25c82b6df029f6098e9d20704172860ee..3e9c5c6dcc87b42eaedc43f2841fb84104fbc66d 100644 GIT binary patch delta 68 zcmaFxopDb$(}oAtd>JeZ4Ida780;*r-}?;hjOU@L#>n@A9s( X@O3aSH24C=6iqW^|LRSiR8|K7fcqGe delta 9 Qcmdnf&Gg_q +#include #include "cli/args.hpp" #include "tokenizer/tokenizer.hpp" #include "parser/parser.hpp" #include "symbol/symbol_table.hpp" #include "symbol/symbol_collector.hpp" #include "diagnostic/diagnostic_engine.hpp" +#include "tools.hpp" + +// ───────────────────────────────────────────────────────────────────────────── +// symbolsToJson — sembol tablosunu JSON olarak serileştir +// ───────────────────────────────────────────────────────────────────────────── + +inline std::string symbolsToJson(const std::string& filePath, + const SymbolTable& table, + const DiagnosticEngine& diag) { + auto symbols = table.allSymbols(); + std::ostringstream ss; + + ss << "{\n"; + ss << " \"file\": \"" << jsonEscape(filePath) << "\",\n"; + ss << " \"symbols\": ["; + + bool firstSym = true; + for (Symbol* s : symbols) { + if (s->isBuiltin) continue; + + if (!firstSym) ss << ","; + firstSym = false; + + ss << "\n {\n"; + ss << " \"name\": \"" << jsonEscape(s->name) << "\",\n"; + ss << " \"kind\": \"" << symbolKindName(s->kind) << "\",\n"; + ss << " \"type\": \"" << jsonEscape(s->type.toString()) << "\",\n"; + ss << " \"typeDetail\": " << s->type.toJson() << ",\n"; + ss << " \"definition\": " << s->definitionLoc.toJson() << ",\n"; + ss << " \"isBuiltin\": " << (s->isBuiltin ? "true" : "false") << ",\n"; + + // referanslar + ss << " \"references\": ["; + bool firstRef = true; + for (const SourceLocation& ref : s->references) { + if (!firstRef) ss << ", "; + firstRef = false; + ss << ref.toJson(); + } + ss << "]\n"; + + ss << " }"; + } + + if (!firstSym) ss << "\n "; + ss << "],\n"; + + // tanılar (diagnostic engine'den hazır JSON al, iç kısmını sar) + ss << " \"diagnostics\": " << diag.toJson() << "\n"; + ss << "}\n"; + + return ss.str(); +} + +// ───────────────────────────────────────────────────────────────────────────── +// cmdSymbols — giriş noktası +// ───────────────────────────────────────────────────────────────────────────── inline int cmdSymbols(const CliArgs& args) { - std::string source = readSource(args); + std::string filePath = inputFilePath(args); + std::string source = readSource(args); if (source.empty()) return 1; Tokenizer tokenizer; - auto tokens = tokenizer.scan(source, inputFilePath(args)); + auto tokens = tokenizer.scan(source, filePath); Parser parser; ASTNode* ast = parser.parse(tokens); if (!ast) { - std::cerr << "Hata: AST üretilemedi\n"; + // AST null olursa boş ama geçerli bir JSON çıktısı üret + DiagnosticEngine diag; + diag.report("E000", SourceLocation{}, "AST üretilemedi"); + SymbolTable empty; + std::cout << symbolsToJson(filePath, empty, diag); for (auto* t : tokens) delete t; return 1; } @@ -33,32 +96,7 @@ inline int cmdSymbols(const CliArgs& args) { DiagnosticEngine diag; SymbolCollector(table, diag).collect(ast); - auto symbols = table.allSymbols(); - - std::cout << "Sembol Tablosu (" << symbols.size() << " sembol):\n"; - std::cout << "────────────────────────────────────────────\n"; - - if (symbols.empty()) { - std::cout << " (sembol bulunamadı)\n"; - } - - for (Symbol* s : symbols) { - if (s->isBuiltin) continue; // builtinleri çıktıda gösterme - std::cout << " [" << symbolKindName(s->kind) << "] " - << s->type.toString() << " " << s->name - << " @" << s->definitionLoc.shortString() - << " refs(" << s->references.size() << "):"; - for (auto& r : s->references) - std::cout << " " << r.shortString(); - std::cout << "\n"; - } - - std::cout << "────────────────────────────────────────────\n"; - - if (diag.hasErrors()) { - std::cerr << "\n"; - diag.printAll(std::cerr); - } + std::cout << symbolsToJson(filePath, table, diag); delete ast; for (auto* t : tokens) delete t; diff --git a/src/parser/parser.cpp b/src/parser/parser.cpp index 398abde..714ef48 100644 --- a/src/parser/parser.cpp +++ b/src/parser/parser.cpp @@ -63,11 +63,13 @@ ASTNode* Parser::parseProgram() { ProgramNode* program = new ProgramNode(); while (currentToken().type != TokenType::SVR_VOID) { + int prevPos = current; ASTNode* decl = parseDeclaration(); if (decl) program->addChild(decl); - else - break; + // İlerleme olmadıysa token atla — syntax hatasında sonsuz döngüyü önler + if (current == prevPos) + nextToken(); } return program;