Files
whetstone_DSL/editor/src/SelfHostCodebaseAudit.h

140 lines
4.8 KiB
C++

#pragma once
// Step 493: Parse Full Whetstone Codebase
// Audits C++ parser coverage across header files.
#include "SelfHostHarness.h"
#include <filesystem>
#include <fstream>
#include <regex>
#include <set>
#include <string>
#include <vector>
struct FileParseAudit {
std::string path;
bool parseSuccess = false;
int classCount = 0;
int functionCount = 0;
int annotationNodeCount = 0;
int textualClassHints = 0;
int textualFunctionHints = 0;
std::vector<std::string> skippedConstructs;
std::vector<std::string> warnings;
};
struct CodebaseParseAudit {
std::vector<FileParseAudit> files;
int totalFiles = 0;
int parsedFiles = 0;
int totalClasses = 0;
int totalFunctions = 0;
int totalAnnotationNodes = 0;
int skippedClassConstructs = 0;
int skippedFunctionConstructs = 0;
std::vector<std::string> unparseableConstructLog;
double parseRate() const {
return totalFiles > 0 ? static_cast<double>(parsedFiles) / totalFiles : 1.0;
}
bool meetsTarget(double target = 0.95) const {
return parseRate() >= target;
}
};
class SelfHostCodebaseAudit {
public:
static std::vector<std::string> listHeaderFiles(const std::vector<std::string>& roots) {
std::set<std::string> unique;
std::error_code ec;
for (const auto& root : roots) {
if (!std::filesystem::exists(root, ec)) continue;
for (const auto& entry : std::filesystem::recursive_directory_iterator(root, ec)) {
if (ec) break;
if (!entry.is_regular_file()) continue;
const auto path = entry.path().string();
if (endsWith(path, ".h")) unique.insert(path);
}
}
return {unique.begin(), unique.end()};
}
static CodebaseParseAudit auditDirectories(const std::vector<std::string>& roots) {
return auditFiles(listHeaderFiles(roots));
}
static CodebaseParseAudit auditFiles(const std::vector<std::string>& files) {
CodebaseParseAudit out;
out.totalFiles = static_cast<int>(files.size());
for (const auto& path : files) {
auto fa = auditFile(path);
out.files.push_back(fa);
if (fa.parseSuccess) out.parsedFiles++;
out.totalClasses += fa.classCount;
out.totalFunctions += fa.functionCount;
out.totalAnnotationNodes += fa.annotationNodeCount;
for (const auto& s : fa.skippedConstructs) {
if (s == "class") out.skippedClassConstructs++;
if (s == "function") out.skippedFunctionConstructs++;
out.unparseableConstructLog.push_back(path + ": skipped " + s);
}
for (const auto& w : fa.warnings) {
out.unparseableConstructLog.push_back(path + ": " + w);
}
}
return out;
}
private:
static FileParseAudit auditFile(const std::string& path) {
FileParseAudit out;
out.path = path;
const std::string source = SelfHostHarness::readFile(path);
out.textualClassHints = countRegex(source, std::regex(R"(\b(class|struct)\s+[A-Za-z_])"));
out.textualFunctionHints = countRegex(source, std::regex(R"(\b[A-Za-z_~][A-Za-z0-9_:<>~]*\s+[A-Za-z_~][A-Za-z0-9_]*\s*\([^;\)]*\)\s*[\{;])"));
auto parsed = SelfHostHarness::parseFile(path);
out.parseSuccess = parsed.parseSuccess;
out.warnings = parsed.warnings;
out.classCount = SelfHostHarness::countClasses(parsed.ast.get());
out.functionCount = SelfHostHarness::countFunctions(parsed.ast.get());
out.annotationNodeCount = countAnnotations(parsed.ast.get());
if (out.textualClassHints > out.classCount) {
out.skippedConstructs.push_back("class");
}
if (out.textualFunctionHints > out.functionCount) {
out.skippedConstructs.push_back("function");
}
return out;
}
static int countRegex(const std::string& text, const std::regex& re) {
if (text.empty()) return 0;
auto begin = std::sregex_iterator(text.begin(), text.end(), re);
auto end = std::sregex_iterator();
int count = 0;
for (auto it = begin; it != end; ++it) ++count;
return count;
}
static bool endsWith(const std::string& value, const std::string& suffix) {
return value.size() >= suffix.size() &&
value.compare(value.size() - suffix.size(), suffix.size(), suffix) == 0;
}
static int countAnnotations(const ASTNode* node) {
if (!node) return 0;
int count = 0;
if (node->conceptType.find("Annotation") != std::string::npos) ++count;
for (auto* child : node->allChildren()) {
count += countAnnotations(child);
}
return count;
}
};