mirror of
https://github.com/ZuneDev/ZuneUIXTools.git
synced 2026-07-27 13:11:59 -07:00
Add instruction schema and some type information
This commit is contained in:
@@ -62,7 +62,7 @@ public class Disassembler
|
|||||||
|
|
||||||
// Insert a label to mark the start of the object section.
|
// Insert a label to mark the start of the object section.
|
||||||
// In the future, this might use a special directive like `.section object`
|
// In the future, this might use a special directive like `.section object`
|
||||||
yield return new Label("code");
|
yield return new SectionDirective("object");
|
||||||
|
|
||||||
while (reader.CurrentOffset < reader.Size)
|
while (reader.CurrentOffset < reader.Size)
|
||||||
{
|
{
|
||||||
@@ -77,7 +77,7 @@ public class Disassembler
|
|||||||
case OpCode.DiscardValue: // DIS
|
case OpCode.DiscardValue: // DIS
|
||||||
case OpCode.ReturnValue: // RET
|
case OpCode.ReturnValue: // RET
|
||||||
case OpCode.ReturnVoid: // RETV
|
case OpCode.ReturnVoid: // RETV
|
||||||
yield return new Instruction(opCode, []);
|
yield return Instruction.CreateWithSchema(opCode);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// CMD <UInt16>
|
// CMD <UInt16>
|
||||||
@@ -107,7 +107,7 @@ public class Disassembler
|
|||||||
case OpCode.TypeOf: // TYP <typeIndex>
|
case OpCode.TypeOf: // TYP <typeIndex>
|
||||||
case OpCode.PushConstant: // PSHC <constantIndex>
|
case OpCode.PushConstant: // PSHC <constantIndex>
|
||||||
case OpCode.ConstructListenerStorage: // CLIS <listenerCount>
|
case OpCode.ConstructListenerStorage: // CLIS <listenerCount>
|
||||||
yield return new Instruction(opCode, [new(reader.ReadUInt16())]);
|
yield return Instruction.CreateWithSchema(opCode, reader.ReadUInt16());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// CMD <UInt32>
|
// CMD <UInt32>
|
||||||
@@ -116,12 +116,12 @@ public class Disassembler
|
|||||||
case OpCode.JumpIfTruePeek: // JMPT <jumpTo>
|
case OpCode.JumpIfTruePeek: // JMPT <jumpTo>
|
||||||
case OpCode.JumpIfNullPeek: // JMPNP <jumpTo>
|
case OpCode.JumpIfNullPeek: // JMPNP <jumpTo>
|
||||||
case OpCode.Jump: // JMP <jumpTo>
|
case OpCode.Jump: // JMP <jumpTo>
|
||||||
yield return new Instruction(opCode, [new(reader.ReadUInt32())]);
|
yield return Instruction.CreateWithSchema(opCode, reader.ReadUInt32());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// CMD <Int32>
|
// CMD <Int32>
|
||||||
case OpCode.EnterDebugState: // DBG <breakpointIndex>
|
case OpCode.EnterDebugState: // DBG <breakpointIndex>
|
||||||
yield return new Instruction(opCode, [new(reader.ReadInt32())]);
|
yield return Instruction.CreateWithSchema(opCode, reader.ReadInt32());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// CMD <UInt16> <UInt16>
|
// CMD <UInt16> <UInt16>
|
||||||
@@ -129,11 +129,11 @@ public class Disassembler
|
|||||||
case OpCode.ConstructFromString: // CSTR <typeIndex> <stringIndex>
|
case OpCode.ConstructFromString: // CSTR <typeIndex> <stringIndex>
|
||||||
case OpCode.PropertyDictionaryAdd: // PDAD <propertyIndex> <keyIndex>
|
case OpCode.PropertyDictionaryAdd: // PDAD <propertyIndex> <keyIndex>
|
||||||
case OpCode.ConvertType: // CON <toTypeIndex> <fromTypeIndex>
|
case OpCode.ConvertType: // CON <toTypeIndex> <fromTypeIndex>
|
||||||
yield return new Instruction(opCode, [new(reader.ReadUInt16()), new(reader.ReadUInt16())]);
|
yield return Instruction.CreateWithSchema(opCode, reader.ReadUInt16(), reader.ReadUInt16());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OpCode.JumpIfDictionaryContains: // JMPD <propertyIndex> <keyIndex> <jumpTo>
|
case OpCode.JumpIfDictionaryContains: // JMPD <propertyIndex> <keyIndex> <jumpTo>
|
||||||
yield return new Instruction(opCode, [new(reader.ReadUInt16()), new(reader.ReadUInt16()), new(reader.ReadUInt32())]);
|
yield return Instruction.CreateWithSchema(opCode, reader.ReadUInt16(), reader.ReadUInt16(), reader.ReadUInt32());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OpCode.ConstructFromBinary: // CBIN <typeIndex> <object>
|
case OpCode.ConstructFromBinary: // CBIN <typeIndex> <object>
|
||||||
@@ -141,25 +141,28 @@ public class Disassembler
|
|||||||
TypeSchema cbinTypeSchema = _loadResult.ImportTables.TypeImports[cbinTypeIndex];
|
TypeSchema cbinTypeSchema = _loadResult.ImportTables.TypeImports[cbinTypeIndex];
|
||||||
object cbinObject = cbinTypeSchema.DecodeBinary(reader);
|
object cbinObject = cbinTypeSchema.DecodeBinary(reader);
|
||||||
|
|
||||||
yield return new Instruction(opCode, [new(cbinTypeIndex), new(cbinObject)]);
|
yield return Instruction.CreateWithSchema(opCode, cbinTypeIndex, cbinObject);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OpCode.Operation: // OPR <opHostIndex> <operation>
|
case OpCode.Operation: // OPR <opHostIndex> <operation>
|
||||||
var opHostIndex = reader.ReadUInt16();
|
var opHostIndex = reader.ReadUInt16();
|
||||||
var op = (OperationType)reader.ReadByte();
|
var op = (OperationType)reader.ReadByte();
|
||||||
|
|
||||||
yield return new Instruction(opCode, op, [new(opHostIndex)]);
|
yield return Instruction.CreateWithSchema(opCode, opHostIndex, op);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OpCode.Listen: // LIS <listenerIndex> <listenerType> <watchIndex> <handlerOffset>
|
case OpCode.Listen: // LIS <listenerIndex> <listenerType> <watchIndex> <handlerOffset>
|
||||||
case OpCode.DestructiveListen: // LISD <listenerIndex> <listenerType> <watchIndex> <handlerOffset> <refreshOffset>
|
case OpCode.DestructiveListen: // LISD <listenerIndex> <listenerType> <watchIndex> <handlerOffset> <refreshOffset>
|
||||||
List<Operand> lisOperands = [new(reader.ReadUInt16()), new(reader.ReadByte()),
|
var listenerIndex = reader.ReadUInt16();
|
||||||
new(reader.ReadUInt16()), new(reader.ReadUInt32())];
|
var listenerType = reader.ReadByte();
|
||||||
|
var watchIndex = reader.ReadUInt16();
|
||||||
|
var handlerOffset = reader.ReadUInt32();
|
||||||
|
|
||||||
if (opCode == OpCode.DestructiveListen)
|
if (opCode == OpCode.DestructiveListen)
|
||||||
lisOperands.Add(new(reader.ReadUInt32()));
|
yield return Instruction.CreateWithSchema(opCode, listenerIndex, listenerType, watchIndex, handlerOffset, reader.ReadUInt32());
|
||||||
|
else
|
||||||
|
yield return Instruction.CreateWithSchema(opCode, listenerIndex, listenerType, watchIndex, handlerOffset);
|
||||||
|
|
||||||
yield return new Instruction(opCode, lisOperands);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -0,0 +1,171 @@
|
|||||||
|
using Microsoft.Iris.Asm.Models;
|
||||||
|
using Microsoft.Iris.Markup;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Microsoft.Iris.Asm;
|
||||||
|
|
||||||
|
internal static class InstructionSet
|
||||||
|
{
|
||||||
|
public static OperationType OperationMnemonicToType(string mnemonic) => OperationMnemonicMap[mnemonic.ToUpperInvariant()];
|
||||||
|
public static OperationType? TryOperationMnemonicToType(string mnemonic)
|
||||||
|
{
|
||||||
|
return OperationMnemonicMap.TryGetRight(mnemonic.ToUpperInvariant(), out var type)
|
||||||
|
? type : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static OpCode MnemonicToOpCode(string mnemonic)
|
||||||
|
{
|
||||||
|
if (MnemonicMap.TryGetRight(mnemonic, out var opCode))
|
||||||
|
return opCode;
|
||||||
|
else if (OperationMnemonicMap.TryGetRight(mnemonic, out _))
|
||||||
|
return OpCode.Operation;
|
||||||
|
|
||||||
|
throw new System.ArgumentException($"'{mnemonic}' is not a known UIXA instruction.", nameof(mnemonic));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetMnemonic(OpCode opCode, OperationType? opType = null)
|
||||||
|
{
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static readonly DoubleDictionary<string, OperationType> OperationMnemonicMap =
|
||||||
|
[
|
||||||
|
("ADD", OperationType.MathAdd),
|
||||||
|
("SUB", OperationType.MathSubtract),
|
||||||
|
("MUL", OperationType.MathMultiply),
|
||||||
|
("DIV", OperationType.MathDivide),
|
||||||
|
("MOD", OperationType.MathModulus),
|
||||||
|
("NEG", OperationType.MathModulus),
|
||||||
|
("AND", OperationType.LogicalAnd),
|
||||||
|
("ORR", OperationType.LogicalOr),
|
||||||
|
("NOT", OperationType.LogicalNot),
|
||||||
|
("REQ", OperationType.RelationalEquals),
|
||||||
|
("RNE", OperationType.RelationalNotEquals),
|
||||||
|
("RLT", OperationType.RelationalLessThan),
|
||||||
|
("RGT", OperationType.RelationalGreaterThan),
|
||||||
|
("RLE", OperationType.RelationalLessThanEquals),
|
||||||
|
("RGE", OperationType.RelationalGreaterThanEquals),
|
||||||
|
("RIS", OperationType.RelationalIs),
|
||||||
|
("INC", OperationType.PostIncrement),
|
||||||
|
("DEC", OperationType.PostDecrement),
|
||||||
|
];
|
||||||
|
|
||||||
|
internal static readonly DoubleDictionary<string, OpCode> MnemonicMap =
|
||||||
|
[
|
||||||
|
("COBJ", OpCode.ConstructObject),
|
||||||
|
("COBJI", OpCode.ConstructObjectIndirect),
|
||||||
|
("COBP", OpCode.ConstructObjectParam),
|
||||||
|
("CSTR", OpCode.ConstructFromString),
|
||||||
|
("CBIN", OpCode.ConstructFromBinary),
|
||||||
|
("INIT", OpCode.InitializeInstance),
|
||||||
|
("INITI", OpCode.InitializeInstanceIndirect),
|
||||||
|
("LSYM", OpCode.LookupSymbol),
|
||||||
|
("WSYM", OpCode.WriteSymbol),
|
||||||
|
("WSYMP", OpCode.WriteSymbolPeek),
|
||||||
|
("CSYM", OpCode.ClearSymbol),
|
||||||
|
("PINI", OpCode.PropertyInitialize),
|
||||||
|
("PINII", OpCode.PropertyInitializeIndirect),
|
||||||
|
("PLAD", OpCode.PropertyListAdd),
|
||||||
|
("PDAD", OpCode.PropertyDictionaryAdd),
|
||||||
|
("PASS", OpCode.PropertyAssign),
|
||||||
|
("PASST", OpCode.PropertyAssignStatic),
|
||||||
|
("PGET", OpCode.PropertyGet),
|
||||||
|
("PGETP", OpCode.PropertyGetPeek),
|
||||||
|
("PGETT", OpCode.PropertyGetStatic),
|
||||||
|
("MINV", OpCode.MethodInvoke),
|
||||||
|
("MINVP", OpCode.MethodInvokePeek),
|
||||||
|
("MINVT", OpCode.MethodInvokeStatic),
|
||||||
|
("MINVA", OpCode.MethodInvokePushLastParam),
|
||||||
|
("MINVAT", OpCode.MethodInvokeStaticPushLastParam), // Avoid using "LT" as suffix
|
||||||
|
("VTC", OpCode.VerifyTypeCast),
|
||||||
|
("CON", OpCode.ConvertType),
|
||||||
|
("OPR", OpCode.Operation), // Generic operation, allow dynamic invocations of operators
|
||||||
|
("ISC", OpCode.IsCheck),
|
||||||
|
("ASC", OpCode.As),
|
||||||
|
("TYP", OpCode.TypeOf),
|
||||||
|
("PSHN", OpCode.PushNull),
|
||||||
|
("PSHC", OpCode.PushConstant),
|
||||||
|
("PSHT", OpCode.PushThis),
|
||||||
|
("DIS", OpCode.DiscardValue),
|
||||||
|
("RET", OpCode.ReturnValue),
|
||||||
|
("RETV", OpCode.ReturnVoid),
|
||||||
|
("JMPF", OpCode.JumpIfFalse),
|
||||||
|
("JMPFP", OpCode.JumpIfFalsePeek),
|
||||||
|
("JMPTP", OpCode.JumpIfTruePeek),
|
||||||
|
("JMPD", OpCode.JumpIfDictionaryContains),
|
||||||
|
("JMPNP", OpCode.JumpIfNullPeek),
|
||||||
|
("JMP", OpCode.Jump),
|
||||||
|
("CLIS", OpCode.ConstructListenerStorage),
|
||||||
|
("LIS", OpCode.Listen),
|
||||||
|
("LISD", OpCode.DestructiveListen),
|
||||||
|
("DBG", OpCode.EnterDebugState),
|
||||||
|
];
|
||||||
|
|
||||||
|
private static readonly OperandDataType[] Inst_UInt16 = [OperandDataType.UInt16];
|
||||||
|
private static readonly OperandDataType[] Inst_UInt32 = [OperandDataType.UInt32];
|
||||||
|
private static readonly OperandDataType[] Inst_UInt16x2 = [OperandDataType.UInt16, OperandDataType.UInt16];
|
||||||
|
|
||||||
|
public static readonly Dictionary<OpCode, OperandDataType[]> InstructionSchema = new()
|
||||||
|
{
|
||||||
|
[OpCode.InitializeInstanceIndirect] = [],
|
||||||
|
[OpCode.PushNull] = [],
|
||||||
|
[OpCode.PushThis] = [],
|
||||||
|
[OpCode.DiscardValue] = [],
|
||||||
|
[OpCode.ReturnValue] = [],
|
||||||
|
[OpCode.ReturnVoid] = [],
|
||||||
|
|
||||||
|
[OpCode.ConstructObject] = Inst_UInt16,
|
||||||
|
[OpCode.ConstructObjectIndirect] = Inst_UInt16,
|
||||||
|
[OpCode.InitializeInstance] = Inst_UInt16,
|
||||||
|
[OpCode.LookupSymbol] = Inst_UInt16,
|
||||||
|
[OpCode.WriteSymbol] = Inst_UInt16,
|
||||||
|
[OpCode.WriteSymbolPeek] = Inst_UInt16,
|
||||||
|
[OpCode.ClearSymbol] = Inst_UInt16,
|
||||||
|
[OpCode.PropertyInitialize] = Inst_UInt16,
|
||||||
|
[OpCode.PropertyInitializeIndirect] = Inst_UInt16,
|
||||||
|
[OpCode.PropertyListAdd] = Inst_UInt16,
|
||||||
|
[OpCode.PropertyAssign] = Inst_UInt16,
|
||||||
|
[OpCode.PropertyAssignStatic] = Inst_UInt16,
|
||||||
|
[OpCode.PropertyGet] = Inst_UInt16,
|
||||||
|
[OpCode.PropertyGetPeek] = Inst_UInt16,
|
||||||
|
[OpCode.PropertyGetStatic] = Inst_UInt16,
|
||||||
|
[OpCode.MethodInvoke] = Inst_UInt16,
|
||||||
|
[OpCode.MethodInvokePeek] = Inst_UInt16,
|
||||||
|
[OpCode.MethodInvokeStatic] = Inst_UInt16,
|
||||||
|
[OpCode.MethodInvokePushLastParam] = Inst_UInt16,
|
||||||
|
[OpCode.MethodInvokeStaticPushLastParam] = Inst_UInt16,
|
||||||
|
[OpCode.VerifyTypeCast] = Inst_UInt16,
|
||||||
|
[OpCode.IsCheck] = Inst_UInt16,
|
||||||
|
[OpCode.As] = Inst_UInt16,
|
||||||
|
[OpCode.TypeOf] = Inst_UInt16,
|
||||||
|
[OpCode.PushConstant] = Inst_UInt16,
|
||||||
|
[OpCode.ConstructListenerStorage] = Inst_UInt16,
|
||||||
|
|
||||||
|
[OpCode.JumpIfFalse] = Inst_UInt32,
|
||||||
|
[OpCode.JumpIfFalsePeek] = Inst_UInt32,
|
||||||
|
[OpCode.JumpIfTruePeek] = Inst_UInt32,
|
||||||
|
[OpCode.JumpIfNullPeek] = Inst_UInt32,
|
||||||
|
[OpCode.Jump] = Inst_UInt32,
|
||||||
|
|
||||||
|
[OpCode.EnterDebugState] = [OperandDataType.Int32],
|
||||||
|
|
||||||
|
[OpCode.ConstructObjectParam] = Inst_UInt16x2,
|
||||||
|
[OpCode.ConstructFromString] = Inst_UInt16x2,
|
||||||
|
[OpCode.PropertyDictionaryAdd] = Inst_UInt16x2,
|
||||||
|
[OpCode.ConvertType] = Inst_UInt16x2,
|
||||||
|
|
||||||
|
[OpCode.JumpIfDictionaryContains] = [OperandDataType.UInt16, OperandDataType.UInt16, OperandDataType.UInt32],
|
||||||
|
|
||||||
|
[OpCode.ConstructFromBinary] = [OperandDataType.UInt16, OperandDataType.Bytes],
|
||||||
|
|
||||||
|
[OpCode.Operation] = [OperandDataType.UInt16, OperandDataType.Byte],
|
||||||
|
|
||||||
|
[OpCode.Listen] = [OperandDataType.UInt16, OperandDataType.Byte, OperandDataType.UInt16, OperandDataType.UInt32],
|
||||||
|
[OpCode.DestructiveListen] = [OperandDataType.UInt16, OperandDataType.Byte, OperandDataType.UInt16, OperandDataType.UInt32, OperandDataType.UInt32],
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -54,8 +54,30 @@ partial class Lexer
|
|||||||
input = ConsumeWhitespace(input);
|
input = ConsumeWhitespace(input);
|
||||||
|
|
||||||
var operandsResult = Parse.Ref(() => AlphanumericText).DelimitedBy(Parse.Char(',').Token())(input);
|
var operandsResult = Parse.Ref(() => AlphanumericText).DelimitedBy(Parse.Char(',').Token())(input);
|
||||||
operands.AddRange(operandsResult.Value.Select(s => new Operand(s) { Line = line }));
|
|
||||||
input = operandsResult.Remainder;
|
input = operandsResult.Remainder;
|
||||||
|
|
||||||
|
var opCode = InstructionSet.MnemonicToOpCode(identifier);
|
||||||
|
var schema = InstructionSet.InstructionSchema[opCode];
|
||||||
|
|
||||||
|
int schemaIndex = 0;
|
||||||
|
foreach (var operandContent in operandsResult.Value)
|
||||||
|
{
|
||||||
|
var operandType = schema[schemaIndex++];
|
||||||
|
|
||||||
|
object operandValue = operandType switch
|
||||||
|
{
|
||||||
|
OperandDataType.Byte => byte.Parse(operandContent),
|
||||||
|
OperandDataType.UInt16 => ushort.Parse(operandContent),
|
||||||
|
OperandDataType.UInt32 => uint.Parse(operandContent),
|
||||||
|
OperandDataType.Int32 => int.Parse(operandContent),
|
||||||
|
OperandDataType.Bytes or _ => operandContent,
|
||||||
|
};
|
||||||
|
|
||||||
|
operands.Add(new(operandValue, operandType, operandContent)
|
||||||
|
{
|
||||||
|
Line = line,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bodyItem = new Instruction(identifier, operands)
|
bodyItem = new Instruction(identifier, operands)
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
using Microsoft.Iris.Markup;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Microsoft.Iris.Asm.Models;
|
||||||
|
|
||||||
|
[DebuggerDisplay("{ToString()} " + DebuggerDisplay)]
|
||||||
|
public record Instruction(string Mnemonic, IEnumerable<Operand> Operands) : BodyItem
|
||||||
|
{
|
||||||
|
public Instruction(OpCode opCode, OperationType? operationType, IEnumerable<Operand> Operands)
|
||||||
|
: this(InstructionSet.GetMnemonic(opCode, operationType), Operands)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
public Instruction(OpCode opCode, IEnumerable<Operand> Operands)
|
||||||
|
: this(opCode, null, Operands)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public OpCode OpCode => InstructionSet.MnemonicToOpCode(Mnemonic);
|
||||||
|
public OperationType? OperationType => InstructionSet.TryOperationMnemonicToType(Mnemonic);
|
||||||
|
|
||||||
|
public override string ToString() => ToString(true);
|
||||||
|
|
||||||
|
public string ToString(bool uppercase)
|
||||||
|
{
|
||||||
|
var mnemonic = uppercase ? Mnemonic.ToUpperInvariant() : Mnemonic.ToLowerInvariant();
|
||||||
|
return Operands.Any()
|
||||||
|
? $"{mnemonic} {string.Join(", ", Operands)}"
|
||||||
|
: mnemonic;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Instruction CreateParamless(OpCode opCode) => new(opCode, Array.Empty<Operand>());
|
||||||
|
|
||||||
|
public static Instruction CreateUInt16(OpCode opCode, ushort operand1)
|
||||||
|
=> new(opCode, [new(operand1, OperandDataType.UInt16)]);
|
||||||
|
|
||||||
|
public static Instruction CreateUInt32(OpCode opCode, uint operand1)
|
||||||
|
=> new(opCode, [new(operand1, OperandDataType.UInt32)]);
|
||||||
|
|
||||||
|
public static Instruction CreateInt32(OpCode opCode, int operand1)
|
||||||
|
=> new(opCode, [new(operand1, OperandDataType.Int32)]);
|
||||||
|
|
||||||
|
public static Instruction CreateUInt16UInt16(OpCode opCode, ushort operand1, ushort operand2)
|
||||||
|
=> new(opCode, [new(operand1, OperandDataType.UInt16), new(operand2, OperandDataType.UInt16)]);
|
||||||
|
|
||||||
|
public static Instruction CreateWithSchema(OpCode opCode, params object[] operands)
|
||||||
|
{
|
||||||
|
var schema = InstructionSet.InstructionSchema[opCode];
|
||||||
|
if (operands.Length != schema.Length)
|
||||||
|
throw new ArgumentException($"{opCode} requires {schema.Length} operands, got {operands.Length}");
|
||||||
|
|
||||||
|
var operandModels = new Operand[operands.Length];
|
||||||
|
for (int i = 0; i < schema.Length; i++)
|
||||||
|
{
|
||||||
|
var operandValue = operands[i];
|
||||||
|
// Should we verify types?
|
||||||
|
|
||||||
|
operandModels[i] = new(operandValue, schema[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
var operationType = operands.Length > 0 ? operands[0] as OperationType? : null;
|
||||||
|
|
||||||
|
return new Instruction(opCode, operationType, operandModels);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user