118 lines
No EOL
3.9 KiB
C++
118 lines
No EOL
3.9 KiB
C++
#include <clang-c/CXDiagnostic.h>
|
|
#include <clang-c/CXFile.h>
|
|
#include <clang-c/CXSourceLocation.h>
|
|
#include <clang-c/CXString.h>
|
|
#include <clang-c/Index.h>
|
|
#include <cstdio>
|
|
#include <fstream>
|
|
#include <filesystem>
|
|
#include "enum/analysis.h"
|
|
#include "enum/codegen.h"
|
|
#include "object/analysis.h"
|
|
#include "object/codegen.h"
|
|
#include "data/analysis.h"
|
|
#include "data/codegen.h"
|
|
#include "util.h"
|
|
|
|
// namespace data {
|
|
// #include "data/analysis.h"
|
|
// #include "data/codegen.h"
|
|
// }
|
|
|
|
namespace fs = std::filesystem;
|
|
|
|
// https://clang.llvm.org/docs/LibClang.html
|
|
int processHeader(fs::path srcRoot, fs::path srcPath, fs::path outPath) {
|
|
std::string srcRootStr = string_of(srcRoot);
|
|
std::string srcPathStr = string_of(srcPath);
|
|
std::string outPathStr = string_of(outPath);
|
|
std::string logFileStr = outPathStr + ".log";
|
|
|
|
const char* cargs[] = { "-xc++", "-std=c++17", "-I", srcRootStr.c_str(), "-D__AUTOGEN__", 0 };
|
|
// THANK YOU SO MUCH THIS STACKOVERFLOW ANSWER IS SO HELPFUL
|
|
// https://stackoverflow.com/a/59206378/16255372
|
|
CXIndex index = clang_createIndex(0, 0);
|
|
CXTranslationUnit unit = clang_parseTranslationUnit(
|
|
index,
|
|
srcPathStr.c_str(), cargs, 5,
|
|
nullptr, 0,
|
|
CXTranslationUnit_None);
|
|
|
|
if (!unit) {
|
|
fprintf(stderr, "Failed to parse file\n");
|
|
return 1;
|
|
}
|
|
|
|
fs::create_directories(outPath.parent_path()); // Make sure generated dir exists before we try writing to it
|
|
|
|
// We write to a special log file instead of stdout/stderr to
|
|
// 1. avoid confusion
|
|
// 2. prevent MSBuild from reading the word "error" and detecting there's a problem with the program (there isn't)
|
|
FILE* logout = fopen(logFileStr.c_str(), "w");
|
|
|
|
// Print errors
|
|
int ndiags = clang_getNumDiagnostics(unit);
|
|
for (int i = 0; i < ndiags; i++) {
|
|
CXDiagnostic diag = clang_getDiagnostic(unit, i);
|
|
CXString str = clang_formatDiagnostic(diag, 0);
|
|
fprintf(logout, "diag: %s\n", clang_getCString(str));
|
|
|
|
clang_disposeString(str);
|
|
clang_disposeDiagnostic(diag);
|
|
}
|
|
|
|
fclose(logout);
|
|
|
|
CXCursor cursor = clang_getTranslationUnitCursor(unit);
|
|
|
|
object::AnalysisState objectAnlyState;
|
|
data::AnalysisState dataAnlyState;
|
|
enum_::AnalysisState enumAnlyState;
|
|
|
|
fs::path relpath = fs::relative(srcPath, srcRoot);
|
|
std::string relpathStr = string_of(relpath);
|
|
printf("[AUTOGEN] Processing file %s...\n", relpathStr.c_str());
|
|
object::analyzeClasses(cursor, srcRootStr, &objectAnlyState);
|
|
data::analyzeClasses(cursor, srcRootStr, &dataAnlyState);
|
|
enum_::analyzeClasses(cursor, srcRootStr, &enumAnlyState);
|
|
|
|
printf("[AUTOGEN] Generating file %s...\n", relpathStr.c_str());
|
|
std::ofstream outStream(outPathStr);
|
|
|
|
if (!objectAnlyState.classes.empty() || !dataAnlyState.classes.empty()) {
|
|
outStream << "/////////////////////////////////////////////////////////////////////////////////////////\n";
|
|
outStream << "// This file was automatically generated by autogen, and should not be edited manually //\n";
|
|
outStream << "/////////////////////////////////////////////////////////////////////////////////////////\n\n";
|
|
}
|
|
|
|
for (auto& [_, clazz] : objectAnlyState.classes) {
|
|
object::writeCodeForClass(outStream, relpathStr, clazz);
|
|
}
|
|
|
|
for (auto& [_, clazz] : dataAnlyState.classes) {
|
|
data::writeCodeForClass(outStream, relpathStr, clazz);
|
|
}
|
|
|
|
for (auto& [_, clazz] : enumAnlyState.classes) {
|
|
enum_::writeCodeForClass(outStream, relpathStr, clazz);
|
|
}
|
|
|
|
outStream.close();
|
|
|
|
return 0;
|
|
}
|
|
|
|
int main(int argc, char** argv) {
|
|
if (argc < 4) {
|
|
fprintf(stderr, "Usage: autogen <src-root> <src-file> <out-dir>\n");
|
|
return 1;
|
|
}
|
|
|
|
fs::path srcRoot = argv[1];
|
|
fs::path srcPath = argv[2];
|
|
fs::path outPath = argv[3];
|
|
|
|
// fprintf(stderr, "Some error here\n");
|
|
// return 0;
|
|
return processHeader(srcRoot, srcPath, outPath);
|
|
} |