C++: Correctly handle nested function pointer definitions
This commit is contained in:
@@ -113,7 +113,7 @@ namespace Il2CppInspector.Cpp
|
|||||||
public List<(string Name, CppType Type)> Arguments { get; }
|
public List<(string Name, CppType Type)> Arguments { get; }
|
||||||
|
|
||||||
// Regex which matches a function pointer
|
// Regex which matches a function pointer
|
||||||
public const string Regex = @"(\S+)\s*\(\s*\*\s*(\S+?)\s*?\)\s*\(\s*(.*?)\s*\)";
|
public const string Regex = @"(\S+)\s*\(\s*\*\s*(\S+?)\s*?\)\s*\(\s*(.*)\s*\)";
|
||||||
|
|
||||||
public CppFnPtrType(int WordSize, CppType returnType, List<(string Name, CppType Type)> arguments) : base(null, WordSize) {
|
public CppFnPtrType(int WordSize, CppType returnType, List<(string Name, CppType Type)> arguments) : base(null, WordSize) {
|
||||||
ReturnType = returnType;
|
ReturnType = returnType;
|
||||||
@@ -121,37 +121,91 @@ namespace Il2CppInspector.Cpp
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Generate a CppFnPtrType from a text signature (typedef or field)
|
// Generate a CppFnPtrType from a text signature (typedef or field)
|
||||||
// TODO: Fails to select correct arguments if one or more arguments are a function pointer; needs recursive parsing
|
|
||||||
public static CppFnPtrType FromSignature(CppTypeCollection types, string text) {
|
public static CppFnPtrType FromSignature(CppTypeCollection types, string text) {
|
||||||
if (text.StartsWith("typedef "))
|
if (text.StartsWith("typedef "))
|
||||||
text = text.Substring(8);
|
text = text.Substring(8);
|
||||||
|
|
||||||
var typedef = System.Text.RegularExpressions.Regex.Match(text, Regex);
|
if (text.EndsWith(";"))
|
||||||
|
text = text[..^1];
|
||||||
|
|
||||||
|
var typedef = System.Text.RegularExpressions.Regex.Match(text, Regex + "$");
|
||||||
|
|
||||||
var returnType = types.GetType(typedef.Groups[1].Captures[0].ToString());
|
var returnType = types.GetType(typedef.Groups[1].Captures[0].ToString());
|
||||||
var name = typedef.Groups[2].Captures[0].ToString();
|
var fnPtrName = typedef.Groups[2].Captures[0].ToString();
|
||||||
|
|
||||||
var argumentText = typedef.Groups[3].Captures[0].ToString().Split(',');
|
var argumentText = typedef.Groups[3].Captures[0].ToString() + ")";
|
||||||
if (argumentText.Length == 1 && argumentText[0] == "")
|
|
||||||
argumentText = new string[0];
|
|
||||||
var argumentNames = argumentText.Select(
|
|
||||||
a => a.IndexOf("*") != -1 ? a.Substring(a.LastIndexOf("*") + 1).Trim() :
|
|
||||||
a.IndexOf(" ") != -1 ? a.Substring(a.LastIndexOf(" ") + 1) : "");
|
|
||||||
|
|
||||||
var arguments = argumentNames.Zip(argumentText, (name, argument) =>
|
// Look for each argument one at a time
|
||||||
(name, types.GetType(argument.Substring(0, argument.Length - name.Length)))).ToList();
|
// An argument is complete when we have zero bracket depth and either a comma or a close bracket (final argument)
|
||||||
|
var arguments = new List<string>();
|
||||||
|
while (argumentText.Length > 0) {
|
||||||
|
string argument = null;
|
||||||
|
var originalArgumentText = argumentText;
|
||||||
|
var depth = 0;
|
||||||
|
while (depth >= 0) {
|
||||||
|
var firstComma = argumentText.IndexOf(",");
|
||||||
|
var firstOpenBracket = argumentText.IndexOf("(");
|
||||||
|
var firstCloseBracket = argumentText.IndexOf(")");
|
||||||
|
if (firstOpenBracket == -1) {
|
||||||
|
argument += argumentText.Substring(0, 1 + ((firstComma != -1) ? firstComma : firstCloseBracket));
|
||||||
|
// End of argument if we get a comma or close bracket at zero depth,
|
||||||
|
// but only for the final close bracket if we are inside a function pointer signature
|
||||||
|
if (depth == 0 || firstComma == -1)
|
||||||
|
depth--;
|
||||||
|
// This condition handles function pointers followed by more arguments, ie. "), "
|
||||||
|
if (firstComma != -1 && firstCloseBracket < firstComma)
|
||||||
|
depth -= 2;
|
||||||
|
} else if (firstOpenBracket < firstCloseBracket) {
|
||||||
|
depth++;
|
||||||
|
argument += argumentText.Substring(0, firstOpenBracket + 1);
|
||||||
|
} else {
|
||||||
|
depth--;
|
||||||
|
argument += argumentText.Substring(0, firstCloseBracket + 1);
|
||||||
|
}
|
||||||
|
argumentText = originalArgumentText.Substring(argument.Length);
|
||||||
|
}
|
||||||
|
|
||||||
return new CppFnPtrType(types.WordSize, returnType, arguments) {Name = name};
|
// Function with no arguments ie. (*foo)()
|
||||||
|
if (argument.Length > 1) {
|
||||||
|
arguments.Add(argument[..^1].Trim());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Split argument names and types
|
||||||
|
var fnPtrArguments = new List<(string, CppType)>();
|
||||||
|
|
||||||
|
foreach (var argument in arguments) {
|
||||||
|
string name;
|
||||||
|
CppType type;
|
||||||
|
|
||||||
|
// Function pointer
|
||||||
|
if (argument.IndexOf("(") != -1) {
|
||||||
|
type = FromSignature(types, argument);
|
||||||
|
name = type.Name;
|
||||||
|
|
||||||
|
// Non-function pointer
|
||||||
|
} else {
|
||||||
|
name = argument.IndexOf("*") != -1? argument.Substring(argument.LastIndexOf("*") + 1).Trim() :
|
||||||
|
argument.IndexOf(" ") != -1? argument.Substring(argument.LastIndexOf(" ") + 1) : "";
|
||||||
|
type = types.GetType(argument.Substring(0, argument.Length - name.Length));
|
||||||
|
}
|
||||||
|
fnPtrArguments.Add((name, type));
|
||||||
|
}
|
||||||
|
return new CppFnPtrType(types.WordSize, returnType, fnPtrArguments) {Name = fnPtrName};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Output as a named field in a type
|
// Output as a named field in a type
|
||||||
public override string ToFieldString(string name) => $"{ReturnType.Name} (*{name})({string.Join(", ", Arguments.Select(a => a.Type.Name + (a.Name.Length > 0? " " + a.Name : "")))})";
|
public override string ToFieldString(string name) => $"{ReturnType.Name} (*{name})("
|
||||||
|
+ string.Join(", ", Arguments.Select(a => a.Type is CppFnPtrType fn ? fn.ToFieldString(a.Name) : a.Type.Name + (a.Name.Length > 0 ? " " + a.Name : "")))
|
||||||
|
+ ")";
|
||||||
|
|
||||||
// Output as a typedef declaration
|
// Output as a typedef declaration
|
||||||
public override string ToString(string format = "") => "typedef " + ToFieldString(Name) + ";\n";
|
public override string ToString(string format = "") => "typedef " + ToFieldString(Name) + ";\n";
|
||||||
|
|
||||||
// Output as a function signature
|
// Output as a function signature
|
||||||
public string ToSignatureString() => $"{ReturnType.Name} {Name}({string.Join(", ", Arguments.Select(a => a.Type.Name + (a.Name.Length > 0? " " + a.Name : "")))})";
|
public string ToSignatureString() => $"{ReturnType.Name} {Name}("
|
||||||
|
+ string.Join(", ", Arguments.Select(a => a.Type is CppFnPtrType fn? fn.ToFieldString(a.Name) : a.Type.Name + (a.Name.Length > 0? " " + a.Name : "")))
|
||||||
|
+ ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
// A named alias for another type
|
// A named alias for another type
|
||||||
|
|||||||
Reference in New Issue
Block a user