WIP: handling vtable generation

This commit is contained in:
Duncan Ogilvie 2023-07-07 11:38:31 +02:00
parent b92d01f5c8
commit 8e19f7ce0d
1 changed files with 165 additions and 97 deletions

View File

@ -6,132 +6,200 @@
#include "helpers.h" #include "helpers.h"
#include "preprocessor.h" #include "preprocessor.h"
#include "types.h" #include "types.h"
#include <unordered_set>
bool TestLexer(Lexer & lexer, const std::string & filename) bool TestLexer(Lexer& lexer, const std::string& filename)
{ {
if(!lexer.ReadInputFile("tests\\" + filename)) if (!lexer.ReadInputFile("tests\\" + filename))
{ {
printf("failed to read \"%s\"\n", filename.c_str()); printf("failed to read \"%s\"\n", filename.c_str());
return false; return false;
} }
std::string actual; std::string actual;
actual.reserve(65536); actual.reserve(65536);
auto success = lexer.Test([&](const std::string & line) auto success = lexer.Test([&](const std::string& line)
{ {
actual.append(line); actual.append(line);
}); });
std::string expected; std::string expected;
if(FileHelper::ReadAllText("tests\\exp_lex\\" + filename, expected) && expected == actual) if (FileHelper::ReadAllText("tests\\exp_lex\\" + filename, expected) && expected == actual)
{ {
printf("lexer test for \"%s\" success!\n", filename.c_str()); printf("lexer test for \"%s\" success!\n", filename.c_str());
return true; return true;
} }
if(success) if (success)
return true; return true;
printf("lexer test for \"%s\" failed...\n", filename.c_str()); printf("lexer test for \"%s\" failed...\n", filename.c_str());
FileHelper::WriteAllText("expected.out", expected); FileHelper::WriteAllText("expected.out", expected);
FileHelper::WriteAllText("actual.out", actual); FileHelper::WriteAllText("actual.out", actual);
return false; return false;
} }
bool DebugLexer(Lexer & lexer, const std::string & filename, bool output) bool DebugLexer(Lexer& lexer, const std::string& filename, bool output)
{ {
if(!lexer.ReadInputFile("tests\\" + filename)) if (!lexer.ReadInputFile("tests\\" + filename))
{ {
printf("failed to read \"%s\"\n", filename.c_str()); printf("failed to read \"%s\"\n", filename.c_str());
return false; return false;
} }
auto success = lexer.Test([](const std::string & line) auto success = lexer.Test([](const std::string& line)
{ {
printf("%s", line.c_str()); printf("%s", line.c_str());
}, output); }, output);
if(output) if (output)
puts(""); puts("");
return success; return success;
} }
void GenerateExpected(Lexer & lexer, const std::string & filename) void GenerateExpected(Lexer& lexer, const std::string& filename)
{ {
if(!lexer.ReadInputFile("tests\\" + filename)) if (!lexer.ReadInputFile("tests\\" + filename))
{ {
printf("failed to read \"%s\"\n", filename.c_str()); printf("failed to read \"%s\"\n", filename.c_str());
return; return;
} }
std::string actual; std::string actual;
actual.reserve(65536); actual.reserve(65536);
lexer.Test([&](const std::string & line) lexer.Test([&](const std::string& line)
{ {
actual.append(line); actual.append(line);
}); });
FileHelper::WriteAllText("tests\\exp_lex\\" + filename, actual); FileHelper::WriteAllText("tests\\exp_lex\\" + filename, actual);
} }
void GenerateExpectedTests() void GenerateExpectedTests()
{ {
Lexer lexer; Lexer lexer;
for(auto file : testFiles) for (auto file : testFiles)
GenerateExpected(lexer, file); GenerateExpected(lexer, file);
} }
void RunLexerTests() void RunLexerTests()
{ {
Lexer lexer; Lexer lexer;
for(auto file : testFiles) for (auto file : testFiles)
TestLexer(lexer, file); TestLexer(lexer, file);
} }
void DebugLexerTests(bool output = true) void DebugLexerTests(bool output = true)
{ {
Lexer lexer; Lexer lexer;
for(auto file : testFiles) for (auto file : testFiles)
DebugLexer(lexer, file, output); DebugLexer(lexer, file, output);
} }
bool DebugParser(const std::string & filename) static std::vector<std::string> SplitNamespace(const std::string& name, std::string& type)
{ {
std::string data; auto namespaces = StringUtils::Split(name, ':');
if (!FileHelper::ReadAllText("tests\\" + filename, data)) if (namespaces.empty())
{ {
printf("Failed to read: %s\n", filename.c_str()); type.clear();
return false; }
} else
{
type = namespaces.back();
namespaces.pop_back();
}
return namespaces;
}
std::string pperror; static void HandleVTable(Types::Model& model)
std::unordered_map<std::string, std::string> definitions; {
definitions["WIN32"] = ""; std::unordered_set<std::string> classes;
definitions["_MSC_VER"] = "1337"; std::unordered_set<std::string> visited;
auto ppData = preprocess(data, pperror, definitions); auto handleType = [&](const Types::QualifiedType& type)
if (!pperror.empty()) {
{ if (!type.kind.empty())
printf("Preprocess error: %s\n", pperror.c_str()); {
return false; const auto& name = type.name;
} const auto& kind = type.kind;
if (visited.count(name) != 0)
return;
visited.insert(name);
std::string rettype;
auto namespaces = SplitNamespace(name, rettype);
if (kind == "class" && rettype[0] == 'I')
classes.insert(name);
for (const auto& ns : namespaces)
{
printf("namespace %s {\n", ns.c_str());
}
printf(" %s %s {\n };\n", kind.c_str(), rettype.c_str());
for (const auto& ns : namespaces)
printf("}\n");
}
};
for (const auto& su : model.structUnions)
{
for (const auto& vf : su.vtable)
{
handleType(vf.rettype);
for (const auto& arg : vf.args)
handleType(arg.type);
}
}
for (const auto& f : model.functions)
{
handleType(f.rettype);
for (const auto& arg : f.args)
handleType(arg.type);
}
FileHelper::WriteAllText("tests\\" + filename + ".pp.h", ppData); puts("Used classes:");
for (const auto& name : classes)
{
printf("%s\n", name.c_str());
}
puts("vtable chuj");
}
std::vector<std::string> errors; bool DebugParser(const std::string& filename)
Types::TypeManager typeManager(sizeof(void*)); {
if (!typeManager.ParseTypes(ppData, filename, errors)) std::string data;
{ if (!FileHelper::ReadAllText("tests\\" + filename, data))
puts("Failed to parse types:"); {
for (const auto& error : errors) printf("Failed to read: %s\n", filename.c_str());
puts(error.c_str()); return false;
return false; }
}
puts("ParseFile success!"); std::string pperror;
return true; std::unordered_map<std::string, std::string> definitions;
definitions["WIN32"] = "";
definitions["_MSC_VER"] = "1337";
auto ppData = preprocess(data, pperror, definitions);
if (!pperror.empty())
{
printf("Preprocess error: %s\n", pperror.c_str());
return false;
}
FileHelper::WriteAllText("tests\\" + filename + ".pp.h", ppData);
std::vector<std::string> errors;
Types::Model model;
if (!Types::ParseModel(ppData, filename, errors, model))
{
puts("Failed to parse types:");
for (const auto& error : errors)
puts(error.c_str());
return false;
}
puts("ParseModel success!");
HandleVTable(model);
return true;
} }
int main() int main()
{ {
//GenerateExpectedTests(); //GenerateExpectedTests();
auto ticks = GetTickCount(); auto ticks = GetTickCount();
DebugParser("cursor.hpp"); DebugParser("cursor.hpp");
//Lexer lexer; //Lexer lexer;
//DebugLexer(lexer, "AndroidManifestTemplate.bt", false); //DebugLexer(lexer, "AndroidManifestTemplate.bt", false);
//RunLexerTests(); //RunLexerTests();
printf("finished in %ums\n", GetTickCount() - ticks); printf("finished in %ums\n", (unsigned int)(GetTickCount() - ticks));
system("pause"); system("pause");
return 0; return 0;
} }