#pragma once // Step 493: Parse Full Whetstone Codebase // Audits C++ parser coverage across header files. #include "SelfHostHarness.h" #include #include #include #include #include #include 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 skippedConstructs; std::vector warnings; }; struct CodebaseParseAudit { std::vector files; int totalFiles = 0; int parsedFiles = 0; int totalClasses = 0; int totalFunctions = 0; int totalAnnotationNodes = 0; int skippedClassConstructs = 0; int skippedFunctionConstructs = 0; std::vector unparseableConstructLog; double parseRate() const { return totalFiles > 0 ? static_cast(parsedFiles) / totalFiles : 1.0; } bool meetsTarget(double target = 0.95) const { return parseRate() >= target; } }; class SelfHostCodebaseAudit { public: static std::vector listHeaderFiles(const std::vector& roots) { std::set 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& roots) { return auditFiles(listHeaderFiles(roots)); } static CodebaseParseAudit auditFiles(const std::vector& files) { CodebaseParseAudit out; out.totalFiles = static_cast(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; } };