115 lines
3.0 KiB
C#
115 lines
3.0 KiB
C#
using System.Reflection.Emit;
|
|
using HarmonyLib;
|
|
|
|
namespace SPTarkov.Reflection.CodeWrapper;
|
|
|
|
/// <summary>
|
|
/// Helper class to generate IL code for transpilers
|
|
/// </summary>
|
|
public class CodeGenerator
|
|
{
|
|
public static List<CodeInstruction> GenerateInstructions(List<Code> codes)
|
|
{
|
|
var list = new List<CodeInstruction>();
|
|
|
|
foreach (Code code in codes)
|
|
{
|
|
list.Add(ParseCode(code));
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
private static CodeInstruction ParseCode(Code code)
|
|
{
|
|
if (!code.HasOperand)
|
|
{
|
|
return new CodeInstruction(code.OpCode) { labels = GetLabelList(code) };
|
|
}
|
|
|
|
if (
|
|
code.OpCode == OpCodes.Ldfld
|
|
|| code.OpCode == OpCodes.Ldflda
|
|
|| code.OpCode == OpCodes.Stfld
|
|
)
|
|
{
|
|
return new CodeInstruction(
|
|
code.OpCode,
|
|
AccessTools.Field(code.CallerType, code.OperandTarget as string)
|
|
)
|
|
{
|
|
labels = GetLabelList(code),
|
|
};
|
|
}
|
|
|
|
if (code.OpCode == OpCodes.Call || code.OpCode == OpCodes.Callvirt)
|
|
{
|
|
return new CodeInstruction(
|
|
code.OpCode,
|
|
AccessTools.Method(code.CallerType, code.OperandTarget as string, code.Parameters)
|
|
)
|
|
{
|
|
labels = GetLabelList(code),
|
|
};
|
|
}
|
|
|
|
if (code.OpCode == OpCodes.Box)
|
|
{
|
|
return new CodeInstruction(code.OpCode, code.CallerType)
|
|
{
|
|
labels = GetLabelList(code),
|
|
};
|
|
}
|
|
|
|
if (
|
|
code.OpCode == OpCodes.Br
|
|
|| code.OpCode == OpCodes.Brfalse
|
|
|| code.OpCode == OpCodes.Brtrue
|
|
|| code.OpCode == OpCodes.Brtrue_S
|
|
|| code.OpCode == OpCodes.Brfalse_S
|
|
|| code.OpCode == OpCodes.Br_S
|
|
)
|
|
{
|
|
return new CodeInstruction(code.OpCode, code.OperandTarget)
|
|
{
|
|
labels = GetLabelList(code),
|
|
};
|
|
}
|
|
|
|
if (code.OpCode == OpCodes.Ldftn)
|
|
{
|
|
return new CodeInstruction(
|
|
code.OpCode,
|
|
AccessTools.Method(code.CallerType, code.OperandTarget as string, code.Parameters)
|
|
)
|
|
{
|
|
labels = GetLabelList(code),
|
|
};
|
|
}
|
|
|
|
if (code.OpCode == OpCodes.Newobj)
|
|
{
|
|
return new CodeInstruction(
|
|
code.OpCode,
|
|
code.CallerType.GetConstructors()
|
|
.FirstOrDefault(x => x.GetParameters().Length == code.Parameters.Length)
|
|
)
|
|
{
|
|
labels = GetLabelList(code),
|
|
};
|
|
}
|
|
|
|
throw new ArgumentException($"Code with OpCode {code.OpCode.ToString()} is not supported.");
|
|
}
|
|
|
|
private static List<Label> GetLabelList(Code code)
|
|
{
|
|
if (code.GetLabel() == null)
|
|
{
|
|
return [];
|
|
}
|
|
|
|
return [(Label)code.GetLabel()];
|
|
}
|
|
}
|