// Copyright (c) 2022 bradson // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. using System.Globalization; using System.Linq; using System.Linq.Expressions; using System.Reflection.Emit; using System.Security; using JetBrains.Annotations; using Verse; // ReSharper disable PossibleMultipleEnumeration namespace FisheryLib; [PublicAPI] public static class FishTranspiler { [PublicAPI] public readonly struct Container : IEquatable, IEquatable { public Container(OpCode opcode, object? operand = null) { OpCode = opcode; Operand = operand; } public Container(CodeInstruction instruction) { Guard.IsNotNull(instruction, nameof(instruction)); OpCode = instruction.opcode; Operand = instruction.operand; } public Container(Container container) { OpCode = container.OpCode; Operand = container.Operand; } public override string ToString() => $"{OpCode} {Operand switch { MemberInfo memberInfo => memberInfo.FullDescription(), null => "NULL", _ => Operand.ToString() }}"; [SecuritySafeCritical] public CodeInstruction ToInstruction() => new(OpCode, Operand); public Container Store() => OpCode.LoadsArgument() ? ToStoreArgument() : new(OpCode.LoadsField() || OpCode.StoresField() ? OpCode.ToStoreField() : OpCode.LoadsLocalVariable() || OpCode.StoresLocalVariable() ? OpCode.ToStoreLocalVariable() : OpCode.StoresArgument() ? OpCode : ThrowHelper.ThrowInvalidOperationException( $"Cannot determine Store instruction for {OpCode}"), Operand); public Container Load() => OpCode.StoresArgument() ? ToLoadArgument() : new(OpCode.LoadsField() || OpCode.StoresField() ? OpCode.ToLoadField() : OpCode.LoadsLocalVariable() || OpCode.StoresLocalVariable() ? OpCode.ToLoadLocalVariable() : OpCode.LoadsArgument() ? OpCode : ThrowHelper.ThrowInvalidOperationException( $"Cannot determine Load instruction for {OpCode}"), Operand); private Container ToStoreArgument() => new(OpCode.ToStoreArgument(), GetIndex()); private Container ToLoadArgument() { var index = GetIndex(); return new(GetLoadArgumentOpCode(index), index > 3 ? index : null); } public Container Address() => new(OpCode.ToAddress(), GetIndex()); public CodeInstruction WithLabels(params Label[] labels) => WithLabels((IEnumerable