Switch to QualifiedType everywhere

This commit is contained in:
Duncan Ogilvie 2023-04-06 10:25:13 +02:00
parent 659a8e87a6
commit 07a7b308e8
4 changed files with 128 additions and 121 deletions

View File

@ -110,7 +110,7 @@ bool DebugParser(const std::string & filename)
FileHelper::WriteAllText("tests\\" + filename + ".pp.h", ppData);
std::vector<std::string> errors;
Types::TypeManager typeManager;
Types::TypeManager typeManager(sizeof(void*));
if (!typeManager.ParseTypes(ppData, filename, errors))
{
puts("Failed to parse types:");

View File

@ -9,7 +9,7 @@ using namespace Types;
#define EXCLUSIVE_ACQUIRE(x)
#define SHARED_ACQUIRE(x)
TypeManager::TypeManager()
TypeManager::TypeManager(size_t pointerSize)
{
auto p = [this](const std::string & n, Primitive p, int size)
{
@ -21,21 +21,21 @@ TypeManager::TypeManager()
addType("", p, split);
}
};
p("int8_t,int8,char,byte,bool,signed char", Int8, sizeof(char));
p("uint8_t,uint8,uchar,unsigned char,ubyte", Uint8, sizeof(unsigned char));
p("int16_t,int16,wchar_t,char16_t,short", Int16, sizeof(short));
p("uint16_t,uint16,ushort,unsigned short", Int16, sizeof(unsigned short));
p("int32_t,int32,int,long", Int32, sizeof(int));
p("uint32_t,uint32,unsigned int,unsigned long", Uint32, sizeof(unsigned int));
p("int64_t,int64,long long", Int64, sizeof(long long));
p("uint64_t,uint64,unsigned long long", Uint64, sizeof(unsigned long long));
p("dsint", Dsint, sizeof(void*));
p("size_t,duint", Duint, sizeof(void*));
p("int8_t,int8,char,byte,bool,signed char", Int8, sizeof(int8_t));
p("uint8_t,uint8,uchar,unsigned char,ubyte", Uint8, sizeof(uint8_t));
p("int16_t,int16,wchar_t,char16_t,short", Int16, sizeof(int16_t));
p("uint16_t,uint16,ushort,unsigned short", Uint16, sizeof(uint16_t));
p("int32_t,int32,int,long", Int32, sizeof(int32_t));
p("uint32_t,uint32,unsigned int,unsigned long", Uint32, sizeof(uint32_t));
p("int64_t,int64,long long", Int64, sizeof(int64_t));
p("uint64_t,uint64,unsigned long long", Uint64, sizeof(uint64_t));
p("ssize_t,dsint", Dsint, pointerSize);
p("size_t,duint", Duint, pointerSize);
p("float", Float, sizeof(float));
p("double", Double, sizeof(double));
p("void*,ptr", Pointer, sizeof(void*));
p("char*,const char*", PtrString, sizeof(char*));
p("wchar_t*,const wchar_t*", PtrWString, sizeof(wchar_t*));
p("void*,ptr", Pointer, pointerSize);
p("char*,const char*", PtrString, pointerSize);
p("wchar_t*,const wchar_t*", PtrWString, pointerSize);
}
std::string Types::TypeManager::PrimitiveName(Primitive primitive)
@ -48,7 +48,6 @@ bool TypeManager::AddType(const std::string & owner, const std::string & type, c
{
if(owner.empty())
return false;
validPtr(type);
auto found = types.find(type);
if(found == types.end())
return false;
@ -60,11 +59,10 @@ bool Types::TypeManager::AddEnum(const std::string& owner, const std::string& na
Enum e;
e.name = name;
e.owner = owner;
auto found = types.find(type);
if (found == types.end())
return false;
if (!found->second.pointto.empty())
return false;
switch (found->second.primitive)
{
case Void:
@ -98,12 +96,12 @@ bool TypeManager::AddUnion(const std::string & owner, const std::string & name)
return addStructUnion(u);
}
bool TypeManager::AddMember(const std::string & parent, const std::string & type, const std::string & name, int arrsize, int offset)
bool TypeManager::AddMember(const std::string & parent, const QualifiedType& type, const std::string & name, int arrsize, int offset)
{
if(!isDefined(type) && !validPtr(type))
if(!isDefined(type.name))
return false;
auto found = structs.find(parent);
if(arrsize < 0 || found == structs.end() || !isDefined(type) || name.empty() || type.empty() || type == parent)
if(arrsize < 0 || found == structs.end() || name.empty() || type.empty() || type.name == parent)
return false;
auto & s = found->second;
@ -128,7 +126,7 @@ bool TypeManager::AddMember(const std::string & parent, const std::string & type
if(offset > s.size)
{
Member pad;
pad.type = "char";
pad.type = QualifiedType("char");
pad.arrsize = offset - s.size;
char padname[32] = "";
sprintf_s(padname, "padding%d", pad.arrsize);
@ -152,7 +150,7 @@ bool TypeManager::AddMember(const std::string & parent, const std::string & type
return true;
}
bool TypeManager::AppendMember(const std::string & type, const std::string & name, int arrsize, int offset)
bool TypeManager::AppendMember(const QualifiedType& type, const std::string & name, int arrsize, int offset)
{
return AddMember(laststruct, type, name, arrsize, offset);
}
@ -175,7 +173,7 @@ bool Types::TypeManager::AddEnumerator(const std::string& enumType, const std::s
return true;
}
bool TypeManager::AddFunction(const std::string & owner, const std::string & name, const QualifiedType& retqtype, CallingConvention callconv, bool noreturn, bool typeonly)
bool TypeManager::AddFunction(const std::string & owner, const std::string & name, const QualifiedType& rettype, CallingConvention callconv, bool noreturn, bool typeonly)
{
auto found = functions.find(name);
if(found != functions.end() || name.empty() || owner.empty())
@ -184,9 +182,10 @@ bool TypeManager::AddFunction(const std::string & owner, const std::string & nam
Function f;
f.owner = owner;
f.name = name;
if (retqtype.name != "void" && !isDefined(retqtype.name))
auto isVoid = !rettype.isPointer() && rettype.name == "void";
if (!isVoid && !isDefined(rettype))
return false;
f.retqtype = retqtype;
f.rettype = rettype;
f.callconv = callconv;
f.noreturn = noreturn;
f.typeonly = typeonly;
@ -194,25 +193,24 @@ bool TypeManager::AddFunction(const std::string & owner, const std::string & nam
return true;
}
bool TypeManager::AddArg(const std::string & function, const std::string & type, const std::string & name, const QualifiedType& qtype)
bool TypeManager::AddArg(const std::string & function, const QualifiedType& type, const std::string & name)
{
auto found = functions.find(function);
if (found == functions.end() || name.empty())
return false;
if(type != "..." && !isDefined(type) && !validPtr(type))
if(type.name != "..." && !isDefined(type))
return false;
lastfunction = function;
Member arg;
arg.name = name;
arg.type = type;
arg.qtype = qtype;
found->second.args.push_back(arg);
return true;
}
bool TypeManager::AppendArg(const std::string & type, const std::string & name, const QualifiedType& qtype)
bool TypeManager::AppendArg(const QualifiedType& type, const std::string & name)
{
return AddArg(lastfunction, type, name, qtype);
return AddArg(lastfunction, type, name);
}
int TypeManager::Sizeof(const std::string& type) const
@ -225,20 +223,22 @@ int TypeManager::Sizeof(const std::string & type) const
return foundS->second.size;
auto foundF = functions.find(type);
if (foundF != functions.end())
{
const auto foundP = primitivesizes.find(Pointer);
if(foundP != primitivesizes.end())
return foundP->second;
return sizeof(void*);
}
return primitivesizes.at(Pointer);
return 0;
}
int TypeManager::Sizeof(const QualifiedType& type) const
{
if (type.isPointer())
return primitivesizes.at(Pointer);
return Sizeof(type.name);
}
bool TypeManager::Visit(const std::string & type, const std::string & name, Visitor & visitor) const
{
Member m;
m.name = name;
m.type = type;
m.type = QualifiedType(type);
return visitMember(m, visitor);
}
@ -363,30 +363,18 @@ static bool mapContains(const std::unordered_map<K, V> & map, const K & k)
return map.find(k) != map.end();
}
bool Types::TypeManager::isDefined(const QualifiedType& type) const
{
if (type.name == "void" && type.isPointer())
return true;
return isDefined(type.name);
}
bool TypeManager::isDefined(const std::string & id) const
{
return mapContains(types, id) || mapContains(structs, id) || mapContains(enums, id) || mapContains(functions, id);
}
bool TypeManager::validPtr(const std::string & id)
{
if(id[id.length() - 1] == '*')
{
auto type = id.substr(0, id.length() - 1);
if(!isDefined(type) && !validPtr(type))
return false;
std::string owner("ptr");
auto foundT = types.find(type);
if(foundT != types.end())
owner = foundT->second.owner;
auto foundS = structs.find(type);
if(foundS != structs.end())
owner = foundS->second.owner;
return addType(owner, Pointer, id, type);
}
return false;
}
bool TypeManager::addStructUnion(const StructUnion & s)
{
laststruct = s.name;
@ -410,7 +398,7 @@ bool TypeManager::addType(const Type & t)
return types.emplace(t.name, t).second;
}
bool TypeManager::addType(const std::string & owner, Primitive primitive, const std::string & name, const std::string & pointto)
bool TypeManager::addType(const std::string & owner, Primitive primitive, const std::string & name)
{
if(name.empty() || isDefined(name))
return false;
@ -419,16 +407,19 @@ bool TypeManager::addType(const std::string & owner, Primitive primitive, const
t.name = name;
t.primitive = primitive;
t.size = primitivesizes[primitive];
t.pointto = pointto;
return addType(t);
}
bool TypeManager::visitMember(const Member & root, Visitor & visitor) const
{
auto foundT = types.find(root.type);
auto foundT = types.find(root.type.name);
if(foundT != types.end())
{
const auto & t = foundT->second;
// TODO: add back pointer support
if (root.type.isPointer())
__debugbreak();
#if 0
if(!t.pointto.empty())
{
if(!isDefined(t.pointto))
@ -441,9 +432,10 @@ bool TypeManager::visitMember(const Member & root, Visitor & visitor) const
}
return true;
}
#endif
return visitor.visitType(root, t);
}
auto foundS = structs.find(root.type);
auto foundS = structs.find(root.type.name);
if(foundS != structs.end())
{
const auto & s = foundS->second;
@ -475,17 +467,17 @@ bool TypeManager::GenerateStubs() const
std::unordered_set<std::string> declared;
auto formatFunctionPointer = [this](const std::string& name, const Function& fn)
{
std::string r = fn.retqtype.pretty();
std::string r = fn.rettype.pretty();
r += " (*";
r += name;
r += ")(";
for(size_t i = 0; i < fn.args.size(); i++)
{
const auto& arg = fn.args[i];
if(functions.count(arg.type) != 0)
if(functions.count(arg.type.name) != 0)
__debugbreak();
r += arg.qtype.pretty();
r += arg.type.pretty();
if(i + 1 < fn.args.size())
{
r += ", ";
@ -513,7 +505,7 @@ bool TypeManager::GenerateStubs() const
auto variadic = false;
for (const auto &arg: fn.args)
{
if (arg.type == "...")
if (arg.type.name == "...")
{
variadic = true;
break;
@ -539,25 +531,25 @@ bool TypeManager::GenerateStubs() const
const auto& fn = functions.at(hook);
puts("");
printf("static ");
printf("%s", fn.retqtype.pretty().c_str());
printf("%s", fn.rettype.pretty().c_str());
printf(" hook_%s(\n", fn.name.c_str());
std::vector<std::string> argtypes;
for(size_t i = 0; i < fn.args.size(); i++)
{
const auto& arg = fn.args[i];
printf(" ");
auto argPtr = functions.find(arg.type);
auto argPtr = functions.find(arg.type.name);
if(argPtr != functions.end())
{
argtypes.push_back(formatFunctionPointer(arg.name, argPtr->second));
printf("%s", argtypes.back().c_str());
if(arg.qtype.isConst)
if(arg.type.isConst)
__debugbreak();
}
else
{
argtypes.push_back(arg.type);
printf("%s", arg.qtype.pretty().c_str());
argtypes.push_back(arg.type.pretty());
printf("%s", arg.type.pretty().c_str());
printf(" ");
printf("%s", arg.name.c_str());
}
@ -574,7 +566,7 @@ bool TypeManager::GenerateStubs() const
{
printf(" LOG_ARGUMENT(\"%s\", %s);\n", argtypes[i].c_str(), fn.args[i].name.c_str());
}
if(fn.retqtype.name == "void")
if(fn.rettype.name == "void")
{
printf(" orig_%s(", fn.name.c_str());
}
@ -592,7 +584,7 @@ bool TypeManager::GenerateStubs() const
}
}
puts(");");
if(fn.retqtype.name == "void")
if(fn.rettype.name == "void")
{
puts(" LOG_RETURN_VOID();");
}

View File

@ -31,7 +31,6 @@ namespace Types
{
std::string owner; //Type owner
std::string name; //Type identifier.
std::string pointto; //Type identifier of *Type (empty when the type is a primitive type)
Primitive primitive = Void; //Primitive type.
int size = 0; //Size in bytes.
};
@ -41,6 +40,12 @@ namespace Types
std::string name; // base name of the type
bool isConst = false; // whether the base type is const
QualifiedType() = default;
explicit QualifiedType(const std::string& name)
: name(name)
{
}
struct Ptr
{
bool isConst = false;
@ -70,13 +75,22 @@ namespace Types
r += '*';
return r;
}
bool empty() const
{
return name.empty();
}
bool isPointer() const
{
return !pointers.empty();
}
};
struct Member
{
std::string name; //Member identifier
std::string type; //Type.name
QualifiedType qtype; // Qualified Type
QualifiedType type; // Qualified Type
int arrsize = 0; //Number of elements if Member is an array (unused for function arguments)
int offset = -1; //Member offset (only stored for reference)
};
@ -94,7 +108,7 @@ namespace Types
{
std::string owner; //Function owner
std::string name; //Function identifier
QualifiedType retqtype; // Function return type
QualifiedType rettype; // Function return type
CallingConvention callconv = DefaultDecl; //Function calling convention
bool noreturn = false; //Function does not return (ExitProcess, _exit)
bool typeonly = false; //Function is only used as a type (the name is based on where it's used)
@ -153,18 +167,19 @@ namespace Types
int size = 0;
};
explicit TypeManager();
explicit TypeManager(size_t pointerSize);
std::string PrimitiveName(Primitive primitive);
bool AddType(const std::string & owner, const std::string & type, const std::string & name);
bool AddEnum(const std::string& owner, const std::string& name, const std::string & type);
bool AddStruct(const std::string & owner, const std::string & name);
bool AddUnion(const std::string & owner, const std::string & name);
bool AddMember(const std::string & parent, const std::string & type, const std::string & name, int arrsize = 0, int offset = -1);
bool AppendMember(const std::string & type, const std::string & name, int arrsize = 0, int offset = -1);
bool AddFunction(const std::string & owner, const std::string & name, const QualifiedType& retqtype, CallingConvention callconv = Cdecl, bool noreturn = false, bool typeonly = false);
bool AddMember(const std::string & parent, const QualifiedType & type, const std::string & name, int arrsize = 0, int offset = -1);
bool AppendMember(const QualifiedType & type, const std::string & name, int arrsize = 0, int offset = -1);
bool AddFunction(const std::string & owner, const std::string & name, const QualifiedType& rettype, CallingConvention callconv = Cdecl, bool noreturn = false, bool typeonly = false);
bool AddEnumerator(const std::string& enumType, const std::string& name, uint64_t value);
bool AddArg(const std::string & function, const std::string & type, const std::string & name, const QualifiedType& qtype);
bool AppendArg(const std::string & type, const std::string & name, const QualifiedType& qtype);
bool AddArg(const std::string & function, const QualifiedType & type, const std::string & name);
bool AppendArg(const QualifiedType& type, const std::string & name);
int Sizeof(const QualifiedType& type) const;
int Sizeof(const std::string& type) const;
bool Visit(const std::string & type, const std::string & name, Visitor & visitor) const;
void Clear(const std::string & owner = "");
@ -186,11 +201,11 @@ namespace Types
std::string laststruct;
std::string lastfunction;
bool isDefined(const QualifiedType& type) const;
bool isDefined(const std::string & id) const;
bool validPtr(const std::string & id);
bool addStructUnion(const StructUnion & s);
bool addEnum(const Enum& e);
bool addType(const std::string & owner, Primitive primitive, const std::string & name, const std::string & pointto = "");
bool addType(const std::string & owner, Primitive primitive, const std::string & name);
bool addType(const Type & t);
bool visitMember(const Member & root, Visitor & visitor) const;
};

View File

@ -78,10 +78,10 @@ struct Parser
index++;
}
bool parseVariable(const std::vector<Lexer::TokenState>& tlist, QualifiedType& qtype, std::string& name)
bool parseVariable(const std::vector<Lexer::TokenState>& tlist, QualifiedType& type, std::string& name)
{
std::string type; // TODO: get rid of this variable
qtype = QualifiedType();
std::string stype; // TODO: get rid of this variable
type = QualifiedType();
name.clear();
bool sawPointer = false;
@ -92,10 +92,10 @@ struct Parser
const auto& t = tlist[i];
if (t.Is(Lexer::tok_const))
{
if(i == 0 || qtype.pointers.empty())
qtype.isConst = true;
if(i == 0 || type.pointers.empty())
type.isConst = true;
else
qtype.pointers.back().isConst = true;
type.pointers.back().isConst = true;
continue;
}
@ -109,9 +109,9 @@ struct Parser
{
if (isKeyword)
{
if (!type.empty())
type += ' ';
type += lexer.TokString(t);
if (!stype.empty())
stype += ' ';
stype += lexer.TokString(t);
}
else
{
@ -121,9 +121,9 @@ struct Parser
}
else if (t.Is(Lexer::tok_identifier))
{
if (type.empty())
if (stype.empty())
{
type = t.IdentifierStr;
stype = t.IdentifierStr;
}
else if (i + 1 == tlist.size())
{
@ -137,25 +137,25 @@ struct Parser
}
else if (t.Is(Lexer::tok_op_mul) || t.Is(Lexer::tok_op_and))
{
if (type.empty())
if (stype.empty())
{
errLine(t, "unexpected * in type");
return false;
}
if (sawPointer && type.back() != '*')
if (sawPointer && stype.back() != '*')
{
errLine(t, "unexpected * in type");
return false;
}
if(!sawPointer)
qtype.name = type;
type.name = stype;
qtype.pointers.emplace_back();
type.pointers.emplace_back();
// Apply the pointer to the type on the left
type += '*';
stype += '*';
sawPointer = true;
}
else
@ -164,10 +164,10 @@ struct Parser
return false;
}
}
if (type.empty())
if (stype.empty())
__debugbreak();
if(!sawPointer)
qtype.name = type;
type.name = stype;
return true;
}
@ -182,7 +182,7 @@ struct Parser
// TODO: calling conventions
std::string retname;
if (!parseVariable(rettypes, fn.retqtype, retname))
if (!parseVariable(rettypes, fn.rettype, retname))
return false;
if (ptr)
@ -248,9 +248,8 @@ struct Parser
auto finalizeArgument = [&]()
{
Member am;
if (!parseVariable(tlist, am.qtype, am.name))
if (!parseVariable(tlist, am.type, am.name))
return false;
am.type = am.qtype.noconst(); // TODO: remove
fn.args.push_back(am);
tlist.clear();
startToken = curToken();
@ -336,7 +335,7 @@ struct Parser
}
Member am;
am.type = "...";
am.type = QualifiedType("...");
fn.args.push_back(am);
break;
}
@ -413,11 +412,10 @@ struct Parser
return false;
}
if (!parseVariable(tlist, m.qtype, m.name))
if (!parseVariable(tlist, m.type, m.name))
return false;
m.type = m.qtype.noconst();
if (m.type == "void")
if (m.type.name == "void" && !m.type.isPointer())
{
errLine(startToken, "void is not a valid member type");
return false;
@ -882,9 +880,8 @@ struct Parser
}
Member tm;
if (!parseVariable(tlist, tm.qtype, tm.name))
if (!parseVariable(tlist, tm.type, tm.name))
return false;
tm.type = tm.qtype.noconst();
model.types.push_back(tm);
}
return true;
@ -1033,11 +1030,14 @@ struct Parser
//Add simple typedefs
for (auto& type : model.types)
{
auto success = typeManager.AddType(owner, type.type, type.name);
// TODO: support pointers
if (type.type.isPointer() || type.type.isConst)
__debugbreak();
auto success = typeManager.AddType(owner, type.type.name, type.name);
if (!success)
{
//TODO properly handle errors
dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to add typedef %s %s;\n"), type.type.c_str(), type.name.c_str());
dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to add typedef %s %s;\n"), type.type.pretty().c_str(), type.name.c_str());
}
}
@ -1067,11 +1067,11 @@ struct Parser
//Add base function types to avoid errors later
for (auto& function : model.functions)
{
auto success = typeManager.AddFunction(owner, function.name, function.retqtype, function.callconv, function.noreturn, function.typeonly);
auto success = typeManager.AddFunction(owner, function.name, function.rettype, function.callconv, function.noreturn, function.typeonly);
if (!success)
{
//TODO properly handle errors
dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to add function %s %s()\n"), function.retqtype.pretty().c_str(), function.name.c_str());
dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to add function %s %s()\n"), function.rettype.pretty().c_str(), function.name.c_str());
function.name.clear(); //signal error
}
}
@ -1087,7 +1087,7 @@ struct Parser
if (!success)
{
//TODO properly handle errors
dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to add member %s %s.%s;\n"), member.type.c_str(), su.name.c_str(), member.name.c_str());
dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to add member %s %s.%s;\n"), member.type.pretty().c_str(), su.name.c_str(), member.name.c_str());
}
}
}
@ -1102,11 +1102,11 @@ struct Parser
auto& arg = function.args[i];
if (arg.name.empty())
arg.name = "__unnamed_arg_" + std::to_string(i);
auto success = typeManager.AddArg(function.name, arg.type, arg.name, arg.qtype);
auto success = typeManager.AddArg(function.name, arg.type, arg.name);
if (!success)
{
//TODO properly handle errors
dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to add argument %s[%zu]: %s %s;\n"), function.name.c_str(), i, arg.type.c_str(), arg.name.c_str());
dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to add argument %s[%zu]: %s %s;\n"), function.name.c_str(), i, arg.type.pretty().c_str(), arg.name.c_str());
}
}
}