diff --git a/libs/UIX.Asm/InstructionSet.cs b/libs/UIX.Asm/InstructionSet.cs index 30a2819..02c25e3 100644 --- a/libs/UIX.Asm/InstructionSet.cs +++ b/libs/UIX.Asm/InstructionSet.cs @@ -25,10 +25,11 @@ internal static class InstructionSet public static string GetMnemonic(OpCode opCode, OperationType? opType = null) { + if (opCode is OpCode.Operation && opType.HasValue && OperationMnemonicMap.TryGetLeft(opType.Value, out var operationMnemonic)) + return operationMnemonic; + if (MnemonicMap.TryGetLeft(opCode, out var mnemonic)) return mnemonic; - else if (opType.HasValue && OperationMnemonicMap.TryGetLeft(opType.Value, out var operationMnemonic)) - return operationMnemonic; throw new System.ArgumentException($"'{opCode}' is not a known UIXA instruction.", nameof(opCode)); } @@ -163,7 +164,7 @@ internal static class InstructionSet [OpCode.ConstructFromBinary] = [LiteralDataType.TypeIndex, LiteralDataType.Bytes], - [OpCode.Operation] = [LiteralDataType.OpHostIndex, LiteralDataType.Byte], + [OpCode.Operation] = [LiteralDataType.OpHostIndex, LiteralDataType.Operation], [OpCode.Listen] = [LiteralDataType.UInt16, LiteralDataType.Byte, LiteralDataType.UInt16, LiteralDataType.UInt32], [OpCode.DestructiveListen] = [LiteralDataType.UInt16, LiteralDataType.Byte, LiteralDataType.UInt16, LiteralDataType.UInt32, LiteralDataType.UInt32], diff --git a/libs/UIX.Asm/Models/Instructions.cs b/libs/UIX.Asm/Models/Instructions.cs index 77f53e2..5a6f453 100644 --- a/libs/UIX.Asm/Models/Instructions.cs +++ b/libs/UIX.Asm/Models/Instructions.cs @@ -12,10 +12,6 @@ public record Instruction(string Mnemonic, IEnumerable Operands, uint O : this(InstructionSet.GetMnemonic(opCode, operationType), operands, offset) { } - public Instruction(OpCode opCode, IEnumerable operands, uint offset) - : this(opCode, null, operands, offset) - { - } public OpCode OpCode => InstructionSet.MnemonicToOpCode(Mnemonic); @@ -30,4 +26,25 @@ public record Instruction(string Mnemonic, IEnumerable Operands, uint O ? $"{mnemonic} {string.Join(", ", Operands)}" : mnemonic; } + + public static Instruction Create(OpCode opCode, IEnumerable operands, uint offset) + { + OperationType? operationType = null; + + if (opCode is OpCode.Operation) + { + var operandsList = operands.ToList(); + if (operandsList.Count != 2) + throw new System.ArgumentException("Operation instructions must have exactly two operands: the operation host index and the operation type.", nameof(operands)); + + var operandOperationValue = operandsList[1].Value; + if (operandOperationValue is byte or Markup.OperationType) + operationType = (OperationType?)(int?)(byte?)operandOperationValue; + + operandsList.RemoveAt(1); + operands = operandsList; + } + + return new(opCode, operationType, operands, offset); + } } diff --git a/libs/UIX.Asm/Models/Operands.cs b/libs/UIX.Asm/Models/Operands.cs index 7255988..c5927cc 100644 --- a/libs/UIX.Asm/Models/Operands.cs +++ b/libs/UIX.Asm/Models/Operands.cs @@ -14,6 +14,7 @@ public enum LiteralDataType : byte Int32 = 0b0011, Bytes = 0b0100, + Operation = 0b0101, TypeIndex = 0b1000, PropertyIndex = 0b1001, @@ -41,6 +42,9 @@ public record OperandLiteral : Operand public static LiteralDataType ReduceDataType(LiteralDataType dataType) { + if (dataType is LiteralDataType.Operation) + return LiteralDataType.Byte; + return IsIndex(dataType) ? LiteralDataType.UInt16 : dataType; } diff --git a/libs/UIX.Asm/ObjectSection.cs b/libs/UIX.Asm/ObjectSection.cs index d1a6c02..b3a98df 100644 --- a/libs/UIX.Asm/ObjectSection.cs +++ b/libs/UIX.Asm/ObjectSection.cs @@ -133,7 +133,7 @@ public class ObjectSection operands[i] = operand; } - yield return new Instruction(opCode, operands, offset); + yield return Instruction.Create(opCode, operands, offset); } } } diff --git a/libs/UIX.DecompXml/Decompiler.Script.cs b/libs/UIX.DecompXml/Decompiler.Script.cs index 731a47d..8efcf35 100644 --- a/libs/UIX.DecompXml/Decompiler.Script.cs +++ b/libs/UIX.DecompXml/Decompiler.Script.cs @@ -536,7 +536,7 @@ partial class Decompiler private ExpressionSyntax DecompileOperation(Instruction instruction, Stack stack) { - var op = (OperationType)(int)(byte)instruction.Operands.ElementAt(1).Value; + var op = instruction.OperationType.Value; var isUnary = TypeSchema.IsUnaryOperation(op); var opSyntax = OperationToSyntaxKind(op);