feat(symbols): JSON çıktı + syntax hata toleransı

- 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 <noreply@anthropic.com>
This commit is contained in:
saqut 2026-06-18 16:11:34 +03:00
parent 218d54ba61
commit 79c51af501
4 changed files with 75 additions and 32 deletions

Binary file not shown.

View File

@ -15,3 +15,6 @@
0 22 1781786586571540360 build.ninja 1876a59d627a585
0 22 1781786586571540360 /home/saqut/Masaüstü/saqutcompiler/build/cmake_install.cmake 1876a59d627a585
1 2086 1781786305407208932 CMakeFiles/saqut.dir/src/symbol/symbol_collector.cpp.o 3348f498f369213d
10 1265 1781788264862998611 CMakeFiles/saqut.dir/src/parser/parser.cpp.o 2c65b7be26cead32
10 2216 1781788264862423222 CMakeFiles/saqut.dir/src/main.cpp.o 110c26cb1d0c3a23
2216 2383 1781788267068424572 saqut 8525928b86934b0a

View File

@ -1,30 +1,93 @@
// ============================================================================
// saQut CLI — symbols komutu (sembol tablosu — Faz 2)
// saQut CLI — symbols komutu (sembol tablosu — JSON çıktı, Faz 2)
// ============================================================================
#ifndef SAQUT_CLI_SYMBOLS
#define SAQUT_CLI_SYMBOLS
#include <iostream>
#include <sstream>
#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 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;

View File

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